/*
 * Sistema Integrado IFEEP — hoja de estilos
 *
 * CSS plano servido directo desde public/, sin compilación ni dependencias.
 *
 * Estilo: Swiss Modernism (rejilla estricta, un solo color de acento, alto
 * contraste, cero decoración gratuita). Elegido por ser el que mejor encaja
 * con una herramienta interna que se usa a diario: prioriza legibilidad y
 * jerarquía clara por encima del impacto visual.
 *
 * Los colores salen del logo y de la web del instituto (ifeep.edu.pe):
 *
 *   #29A0D7  celeste de marca  2.96:1 sobre blanco  → color de acción
 *   #0D5187  azul profundo     8.25:1 sobre blanco  → panel de acceso
 *   #1776AC  azul anterior     4.97:1 sobre blanco  → ya no se usa
 *
 * ATENCIÓN — EL COLOR DE ACCIÓN NO CUMPLE WCAG PARA TEXTO.
 *
 * El sistema empezó con #0D5187, se aclaró a #1776AC porque el usuario lo veía
 * oscuro, y el 14/08/2026 pasó al celeste #29A0D7 por el mismo motivo. Ese
 * último salto cruza el mínimo: da 2.96:1 tanto como color de letra sobre
 * blanco como con texto blanco encima, y el mínimo son 4.5:1.
 *
 * Se hizo con los números sobre la mesa y es una decisión del dueño del
 * sistema, no un descuido: NO revertirlo por iniciativa propia. La salida
 * para recuperar la accesibilidad sin perder el color de marca sería usar
 * texto oscuro sobre el celeste (4.92:1) en vez de texto blanco.
 *
 * SOLO MODO CLARO. No hay bloque `prefers-color-scheme: dark`: el sistema se
 * ve igual aunque el equipo esté configurado en oscuro, que es lo que se
 * decidió para mantener una sola apariencia institucional. Si algún día se
 * quisiera modo oscuro, no basta con invertir los colores: el azul de acción
 * pierde legibilidad sobre fondo oscuro (1.93:1) y habría que separar el color
 * de relleno del color de texto, además de aclarar los grises.
 */

/* ========================================================================
   Fichas de diseño
   ======================================================================== */

:root {
    /* ---- Marca ---- */
    --marca-azul: #1776AC;
    --marca-azul-oscuro: #13648F;
    --marca-azul-profundo: #0D5187;
    --marca-celeste: #29A0D7;
    --marca-marino: #3D4A5F;
    --marca-tinte: #EFF7FB;

    /* ---- Semánticos: superficies ---- */
    --fondo: #F5F8FA;
    --superficie: #FFFFFF;
    --superficie-alt: #F7FAFC;
    --borde: #E4EAF0;
    --borde-fuerte: #C6D2DE;

    /* ---- Semánticos: texto ---- */
    --texto: #1F2A37;
    --texto-suave: #4A5A6B;
    /* Este gris se aclaró hasta #6B7C8F en una primera versión y daba 3.95:1
       sobre el fondo con tinte, por debajo del mínimo de 4.5. Con #5B6A7C
       pasa en las tres superficies (blanco 5.53, tinte 5.10, alterna 5.28). */
    --texto-tenue: #5B6A7C;
    --texto-sobre-color: #FFFFFF;

    /* ---- Semánticos: acción ----
       El celeste de la marca, a pedido expreso del usuario (14/08/2026), que
       encontraba el azul anterior demasiado apagado. Se le dieron los números
       antes de cambiarlo:

         celeste como texto sobre blanco ....... 2.96:1  (mínimo 4.5)
         texto blanco sobre celeste ............ 2.96:1  (mínimo 4.5)
         texto oscuro sobre celeste ............ 4.92:1  cumple
         el azul anterior #1776AC .............. 4.97:1  cumplía

       Es decir: esto NO cumple WCAG para texto, y es una decisión consciente
       del dueño del sistema, no un descuido. No revertirlo por iniciativa
       propia. Si algún día se quiere recuperar la accesibilidad sin perder el
       color, la salida es texto oscuro sobre el celeste en vez de blanco. */
    --accion: var(--marca-celeste);
    --accion-hover: #1E8CBE;
    --accion-tenue: rgba(41, 160, 215, 0.14);
    --foco: rgba(41, 160, 215, 0.45);

    /* ---- Acción: variantes que sí cumplen WCAG para texto chico ----
       Aprobado el 04/09/2026, con alcance acotado a texto pequeño (enlaces,
       etiquetas, números de página) — no reemplaza a `--accion` como color de
       marca en fondos y acentos grandes, que sigue siendo el celeste de
       siempre.

       `--accion-texto` es el azul anterior (#1776AC, 4.97:1): se usa donde el
       celeste hace de TEXTO sobre un fondo claro. `--texto` (#1F2A37, 4.92:1)
       se reutiliza donde el texto va BLANCO sobre un fondo celeste, siguiendo
       la salida que ya proponía el comentario de arriba. */
    --accion-texto: var(--marca-azul);
    --accion-texto-hover: var(--marca-azul-oscuro);

    /* ---- Panel de acceso: sigue siendo azul a sangre ----
       Contrastes verificados sobre el azul profundo #0D5187:
         blanco    8.25:1  → texto principal
         #B9D6E9   5.45:1  → texto secundario */
    --marca-superficie: var(--marca-azul-profundo);
    --sobre-marca: #FFFFFF;
    --sobre-marca-suave: #B9D6E9;
    --sobre-marca-borde: rgba(255, 255, 255, 0.16);

    /* ---- Menú lateral: claro, con el elemento activo en azul ----
       Es el patrón del dashboard que sirvió de referencia: la barra no compite
       con el contenido y el azul se reserva para señalar dónde estás. */
    --menu-fondo: #FFFFFF;
    --menu-borde: var(--borde);
    --menu-enlace: #4A5A6B;
    --menu-enlace-hover: var(--superficie-alt);
    /* Ya no es una excepción: desde el 14/08/2026 todo el color de acción es
       el celeste de la marca. Ver la nota de --accion más abajo. */
    --menu-activo-fondo: var(--accion);
    --menu-activo-texto: #FFFFFF;

    /* ---- Semánticos: estado ---- */
    --peligro: #A61B1B;
    --peligro-fondo: #FDF2F2;
    --peligro-borde: #F3C6C6;
    --exito: #10633C;
    --exito-fondo: #F0FAF5;
    --exito-borde: #B6E3CC;

    /* ---- Rejilla de 8px (Swiss Modernism) ---- */
    --e1: 4px;
    --e2: 8px;
    --e3: 16px;
    --e4: 24px;
    --e5: 32px;
    --e6: 48px;
    --e7: 64px;

    /* ---- Formas ---- */
    --radio: 10px;
    --radio-sm: 6px;
    --radio-pastilla: 999px;
    --sombra: 0 1px 2px rgba(31, 42, 55, 0.05), 0 10px 30px rgba(31, 42, 55, 0.07);
    --sombra-sutil: 0 1px 2px rgba(31, 42, 55, 0.05);

    /* ---- Tipografía ---- */
    /* Inter para todo. Se mantienen las dos variables —en vez de dejar una
       sola— porque el sistema distingue titulos de texto en varios sitios, y
       asi se puede volver a separar en dos familias sin tocar cada regla. */
    --fuente-titulo: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --fuente-texto: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

    /* ---- Movimiento (150–300ms, según reglas de la skill) ---- */
    --transicion: 180ms cubic-bezier(0.4, 0, 0.2, 1);

    --ancho-pagina: 1080px;

    /* El sistema es solo de modo claro. Esto hace que el navegador pinte
       también sus propios controles (scroll, autocompletado, selectores)
       en claro, aunque el sistema operativo esté en oscuro. */
    color-scheme: light;
}

/* ========================================================================
   Base
   ======================================================================== */

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

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background-color: var(--fondo);
    color: var(--texto);
    font-family: var(--fuente-texto);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
    font-family: var(--fuente-titulo);
    letter-spacing: -0.015em;
    line-height: 1.25;
}

a {
    color: var(--accion);
}

/* Quien prefiera menos movimiento no debería sufrir animaciones. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

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

/* ========================================================================
   Pantallas de acceso — dos paneles
   ========================================================================
   A la izquierda, la marca a sangre sobre el azul institucional. A la
   derecha, el formulario sobre blanco. En pantallas angostas el panel de
   marca se convierte en una franja superior, para no robarle espacio al
   formulario.
   ======================================================================== */

/* Una sola columna centrada.
 *
 * Hasta el 22/08/2026 esto eran dos mitades: a la izquierda un panel azul a
 * sangre con un lema grande («Un solo acceso para todos los sistemas del
 * instituto»), un párrafo de presentación y un círculo decorativo de fondo; a
 * la derecha el formulario. El usuario retiró esos textos, y sin ellos la
 * mitad azul quedaba ocupando media pantalla para no decir nada, así que se
 * retiró entera.
 *
 * Lo que queda es lo justo para entrar: la marca, el formulario y de quién es
 * el sistema. El único color sigue siendo el celeste, ahora reducido al filo
 * superior de la tarjeta. */
.acceso {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--e5) var(--e3);
    background-color: var(--fondo);
}

.acceso__panel {
    width: 100%;
    max-width: 400px;
}

/* El logo a color, el mismo del menú lateral. El anterior era la versión en
   blanco, que solo existía para verse sobre el azul del panel retirado.

   Alineado a la izquierda, no centrado: centrarlo todo es justo lo que hace
   que una pantalla de acceso se vea como una plantilla cualquiera. Contra el
   filo izquierdo de la tarjeta, la marca y el formulario comparten un mismo
   eje y el conjunto se lee como un documento del instituto. */
.acceso__logo {
    display: block;
    width: 118px;
    height: auto;
    margin: 0 0 var(--e4);
}

/* El filo celeste de 3px que llevaba arriba se retiró el 22/08/2026: al
   usuario le sobraba, y tenía razón — la marca ya está en el logo justo
   encima, así que la línea repetía el color sin añadir información. La tarjeta
   se apoya ahora solo en su borde y en el espacio. */
.acceso__cuerpo {
    padding: 36px 32px 32px;
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    /* Sombra sutil y no la grande: la hoja de estilos se rige por "cero
       decoración gratuita", y una tarjeta flotando con sombra marcada es
       precisamente el recurso que sobra aquí. */
    box-shadow: var(--sombra-sutil);
}

.acceso__titulo {
    margin: 0 0 var(--e1);
    font-size: 27px;
    font-weight: 650;
    line-height: 1.2;
    letter-spacing: -0.022em;
}

/* La línea de abajo separa el encabezado del formulario. Es lo que sustituye
   al filo celeste: da estructura a la tarjeta sin meter color, y es la misma
   solución que ya usa `.acceso__opciones` al otro extremo. */
.acceso__subtitulo {
    margin: 0 0 var(--e4);
    padding-bottom: var(--e4);
    border-bottom: 1px solid var(--borde);
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--texto-suave);
}

/* Campos algo más altos que en el resto del sistema. En una pantalla de dos
   campos y un botón, el objetivo no es la densidad —que es lo que persigue el
   panel— sino que cada uno sea un blanco cómodo y la pantalla no se vea
   apretada. */
.acceso .campo__control {
    height: 48px;
}

.acceso__nota {
    margin: var(--e3) 0 0;
    font-size: 13px;
    line-height: 1.6;
    color: var(--texto-tenue);
}

.acceso__opciones {
    margin-top: var(--e4);
    padding-top: var(--e3);
    border-top: 1px solid var(--borde);
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--e2);
}

/* Fuera de la tarjeta y en gris: dice de quién es el sistema, no es parte de
   lo que hay que rellenar. Sobre el mismo eje izquierdo que el logo y el
   formulario. */
.acceso__institucion {
    margin: var(--e3) 0 0;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--texto-tenue);
}

@media (max-width: 600px) {
    .acceso {
        padding: var(--e4) var(--e3);
    }

    .acceso__cuerpo {
        padding: var(--e4) var(--e3);
    }

    .acceso__titulo {
        font-size: 23px;
    }
}

/* ========================================================================
   Formularios
   ======================================================================== */

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

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

.campo__etiqueta {
    font-size: 14px;
    font-weight: 600;
    color: var(--texto);
}

.campo__opcional {
    font-weight: 400;
    color: var(--texto-tenue);
}

.campo__control {
    width: 100%;
    height: 46px;
    padding: 0 14px;
    font-family: inherit;
    font-size: 15px;
    color: var(--texto);
    background-color: var(--superficie);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-sm);
    transition: border-color var(--transicion), box-shadow var(--transicion);
}

.campo__control::placeholder {
    color: var(--texto-tenue);
}

.campo__control:focus {
    outline: none;
    border-color: var(--accion);
    box-shadow: 0 0 0 3px var(--foco);
}

.campo__control--error {
    border-color: var(--peligro-borde);
}

.campo__control--pin {
    height: 64px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 30px;
    font-weight: 600;
    text-align: center;
    letter-spacing: 12px;
    text-indent: 12px; /* compensa el espaciado sobrante del último dígito */
}

.campo__ayuda {
    margin: 0;
    font-size: 13px;
    color: var(--texto-tenue);
}

.campo__error {
    margin: 0;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--peligro);
}

.formulario__acciones {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e3);
}

/* Agrupaciones de opciones (rol, áreas) */
.grupo {
    margin: 0;
    padding: var(--e3);
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
}

.grupo__titulo {
    padding: 0 6px;
    font-family: var(--fuente-titulo);
    font-size: 14px;
    font-weight: 600;
}

.grupo__ayuda {
    margin: 0 0 var(--e2);
    font-size: 13px;
    line-height: 1.6;
    color: var(--texto-tenue);
}

.opcion {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 8px;
    margin: 0 -8px;
    border-radius: var(--radio-sm);
    cursor: pointer;
    transition: background-color var(--transicion);
}

.opcion:hover {
    background-color: var(--superficie-alt);
}

.opcion + .opcion {
    box-shadow: inset 0 1px 0 var(--borde);
}

.opcion input {
    flex: none;
    width: 17px;
    height: 17px;
    margin-top: 3px;
    accent-color: var(--accion);
    cursor: pointer;
}

.opcion__titulo {
    display: block;
    font-size: 14.5px;
    font-weight: 600;
}

.opcion__texto {
    display: block;
    font-size: 13px;
    line-height: 1.5;
    color: var(--texto-tenue);
}

/* ========================================================================
   Botones
   ======================================================================== */

.boton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--e2);
    font-family: var(--fuente-texto);
    font-size: 15px;
    font-weight: 600;
    text-decoration: none;
    border-radius: var(--radio-sm);
    cursor: pointer;
    transition: background-color var(--transicion), border-color var(--transicion),
                color var(--transicion);
}

.boton:focus-visible {
    outline: 2px solid var(--accion);
    outline-offset: 2px;
}

.boton[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

.boton--principal {
    height: 46px;
    width: 100%;
    padding: 0 var(--e4);
    color: var(--texto-sobre-color);
    background-color: var(--accion);
    border: 1px solid var(--accion);
}

.boton--principal:hover:not([disabled]) {
    background-color: var(--accion-hover);
    border-color: var(--accion-hover);
}

/* En el panel los botones no ocupan todo el ancho. */
.boton--compacto {
    width: auto;
    height: 42px;
}

.boton--secundario {
    height: 38px;
    padding: 0 var(--e3);
    font-size: 14px;
    color: var(--texto-suave);
    background-color: transparent;
    border: 1px solid var(--borde-fuerte);
}

.boton--secundario:hover {
    color: var(--texto);
    background-color: var(--superficie-alt);
    border-color: var(--texto-tenue);
}

.boton--enlace {
    padding: 0;
    font-size: 13.5px;
    color: var(--accion);
    background: none;
    border: none;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.boton--enlace:hover {
    color: var(--accion);
    text-decoration-thickness: 2px;
}

.boton--peligro {
    color: var(--peligro);
}

.boton--peligro:hover {
    color: var(--peligro);
    text-decoration-thickness: 2px;
}

/* ========================================================================
   Avisos
   ======================================================================== */

.aviso {
    display: flex;
    gap: 10px;
    margin: 0 0 var(--e3);
    padding: 12px var(--e3);
    font-size: 14.5px;
    border-radius: var(--radio-sm);
    border: 1px solid transparent;
}

.aviso__icono {
    flex: none;
    width: 18px;
    height: 18px;
    margin-top: 3px;
}

.aviso__texto {
    margin: 0;
}

.aviso__texto + .aviso__texto {
    margin-top: var(--e1);
}

.aviso--exito {
    color: var(--exito);
    background-color: var(--exito-fondo);
    border-color: var(--exito-borde);
}

.aviso--error {
    color: var(--peligro);
    background-color: var(--peligro-fondo);
    border-color: var(--peligro-borde);
}

/* ========================================================================
   Menú lateral
   ========================================================================
   Barra clara, con el elemento activo en azul. Se puede plegar para dejar
   solo los iconos y liberar ancho: la preferencia se guarda en el navegador
   y se aplica antes de pintar, para que no se vea un salto al cargar.
   ======================================================================== */

.armazon {
    display: grid;
    grid-template-columns: 252px minmax(0, 1fr);
    min-height: 100vh;
    min-height: 100dvh;
    transition: grid-template-columns var(--transicion);
}

.menu-plegado .armazon {
    grid-template-columns: 76px minmax(0, 1fr);
}

.menu {
    display: flex;
    flex-direction: column;
    gap: var(--e4);
    padding: var(--e3) var(--e2);
    background-color: var(--menu-fondo);
    border-right: 1px solid var(--menu-borde);
}

/* ---- Cabecera: logotipo y botón de plegar ---- */

.menu__cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--e2);
    padding: var(--e2) var(--e2) 0;
}

.menu__logo {
    display: block;
    width: 108px;
    height: auto;
}

/* Plegado se cambia el logotipo completo por la marca circular. */
.menu__logo--marca {
    display: none;
    width: 34px;
}

.menu-plegado .menu__logo {
    display: none;
}

.menu-plegado .menu__logo--marca {
    display: block;
}

.menu-plegado .menu__cabecera {
    flex-direction: column;
    gap: var(--e3);
}

.menu__plegar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    color: var(--texto-tenue);
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radio-sm);
    cursor: pointer;
    transition: background-color var(--transicion), color var(--transicion);
}

.menu__plegar:hover {
    color: var(--accion);
    background-color: var(--accion-tenue);
}

.menu__plegar:focus-visible {
    outline: 2px solid var(--accion);
    outline-offset: 2px;
}

.menu__plegar svg {
    width: 18px;
    height: 18px;
    transition: transform var(--transicion);
}

.menu-plegado .menu__plegar svg {
    transform: rotate(180deg);
}

/* ---- Navegación ---- */

.menu__nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.menu__titulo {
    margin: 0 0 var(--e2);
    padding: 0 var(--e2);
    font-family: var(--fuente-titulo);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--texto-tenue);
}

.menu-plegado .menu__titulo {
    display: none;
}

.menu__enlace {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px var(--e2);
    font-size: 14.5px;
    font-weight: 600;
    color: var(--menu-enlace);
    text-decoration: none;
    border-radius: var(--radio-sm);
    white-space: nowrap;
    transition: background-color var(--transicion), color var(--transicion);
}

.menu__enlace:hover {
    color: var(--texto);
    background-color: var(--menu-enlace-hover);
}

/* La pastilla del elemento en el que estás. Más redondeada que el resto y con
   una sombra suave, para que se despegue de la lista en vez de parecer solo un
   rectángulo pintado. */
.menu__enlace[aria-current='page'] {
    color: var(--menu-activo-texto);
    background-color: var(--menu-activo-fondo);
    border-radius: var(--radio);
    box-shadow: 0 2px 8px rgba(41, 160, 215, 0.35);
}

/* El hover no debe apagar la pastilla activa. */
.menu__enlace[aria-current='page']:hover {
    color: var(--menu-activo-texto);
    background-color: var(--menu-activo-fondo);
}

.menu__icono {
    flex: none;
    width: 18px;
    height: 18px;
}

/* Plegado, el enlace se reduce al icono centrado. El texto no se oculta con
   display:none sino con la técnica de solo-lectores: así el lector de
   pantalla sigue diciendo "Usuarios" y no un botón sin nombre. */
.menu-plegado .menu__enlace {
    justify-content: center;
    padding: 11px var(--e2);
}

.menu-plegado .menu__texto {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---- Pie: usuario y salida ---- */

.menu__pie {
    margin-top: auto;
    padding: var(--e3) var(--e2) 0;
    border-top: 1px solid var(--menu-borde);
}

.menu__usuario {
    margin: 0 0 2px;
    font-size: 14px;
    font-weight: 600;
    color: var(--texto);
}

.menu__rol {
    margin: 0 0 var(--e3);
    font-size: 12.5px;
    color: var(--texto-tenue);
}

.menu-plegado .menu__usuario,
.menu-plegado .menu__rol {
    display: none;
}

.menu__salir {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--e2);
    width: 100%;
    height: 38px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    color: var(--texto-suave);
    background-color: transparent;
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-sm);
    cursor: pointer;
    white-space: nowrap;
    transition: background-color var(--transicion), color var(--transicion),
                border-color var(--transicion);
}

.menu__salir:hover {
    color: var(--peligro);
    background-color: var(--peligro-fondo);
    border-color: var(--peligro-borde);
}

.menu__salir:focus-visible {
    outline: 2px solid var(--accion);
    outline-offset: 2px;
}

.menu__salir svg {
    flex: none;
    width: 16px;
    height: 16px;
}

.menu-plegado .menu__salir span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---- Pantallas angostas: el menú pasa arriba y no se pliega ---- */

@media (max-width: 860px) {
    .armazon,
    .menu-plegado .armazon {
        grid-template-columns: minmax(0, 1fr);
        /* El menú ocupa solo lo que necesita y el contenido se queda con el
           resto. Sin esta línea, la rejilla reparte a partes iguales la altura
           mínima de la pantalla entre las dos filas y el menú se estira. */
        grid-template-rows: auto 1fr;
    }

    .menu,
    .menu-plegado .menu {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        align-content: center;
        gap: 10px var(--e3);
        padding: 10px var(--e3);
        border-right: none;
        border-bottom: 1px solid var(--menu-borde);
    }

    .menu__cabecera,
    .menu-plegado .menu__cabecera {
        flex-direction: row;
        order: 0;
        padding: 0;
    }

    /* Plegar no tiene sentido cuando el menú ya está arriba. */
    .menu__plegar {
        display: none;
    }

    .menu__logo:not(.menu__logo--marca),
    .menu-plegado .menu__logo:not(.menu__logo--marca) {
        display: block;
        width: 92px;
    }

    .menu__logo--marca,
    .menu-plegado .menu__logo--marca {
        display: none;
    }

    .menu__nav,
    .menu-plegado .menu__nav {
        order: 2;
        flex: 1 0 100%;
        flex-direction: row;
        gap: var(--e1);
    }

    .menu__enlace,
    .menu-plegado .menu__enlace {
        justify-content: flex-start;
        padding: 8px var(--e2);
    }

    .menu-plegado .menu__texto {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        clip: auto;
    }

    .menu__titulo,
    .menu-plegado .menu__titulo {
        display: none;
    }

    .menu__pie,
    .menu-plegado .menu__pie {
        order: 1;
        margin: 0;
        padding: 0;
        border: none;
    }

    .menu__usuario,
    .menu__rol,
    .menu-plegado .menu__usuario,
    .menu-plegado .menu__rol {
        display: none;
    }

    .menu__salir,
    .menu-plegado .menu__salir {
        width: auto;
        padding: 0 var(--e3);
    }

    .menu-plegado .menu__salir span {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        clip: auto;
    }
}

/* ========================================================================
   Página
   ======================================================================== */

.pagina {
    width: 100%;
    max-width: var(--ancho-pagina);
    padding: var(--e6) var(--e5) var(--e7);
}

@media (max-width: 860px) {
    .pagina {
        padding: var(--e5) var(--e3) var(--e6);
    }
}

.pagina__cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--e3);
    margin-bottom: var(--e5);
}

.pagina__titulo {
    margin: 0 0 4px;
    font-size: 30px;
    font-weight: 650;
    /* El tracking se cierra a medida que crece el cuerpo: en tamaños grandes
       las letras ya se separan solas y el texto se ve disperso si no. */
    letter-spacing: -0.022em;
}

.pagina__entrada {
    margin: 0;
    font-size: 15px;
    line-height: 1.5;
    color: var(--texto-tenue);
}

.pagina__nota {
    margin: var(--e5) 0 0;
    font-size: 13.5px;
    color: var(--texto-tenue);
}

.seccion__titulo {
    margin: 0 0 var(--e3);
    font-size: 11.5px;
    /* 550 en vez de 600: con Inter variable se puede afinar el peso a medio
       camino, y a este tamaño el 600 se veía pesado junto al texto normal. */
    font-weight: 550;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--texto-tenue);
}

/* ========================================================================
   Tarjetas de área
   ======================================================================== */

.areas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(252px, 1fr));
    gap: var(--e3);
    margin-bottom: var(--e6);
}

.area {
    position: relative;
    padding: var(--e4) var(--e3) var(--e3);
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    transition: border-color var(--transicion), box-shadow var(--transicion);
}

/* La franja celeste superior se quitó el 21/08/2026 a pedido del usuario:
   con el ícono ya coloreado, la tarjeta se identifica sin ella y el conjunto
   queda más limpio. Si alguna vez se quiere recuperar, era un ::before de
   3px de alto anclado arriba, con margen lateral de var(--e3). */

.area:hover {
    border-color: var(--borde-fuerte);
    box-shadow: var(--sombra-sutil);
}

.area__titulo {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--e2);
    margin: 0 0 6px;
    font-size: 16px;
    font-weight: 600;
    letter-spacing: -0.011em;
}

.area__texto {
    margin: 0 0 var(--e3);
    font-size: 14px;
    line-height: 1.55;
    color: var(--texto-suave);
}

.area__pie {
    margin: 0;
    padding-top: var(--e2);
    border-top: 1px solid var(--borde);
    font-size: 12.5px;
    color: var(--texto-tenue);
}

.vacio {
    padding: var(--e5) var(--e4);
    margin-bottom: var(--e6);
    text-align: center;
    font-size: 14.5px;
    color: var(--texto-suave);
    background-color: var(--superficie);
    border: 1px dashed var(--borde-fuerte);
    border-radius: var(--radio);
}

/* ========================================================================
   Ficha de datos
   ======================================================================== */

.ficha {
    margin: 0;
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    overflow: hidden;
}

.ficha__fila {
    display: flex;
    flex-wrap: wrap;
    gap: var(--e2);
    padding: 14px var(--e3);
}

.ficha__fila + .ficha__fila {
    border-top: 1px solid var(--borde);
}

.ficha dt {
    flex: 0 0 150px;
    font-size: 14px;
    color: var(--texto-tenue);
}

.ficha dd {
    margin: 0;
    font-size: 14.5px;
    font-weight: 600;
}

/* ========================================================================
   Tabla
   ======================================================================== */

.tabla-marco {
    overflow-x: auto;
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.tabla {
    width: 100%;
    border-collapse: collapse;
    font-size: 14.5px;
}

.tabla th,
.tabla td {
    /* 12px en vez de 16: con el menú lateral ocupando 252px, la tabla de 8
       columnas ya no entraba en el espacio restante. Un poco más densa es
       además lo apropiado para una tabla de datos. */
    padding: 20px 14px;
    text-align: left;
    /* Arriba y no al centro: con celdas de una linea junto a otras de tres,
       centrar dejaba los datos flotando a alturas distintas en la misma fila. */
    vertical-align: top;
    white-space: nowrap;
}

.tabla thead th {
    padding-top: 14px;
    padding-bottom: 14px;
    font-size: 11.5px;
    font-weight: 550;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--texto-tenue);
    background-color: var(--superficie);
    /* Reforzada el 04/09/2026 (era 1px var(--borde)): con muchas columnas de
       texto gris, la cabecera se perdía contra el resto. Sigue sin fondo ni
       color de más — solo una línea más firme que la ancla arriba. */
    border-bottom: 2px solid var(--borde-fuerte);
}

.tabla tbody tr + tr td {
    /* Reforzada el 04/09/2026 (era var(--borde)): con varias columnas en gris
       claro (Grupo, Cuota, Vendedor, Cerrador, Cobrador) las filas se fundían
       entre sí. Sigue siendo una línea, no una franja — no es el rayado de
       filas alternas que se sacó el 21/08/2026 por sumar ruido. */
    border-top: 1px solid var(--borde-fuerte);
}

.tabla tbody tr {
    transition: background-color var(--transicion);
}

.tabla tbody tr:hover {
    background-color: var(--superficie-alt);
}

.tabla__principal {
    font-weight: 600;
    /* Es el dato por el que se busca una fila: se le deja el color más oscuro
       de la paleta mientras el resto de la fila queda en grises. */
    color: var(--texto);
}

.tabla__tenue {
    color: var(--texto-tenue);
}

/* Números alineados: evita que las columnas bailen entre filas. */
.tabla__numero {
    font-variant-numeric: tabular-nums;
}

/* Celda que sí puede partir en varias líneas. Sin esto, una lista larga de
   áreas ensancha la tabla y empuja la columna de acciones fuera de la vista. */
.tabla td.tabla__ajustable {
    white-space: normal;
    min-width: 150px;
}

.tabla__acciones {
    display: flex;
    align-items: center;
    gap: var(--e3);
}

/* ========================================================================
   Etiquetas de estado
   ======================================================================== */

.etiqueta {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    /* Mas chica y con menos peso que antes (era 12.5px/600). En la tabla de
       pagos van dos o tres por fila y competian con el nombre del alumno,
       que es el dato que de verdad se busca al escanear la lista. */
    padding: 2px 8px;
    font-size: 11.5px;
    font-weight: 550;
    letter-spacing: 0.01em;
    white-space: nowrap;
    border-radius: var(--radio-pastilla);
    border: 1px solid transparent;
}

/* El punto acompaña al color: quien no distingue colores igual lee el estado. */
.etiqueta__punto {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: currentColor;
}

.etiqueta--acento {
    /* var(--accion-texto) y no var(--accion): el celeste como texto sobre
       este fondo tan claro no llega al mínimo de contraste. Ver la nota en
       :root. */
    color: var(--accion-texto);
    background-color: var(--accion-tenue);
    border-color: var(--accion-tenue);
}

.etiqueta--neutra {
    color: var(--texto-tenue);
    background-color: var(--superficie-alt);
    border-color: var(--borde);
}

.etiqueta--exito {
    color: var(--exito);
    background-color: var(--exito-fondo);
    border-color: var(--exito-borde);
}

.etiqueta--baja {
    color: var(--peligro);
    background-color: var(--peligro-fondo);
    border-color: var(--peligro-borde);
}

/* ========================================================================
   Paginación
   ======================================================================== */

.paginacion {
    margin-top: var(--e4);
}

.paginas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--e3);
}

.paginas__resumen {
    margin: 0;
    font-size: 14px;
    color: var(--texto-tenue);
    font-variant-numeric: tabular-nums;
}

.paginas__controles {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--e1);
}

.paginas__enlace {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 44px de alto: es el mínimo para poder pulsarlo con el dedo sin fallar. */
    min-width: 44px;
    height: 44px;
    padding: 0 12px;
    font-size: 14px;
    font-weight: 600;
    /* var(--accion-texto) y no var(--accion): ver la nota en :root. */
    color: var(--accion-texto);
    text-decoration: none;
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    transition: background-color var(--transicion), border-color var(--transicion);
}

.paginas__enlace:hover {
    background-color: var(--superficie-alt);
    border-color: var(--borde-fuerte);
}

/* La página actual: fondo celeste, así que va con texto oscuro y no blanco
   (var(--texto), 4.92:1) por el mismo motivo que la pastilla de arriba. */
.paginas__enlace--actual {
    color: var(--texto);
    background-color: var(--accion);
    border-color: var(--accion);
}

.paginas__enlace--inerte {
    color: var(--texto-tenue);
    background-color: transparent;
    border-color: transparent;
    cursor: default;
}

.paginas__enlace--inerte:hover {
    background-color: transparent;
    border-color: transparent;
}

.paginas__puntos {
    padding: 0 var(--e1);
    color: var(--texto-tenue);
}

/* ========================================================================
   Pantallas angostas
   ======================================================================== */

@media (max-width: 640px) {
    .pagina {
        padding: var(--e5) var(--e3) var(--e6);
    }

    .barra__interior {
        padding: 12px var(--e3);
    }

    .pagina__titulo {
        font-size: 22px;
    }

    .ficha dt {
        flex: 1 1 100%;
    }

    .campo__control--pin {
        font-size: 26px;
        letter-spacing: 8px;
        text-indent: 8px;
    }
}

/* ========================================================================
   Formulario dentro de una tarjeta (alta y edición de usuarios)
   ======================================================================== */

.formulario--tarjeta {
    max-width: 580px;
    padding: var(--e4);
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

/* ========================================================================
   Estado de envío
   ======================================================================== */

.girador {
    flex: none;
    width: 16px;
    height: 16px;
    border: 2px solid rgba(255, 255, 255, 0.35);
    border-top-color: #FFFFFF;
    border-radius: 50%;
    animation: girar 700ms linear infinite;
}

@keyframes girar {
    to {
        transform: rotate(360deg);
    }
}

/* Con movimiento reducido el círculo no gira, pero sigue viéndose: el aviso
   de "algo está pasando" no debe depender de la animación. */
@media (prefers-reduced-motion: reduce) {
    .girador {
        animation: none;
        border-top-color: rgba(255, 255, 255, 0.9);
    }
}

/* Atenúa los campos mientras se envía, para que se note que están bloqueados. */
.formulario--enviando .campo,
.formulario--enviando .grupo {
    opacity: 0.55;
    pointer-events: none;
    transition: opacity var(--transicion);
}

/* El campo del PIN es la excepción: es donde el usuario tiene la vista puesta,
   así que en vez de atenuarse se marca con el color de acción. */
.formulario--enviando .campo:has(.campo__control--verificando) {
    opacity: 1;
}

.campo__control--verificando {
    border-color: var(--accion);
    box-shadow: 0 0 0 3px var(--foco);
}

/* ========================================================================
   Tarjetas de resumen y filtros
   ======================================================================== */

.resumen {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--e3);
    margin-bottom: var(--e4);
}

.resumen__dato {
    padding: var(--e3) var(--e4);
    background-color: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.resumen__etiqueta {
    margin: 0 0 var(--e1);
    font-size: 11.5px;
    font-weight: 550;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--texto-tenue);
}

.resumen__cifra {
    margin: 0;
    font-size: 30px;
    font-weight: 650;
    letter-spacing: -0.02em;
    line-height: 1.1;
    /* Cifras de ancho fijo: evita que los números bailen al recargar. */
    font-variant-numeric: tabular-nums;
    color: var(--texto);
}

/* Versión de una sola línea de ".resumen", para pantallas con una sola
   cifra (Registro de Pagos). Nada de tarjeta: solo el número resaltado
   metido en la oración, así el ojo lo encuentra sin que ocupe una fila
   entera para decir una sola cosa. */
.resumen-linea {
    margin: 0 0 var(--e3);
    font-size: 14.5px;
    color: var(--texto-suave);
}

.resumen-linea__cifra {
    font-size: 17px;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--texto);
}

.filtros {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--e2);
    margin-bottom: var(--e3);
}

/* flex-grow:1 y no 0: con nueve campos, el último de una fila queda solo casi
   siempre — antes se quedaba en 190px con medio ancho de pantalla vacío al
   lado. Así crece para ocupar el resto de su fila, con un tope para que no
   se estire un desplegable chico hasta el borde. */
.filtros__campo {
    flex: 1 1 160px;
    max-width: 260px;
}

.filtros__campo--ancho {
    flex: 2 1 260px;
    max-width: none;
}

.filtros .campo__control {
    /* 38px y no 42px: en una barra con hasta nueve campos, esos 4px de menos
       por fila se notan en el total sin que el campo se sienta apretado. */
    height: 38px;
}

/* Un filtro con valor puesto se distingue de uno vacío: mismo peso que tenía
   "Desde"/"Hasta" antes para todos, ahora reservado para lo que de verdad
   está filtrando en este momento. */
.filtros__campo--activo .campo__control {
    color: var(--texto);
    font-weight: 600;
    background-color: var(--accion-tenue);
    border-color: var(--accion-texto);
}

.filtros__campo--activo .filtros__etiqueta {
    color: var(--accion-texto);
}

/* Los desplegables nativos no muestran su flecha si se les quita la
   apariencia, así que se dibuja una y se deja sitio a la derecha. */
.filtros select.campo__control {
    appearance: none;
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%235B6A7C'%3E%3Cpath d='M5.5 7.5 10 12l4.5-4.5'  stroke='%235B6A7C' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 18px 18px;
    cursor: pointer;
}

@media (max-width: 640px) {
    .filtros__campo,
    .filtros__campo--ancho {
        flex: 1 1 100%;
    }
}


/* ========================================================================
   Objetivos táctiles
   ========================================================================
   En pantallas que se usan con el dedo, todo lo pulsable sube a 44px de
   alto: es el mínimo por debajo del cual se falla el toque con frecuencia.
   Se aplica por tipo de puntero, no por ancho de pantalla, para que una
   tablet grande con dedo también lo reciba.
   ======================================================================== */

@media (pointer: coarse) {
    .boton--secundario,
    .boton--compacto,
    .menu__salir {
        height: 44px;
    }

    .menu__enlace {
        padding-top: 12px;
        padding-bottom: 12px;
    }

    .filtros .campo__control {
        height: 44px;
    }

    /* Los enlaces de texto ganan área alrededor sin moverse de sitio. */
    .boton--enlace,
    .tabla__acciones .boton--enlace {
        padding: 11px 0;
    }
}

/* La tarjeta de resumen que señala un problema se marca en rojo, además de
   con su número: el color solo no basta si el dato es cero. */
.resumen__dato--alerta {
    border-color: var(--peligro-borde);
    background-color: var(--peligro-fondo);
}

.resumen__dato--alerta .resumen__cifra,
.resumen__dato--alerta .resumen__etiqueta {
    color: var(--peligro);
}

/* Nombres de base y otros literales técnicos dentro de un aviso. */
.aviso code {
    padding: 1px 5px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.92em;
    background-color: rgba(31, 42, 55, 0.07);
    border-radius: 4px;
}

/* ========================================================================
   Módulos y tabla de pagos
   ======================================================================== */

/* Tarjeta de módulo de la pantalla de inicio. Es la misma tarjeta de área,
   pero como ahora lleva a algún sitio, se comporta como enlace. */
.area--enlace {
    display: block;
    color: inherit;
    text-decoration: none;
}

.area--enlace:hover .area__titulo,
.area--enlace:focus-visible .area__titulo {
    color: var(--accion);
}

.area__icono {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--accion);
}

/* Etiqueta visible de un filtro (Desde / Hasta). Los desplegables se explican
   solos con su primera opción, pero un campo de fecha en blanco no dice de qué
   fecha habla, así que estos dos sí llevan rótulo a la vista. */
.filtros__etiqueta {
    display: block;
    margin-bottom: 4px;
    font-size: 12px;
    font-weight: 600;
    color: var(--texto-tenue);
}

/* Segunda línea dentro de una celda: el DNI bajo el alumno, la hora bajo la
   fecha, el papel bajo el nombre. Con #5B6A7C sobre blanco da 5.53:1 y sobre
   la fila resaltada 5.28:1, así que cumple el mínimo en ambos casos. */
.tabla__secundario {
    display: block;
    font-size: 12px;
    line-height: 1.5;
    color: var(--texto-tenue);
}

/* El primer secundario se despega del dato principal; los siguientes van
   pegados entre sí. Así cada celda se lee como "un dato y su ficha", en vez
   de como una lista de cosas sueltas del mismo peso. */
.tabla__principal + .tabla__secundario,
.tabla__descripcion + .tabla__secundario {
    margin-top: 5px;
}

/* El concepto del pago llega a pasar de cien caracteres. Se le deja partir en
   varias líneas y se le pone tope de ancho para que no empuje al resto de
   columnas fuera de la pantalla. */
.tabla td.tabla__concepto {
    white-space: normal;
    /* Se estrechó al sacar el grupo a su propia columna (22/08/2026): la
       celda perdió un renglón, así que no necesita tanto ancho y esos píxeles
       le hacen más falta a las columnas nuevas. */
    min-width: 240px;
    max-width: 340px;
    line-height: 1.5;
}

/* El grupo de pago, en columna propia desde el 22/08/2026 (antes iba de
   segundo renglón dentro del concepto).
   Son quince valores fijos que se repiten en las 6.379 filas, y el más largo
   —"PROTECCION C. EQUIPO DANTE"— tiene 26 caracteres: cabe en dos renglones
   con este ancho. Va en gris y a 13px porque es una categoría, no el dato por
   el que se busca la fila. */
.tabla td.tabla__grupo {
    white-space: normal;
    /* 152px y no 140: medido en vivo, con 140 el valor más repetido
       —"PAGOS PROTECCIÓN CIUDADANA", 2.746 filas— se partía en tres renglones
       y estiraba la fila entera. Con 152 entra en dos. */
    min-width: 152px;
    max-width: 176px;
}

/* La marca del grupo, en celeste clarito desde el 04/09/2026 (antes texto
   gris suelto). No se usa `.etiqueta` (la pastilla de VENTA/COBRANZA): esa
   está pensada para una sola línea y con dos renglones —el grupo más largo
   ocupa dos— una pastilla completa se ve rara. Esquinas más chicas
   (var(--radio-sm)) en vez de pastilla resuelven el mismo look en dos líneas. */
.tabla__marca-grupo {
    display: inline-block;
    padding: 3px 8px;
    font-size: 12.5px;
    font-weight: 550;
    line-height: 1.4;
    color: var(--accion-texto);
    background-color: var(--accion-tenue);
    border-radius: var(--radio-sm);
}

/* La cuota, en columna propia desde el 04/09/2026 (antes iba de etiqueta,
   intermitente, debajo del concepto). Valores cortos ("1", "2DA CUOTA",
   "PAGO UNICO"): el más largo real es "2DA Y 3RA CUOTA", 15 caracteres. */
.tabla td.tabla__cuota {
    white-space: normal;
    min-width: 110px;
    max-width: 140px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--texto-suave);
    font-weight: 600;
}

/* El DNI, en columna propia desde el 04/09/2026 (antes iba de segundo
   renglón bajo el alumno). Ocho dígitos fijos: mismo tratamiento tabular que
   el número de operación. */
.tabla td.tabla__dni {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    white-space: nowrap;
    color: var(--texto-suave);
    font-weight: 600;
}

/* El número de operación, también en columna propia desde esa fecha. Se
   compara contra el extracto del banco, y para eso hay que poder recorrer la
   columna de arriba abajo: cifras de ancho fijo y sin partir. La mayoría son
   de 6 a 8 dígitos, alguno llega a 13. */
.tabla th.tabla__operacion,
.tabla td.tabla__operacion {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.tabla td.tabla__operacion {
    color: var(--texto-suave);
}

/* La descripción se recorta a tres renglones. Algunas pasan de 130 caracteres
   y una sola fila se comía la pantalla; el texto completo sigue disponible al
   pasar el ratón por encima (atributo title). Peso 500 y no el 400 por
   defecto: es uno de los tres datos que de verdad importan en la fila (junto
   a Alumno y Pago total), y antes se leía con el mismo peso que un banco o
   un número de operación. */
.tabla__descripcion {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-weight: 500;
    color: var(--texto);
}

/* Observación, en columna propia desde el 04/09/2026 (antes iba de segundo
   renglón dentro de Concepto, mezclada con la descripción del pago — dos
   cosas distintas: una es qué se cobró, la otra es una nota suelta de quien
   registró). Es una nota al margen, así que sigue en cursiva y en el grupo
   "secundario" (ver var(--texto-suave) más abajo), no compite con el
   concepto. */
.tabla td.tabla__observacion-col {
    white-space: normal;
    min-width: 160px;
    max-width: 220px;
}

.tabla__observacion {
    font-style: italic;
}

/* ========================================================================
   Jerarquía: lo importante vs. lo de apoyo
   ======================================================================== */

/* Solo tres cosas se leen "fuertes" en una fila: Alumno y Pago total (negrita,
   con su propio estilo ya de antes) y Concepto (peso 500, arriba). Todo lo
   demás es información de apoyo —prueba del pago, categoría, quién y cuándo—
   y se lee más chico y en gris para no competir por la atención. Antes solo
   una parte de estas columnas tenía este tratamiento (DNI, Cuota, N.º de
   operación, Vendedor/Cerrador/Cobrador); Banco, Fecha, Registró y
   Observación se suman el 04/09/2026 para que el criterio sea el mismo en
   toda la fila. */
.tabla td.tabla__dato-secundario {
    font-size: 13.5px;
    color: var(--texto-suave);
}

/* Celda ajustable más estrecha. La de 150px por defecto está pensada para
   listas de etiquetas; para un nombre de persona o de banco sobra, y con ocho
   columnas esos 30px de más por celda eran los que sacaban la tabla de la
   pantalla. */
.tabla td.tabla__ajustable--estrecho {
    min-width: 118px;
}

/* Banco y Registró comparten esta clase (las dos únicas columnas que la usan):
   pedido explícito de resaltarlas junto con Cuota y DNI. */
.tabla td.tabla__ajustable--estrecho .tabla__valor {
    font-weight: 600;
}

/* Vendedor, cerrador y cobrador, cada uno en su columna. Los nombres del
   instituto son largos, así que se les da sitio para que quepan en uno o dos
   renglones y las tres columnas queden alineadas entre sí. */
.tabla td.tabla__papel {
    min-width: 132px;
    font-size: 13px;
    color: var(--texto-suave);
}

.tabla__marcas {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 8px;
}

/* El importe se alinea a la derecha y con cifras de ancho fijo, que es como se
   comparan las columnas de dinero de un vistazo. */
.tabla th.tabla__monto,
.tabla td.tabla__monto {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.tabla td.tabla__monto {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--texto);
    white-space: nowrap;
}

/* Enlace dentro de una tabla: subrayado siempre, para que no dependa solo del
   color el saber que se puede pulsar. var(--accion-texto) y no var(--accion):
   ver la nota en :root. */
.enlace-tabla {
    color: var(--accion-texto);
    font-weight: 500;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.enlace-tabla:hover {
    color: var(--accion-texto-hover);
}

/* Nombre del área que encabeza su bloque de módulos en el formulario de
   usuarios. Separa los grupos sin convertirse en otro nivel de título. */
.grupo__area {
    margin: var(--e3) 0 var(--e2);
    font-family: var(--fuente-titulo);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--texto-tenue);
}

.grupo__area:first-of-type {
    margin-top: var(--e2);
}

/* Se esconde de verdad, para todo el mundo. Distinto de .oculto-visual, que
   deja el texto para los lectores de pantalla. */
.oculto {
    display: none !important;
}

/* Mientras llegan los resultados filtrados. Se atenúa en vez de vaciarse: así
   la lista no salta ni desaparece a cada pulsación del buscador. */
.resultados--cargando {
    opacity: 0.55;
    transition: opacity var(--transicion);
}

/* Quien prefiere menos movimiento no ve el atenuado, solo el cambio. */
@media (prefers-reduced-motion: reduce) {
    .resultados--cargando {
        opacity: 1;
        transition: none;
    }
}

/* ========================================================================
   Pantallas de tabla ancha
   ======================================================================== */

/* El ancho de 1080px está pensado para leer texto: en una pantalla grande deja
   media pantalla vacía a la derecha, que en una tabla de doce columnas es
   espacio desperdiciado. Estas pantallas se quedan con todo el hueco. */
.pagina--ancha {
    max-width: none;
}

/* La tabla scrollea por dentro y su cabecera se queda fija arriba. Sin esto,
   al bajar por una página de cincuenta pagos se pierde de vista qué columna es
   cada una. El tope de altura es lo que hace que el sticky funcione: necesita
   un contenedor con scroll propio. */
.tabla-marco--fija {
    max-height: calc(100vh - 340px);
    min-height: 320px;
    overflow: auto;
    /* Sin esto, el alto de la tabla recortada seguía sumando al área de scroll
       de la página: el documento medía 4448px cuando el contenido acababa a
       1082px, y se bajaba a un vacío enorme. `contain: paint` le dice al
       navegador que aquí dentro no se pinta nada fuera de la caja, con lo que
       deja de propagar ese desbordamiento hacia arriba. */
    contain: paint;
}

.tabla-marco--fija thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    /* Con tinte celeste desde el 04/09/2026 (antes var(--superficie-alt), un
       gris neutro): en tablas anchas y densas la cabecera es lo que más se
       mira para ubicarse, y le da algo de color de marca sin tocar el texto
       (que sigue siendo gris legible, no celeste). Opaco a la fuerza: debajo
       pasan las filas al scrollear. */
    background-color: var(--marca-tinte);
    /* La línea de cierre se probó en celeste el mismo día y se sacó a pedido
       del usuario — quedaba como una raya delgada suelta, no aportaba.
       Vuelve a var(--borde-fuerte), el mismo refuerzo gris que ya tenía. */
    box-shadow: inset 0 -2px 0 var(--borde-fuerte);
}

/* La barra de desplazamiento propia: la que trae el sistema operativo es
   delgada y gris, fácil de no ver — sobre todo en Windows, donde no hay gesto
   de trackpad y hay que engancharla con el mouse. Más ancha y en celeste, se
   nota que existe y de qué color es la marca. Solo Chrome/Edge/Safari
   (`::-webkit-scrollbar`) y Firefox (`scrollbar-width/color`) tienen forma de
   estilarla; donde no, queda la barra del sistema, sin romper nada. */
.tabla-marco--fija {
    scrollbar-width: auto;
    scrollbar-color: var(--accion) var(--superficie-alt);
}

.tabla-marco--fija::-webkit-scrollbar {
    width: 14px;
    height: 14px;
}

.tabla-marco--fija::-webkit-scrollbar-track {
    background: var(--superficie-alt);
}

.tabla-marco--fija::-webkit-scrollbar-thumb {
    background-color: var(--accion);
    border-radius: var(--radio-pastilla);
    /* El "marco" claro alrededor del pulgar es lo que le da el grosor
       generoso sin que se vea pegado al borde de la pista. */
    border: 3px solid var(--superficie-alt);
}

.tabla-marco--fija::-webkit-scrollbar-thumb:hover {
    background-color: var(--accion-hover);
}

/* ========================================================================
   Arrastrar la tabla ancha con el mouse (public/js/tabla-arrastre.js)
   ======================================================================== */

/* La celda entera invita a agarrar y arrastrar... */
.tabla-marco--fija tbody td,
.tabla-marco--fija thead th {
    cursor: grab;
}

/* ...pero el dato en sí adentro vuelve al cursor normal, para no sugerir que
   se puede arrastrar desde ahí cuando lo que se puede es seleccionar texto. */
.tabla-marco--fija .tabla__valor,
.tabla-marco--fija .tabla__principal,
.tabla-marco--fija .tabla__secundario,
.tabla-marco--fija .tabla__descripcion,
.tabla-marco--fija .tabla__marca-grupo,
.tabla-marco--fija .tabla__tenue {
    cursor: auto;
}

/* Mientras se arrastra de verdad: cursor de "agarrado" en toda la tabla (aunque
   el mouse pase sobre un dato) y sin selección de texto accidental. */
.tabla-marco--fija.tabla-marco--arrastrando,
.tabla-marco--fija.tabla-marco--arrastrando * {
    cursor: grabbing !important;
}

.tabla-marco--fija.tabla-marco--arrastrando {
    user-select: none;
}

/* El rayado de filas alternas se quitó el 21/08/2026: con las filas ya más
   bajas, sumaba ruido en vez de ayudar a seguir el renglón. Queda solo el
   realce al pasar el ratón, que sí señala una fila concreta. */
.tabla--rayada tbody tr:hover {
    background-color: var(--superficie-alt);
}

/* La primera columna se queda fija al desplazar la tabla a lo ancho.
 *
 * Con doce columnas hay unos 500px que solo se ven scrolleando: al llegar a
 * "Cobrador" o "Registró" se había perdido de vista de qué alumno era la
 * fila, y había que volver atrás para comprobarlo. Fijando el alumno, el
 * nombre acompaña siempre al dato que se está mirando.
 *
 * Es lo que compensa el coste de haber añadido dos columnas: la tabla se
 * desplaza más, pero deja de perderse la referencia al hacerlo. */
.tabla--primera-fija th:first-child,
.tabla--primera-fija td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    /* Opaco a la fuerza: por debajo pasan las demás columnas al desplazar. */
    background-color: var(--superficie);
    /* Filo derecho con `inset` y no un `border`: un borde de verdad sumaría
       ancho a la celda y descuadraría la alineación con la cabecera. */
    box-shadow: inset -1px 0 0 var(--borde);
}

/* Sin esto, la fila se resalta al pasar el ratón menos la celda fija, que se
   quedaría blanca y partiría el realce en dos. */
.tabla--primera-fija tbody tr:hover td:first-child {
    background-color: var(--superficie-alt);
}

/* La esquina: esa celda es a la vez cabecera pegada arriba y columna pegada a
   la izquierda, así que tiene que quedar por encima de las otras dos. Mismo
   tinte celeste que el resto de la cabecera, para que no se note la costura. */
.tabla-marco--fija .tabla--primera-fija thead th:first-child {
    z-index: 3;
    background-color: var(--marca-tinte);
}

/* Pie de la tabla: tamaño de página a la izquierda, paginación a la derecha. */
.pie-tabla {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--e3);
    margin-top: var(--e3);
}

.pie-tabla__tamano {
    display: flex;
    align-items: center;
    gap: var(--e2);
    font-size: 13px;
    color: var(--texto-tenue);
}

.pie-tabla__paginas .paginacion,
.pie-tabla__paginas .paginas {
    margin: 0;
}

/* Grupo de opciones excluyentes, en pastilla. Se usa para las filas por
   página; la activa se distingue por fondo y por peso, no solo por color. */
.segmentado {
    display: inline-flex;
    padding: 2px;
    background-color: var(--superficie-alt);
    border: 1px solid var(--borde);
    border-radius: var(--radio-pastilla);
}

.segmentado__opcion {
    min-width: 38px;
    padding: 4px 10px;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    text-align: center;
    text-decoration: none;
    color: var(--texto-suave);
    border-radius: var(--radio-pastilla);
    transition: background-color var(--transicion), color var(--transicion);
}

.segmentado__opcion:hover {
    color: var(--accion-texto);
    background-color: var(--superficie);
}

/* Este comentario decía "blanco sobre el azul de acción: 4.97:1", pero esa
   cifra era del azul anterior (#1776AC). Con el celeste actual el blanco
   sobre este fondo da 2.96:1 — no cumple. Corregido el 04/09/2026 pasando el
   texto a var(--texto), que sobre este celeste sí da 4.92:1. */
.segmentado__opcion--activa,
.segmentado__opcion--activa:hover {
    font-weight: 600;
    color: var(--texto);
    background-color: var(--accion);
}

/* Enlace del voucher con su ícono delante. */
.enlace-tabla--icono {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

/* ========================================================================
   Códigos de respaldo
   ======================================================================== */

/* El recuadro que se entrega impreso. Se diseña para el papel tanto como para
   la pantalla: nadie va a teclear un código de emergencia desde el navegador,
   lo va a leer de una hoja, probablemente con prisa. */
.codigos {
    margin-bottom: var(--e4);
    padding: var(--e4);
    background-color: var(--superficie);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio);
}

.codigos__lista {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--e2);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: codigo;
}

/* Monoespaciada y con mucho espacio entre letras: en un papel impreso hay que
   poder distinguir un carácter de otro sin dudar. El alfabeto ya evita los
   pares que se confunden (0/O, 1/I/L), pero el tipo de letra remata el
   trabajo. El número delante permite comprobar de un vistazo que están los
   ocho y saber cuál se ha usado ya. */
.codigos__codigo {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 17px;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: var(--texto);
    background-color: var(--superficie-alt);
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
}

.codigos__codigo::before {
    counter-increment: codigo;
    content: counter(codigo);
    flex: none;
    width: 20px;
    font-family: var(--fuente-titulo);
    font-size: 12px;
    font-weight: 550;
    letter-spacing: 0;
    color: var(--texto-tenue);
}

.codigos__pie {
    margin: var(--e3) 0 0;
    padding-top: var(--e3);
    border-top: 1px solid var(--borde);
    font-size: 12px;
    color: var(--texto-tenue);
}

/* Al imprimir se deja solo el recuadro: sin menú lateral, sin avisos y sin
   botones. Una hoja con los ocho códigos y de quién son. */
@media print {
    .menu,
    .pagina__cabecera,
    .aviso,
    .formulario__acciones {
        display: none !important;
    }

    .armazon,
    .pagina {
        display: block;
        max-width: none;
        margin: 0;
        padding: 0;
    }

    .codigos {
        border-color: #000;
    }
}

/* La salida cuando el correo del PIN no llega. Separada de las otras opciones
   y en gris: es lo que se busca cuando ya nada más ha servido, no una
   alternativa que ofrecer de entrada. */
.acceso__nota--respaldo {
    margin-top: var(--e3);
    padding-top: var(--e3);
    border-top: 1px solid var(--borde);
    text-align: center;
}

/* Los códigos se leen de un papel y se teclean de una vez. Se separan las
   letras y se centran, igual que el PIN, para poder comprobar sobre la marcha
   que lo escrito coincide con lo impreso. */
.campo__control--respaldo {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 20px;
    font-weight: 600;
    text-align: center;
    letter-spacing: 4px;
    text-transform: uppercase;
}

/* La casilla de "no volver a pedirme el código". Va dentro del formulario de
   acceso, donde `.opcion` sola quedaba demasiado suelta. */
.opcion--recordar {
    align-items: flex-start;
    margin: 0;
    padding: 12px;
    background-color: var(--superficie-alt);
    border: 1px solid var(--borde);
    border-radius: var(--radio-sm);
    font-size: 14px;
    line-height: 1.45;
}

.opcion--recordar:hover {
    background-color: var(--superficie-alt);
    border-color: var(--borde-fuerte);
}

/* La explicación de qué implica marcarla. Va debajo y en gris: quien ya sabe
   lo que hace no necesita leerla, y quien no, sí. */
.opcion__ayuda {
    display: block;
    margin-top: 4px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--texto-tenue);
}

/* ========================================================================
   Modal de exportar (Registro de Pagos)
   ======================================================================== */

/* <dialog> nativo: trae su propio posicionamiento centrado y su ::backdrop
   del navegador, así que casi todo lo que hace falta es quitarle el borde
   por defecto y ponerle el estilo del sistema. */
.dialogo {
    width: min(560px, calc(100vw - 48px));
    max-height: min(680px, calc(100vh - 64px));
    padding: 0;
    border: none;
    border-radius: var(--radio);
    background-color: var(--superficie);
    box-shadow: var(--sombra);
}

/* [open] y no ".dialogo" a secas: un <dialog> cerrado trae "display: none"
   del propio navegador, y un selector de clase sin ese calce se lo pisa —
   quedaba SIEMPRE visible, en el sitio exacto del HTML donde está escrito
   (sin fondo oscuro, sin centrar, arrastrado por el scroll de la página, sin
   depender para nada de showModal()). Este fue el bug real detrás de "el
   modal se ve movido/como colgado" — no tenía que ver ni con la descarga ni
   con formularios.js, aunque esos dos arreglos también quedan bien puestos. */
.dialogo[open] {
    /* El propio <dialog> no scrollea: lo hace su contenido, así el pie con
       los botones puede quedar fijo abajo mientras la lista de arriba sí
       se desplaza. */
    display: flex;
    flex-direction: column;
}

.dialogo::backdrop {
    background-color: rgba(31, 42, 55, 0.45);
}

.dialogo__cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--e3);
    padding: var(--e4) var(--e4) 0;
}

.dialogo__titulo {
    margin: 0;
    font-size: 19px;
    font-weight: 650;
    letter-spacing: -0.01em;
}

.dialogo__cerrar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    color: var(--texto-tenue);
    background: none;
    border: none;
    border-radius: var(--radio-sm);
    cursor: pointer;
    transition: background-color var(--transicion), color var(--transicion);
}

.dialogo__cerrar:hover {
    color: var(--texto);
    background-color: var(--superficie-alt);
}

.dialogo__cerrar svg {
    width: 16px;
    height: 16px;
}

.dialogo__entrada {
    margin: var(--e2) var(--e4) 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--texto-tenue);
}

.dialogo__formulario {
    display: flex;
    flex-direction: column;
    min-height: 0;
    /* El formulario entero es el que crece hasta el alto del <dialog>, para
       que el pie quede pegado abajo y solo scrollee la lista de opciones. */
    flex: 1;
}

.dialogo__opciones {
    overflow-y: auto;
    padding: var(--e3) var(--e4);
}

.dialogo__campos {
    /* Alineado con el texto de la opción (17px del radio + 10px de gap del
       .opcion), para que se lea como parte de la opción marcada y no como
       un campo suelto. */
    margin: 2px 0 var(--e2) 27px;
    padding: var(--e2) var(--e3);
    background-color: var(--superficie-alt);
    border-radius: var(--radio-sm);
}

.dialogo__campos .filtros__etiqueta {
    margin-top: var(--e2);
}

.dialogo__campos .filtros__etiqueta:first-child {
    margin-top: 0;
}

.dialogo__campos-fila {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--e2);
}

.dialogo__grupos {
    display: flex;
    flex-direction: column;
    max-height: 180px;
    overflow-y: auto;
}

.grupo--anidado {
    margin-top: var(--e2);
    padding: var(--e2);
}

.opcion--chica .opcion__titulo {
    font-size: 13.5px;
    font-weight: 550;
}

.opcion--chica .opcion__texto {
    font-size: 12px;
}

.campo__control--textarea {
    height: auto;
    padding: 10px 14px;
    font-family: var(--fuente-texto);
    resize: vertical;
}

.dialogo__pie {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--e2);
    padding: var(--e3) var(--e4);
    border-top: 1px solid var(--borde);
}

@media (max-width: 480px) {
    .dialogo__campos-fila {
        grid-template-columns: 1fr;
    }
}
