/* Control de Vacaciones — hoja de estilo propia.

   Escrita a mano: no hay framework, no hay npm y no hay paso de build. Lo que se
   ve aquí es lo que se sirve.

   OJO: el CSP lleva «style-src 'self'», que también gobierna style-src-attr, así
   que un atributo style="…" en el markup queda bloqueado. Todo va en clases.

   ---------------------------------------------------------------------------
   LA PALETA ES LA DEL GRUPO TÉCNICA DIELÉCTRICA
   ---------------------------------------------------------------------------

   Tomada de `SistemaGTD.Web`, que es de la misma empresa, y de su
   `docs/brand/brand-guidelines.md`, que es la guía de la empresa y la autoridad.
   Azul marino la estructura, naranja el acento — nunca al revés: esta aplicación
   se mira ocho horas al día.

   **Los dos naranjas no son dos tonos, son dos contratos.** Es lo único de
   esta hoja que se rompe callado:

     --marca        #fc5000  la marca. Superficies que NO llevan texto encima.
                             Blanco sobre este color da 3.15:1 y REPRUEBA WCAG AA.
     --marca-tinta  #a33f0f  el que sí lleva etiqueta. 6.41:1 sobre blanco y
                             5.88:1 sobre el fondo de página.

   No se «arregla» un control deslavado igualando el color del logo. Esa es la
   equivocación que esta nota existe para evitar, y viene copiada del encabezado
   de la hoja de la otra aplicación junto con los colores.

   **Son dos y no tres, y ahí nos separamos de la otra aplicación a propósito.**
   Ella guarda un naranja intermedio (#c74e14, 4.64:1) para lo que lleva etiqueta,
   y le funciona porque sus superficies son blanco puro. Aquí el fondo de página
   es #f4f5f7, donde ese mismo color da 4.25:1 y no pasa. Un token cuyo contrato
   es «depende de qué haya debajo» es el que se va a usar mal, así que no existe.

   Las razones están medidas, no juzgadas: `HojaDeEstiloTests` calcula cada par
   que lleva texto en los dos temas y falla si alguno baja de 4.5:1.

   ---------------------------------------------------------------------------
   EL TEMA SON TRES ESTADOS, NO DOS
   ---------------------------------------------------------------------------

   «Automático» no es lo mismo que «claro»: sigue a prefers-color-scheme. Por eso
   los colores no se pueden declarar «claro en :root, oscuro en la media query» a
   secas — haría falta que la clase .tema-claro volviera a escribir toda la paleta
   para poder ganarle a la media query.

   El orden que sí funciona, y es el de abajo:

     1. :root                              la paleta clara, y el valor por omisión
     2. @media (prefers-color-scheme:dark) la oscura, pero solo si NO hay .tema-claro
     3. :root.tema-oscuro                  la oscura, gane lo que gane el sistema

   Así «automático» no lleva clase ninguna, y cada una de las otras dos escribe la
   paleta una sola vez. La clase la pone el servidor en <html>, antes de que se
   escriba la respuesta: ver Presentacion/Tema.cs, y por qué no es un script que
   lee localStorage después de pintar.

   **Un color escrito una vez en lugar de tres no falla: convierte «automático» en
   «claro» para todo el que nunca tocó el interruptor**, que son casi todos.
   `HojaDeEstiloTests` lo custodia. */

:root {
    color-scheme: light;

    /* Neutros */
    --fondo: #f4f5f7;
    --fondo-elevado: #ffffff;
    --fondo-hundido: #eef0f3;
    --texto: #1b2430;
    --texto-tenue: #5c6673;
    --borde: #d6dce4;

    /* Dónde se escribe.

       NO es --fondo, y esa era la falla: en /contactos/editar el formulario va
       directo sobre el fondo de la página, así que la caja y la página eran
       exactamente el mismo #f4f5f7 y solo un borde de #d6dce4 decía dónde empezaba
       una.

       Un solo color de relleno no alcanza, porque un campo aparece sobre DOS
       superficies —la página y lo elevado, que son la tarjeta y la barra— y un
       relleno que contraste con las dos tendría que salirse del rango de ambas. Así
       que se reparten el trabajo: sobre la página lo dice el relleno (blanco sobre
       #f4f5f7), y sobre lo elevado lo dice el borde, que por eso vale 3.04:1 contra
       el blanco. Es el mínimo de la 1.4.11 para el contorno de un control, medido.
       No es el borde decorativo --borde; es el que hace que el campo exista. */
    --campo: #ffffff;
    --campo-borde: #8a95a3;

    /* Lo interactivo: enlaces, foco, la entrada activa del riel, el botón
       principal. Azul marino, que es la estructura de la marca. NO naranja: el
       naranja es el acento y esta aplicación se mira ocho horas al día. */
    --acento: #1e2d3b;
    --acento-tenue: #e6eaf0;
    --sobre-acento: #ffffff;

    /* El armazón: el riel y el encabezado. */
    --estructura: #1e2d3b;
    --estructura-honda: #1b2430;
    --sobre-marca: #ffffff;
    --sobre-marca-tenue: #b8c4d4;

    /* Los tres naranjas, y sus contratos. Ver el encabezado. */
    --marca: #fc5000;
    --marca-tinta: #a33f0f;

    --destacado: #edcd1f;

    --alerta: #b3261e;

    /* La sombra que dice «aquí sigue la tabla». Translúcida y no un gris fijo,
       para que sirva encima de --fondo y de --fondo-elevado igual. */
    --sombra-scroll: rgba(27, 36, 48, 0.28);

    --tipo-titular: "Poppins", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;

    --radio-chico: 3px;
    --radio: 5px;
    --espacio: 1rem;
    --riel: 15rem;
    --riel-angosto: 3.5rem;
}

@media (prefers-color-scheme: dark) {
    :root:not(.tema-claro) {
        color-scheme: dark;

        /* Derivada del azul marino de la marca, no de grises: #1e2d3b es la
           superficie elevada tal cual, así que el riel es literalmente el mismo
           color en los dos temas. */
        --fondo: #151c25;
        --fondo-elevado: #1e2d3b;
        --fondo-hundido: #10161d;
        --texto: #e8ecf2;
        --texto-tenue: #a2b1c2;
        --borde: #33455a;

        /* En oscuro sube en vez de bajar: #26374a es más claro que la página
           (#151c25) y que la tarjeta (#1e2d3b), así que el relleno se distingue de
           las dos. El borde vale 4.4:1 contra la página y 3.6:1 contra la tarjeta. */
        --campo: #26374a;
        --campo-borde: #6b83a0;

        /* El marino no se ve sobre el marino: lo interactivo sube a un azul claro. */
        --acento: #8ab4e0;
        --acento-tenue: #223247;
        --sobre-acento: #10161d;

        --estructura: #1b2430;
        --estructura-honda: #10161d;
        --sobre-marca: #ffffff;
        --sobre-marca-tenue: #b8c4d4;

        /* El naranja de superficie es el mismo; los dos que llevan etiqueta suben
           en vez de bajar, que es la trampa al revés. */
        --marca: #fc5000;
        --marca-tinta: #ff8a52;

        --destacado: #edcd1f;

        --sombra-scroll: rgba(0, 0, 0, 0.55);
        --alerta: #f08a80;
    }
}

:root.tema-oscuro {
    color-scheme: dark;

    /* Derivada del azul marino de la marca, no de grises: #1e2d3b es la
       superficie elevada tal cual, así que el riel es literalmente el mismo
       color en los dos temas. */
    --fondo: #151c25;
    --fondo-elevado: #1e2d3b;
    --fondo-hundido: #10161d;
    --texto: #e8ecf2;
    --texto-tenue: #a2b1c2;
    --borde: #33455a;

    --campo: #26374a;
    --campo-borde: #6b83a0;

    /* El marino no se ve sobre el marino: lo interactivo sube a un azul claro. */
    --acento: #8ab4e0;
    --acento-tenue: #223247;
    --sobre-acento: #10161d;

    --estructura: #1b2430;
    --estructura-honda: #10161d;
    --sobre-marca: #ffffff;
    --sobre-marca-tenue: #b8c4d4;

    /* El naranja de superficie es el mismo; los dos que llevan etiqueta suben
       en vez de bajar, que es la trampa al revés. */
    --marca: #fc5000;
    --marca-tinta: #ff8a52;

    --destacado: #edcd1f;

    --sombra-scroll: rgba(0, 0, 0, 0.55);
    --alerta: #f08a80;
}

/* --- La tipografía: DOS pilas, y la división es a propósito -----------------

   Poppins es la tipografía de la empresa y va vendida, no traída de un CDN: tres
   woff2 de 24 KB en total bajo licencia SIL OFL, en wwwroot/lib/poppins/ con su
   VERSION.txt. El CSP lleva «font-src 'self'» y esto no le pide ninguna excepción
   -- si algo pidiera una, sería la señal de que se bajó de un CDN por error.

   --tipo-titular  lo que se OJEA: títulos, la marca, el riel.
   (la del body)   lo que se MIRA FIJO: datos de tabla, controles, etiquetas. Se
                   queda en la pila del sistema, porque esta aplicación es una
                   tabla que se lee ocho horas al día y Segoe UI es la cara que
                   Windows afinó justo para eso. La guía de la empresa pide la
                   misma división con las mismas palabras.

   Solo pesos de titular: no hay 400 ni cursiva. Pedirle a CSS un peso que no está
   aquí hace que el navegador lo finja, que se ve peor que no tenerlo. */

@font-face {
    font-family: "Poppins";
    src: url("../lib/poppins/poppins-500.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Poppins";
    src: url("../lib/poppins/poppins-600.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Poppins";
    src: url("../lib/poppins/poppins-700.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

body {
    margin: 0;
    background: var(--fondo);
    color: var(--texto);
    font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
    font-size: 15px;
    line-height: 1.5;
}

h1,
h2,
h3 {
    font-family: var(--tipo-titular);
}

a {
    color: var(--acento);
}

/* Marino y texto son casi el mismo color -- 14:1 los dos contra el fondo --, así
   que en una tabla de 312 nombres el enlace se distingue por el subrayado y por
   esto. Es el naranja de la marca, y es lo mismo que hace SistemaGTD. */
a:hover,
a:focus-visible {
    color: var(--marca-tinta);
}

/* Primer elemento enfocable del documento. Claudia va a capturar con el teclado
   durante horas; llegar al contenido sin tabular por trece entradas del riel es
   la diferencia entre un atajo y una molestia. */
.salto {
    position: absolute;
    left: -9999px;
}

/* Visible solo para un lector de pantalla. La etiqueta del buscador vive aquí:
   la caja lleva un placeholder, que no es una etiqueta. */
.solo-lectores {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.salto:focus {
    position: static;
    display: inline-block;
    margin: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--acento-tenue);
    border-radius: var(--radio);
}

/* --- El armazón: riel a la izquierda, todo lo demás a la derecha ------------ */

.armazon {
    display: grid;
    grid-template-columns: var(--riel) minmax(0, 1fr);
    min-height: 100vh;
}

/* El riel encogido a una tira de iconos, guardado por usuario como el tema.
   Recupera 184px de los 240 que el riel se lleva de cada pantalla -- que en la
   hoja anual son casi dos meses de columnas más. Ver Presentacion/Riel.cs para
   por qué son dos estados y no tres, y por qué la clase la pone el servidor. */
/* ⚠ SOLO EN DOS COLUMNAS, Y ESO NO ES ORDEN.

   Encoger el riel es una idea de la disposición de dos columnas. Por debajo de
   56rem el riel ya se acostó solo, y ahí estas reglas hacían dos cosas malas a la
   vez: `.armazon.riel-angosto` gana por especificidad a `.armazon` de la media
   query -- una @media no agrega especificidad --, así que el armazón se quedaba
   en DOS COLUMNAS con un riel de 3.5rem, y dentro de esa tira de 56px iban las
   trece áreas puestas en fila. El menú desaparecía. Lo reportó el usuario con
   estas palabras: «solo esconde el menú y no puedo ver nada».

   `not all and (max-width: 56rem)` es el complemento exacto de la media query de
   abajo -- sin hueco en el límite, que es lo que dejaría un `min-width: 56.01rem`.
   La preferencia se sigue guardando: al volver a una ventana ancha, vuelve. */
@media not all and (max-width: 56rem) {
    .armazon.riel-angosto {
        grid-template-columns: var(--riel-angosto) minmax(0, 1fr);
    }

    /* Lo único que se esconde es la palabra. El icono, el enlace y su area de clic
       se quedan; el nombre lo lleva el aria-label, porque display:none saca al <span>
       del arbol de accesibilidad y el enlace se quedaría sin nombre. */
    .riel-angosto .areas-etiqueta,
    .riel-angosto .marca-texto {
        display: none;
    }

    .riel-angosto .riel {
        padding-inline: 0.5rem;
    }

    .riel-angosto .areas a,
    .riel-angosto .riel-encoger button {
        justify-content: center;
        gap: 0;
    }

    .riel-angosto .marca {
        align-items: center;
    }
}

/* --- Las pantallas que se atan a la ventana --------------------------------

   Una pantalla larga —empleados, contactos, un reporte, la hoja anual— deja de
   desplazarse: el cromo de arriba se queda quieto y la caja de la tabla ocupa
   exactamente lo que sobra, con sus dos barras de desplazamiento pegadas al borde
   de la ventana.

   ES OPT-IN Y LO PIDE LA PÁGINA: `PaginaBase.AltoFijo`. Todo lo demás del sitio se
   desplaza como siempre.

   POR QUÉ `tabla-alta` SOLA NO ALCANZABA. Recortar a 70vh dice cuánto mide la caja
   y no dice DÓNDE EMPIEZA. Medido en la pantalla, a 1366×768:

       /empleados       la caja va de 264 a 802 · el borde está en 768
       /contactos       de 252 a 790
       /reportes/anual  de 258 a 796

   Las tres terminan abajo del doblez, así que su barra horizontal —la que dice que
   «Saldo» y «Estado» siguen a la derecha— queda fuera de la pantalla. Existe,
   funciona, y nadie la ve nunca. Eso es R1, R3 y R4 del inventario de la tarea 01,
   los tres el mismo defecto.

   La tarea 04d ya había diagnosticado esta forma de error —«lo que hay arriba y lo
   que mide el panel son PÍXELES, no una fracción de la ventana»— y la resolvió
   restando una constante medida a mano. Aquí se deja de adivinar el número: un
   contenedor flex lo mide solo, que es exactamente para lo que existe.

   `min-height: 0` EN CADA ESLABÓN NO ES ADORNO. Sin él un hijo flex no baja de su
   min-content, y el min-content de una tabla de 312 renglones es la tabla entera:
   la cadena se rompe en silencio y la página vuelve a desplazarse. */
.armazon.alto-fijo {
    height: 100vh;
    height: 100dvh;
}

/* Trece entradas y un pie de riel. A 768 ya no le sobra tanto. */
.alto-fijo .riel {
    overflow-y: auto;
}

.alto-fijo .columna {
    min-height: 0;
}

.alto-fijo .contenido {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

/* Lo único que crece es la caja de la tabla; lo de arriba mide lo que mide. Las
   8rem son el piso: con el desglose abierto la tabla cede, pero no hasta
   desaparecer. */
.alto-fijo .contenido > .tabla-alta {
    flex: 1 1 auto;
    min-height: 8rem;
    max-height: none;
}

/* La hoja anual mete su caja dentro de una <section> —ahí van el encabezado que se
   imprime y el enlace de «Saltar la hoja»—, así que la sección es un eslabón más de
   la cadena y necesita las mismas tres declaraciones. */
.alto-fijo .hoja-marco {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
}

.alto-fijo .hoja-marco > .tabla-alta {
    flex: 1 1 auto;
    min-height: 8rem;
    max-height: none;
}

/* El desglose es hermano de la tabla, no vive dentro de ella, y EL QUE CEDE ES LA
   HOJA. Eso es `flex-shrink: 0` aquí y `1` allá, y no es un detalle: el reparto de
   flex pesa el encogimiento por el tamaño base, y la hoja mide miles de píxeles
   contra los ciento y pico del panel, así que con las dos encogiendo la hoja se
   queda casi entera y el panel se aplasta a diecisiete píxeles. Medido, así salió.
   Y el panel es justo lo que se acaba de pedir.

   El tope es una fracción de la CAJA, no de la ventana, que es la diferencia con el
   número que la tarea 04d tuvo que corregir: lo que hay arriba ya está descontado
   cuando esto se resuelve. Un desglose más largo que eso se desplaza por dentro. */
.alto-fijo .desglose-envuelto {
    flex: 0 0 auto;
    max-height: 55%;
    overflow-y: auto;
}

/* Azul marino, que es la estructura de la marca. En los dos temas es el mismo
   color: en oscuro --fondo-elevado ya ES #1e2d3b, así que el riel no cambia de
   tono al cambiar de tema y la aplicación se reconoce igual en los dos. */
.riel {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: var(--espacio) 0.75rem;
    background: var(--estructura);
    border-right: 1px solid var(--estructura-honda);
    font-family: var(--tipo-titular);
}

/* La marca del encabezado suelto -- acceso, cambiar contraseña, la página de
   error --, que no lleva riel. */
.marca {
    padding: 0 0.5rem;
    color: var(--texto);
    font-family: var(--tipo-titular);
    font-weight: 600;
    text-decoration: none;
}

/* La del riel: la teja arriba y dos renglones de texto debajo.

   En fila no cabe, y se midió en vez de suponerlo: el riel son 240px, de los
   cuales la teja se lleva 40 y los rellenos otros 47, y en los 153 que quedan
   «Control de Vacaciones» en Poppins 600 se corta -- salía «Control de Vacaci…».
   Apilado, el texto dispone de los 192px completos y los dos renglones entran.
   Y el espacio vertical lo hay de sobra: el riel tiene trece entradas y termina
   a media pantalla (hallazgo D10). */
.riel .marca {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    padding: 0.25rem 0.4rem 0.5rem;
    color: var(--sobre-marca);
}

/* ⚠ Ni padding ni background aquí, y es un arreglo y no un olvido: la teja blanca
   y su margen de 2px viven DENTRO del PNG, definidos de una vez en el
   build-assets.ps1 de SistemaGTD, donde el resultado se puede mirar. Esta regla
   pone tamaño y esquina y no debe poner nada más -- con box-sizing: border-box,
   un padding aquí encogería el dibujo entero dentro de la caja. */
.marca-teja {
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: var(--radio);
}

.marca-texto {
    display: flex;
    min-width: 0;
    flex-direction: column;
    line-height: 1.2;
}

/* El nombre de la empresa arriba y el del producto abajo. Es el orden que usa la
   otra aplicación, y el que contesta «¿de quién es esto?» antes que «¿qué es?». */
.marca-empresa {
    overflow: hidden;
    color: var(--sobre-marca-tenue);
    font-size: 0.72rem;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.marca-producto {
    overflow: hidden;
    font-size: 0.95rem;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.areas {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.areas a {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.5rem;
    border-left: 3px solid transparent;
    border-radius: var(--radio);
    color: var(--sobre-marca);
    text-decoration: none;
    white-space: nowrap;
}

/* Decorativo mientras la etiqueta esté al lado -- lleva aria-hidden en el markup.
   Cuando la tarea 04 colapse el riel, la etiqueta se esconde y el ícono se queda
   solo: ahí deja de ser decoración, y lo que lo nombra es el título del enlace. */
.areas a .bi {
    flex: none;
    width: 1.15rem;
    font-size: 1.05rem;
    text-align: center;
}

.areas-etiqueta {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Un lavado translúcido y no un color mezclado, para que siga funcionando si el
   fondo del riel cambia alguna vez. */
.areas a:hover {
    background: rgba(255, 255, 255, 0.08);
}

/* El amarillo de la marca marca la sección activa. Es una regla, no texto: el
   texto encima sigue siendo blanco sobre el marino. */
.areas a.actual {
    background: rgba(255, 255, 255, 0.10);
    border-left-color: var(--destacado);
    color: var(--sobre-marca);
    font-weight: 600;
}

/* El botón de encoger. `margin-top: auto` lo pega abajo: el riel es una columna
   flex y el hueco vacío de su mitad inferior (hallazgo D10) es justo lo que lo
   empuja hasta el pie. */
.riel-encoger {
    margin-top: auto;
    padding-top: var(--espacio);
}

.riel-encoger button {
    display: flex;
    width: 100%;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.5rem;
    border: 0;
    border-radius: var(--radio);
    background: none;
    color: var(--sobre-marca-tenue);
    font: inherit;
    cursor: pointer;
}

.riel-encoger button:hover {
    background: rgba(255, 255, 255, 0.08);
    color: var(--sobre-marca);
}

/* Las áreas que todavía no existen. Se listan a propósito —un riel de dos
   entradas parece una aplicación rota, no una a medio construir— y se ven
   apagadas para que nadie las confunda con las que sí llevan a algo. */
.areas a.pendiente {
    color: var(--sobre-marca-tenue);
}

.columna {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.barra {
    display: flex;
    align-items: center;
    gap: var(--espacio);
    padding: 0.6rem var(--espacio);
    background: var(--fondo-elevado);
    border-bottom: 1px solid var(--borde);
}

.contenido {
    padding: 0.75rem var(--espacio) calc(var(--espacio) * 1.25);
}

/* El título de la pantalla, y lo que va en su renglón.

   El h1 traía las medidas del navegador —2em de cuerpo y dos márgenes de 0.67em—
   encima de una miga que ya dice dónde está uno. En /contactos eso eran 40px de
   nada arriba del título y 20 abajo, en una pantalla cuyo trabajo es enseñar 307
   renglones. Es lo primero que la clienta señaló al ver la aplicación corriendo.

   `.encabezado-pagina` es el renglón: el título a la izquierda y a la derecha lo
   que se hace desde aquí —«Nuevo usuario», anterior/siguiente—. Antes eso era un
   bloque debajo del título y costaba otros ~50px en cada pantalla que lo tuviera. */
.contenido h1 {
    margin: 0 0 0.5rem;
    font-size: 1.45rem;
    line-height: 1.25;
}

.encabezado-pagina {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem var(--espacio);
    margin-bottom: 0.5rem;
}

/* Adentro del renglón el que separa es el renglón. Va después de `.contenido h1`
   a propósito: misma especificidad, y aquí gana la de abajo. */
.encabezado-pagina > h1 {
    margin: 0;
}

/* Adentro del renglón dejan de ser bloques con su propio margen: el renglón ya
   separa. */
.encabezado-pagina > .acciones,
.encabezado-pagina > .recorrido {
    margin: 0;
}

/* Una pantalla sin shell: entrar, cambiar contraseña. */
.contenido-suelto {
    max-width: 70rem;
    margin: 0 auto;
    padding: calc(var(--espacio) * 1.5) var(--espacio);
}

.encabezado {
    display: flex;
    align-items: center;
    gap: var(--espacio);
    padding: 0.75rem var(--espacio);
    background: var(--fondo-elevado);
    border-bottom: 1px solid var(--borde);
}

/* --- Migas ---------------------------------------------------------------- */

.migas {
    padding: 0.45rem var(--espacio) 0;
    color: var(--texto-tenue);
    font-size: 0.92em;
}

.migas ol {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.migas li::after {
    content: "›";
    margin-left: 0.4rem;
    color: var(--borde);
}

.migas li:last-child::after {
    content: "";
}

.migas li:last-child {
    color: var(--texto);
    font-weight: 600;
}

/* --- Buscador global ------------------------------------------------------ */

.buscador {
    position: relative;
    flex: 1 1 auto;
    max-width: 26rem;
    margin: 0;
}

.buscador input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

.buscador input:focus {
    border-color: var(--acento);
    outline: 2px solid var(--acento);
    outline-offset: 1px;
}

.resultados:not(:empty) {
    position: absolute;
    z-index: 20;
    right: 0;
    left: 0;
    margin-top: 0.25rem;
    padding: 0.25rem;
    background: var(--fondo-elevado);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    box-shadow: 0 6px 20px rgb(0 0 0 / 18%);
}

.resultados ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

.resultados a {
    display: block;
    padding: 0.35rem 0.5rem;
    border-radius: var(--radio);
    color: var(--texto);
    text-decoration: none;
}

.resultados a:hover,
.resultados a:focus {
    background: var(--acento-tenue);
    outline: none;
}

.resultados .detalle,
.resultados .vacio {
    display: block;
    color: var(--texto-tenue);
    font-size: 0.88em;
}

.resultados .vacio {
    padding: 0.35rem 0.5rem;
}

.atajo {
    color: var(--texto-tenue);
    font-size: 0.85em;
    white-space: nowrap;
}

/* --- Tema y sesión -------------------------------------------------------- */

.sesion {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-left: auto;
}

.quien {
    color: var(--texto-tenue);
    white-space: nowrap;
}

.salida {
    margin: 0;
}

.tema {
    display: flex;
    gap: 0.15rem;
    margin: 0;
    padding: 0.15rem;
    background: var(--fondo-hundido);
    border-radius: var(--radio);
}

/* El icono viaja en el markup y no se ve: la palabra es lo que se lee mientras
   quepa. Lo cambia el bloque del teléfono, y solo ahí. */
.tema-icono {
    display: none;
}

.tema button {
    padding: 0.2rem 0.5rem;
    border: none;
    border-radius: var(--radio);
    background: none;
    color: var(--texto-tenue);
    font: inherit;
    font-size: 0.85em;
    cursor: pointer;
}

.tema button:hover {
    color: var(--acento);
}

.tema button.actual {
    background: var(--fondo-elevado);
    color: var(--texto);
    font-weight: 600;
}

/* --- Paneles del menú principal ------------------------------------------- */

.paneles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: var(--espacio);
    margin-top: var(--espacio);
}

.panel {
    padding: var(--espacio);
    background: var(--fondo-elevado);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.panel h2 {
    margin: 0 0 0.5rem;
    font-size: 1.05rem;
}

.panel .cuenta {
    color: var(--texto-tenue);
    font-weight: 400;
}

.panel ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

.panel li {
    padding: 0.25rem 0;
    border-top: 1px solid var(--borde);
}

.panel li:first-child {
    border-top: none;
}

.panel .detalle {
    display: block;
    color: var(--texto-tenue);
    font-size: 0.88em;
}

/* --- Tablas y listas ------------------------------------------------------ */

/* Que la tabla se desplaza tiene que VERSE. Hallazgos R1 a R4.

   Aquí se intentó primero el truco de los cuatro degradados —dos anclados al
   contenido que tapan y dos anclados al marco que asoman— y NO sirve en esta
   aplicación: se pintan en el fondo del contenedor y la tabla va encima con
   celdas opacas, así que la sombra queda debajo y no se ve nunca. Queda anotado
   para que nadie lo vuelva a intentar.

   Lo que sí sirve es `.tabla-alta`, que la tarea 12 ya había escrito para las
   constancias: acota la caja a 70vh y le pega el encabezado. La diferencia no es
   el alto, es DÓNDE QUEDA EL SCROLLBAR — en un contenedor de 12,000px de alto la
   barra horizontal está al pie de la página y nadie la ve nunca; en una caja de
   70vh está al pie de lo que se está mirando. Las tablas largas lo llevan ahora
   en su markup. */
.tabla-envuelta {
    overflow-x: auto;
}

.tabla {
    width: 100%;
    border-collapse: collapse;
}

.tabla th,
.tabla td {
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--borde);
    text-align: left;
    white-space: nowrap;
}

.tabla th {
    color: var(--texto-tenue);
    font-size: 0.88em;
}

/* D6 — el sobrante se junta al final en vez de repartirse entre las columnas.

   `.tabla` mide el 100% del contenedor, y cuando el contenido no llega a tanto el
   navegador reparte la diferencia entre TODAS las columnas. A 1920 en /empleados
   eso daba ~110px de hueco entre «Nombre» y «División», ~300px entre «Puesto» e
   «Ingreso», y «Saldo» y «Estado» apretados contra el borde. Datos que se leen
   juntos quedan lejos, y el ojo tiene que cruzar el hueco para saber de quién es la
   cifra.

   `width: 100%` en UNA columna se lleva todo el sobrante, y como las demás celdas ya
   son `nowrap`, se ajustan a su contenido. **Y esa columna es la última**, que es la
   parte que hay que decir: se probó primero con «Nombre» y sale peor —la columna
   mide 634px para nombres de 260 y el hueco se muda enterito entre el nombre y su
   división—. Al final, el hueco queda DESPUÉS del último dato, que es donde no
   separa nada.

   Va por `:last-child` y no por una clase en el <th> porque en /contactos la última
   columna es «Acciones» y solo existe si quien mira tiene permiso de editar, emplear
   o borrar. Una clase escrita a mano se quedaría en la columna equivocada para quien
   solo consulta. */
.tabla-holgada th:last-child {
    width: 100%;
}

.tabla tbody tr:hover {
    background: var(--fondo-hundido);
}

/* --- Ordenar por el encabezado -------------------------------------------

   El botón lo fabrica wwwroot/js/orden.js, no el markup: sin JavaScript el
   encabezado se queda como está y la tabla sale en el orden del servidor, que es el
   orden con el que se leía antes. Un botón que no hiciera nada sería peor.

   Hereda todo del <th> —color, tamaño, peso— para que el encabezado siga siendo un
   encabezado y no un control de más. Lo único que se ve de más es la flecha, y solo
   cuando el puntero está encima o cuando esa es la columna ordenada. */
.tabla th:has(> .orden) {
    padding: 0;
}

.orden {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    width: 100%;
    padding: 0.4rem 0.6rem;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: inherit;
    cursor: pointer;
}

/* La columna de números lleva su encabezado a la derecha, y el botón tiene que
   seguirlo o el título se despega de su columna. */
.tabla th.numero .orden {
    justify-content: flex-end;
}

.orden:hover,
.orden:focus-visible {
    color: var(--texto);
}

.orden:focus-visible {
    outline: 2px solid var(--acento);
    outline-offset: -2px;
}

/* En reposo la flecha doble no se ve: doce encabezados con una flecha cada uno son
   doce cosas pidiendo atención en una tabla que se lee, no se opera. Aparece al
   pasar el puntero —«aquí se puede»— y se queda fija en la columna ordenada. */
.orden-flecha {
    opacity: 0;
    font-size: 0.9em;
}

.orden:hover .orden-flecha,
.orden:focus-visible .orden-flecha,
.tabla th[aria-sort="ascending"] .orden-flecha,
.tabla th[aria-sort="descending"] .orden-flecha {
    opacity: 1;
}

.tabla th[aria-sort="ascending"],
.tabla th[aria-sort="descending"] {
    color: var(--texto);
}

.filtros {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.6rem;
    margin: var(--espacio) 0;
}

/* La etiqueta al lado del control y no encima. Encima cuesta un renglón de 18px
   por filtro y estas barras traen hasta cinco; al lado, la barra entera mide un
   renglón. Lo pidió la clienta por el buscador de contactos y aplica a todas. */
.filtros label {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.4rem;
    color: var(--texto-tenue);
    font-size: 0.88em;
}

.filtros select,
.filtros input {
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

/* Una caja de búsqueda del ancho de un nombre. Los de esta empresa son de cuatro
   palabras —«Aceviz Parra Petra Eleuteria»— y la caja medía lo que el navegador
   quisiera darle, que son unas veinte letras. */
.filtros input[type="search"] {
    width: 20rem;
    max-width: 100%;
}

.baja {
    color: var(--texto-tenue);
}

/* --- Anterior / siguiente ------------------------------------------------- */

.recorrido {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: var(--espacio) 0;
}

.recorrido .posicion {
    color: var(--texto-tenue);
    font-size: 0.9em;
}

.recorrido .apagado {
    color: var(--texto-tenue);
    opacity: 0.5;
}

/* --- Piezas compartidas --------------------------------------------------- */

.boton {
    display: inline-block;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo-elevado);
    color: var(--texto);
    font: inherit;
    text-decoration: none;
    cursor: pointer;
}

.boton:hover {
    border-color: var(--acento);
    color: var(--acento);
}

/* Relleno, no solo con borde de color. Antes solo cambiaba borde, color y peso
   -- que es literalmente lo que hace .boton:hover --, así que la acción principal
   de cada pantalla pesaba lo mismo que las demás y no había un solo botón relleno
   en todo el sistema. Hallazgo R6/I2 de la tarea 01. */
.boton-principal {
    border-color: var(--acento);
    background: var(--acento);
    color: var(--sobre-acento);
    font-weight: 600;
}

.boton-principal:hover {
    border-color: var(--estructura-honda);
    background: var(--estructura-honda);
    color: var(--sobre-acento);
}

.tarjeta {
    padding: calc(var(--espacio) * 1.25);
    background: var(--fondo-elevado);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.tarjeta-angosta {
    max-width: 24rem;
    margin: 0 auto;
}

/* La pantalla de acceso es la única que alguien mira ANTES de decidir si confía
   en esto. La tarjeta es blanca, así que el logo va sin la teja del riel. */
.marca-acceso {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
    margin-bottom: var(--espacio);
    text-align: center;
}

.marca-acceso img {
    width: 96px;
    height: 96px;
}

.marca-acceso .empresa {
    color: var(--texto);
    font-family: var(--tipo-titular);
    font-size: 1rem;
    font-weight: 600;
}

.tarjeta h1 {
    margin-top: 0;
    font-size: 1.3rem;
}

.formulario {
    display: grid;
    gap: 0.35rem;
}

.formulario label {
    margin-top: 0.5rem;
    font-weight: 600;
}

.formulario input {
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

.formulario input:focus {
    border-color: var(--acento);
    outline: 2px solid var(--acento);
    outline-offset: 1px;
}

.formulario .boton {
    margin-top: var(--espacio);
}

/* Turnstile. El recuadro lo dibuja Cloudflare dentro de un <iframe> suyo y no se
   le da estilo desde aquí -- lo único nuestro es el hueco que ocupa mientras
   carga, para que el botón «Entrar» no salte hacia abajo a media pantalla. 65px
   es el alto del widget normal; si Cloudflare lo entrega en modo invisible el
   marco mide 0 y este min-height deja un espacio vacío que hay que quitar. */
.turnstile {
    margin-top: var(--espacio);
    min-height: 65px;
}

/* Aviso: lo que salió mal, en la misma tarjeta. Rojo no: el mensaje más común es
   «contraseña incorrecta», que no es una falla del sistema. */
.aviso {
    margin: 0 0 var(--espacio);
    padding: 0.6rem 0.75rem;
    border-left: 3px solid var(--acento);
    background: var(--fondo);
    border-radius: var(--radio);
}

.nota {
    margin: 0.25rem 0 0;
    color: var(--texto-tenue);
    font-size: 0.9em;
}

.diagnostico {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.25rem 1rem;
    margin: var(--espacio) 0;
    color: var(--texto-tenue);
}

.diagnostico dt {
    font-weight: 600;
}

.diagnostico dd {
    margin: 0;
}

/* --- Ventana angosta ------------------------------------------------------ */

/* Una laptop de 1366 sigue entrando en dos columnas; por debajo de eso el riel se
   acuesta y se vuelve una tira que se desliza. No hay botón de hamburguesa: un
   menú que hay que abrir para saber dónde está uno es peor que uno que se lee de
   corrido, y no necesita JavaScript. */
@media (max-width: 56rem) {
    .armazon {
        grid-template-columns: minmax(0, 1fr);

        /* ⚠ Los dos renglones se declaran, y no es orden: es que el riel deja de
           inflarse. Sin esto son dos renglones implícitos `auto` dentro de una
           rejilla con `min-height: 100vh`, y el sobrante de una pantalla corta se
           reparte ENTRE LOS DOS — así que la tira del riel crece en cada pantalla
           cuyo contenido no llena la ventana. En /captura, en un teléfono, eran
           265px de banda azul vacía: el 31% de la pantalla, y ni un dato. */
        grid-template-rows: auto minmax(0, 1fr);
    }

    .riel {
        flex-direction: row;
        align-items: center;
        gap: var(--espacio);
        overflow-x: auto;
        border-right: none;
        border-bottom: 1px solid var(--borde);
    }

    .areas {
        flex-direction: row;
    }

    .barra {
        flex-wrap: wrap;
    }

    .sesion {
        margin-left: 0;
    }

    /* Y el botón que encoge tampoco se ofrece. La ventana ya decidió sola que el
       riel se acuesta, y ofrecer un segundo mecanismo que dice lo contrario es lo
       que dejaba al usuario sin menú y sin forma de recuperarlo. */
    .riel-encoger {
        display: none;
    }
}

/* --- Usuarios (tarea 08) --------------------------------------------------

   La rejilla de permisos es la pieza cara: treinta y un renglones por tres
   botones, y lo que hace legible el bloque no es el color sino que la columna del
   ajuste sea la ancha y las otras tres estrechas. La de «Resultado» es la que se
   lee de un vistazo, así que va en negrita y con color propio. */

.pastilla {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border: 1px solid var(--borde);
    border-radius: 999px;
    background: var(--acento-tenue);
    font-size: 0.85em;
    white-space: nowrap;
}

.pastilla.alerta {
    border-color: var(--alerta);
    background: transparent;
    color: var(--alerta);
}

.apagado {
    color: var(--texto-tenue);
    font-style: italic;
}

.detalle {
    color: var(--texto-tenue);
    font-size: 0.85em;
}

.acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin: var(--espacio) 0;
}

.acciones-fila {
    white-space: nowrap;
}

.acciones-fila a + a {
    margin-left: 0.75rem;
}

.roles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--espacio);
}

/* `.panel .cuenta` mide 1.8rem porque en el repartidor de catálogos la cifra ES la
   tarjeta. Aquí no: la tarjeta es el rol, y «32 de 32 permisos» es un pie de foto
   que estaba costando 20px de alto en cada una de las tres. */
.roles .panel .cuenta {
    font-size: 1rem;
    font-weight: 600;
}

.casilla {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.5rem 0;
}

.casilla label {
    margin: 0;
    font-weight: normal;
}

.modulo {
    margin: calc(var(--espacio) * 1.5) 0;
}

.modulo h2 {
    margin-bottom: 0.35rem;
    font-size: 1.05rem;
}

/* Hallazgo I1: son ocho tablas, una por módulo, y cada una repartía sus anchos por
   su cuenta -- «El rol» caía en x=955 en la primera y en x=1,017 en la segunda, y
   se notaba de un vistazo. Con `table-layout: fixed` y anchos declarados, las ocho
   se leen como una sola rejilla, que es lo que son. */
.permisos {
    table-layout: fixed;
}

.permisos col.permiso-que { width: auto; }
.permisos col.permiso-rol { width: 6rem; }
.permisos col.permiso-ajuste { width: 26rem; }
.permisos col.permiso-resultado { width: 7rem; }

.permisos th[scope="row"] {
    font-weight: normal;
    text-align: left;
}

.permisos th[scope="row"] code {
    display: block;
}

.permisos td:last-child {
    font-weight: 600;
    white-space: nowrap;
}

.permisos .si {
    color: var(--acento);
}

.permisos .no {
    color: var(--texto-tenue);
}

.opciones {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
}

.opcion {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}

.opcion label {
    font-size: 0.9em;
}

/* La contraseña temporal se dicta por teléfono, así que se muestra grande y
   separada: es lo único de la página que hay que poder leer de lejos. */
.clave-temporal .clave {
    margin: var(--espacio) 0;
    font-size: 1.6rem;
    letter-spacing: 0.05em;
}

.aviso.guardado {
    border-color: var(--acento);
    color: var(--texto);
}

/* --- Contactos (tarea 09 / sub 01) ----------------------------------------

   La lista y el formulario reutilizan casi todo de la tarea 08: .tabla,
   .formulario, .pastilla, .aviso. Lo de aquí es lo que no existia. */

/* El formulario de contacto es el primero con secciones: nombre por un lado,
   datos personales por otro. */
.formulario h2 {
    margin: calc(var(--espacio) * 1.5) 0 var(--espacio);
    font-size: 1.05rem;
    color: var(--texto-tenue);
}

.formulario h2:first-child {
    margin-top: 0;
}

/* Dos pastillas seguidas en la columna de situacion: "empleo activo" y
   "3 empleos". */
.tabla .pastilla + .pastilla {
    margin-left: 0.35rem;
}

/* Aviso dentro del formulario: pegado a la caja de arriba, no flotando. */
.formulario .aviso {
    margin-top: 0;
}

/* Alpine: evita el parpadeo del contenido que arranca oculto, antes de que Alpine
   procese el documento. */
[x-cloak] {
    display: none !important;
}

/* htmx: normalmente inyecta estas reglas en un <style> al cargar, y el CSP lo
   bloquea. Por eso el layout trae <meta name="htmx-config"> con
   includeIndicatorStyles en false, y las reglas viven aquí. */
.htmx-indicator {
    opacity: 0;
    transition: opacity 200ms ease-in;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
    opacity: 1;
}

/* --- Lista de empleados y «vistos» (tarea 09 / sub 02) --------------------

   La tabla, los filtros y .baja ya existían. Lo de aquí es la columna de saldo y
   la tira de «últimos vistos», que aparece en la lista y en el menú principal. */

/* Cifras a la derecha y con ancho de dígito fijo: así se comparan de un vistazo
   sin que un -203.0 empuje la columna. */
.tabla .numero {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Un saldo en contra es un hecho, no una falla — aquí hay quien debe más de
   doscientos días. Se marca para poder localizarlo, y no en rojo: rojo en una
   tabla se lee como error, y esto no lo es. */
.tabla .en-contra {
    color: var(--acento);
    font-weight: 600;
}

/* La tira de «últimos vistos»: un renglón, no una caja. Es un atajo de
   navegación y no una de las tres preguntas que responde el menú. */
/* `width: fit-content`, que es el hallazgo D9: la banda se estiraba a los 1,648px
   del contenido para decir un nombre. Ahora mide lo que dice. */
.vistos {
    display: flex;
    width: fit-content;
    max-width: 100%;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem 0.8rem;
    margin: var(--espacio) 0;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo-hundido);
}

.vistos-titulo {
    color: var(--texto-tenue);
    font-size: 0.88em;
}

.vistos ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.vistos li {
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
}

/* --- Ficha del empleado (tarea 09 / sub 03) -------------------------------

   La pantalla central del sistema: el saldo arriba y el historial completo abajo.
   Lo que se resuelve aquí es la jerarquía —una cifra grande, unos datos, y una
   tabla larga que se lee de corrido— y que un saldo en contra se distinga sin
   pintarse como error. Aquí hay quien debe más de doscientos días. */

.saldo-grande {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin: 0 0 var(--espacio);
}

.saldo-cifra {
    font-size: 2.4rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.saldo-rotulo {
    color: var(--texto-tenue);
}

/* Distinguible y a propósito no en rojo: rojo se lee como falla, y deber días es
   lo normal en esta empresa. Es el mismo criterio de .tabla .en-contra. */
.saldo-grande.en-contra .saldo-cifra {
    color: var(--acento);
}

/* Los cinco números del reporte 1: anterior + corresponden − disfrutados + otros
   = final. Es una línea, no una tabla, porque se lee como una frase. */
.resumen-anio {
    margin: var(--espacio) 0 0;
    padding-top: var(--espacio);
    border-top: 1px solid var(--borde);
    color: var(--texto-tenue);
    font-size: 0.92em;
}

/* Divisiones y jornada caben lado a lado en cuanto hay ancho, y se apilan solas
   cuando no lo hay. Ninguna de las dos es larga. */
.columnas-ficha {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: var(--espacio);
}

.columnas-ficha .tarjeta {
    margin: 0;
}

.lista-simple {
    margin: 0;
    padding: 0;
    list-style: none;
}

.lista-simple li {
    padding: 0.35rem 0;
    border-bottom: 1px solid var(--borde);
}

.lista-simple li:last-child {
    border-bottom: none;
}

/* Dos firmas y no una: quién capturó a la persona y quién capturó el empleo son
   dos preguntas distintas, y se ven lado a lado para poder compararlas. */
.firmas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: 0 calc(var(--espacio) * 2);
}

.firmas .diagnostico {
    margin-top: 0;
}

/* Un dato con su aclaración debajo: «8 años» y luego de qué tabla sale. */
.diagnostico dd .detalle {
    display: block;
}

/* --- El historial --------------------------------------------------------- */

.historial {
    margin: calc(var(--espacio) * 1.5) 0;
}

/* <details> y no un acordeón de JavaScript: el año se pliega sin una línea de
   script, y sin JavaScript sigue funcionando igual. */
.anio {
    margin-bottom: var(--espacio);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo-elevado);
}

.anio > summary {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem 0.8rem;
    padding: 0.6rem 0.8rem;
    cursor: pointer;
}

.anio-numero {
    font-size: 1.15em;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.anio > summary .cierre {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.anio > summary .cierre.en-contra {
    color: var(--acento);
}

.anio .tabla-envuelta,
.anio > .nota {
    margin: 0 0.8rem 0.8rem;
}

/* Ocho columnas es lo que tiene un renglón del libro. Se aprieta la letra en vez
   de esconder columnas: la hoja que esto reemplaza las trae todas. */
.ledger {
    font-size: 0.92em;
}

.ledger .pastilla + .pastilla {
    margin-left: 0.25rem;
}

.ledger td > div + div {
    margin-top: 0.15rem;
}

/* Empleo y jornada (tarea 09 / sub 04) --------------------------------------- */

/* Un dato que la pantalla afirma en vez de ofrecer: la división de un empleo que
   ya existe, y la fecha de una versión de jornada que se está corrigiendo. No es
   un campo deshabilitado —un control apagado se ve como algo que se podría
   encender— sino texto con su rótulo. */
.campo-fijo {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin: 0.5rem 0 var(--espacio);
}

.campo-fijo .rotulo {
    font-weight: 600;
    font-size: 0.9em;
}

.campo-fijo .detalle {
    display: block;
}

.semana {
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: 0.75rem var(--espacio);
    margin: var(--espacio) 0;
}

.semana legend {
    font-weight: 600;
    padding: 0 0.35rem;
}

.abonos {
    margin: var(--espacio) 0;
}

.abonos h2 {
    margin-top: 0;
}

.abonos tfoot th,
.abonos tfoot td {
    font-weight: 600;
    border-top: 2px solid var(--borde);
}

/* Un formulario dentro de una celda de acciones: borrar no es un enlace —lleva
   token antifalsificación y método POST— pero tiene que leerse como los enlaces
   que están a su lado. */
form.en-linea {
    display: inline;
}

button.enlace {
    background: none;
    border: none;
    padding: 0;
    margin: 0 0 0 0.75rem;
    font: inherit;
    color: var(--acento);
    cursor: pointer;
    text-decoration: underline;
}

/* ---------------------------------------------------------------------------
   Baja, reingreso y cambio de división (tarea 09 / sub 05)
   --------------------------------------------------------------------------- */

/* Un reingreso y un cambio de división están a un clic de distancia y hacen lo
   contrario. La tarjeta que explica cuál de los dos es lleva el borde de alerta:
   no es un error, es lo único de la pantalla que hay que leer antes de guardar. */
.tarjeta.advertencia {
    border-left: 4px solid var(--alerta);
}

.tarjeta.advertencia h2 {
    margin-top: 0;
    color: var(--alerta);
}

/* El finiquito es un bloque dentro del formulario de baja: la casilla, la caja de
   días y el saldo que htmx redibuja. Agrupado para que se lea como una sola
   decisión y no como tres campos sueltos. */
.finiquito {
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: var(--espacio);
    margin: var(--espacio) 0;
}

.finiquito legend {
    padding: 0 0.5rem;
    font-weight: 600;
}

/* ---------------------------------------------------------------------------
   El calendario de captura (tarea 10 / sub 01)
   --------------------------------------------------------------------------- */

/* La pantalla de captura, a dos columnas: el calendario a la izquierda y lo que se
   está capturando —el conteo, las casillas de la falta, el motivo y el botón de
   guardar— a la derecha, como lo tenía el escritorio. Apilados, marcar un periodo
   y escribir su número eran dos cosas que no cabían juntas en la pantalla.

   Flex y no grid, y sin `@media`: el ancho disponible depende del riel, que es una
   preferencia por usuario, así que una consulta contra el ancho de la VENTANA
   partiría en el lugar equivocado para la mitad de las combinaciones. Con
   `flex-wrap` y una base en cada columna, se acuestan cuando ya no caben lado a
   lado, lo mida lo que lo mida el contenedor.

   La clase la lleva `#cuerpo`, que es justo lo que htmx reemplaza al cambiar de
   tipo, y solo cuando ese tipo trae calendario: un pago no lo trae, y una columna
   izquierda vacía sería peor que la pila. */
.cuerpo-captura {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--espacio);
}

/* El tope es el mismo que el de la rejilla, y sin él la columna izquierda crecía
   más que su calendario: a 1920 el mes medía 1,280px con una rejilla de 832 adentro,
   así que quedaba un hueco de 450px entre la rejilla y lo que se está capturando —y
   la barra del mes, que reparte con `space-between`, mandaba las dos flechas a
   esquinas separadas por metro y medio de nada—. La clienta lo reportó así: «el
   calendario de capturar se ve raro en 1080p, se ve bien cuando haces la pantalla un
   75% más pequeña».

   El tope va en `max-width` y no en la base, a propósito: la base es lo que decide
   cuándo las dos columnas se acuestan, y subirla a 52rem las acostaría a 1366 con el
   riel abierto, que es justo donde se logró que cupieran de lado. */
.cuerpo-captura > .mes {
    flex: 1 1 32rem;
    max-width: 52rem;
    min-width: 0;
    margin: 0;
}

/* Las tarjetas de la captura llevan pares de etiqueta y control, y para apilarse
   dependían del `display: grid` del <form> — que no llega aquí adentro. Se estaban
   acomodando en renglón: «Motivo [caja] Notas [caja]». A 1,648px de ancho eso se
   leía tolerable; con la tarjeta en una columna de 350px, «Notas» quedaba a la
   derecha de la caja del motivo. La rejilla que ya usaba el formulario, adentro. */
.formulario .tarjeta {
    display: grid;
    align-content: start;
    gap: 0.35rem;
}

/* La rejilla ya separa; los márgenes del navegador sumaban encima. */
.formulario .tarjeta > p,
.formulario .tarjeta > h2 {
    margin: 0;
}

/* El tope de las cajas, por lo que se escribe adentro y no por lo que mide la
   pantalla. `.formulario` es una rejilla y estira a sus hijos, así que en un
   monitor de 1920 el apellido se capturaba en una caja de 1,650px y los días en
   una de 1,050 para escribir «22». 38rem son unos 600px, más que cualquier dato
   de esta nómina, y en la tarjeta angosta del acceso no ata nada. */
.formulario input,
.formulario select,
.formulario textarea {
    max-width: 38rem;
}

.formulario input[type="number"] {
    max-width: 10rem;
}

.formulario input[type="date"] {
    max-width: 12rem;
}

/* La columna derecha es una rejilla también cuando es la única —el pago— para que
   las tarjetas se separen igual en los dos casos. Antes no se separaban: `.tarjeta`
   no trae margen y `#cuerpo` era un bloque, así que la del conteo y la del motivo
   quedaban pegadas. */
.captura-lado {
    display: grid;
    align-content: start;
    gap: var(--espacio);
    min-width: 0;
}

/* Y lo que sobra se lo lleva esta columna, que es «la captura» de la que hablaba el
   reporte: a 1920 el motivo y las notas pasan de 352px a 544. Con tope, porque una
   caja de notas de 800px es una línea de texto que ya no se lee de un vistazo — es
   la misma regla que D29. */
.cuerpo-captura > .captura-lado {
    flex: 1 1 22rem;
    max-width: 34rem;
}

/* Dentro de la columna el separador es el `gap`, así que los márgenes propios se
   apagan: con los dos, la falta quedaba al doble de distancia de la caja del
   conteo que el motivo de la falta. */
.captura-lado > .falta,
.captura-lado > .ajuste {
    margin: 0;
}

.mes {
    margin: var(--espacio) 0;
}

.mes-barra {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--espacio);
}

.mes-titulo {
    margin: 0;
    font-size: 1.1rem;
}

/* Siete columnas fijas. La rejilla mide siempre seis renglones de días más el
   encabezado: una que midiera cinco en febrero y seis en marzo movería todo lo de
   abajo al cambiar de mes, y ella cambia de mes doce veces por persona. */
/* Acotada, y esto es el arreglo del hallazgo D1. La celda es cuadrada porque la
   clienta del escritorio lo pidió (d014e6d) y eso no se toca -- pero estirada a los
   1,648px del contenido, siete columnas dan celdas de 235px, y cuadradas son 235px
   de alto: seis renglones son 1,410px de rejilla, así que en la pantalla de captura
   cabían dos semanas y media y la caja del conteo y el botón de guardar quedaban
   bajo el doblez. En la pantalla que ella usa todo el día.

   52rem dan celdas de unos 112px, que es lo que hace falta para el número más tres
   chips, y la rejilla completa mide unos 680px. El cuadrado se queda; lo que se va
   es el estiramiento. */
.rejilla {
    display: grid;
    max-width: 52rem;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
    margin-top: var(--espacio);
}

.rejilla-encabezado {
    padding: 0.35rem 0;
    text-align: center;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--texto-tenue);
}

/* La celda es una etiqueta con una casilla adentro: se marca con clic y con
   teclado, y sin JavaScript funciona igual. */
.dia {
    position: relative;
    display: block;
    min-height: 3rem;
    padding: 0.35rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo-elevado);
    cursor: pointer;
}

/* La casilla no se ve, pero sigue ahí para el teclado y para el lector de
   pantalla: no se usa display:none, que la sacaría de la tabulación. */
.dia input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    opacity: 0;
}

.dia:focus-within {
    outline: 2px solid var(--acento);
    outline-offset: 1px;
}

.dia:has(input:checked) {
    background: var(--acento);
    border-color: var(--acento);
}

.dia:has(input:checked) .dia-numero {
    color: var(--sobre-acento);
    font-weight: 700;
}

.dia-numero {
    font-size: 0.9rem;
}

/* Los días de los meses vecinos: tenues y marcables. Un periodo del 28 de
   diciembre al 3 de enero es normal aquí y tiene que caber en una captura. */
.dia-numero.fuera {
    color: var(--texto-tenue);
    opacity: 0.6;
}

.dia-numero.hoy {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* El sombreado sale del servidor: domingos, festivos y los días que esta persona
   no trabaja, resueltos por fecha contra su jornada versionada. */
.dia-domingo,
.dia-nolaborable {
    background: var(--fondo-hundido);
}

.dia-festivo {
    background: var(--acento-tenue);
}

.dia-eventos {
    display: block;
    margin-top: 0.25rem;
}

.leyenda {
    margin-top: var(--espacio);
    font-size: 0.85rem;
    color: var(--texto-tenue);
}

.dia-muestra {
    display: inline-block;
    width: 0.9rem;
    height: 0.9rem;
    margin: 0 0.25rem 0 0.75rem;
    border: 1px solid var(--borde);
    border-radius: 3px;
    vertical-align: -1px;
}

.leyenda .dia-muestra:first-child {
    margin-left: 0;
}

/* ---------------------------------------------------------------------------
   La captura del movimiento (tarea 10 / sub 02)
   --------------------------------------------------------------------------- */

/* El select y el textarea no existían en ningún formulario hasta esta pantalla, y
   sin esto se ven como controles del sistema operativo al lado de cajas estilizadas. */
.formulario select,
.formulario textarea {
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

.formulario select:focus,
.formulario textarea:focus {
    border-color: var(--acento);
    outline: 2px solid var(--acento);
    outline-offset: 1px;
}

/* El tipo va en su propio formulario GET, arriba y separado del que escribe. */
.formulario.tipo {
    margin-bottom: var(--espacio);
}

/* El select y su botón «Cambiar» en el mismo renglón: el botón es el camino sin
   JavaScript y no debe leerse como el que guarda. */
.tipo-fila {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

/* Hallazgo D7: sin tope el select se estiraba a todo el ancho del contenido --
   1,550px para la palabra «Vacaciones». La lista más larga es «Descanso
   laborado». */
.tipo-fila select {
    max-width: 22rem;
}

.tipo-fila select {
    flex: 1 1 14rem;
}

.formulario.tipo .boton {
    margin-top: 0;
}

.falta,
.ajuste {
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: var(--espacio);
    margin: var(--espacio) 0;
}

.falta legend,
.ajuste legend {
    padding: 0 0.5rem;
    font-weight: 600;
}

/* --- Corregir y eliminar un movimiento (tarea 10 / sub 03) ----------------- */

/* Eliminar no se pinta como el botón que guarda. Es la única acción del sistema
   que no deja renglón donde firmar, y la que menos debe apretarse por inercia. */
.boton-peligro {
    border-color: var(--alerta);
    color: var(--alerta);
}

.boton-peligro:hover {
    border-color: var(--alerta);
    color: var(--alerta);
    font-weight: 600;
}

/* El saldo antes y después, en el mismo renglón y en grande: es toda la
   consecuencia del botón que está debajo. */
.saldo-cambio {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: baseline;
    font-size: 1.5rem;
}

.saldo-cambio .detalle {
    font-size: 0.9rem;
}

/* Los dos enlaces del renglón del historial. Enlaces y no botones: la tabla ya
   tiene ocho columnas y dos botones por renglón la volverían un teclado. Y sin
   display:flex, que en un <td> le quita el comportamiento de celda y desalinea la
   columna. */
.acciones-renglon {
    white-space: nowrap;
}

.acciones-renglon a + a {
    margin-left: 0.75rem;
}

/* --- La puerta de Captura y los días del año (tarea 10 / sub 04) ----------- */

/* El mismo buscador del encabezado, pero en el cuerpo de una pantalla: ancho
   completo, con su etiqueta a la vista y su botón «Buscar» al lado —que es el
   camino sin JavaScript—. */
.buscador-ancho {
    display: grid;
    grid-template-columns: 1fr max-content;
    gap: 0.5rem;
    align-items: end;
    max-width: none;
    margin: var(--espacio) 0;
}

.buscador-ancho label {
    grid-column: 1 / -1;
    color: var(--texto-tenue);
    font-size: 0.88em;
}

/* Y la lista sale del flujo, no encima de la pantalla. Arriba es un desplegable
   que tapa lo que haya debajo; aquí es lo único que hay debajo, y flotarla dejaría
   un hueco del alto de la lista entre el buscador y lo que sigue. */
.buscador-ancho .resultados {
    grid-column: 1 / -1;
}

.buscador-ancho .resultados:not(:empty) {
    position: static;
    margin-top: 0;
    box-shadow: none;
}

/* ---------------------------------------------------------------------------
   El calendario de la empresa (tarea 11)
   ---------------------------------------------------------------------------

   La paleta de los eventos. Siete colores, y ninguno de ellos es el único canal:
   cada chip lleva su etiqueta dibujada encima —V, C, F, I, X, FL, DL— así que
   sobrevive a una impresión en gris, que es como esta usuaria lee estas hojas, y
   a una deficiencia rojo-verde.

   Van como variables y no como colores sueltos porque el tema oscuro los vuelve a
   escribir enteros más abajo, y una paleta declarada dos veces en dos lugares es
   una que se desincroniza. */

:root {
    --evento-vacacion: #1f5fa9;
    --evento-cumpleanos: #7a4fa3;
    --evento-festivo: #2f7d4f;
    --evento-incapacidad: #9e5e12;
    --evento-falta: #a13a2a;
    --evento-festivolaborado: #12707d;
    --evento-descansolaborado: #55606b;

    /* El texto que va ENCIMA del chip. Era «#fff» fijo, y sobre los colores
       claros del tema oscuro eso daba entre 2.45:1 y 3.13:1 en los siete.
       Medido, no visto: ver HojaDeEstiloTests. */
    --sobre-chip: #ffffff;
}

@media (prefers-color-scheme: dark) {
    :root:not(.tema-claro) {
        --evento-vacacion: #5f95d4;
        --evento-cumpleanos: #ac86cf;
        --evento-festivo: #5fae7c;
        --evento-incapacidad: #d69a45;
        --evento-falta: #d9756a;
        --evento-festivolaborado: #4aa5ae;
        --evento-descansolaborado: #97a2ad;
        --sobre-chip: #1b2430;
    }
}

:root.tema-oscuro {
    --evento-vacacion: #5f95d4;
    --evento-cumpleanos: #ac86cf;
    --evento-festivo: #5fae7c;
    --evento-incapacidad: #d69a45;
    --evento-falta: #d9756a;
    --evento-festivolaborado: #4aa5ae;
    --evento-descansolaborado: #97a2ad;
    --sobre-chip: #1b2430;
}

/* El chip: color de fondo y una o dos letras encima. Es lo mismo en la celda del
   mes, en el renglón de la agenda y en la casilla del filtro, para que el filtro
   se lea como una leyenda de lo que se está mirando. */
.chip {
    display: inline-block;
    min-width: 1.35rem;
    padding: 0 0.3rem;
    border-radius: var(--radio-chico);
    background: var(--texto-tenue);
    color: var(--sobre-chip);
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.35;
    text-align: center;
    text-decoration: none;
}

a.chip:hover,
a.chip:focus-visible {
    outline: 2px solid var(--acento);
    outline-offset: 1px;
}

.chip-vacacion { background: var(--evento-vacacion); }
.chip-cumpleanos { background: var(--evento-cumpleanos); }
.chip-festivo { background: var(--evento-festivo); }
.chip-incapacidad { background: var(--evento-incapacidad); }
.chip-falta { background: var(--evento-falta); }
.chip-festivolaborado { background: var(--evento-festivolaborado); }
.chip-descansolaborado { background: var(--evento-descansolaborado); }

/* Los que no cupieron en la celda. Sin color propio: no representa un tipo, dice
   cuántos faltan, y están completos en el title del día. */
.chip-mas {
    background: transparent;
    border: 1px solid var(--borde);
    color: var(--texto-tenue);
}

/* Cada caja del filtro con su etiqueta al lado. Iba encima, y en /reportes eso
   convertía la barra de cuatro filtros en dos renglones antes de la primera cifra;
   la clienta lo señaló ahí y en la relación anual. */
.filtro {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.4rem;
}

/* `flex: 1 1 24rem` y no `flex: 0 0 auto`, que es el arreglo del hallazgo R5. Sin
   una base, este fieldset se encogía a la anchura de su chip más largo y apilaba
   las siete casillas en una columna de unos 140px de alto; como `.filtros` alinea
   por abajo, los controles cortos se hundían al pie y quedaba un rectángulo vacío
   de unos 620x140 entre el título y la fila de filtros. Con una base que puede
   crecer, los siete tipos se reparten a lo ancho y el hueco desaparece. */
.filtro-tipos {
    display: flex;

    /* ⚠ `flex-direction: row` explícito. Fue LA causa del hallazgo R5 y hoy es
       el seguro contra que vuelva. El markup es `class="filtro filtro-tipos"`, y
       `.filtro` —una regla de la misma especificidad, unas líneas más arriba—
       declaraba `flex-direction: column`; esta regla declaraba `display`,
       `flex-wrap` y `align-items` pero no la dirección, así que la columna de
       `.filtro` seguía ganando: las siete casillas se apilaban, el fieldset se
       encogía a la anchura de su chip más largo y crecía a unos 140px de alto, y
       como `.filtros` alinea por abajo los controles cortos se hundían al pie
       dejando un rectángulo vacío de unos 620x140 entre el título y los filtros.
       `.filtro` ya no dice `column` —la barra entera pasó a un renglón—, así que
       hoy esta línea no arregla nada; se queda porque si alguien devuelve
       `.filtro` a columna, sin ella vuelve el hueco y nada lo señalaría. */
    flex-direction: row;
    flex: 1 1 24rem;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem 0.85rem;
    margin: 0;
    padding: 0.35rem 0.6rem 0.5rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.filtro-tipos legend {
    padding: 0 0.25rem;
    color: var(--texto-tenue);
    font-size: 0.88em;
}

/* Redundante desde que `.filtros label` va en renglón, y se queda por lo mismo
   que la línea de `.filtro-tipos`: una casilla con su texto debajo no es una
   casilla, y esta es la regla que lo impide si aquello cambia. */
.filtros .casilla {
    flex-direction: row;
    align-items: center;
    gap: 0.35rem;
    margin: 0;
    color: var(--texto);
    font-size: 0.88em;
}

/* Agenda o mes. Dos enlaces, y el actual es el que va resaltado. */
.modos {
    display: flex;
    gap: 0.4rem;
    margin: var(--espacio) 0 0.4rem;
}

.resumen {
    margin: 0 0 var(--espacio);
    color: var(--texto-tenue);
    font-size: 0.9rem;
}

/* La agenda: un encabezado por día y sus renglones debajo. Numerada en el markup
   —es una lista ordenada por fecha— y sin viñetas a la vista. */
.agenda {
    margin: 0;
    padding: 0;
    list-style: none;
}

.agenda-dia {
    margin-bottom: var(--espacio);
}

.agenda-encabezado {
    margin: 0 0 0.3rem;
    padding-bottom: 0.2rem;
    border-bottom: 1px solid var(--borde);
    font-size: 0.95rem;
}

.agenda-renglones {
    margin: 0;
    padding: 0;
    list-style: none;
}

.agenda-renglon {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.25rem 0;
    border-bottom: 1px solid var(--fondo-hundido);
}

.agenda-titulo {
    font-weight: 600;
}

/* El selector de mes y año, debajo de las flechas. */
.mes-selector {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.5rem;
    font-size: 0.9rem;
}

.mes-selector input[type="number"] {
    width: 6rem;
}

.mes-selector select,
.mes-selector input {
    padding: 0.3rem 0.45rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

.leyenda-eventos {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 0.8rem;
}

.leyenda-item {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

/* La celda de solo lectura es un div y no una etiqueta: sin casilla dentro, el
   cursor de mano prometería un clic que no hace nada. */
div.dia {
    cursor: default;
}

/* Un día es un cuadrado. Lo pidió la clienta del escritorio en d014e6d y vale
   igual aquí: una rejilla de celdas más anchas que altas no se lee como un mes.
   Se aplica a la celda, así que las dos pantallas cambian juntas — que es la
   razón de que la celda sea una sola. */
.dia {
    aspect-ratio: 1;
    overflow: hidden;
}

/* Para un rótulo que el lector de pantalla necesita y la pantalla no. No se usa
   display:none, que lo quitaría también del lector. */
.visualmente-oculto {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ------------------------------------------------------------------------
   Constancias y catálogos (tarea 12)
   ------------------------------------------------------------------------ */

/* La tabla de constancias se recorre con la vista de arriba abajo y de un lado a
   otro, y el encabezado tiene que seguir diciendo cuál columna es cuál. El envuelto
   es el que se desplaza en los dos sentidos —el cuerpo de la página nunca— y por eso
   el sticky se ancla a él y no a la ventana. */
.tabla-alta {
    max-height: 70vh;
    overflow: auto;
}

.tabla-alta thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--fondo-elevado);
}

/* Las dos celdas de marca. Un botón y no una casilla: ver el comentario de la
   pantalla. Ancho fijo para que las dos columnas no se muevan al cambiar el texto de
   «Marcar» a una fecha. */
.tabla-constancias .marca {
    white-space: nowrap;
}

.marca-boton {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 8.5rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo);
    color: var(--texto);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.marca-boton:hover {
    border-color: var(--acento);
}

/* La diferencia entre marcado y pendiente es una figura y no un tono: una palomita
   dentro de un cuadro. Un relleno de color solo se lee en uno de los dos temas, y
   esto ya se aprendió tres veces en este proyecto. */
.marca-caja {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.1rem;
    height: 1.1rem;
    flex: none;
    border: 1px solid var(--texto-tenue);
    border-radius: 3px;
    font-size: 0.85em;
    line-height: 1;
}

.marca-boton.marcada .marca-caja {
    border-color: var(--acento);
    color: var(--acento);
    font-weight: 700;
}

.marca-texto {
    font-size: 0.9em;
}

.marca-boton.pendiente .marca-texto {
    color: var(--texto-tenue);
}

/* Un formulario que vive dentro de una celda: los campos en fila, sin el salto de
   línea que el formulario de página les pone. */
.renglon-forma {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
}

.renglon-forma input {
    padding: 0.3rem 0.45rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

.renglon-forma input[name="nombre"],
.renglon-forma input[name="descripcion"] {
    flex: 1 1 12rem;
    min-width: 8rem;
}

/* El renglón que se acaba de guardar, para no tener que buscarlo con la vista
   después de un redirect. Un borde y no un fondo, por lo mismo que la palomita. */
.recien-guardado > td,
.recien-guardado > th {
    box-shadow: inset 2px 0 0 var(--acento);
}

/* La cuenta grande de las tarjetas del repartidor de catálogos. */
.panel .cuenta {
    margin: 0.2rem 0 0;
    font-size: 1.8rem;
    font-weight: 600;
    line-height: 1;
}

/* ------------------------------------------------------------------------
   Reportes y la hoja impresa (tarea 13)
   ------------------------------------------------------------------------ */

/* El brinco por encima de la hoja. Invisible hasta que el tabulador lo toca, que
   es cuando sirve: la hoja anual son veinte columnas vivas por ciento nueve
   personas, y sin esto llegar al pie de la página con el teclado son dos mil
   pulsaciones. */
.brinco {
    position: absolute;
    left: -1000px;
}

.brinco:focus {
    position: static;
    display: inline-block;
    margin-bottom: 0.4rem;
}

.selector-reporte {
    max-width: 24rem;
}

.filtro-ancho select {
    max-width: 28rem;
}

/* De quién es la corrida, arriba de todo. Los dos reportes individuales lo traen;
   los otros diez no. */
.reporte-titulo {
    margin: 0.4rem 0 0.2rem;
    font-size: 1.1em;
    font-weight: 600;
}

/* Qué filtros se aplicaron de verdad, en palabras del propio reporte, y cuántos
   renglones salieron. Viaja con la tabla porque la tabla sobrevive a la pantalla:
   se exporta a un archivo que alguien abre la semana que entra, y una hoja de
   números sin decir qué abarca es una hoja en la que no se puede confiar.

   En UN renglón. Eran cuatro —«Año: 2026», «División: todas», «Empleados:
   activos» y «116 renglones», uno debajo del otro— y son ~60px entre los filtros
   y la primera cifra, en las dos pantallas que la clienta señaló. */
/* Los filtros y el contexto comparten renglón cuando caben. `align-items: baseline`
   y no `center`: lo que se alinea es el texto del contexto con las etiquetas de los
   filtros, no las cajas con las cajas. */
.reporte-barra {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 var(--espacio);
}

/* Dentro de la barra los márgenes propios del formulario sobran: el renglón ya
   separa, y el de arriba lo pone el título de la página. */
.reporte-barra > .filtros {
    margin: 0.5rem 0;
}

.reporte-encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 0.9rem;
    margin: 0 0 0.4rem;
}

.reporte-encabezado .resumen {
    margin: 0;
}

.reporte-contexto {
    display: flex;
    flex-wrap: wrap;
    gap: 0 0.55rem;
    margin: 0;
    padding: 0;
    list-style: none;
    color: var(--texto-tenue);
    font-size: 0.88em;
}

.reporte-contexto li + li::before {
    content: "·";
    margin-right: 0.55rem;
    color: var(--borde);
}

/* La descarga, al extremo de la barra.

   `margin-left: auto` la empuja hasta el otro lado del renglón, que es donde el
   escritorio la tenía: separada de los filtros, porque producir un archivo no es un
   paso de elegir qué mirar. Dentro del formulario, pegada a «Aplicar», se leía como
   el último filtro. */
.reporte-exportar {
    align-self: center;
    margin-left: auto;
}

/* --- El selector en el que se escribe ------------------------------------ */

/* Lo arma wwwroot/js/combo.js sobre un <select data-buscable>. Sin JavaScript nada
   de esto existe y el <select> se dibuja con las reglas de `.filtros select`. */
.combo {
    position: relative;
    display: flex;
}

.combo-caja {
    width: 22rem;
    max-width: 100%;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--campo-borde);
    border-radius: var(--radio);
    background: var(--campo);
    color: var(--texto);
    font: inherit;
}

/* Flota sobre lo que sigue en vez de empujarlo: la barra de filtros vive encima de
   una hoja de 109 renglones, y abrir una lista de 313 opciones que empujara la hoja
   hacia abajo movería justo lo que se está mirando. */
/* Más ancha que la caja si le hace falta.

   Cada renglón es «Aceviz Parra Petra Eleuteria · Hotel Hacienda Flamingos · baja»:
   el nombre, la división y si está de baja, y las tres partes están ahí porque dos
   personas del libro comparten apellidos y un reingreso pone a la misma persona dos
   veces. Recortada al ancho de la caja, lo que se pierde por la derecha es justo lo
   que distingue a dos renglones idénticos. */
.combo-lista {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    min-width: 100%;
    width: max-content;
    max-width: min(44rem, 90vw);
    max-height: 18rem;
    margin: 0.2rem 0 0;
    padding: 0.2rem;
    overflow-y: auto;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo-elevado);
    box-shadow: 0 6px 20px rgb(0 0 0 / 18%);
    list-style: none;
}

.combo-opcion {
    padding: 0.3rem 0.45rem;
    border-radius: var(--radio);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Una sola marca para las dos formas de señalar: la rueda del ratón y las flechas
   dejan la misma opción marcada, así que Enter siempre elige lo que se está viendo
   resaltado. */
.combo-opcion:hover,
.combo-activa {
    background: var(--acento-tenue);
}

.combo-opcion[aria-selected="true"] {
    font-weight: 600;
}

/* Cuando lo escrito no encuentra a nadie. La lista queda vacía y una caja vacía no
   dice nada, así que lo dice ella. */
.combo-vacia::after {
    content: "Nadie con ese nombre";
    display: block;
    padding: 0.3rem 0.45rem;
    color: var(--texto-tenue);
}

.tabla-reporte td.numero,
.tabla-reporte th.numero {
    text-align: right;
}

.notas {
    margin-top: var(--espacio);
    color: var(--texto-tenue);
    font-size: 0.9em;
}

.notas h2 {
    margin: 0 0 0.2rem;
    font-size: 1em;
}

/* --- La hoja ------------------------------------------------------------- */

.hoja-marco {
    margin-top: 0.4rem;
}

/* En pantalla, el nombre de la empresa y el del reporte comparten renglón: son dos
   líneas centradas encima de una hoja cuya barra de filtros ya dice lo mismo. En
   papel vuelven a ser dos, que es como se lee un encabezado impreso —ver la regla
   de `@media print` más abajo—. */
.hoja-encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    gap: 0 0.6rem;
    text-align: center;
}

.hoja-encabezado h2 {
    margin: 0;
    font-size: 1.05em;
    letter-spacing: 0.04em;
}

.hoja-encabezado p {
    margin: 0 0 0.4rem;
    color: var(--texto-tenue);
}

/* Cuánto mide el primer renglón de encabezados, que es de dónde cuelga el segundo
   cuando la hoja se recorre hacia abajo. Es una variable porque la leen dos reglas
   y tienen que decir el mismo número. */
.hoja-envuelta {
    --hoja-alto-encabezado: 2.1rem;
}

.hoja {
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.8em;
    white-space: nowrap;
}

.hoja th,
.hoja td {
    padding: 0.25rem 0.45rem;
    border-right: 1px solid var(--borde);
    border-bottom: 1px solid var(--borde);
    text-align: left;
    vertical-align: top;
}

.hoja thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    height: var(--hoja-alto-encabezado);
    background: var(--fondo-elevado);
    text-align: center;
    font-size: 0.92em;
}

.hoja thead tr + tr th {
    top: var(--hoja-alto-encabezado);
}

.hoja-grupo {
    letter-spacing: 0.06em;
}

/* La banda de división. El renglón cruza toda la hoja, así que fijar el recuadro
   por la izquierda no sirve de nada —ya empieza a la izquierda—; lo que se fija es
   el texto, para que al recorrer hasta diciembre siga diciendo en qué división
   vamos. */
.hoja-banda th {
    position: sticky;
    left: 0;
    background: var(--fondo-hundido);
    font-weight: 600;
    letter-spacing: 0.03em;
}

.hoja-banda th > span {
    position: sticky;
    left: 0.45rem;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

/* El botón de plegar una división. Lo fabrica wwwroot/js/hoja.js, así que sin
   JavaScript esta regla no aplica a nada y la banda sigue siendo un encabezado. */
.hoja-plegar {
    display: inline-flex;
    padding: 0;
    border: 0;
    background: none;
    color: var(--texto-tenue);
    font: inherit;
    cursor: pointer;
}

.hoja-plegar:hover {
    color: var(--acento);
}

/* La flecha apunta a dónde está lo que se ve: abajo mientras la división está
   abierta, de lado cuando está plegada. Es una rotación y no un ícono distinto,
   porque cambiar de ícono a media pulsación se ve como un parpadeo. */
.hoja-plegar[aria-expanded="false"] i {
    display: inline-block;
    transform: rotate(-90deg);
}

/* Las columnas ancladas. Cuántas son lo declara el reporte; dónde queda cada una lo
   dice esto, y por eso los anchos están fijados: `position: sticky` necesita un
   desplazamiento, y un desplazamiento necesita saber qué tan ancha es la de al
   lado. Recorrer hasta diciembre se llevaba el nombre fuera de la pantalla, y una
   cifra que nadie puede atribuir a una persona no sirve de nada. */
.hoja .hoja-fija {
    position: sticky;
    z-index: 1;
    background: var(--fondo);
}

.hoja thead .hoja-fija {
    z-index: 3;
    background: var(--fondo-elevado);
}

.hoja .hoja-fija-0 {
    left: 0;
    width: 7rem;
    min-width: 7rem;
}

.hoja .hoja-fija-1 {
    left: 7rem;
    width: 15rem;
    min-width: 15rem;
    max-width: 15rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hoja .hoja-fija-2 {
    left: 22rem;
}

.hoja td.numero {
    text-align: right;
}

.hoja-doble {
    text-align: center;
}

/* Las dos líneas de una celda de mes: el número arriba, los días de abajo. No son
   dos columnas porque en la hoja de papel son una sola celda —un 2 sobre 16-17— y
   partirlas duplicaría doce columnas en veinticuatro perdiendo justo el emparejado
   que las hace legibles. Los dos renglones no tienen por qué coincidir, y ese es
   el punto: 24-31 son ocho fechas sobre un 6. */
.hoja-arriba {
    display: block;
}

.hoja-abajo {
    display: block;
    color: var(--texto-tenue);
    font-size: 0.85em;
}

/* Una celda viva. Se dibuja como texto hasta que el apuntador la toca: dos mil
   cosas con cara de botón al mismo tiempo son una hoja que no se puede leer. */
.hoja-celda {
    display: block;
    color: inherit;
    text-decoration: none;
}

.hoja-celda:hover,
.hoja-celda:focus-visible {
    background: var(--acento-tenue);
    text-decoration: underline;
}

/* El renglón bajo el puntero, entero.

   Es lo único que el escritorio tenía en la hoja y la versión web no, y por la razón
   que HojaAnualView dejó escrita: son veintitrés columnas, y seguir un renglón de
   enero a diciembre sin nada que lo marque es perder de vista de quién era la cifra
   a mitad del camino. Las columnas ancladas van aparte porque se pintan su propio
   fondo para quedarse quietas encima de lo que pasa por debajo; sin este segundo
   selector, el nombre sería el único pedazo del renglón que no se enciende. */
.hoja tbody tr:hover td,
.hoja tbody tr:hover td.hoja-fija {
    background: var(--fondo-hundido);
}

/* Un mes sin nada capturado. Se marca al pasar por encima porque si no es una
   celda en blanco que además se puede clicar —una promesa que nadie ve—, y la
   usuaria lo preguntó con todas sus letras: las celdas vacías se supone que pueden
   darse clic, pero cuando están vacías, ¿a qué le das clic? */
.hoja-vacia {
    min-height: 1.2em;
}

.hoja-vacia:hover::after,
.hoja-vacia:focus-visible::after {
    content: "+";
    color: var(--texto-tenue);
}

/* --- El desglose --------------------------------------------------------- */

.desglose-envuelto:empty {
    display: none;
}

/* EL TOPE QUE ESTABA AQUÍ SE FUE, Y VALE LA PENA DEJAR ESCRITO POR QUÉ.

   La tarea 04c dejó `max-height: 45vh` sobre la hoja para que un clic en una cifra
   no la empujara fuera de la pantalla, y la 04d corrigió el número a
   `min(70vh, calc(100vh - 28rem))` con este razonamiento, que sigue siendo correcto:
   lo que hay arriba de la hoja y lo que mide el panel son PÍXELES, no una fracción
   de la ventana, así que restar escala y multiplicar no. A 1080 el 45% dejaba una
   franja vacía de 199px al final, que es lo que la clienta reportó.

   Pero `28rem` seguía siendo una constante medida a mano, y una constante medida a
   mano envejece: cambia el cromo de arriba y nadie se entera. El armazón de alto
   fijo lo mide solo —ver `.alto-fijo` arriba—, así que la regla se fue con todo y
   su número. Lo que no se va es la lección. */

.desglose {
    margin-top: var(--espacio);
    padding: var(--espacio);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--fondo-elevado);
}

.desglose-encabezado {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.6rem;
}

.desglose-encabezado h2 {
    margin: 0;

    /* Empuja el total y el botón al otro extremo, que es lo que `space-between`
       hacía con dos hijos y deja de hacer con tres. */
    margin-right: auto;
    font-size: 1em;
}

/* Cerrar. Es un enlace con forma de botón porque lo que hace es ir a esta misma
   pantalla sin celda; ver el comentario de _Desglose.cshtml. */
.desglose-cerrar {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    align-self: center;
}

.desglose-total {
    margin: 0;
    font-size: 1.4em;
    font-weight: 600;
}

/* Lo capturado no es lo que el sistema propuso. La diferencia es una decisión que
   alguien tomó, y este es el primer lugar del programa donde se ve sin abrir el
   movimiento. */
.difiere {
    color: var(--texto-tenue);
}

/* ---------------------------------------------------------------------------
   Importación y su cola de revisión (tarea 14)
   ------------------------------------------------------------------------ */

/* El reporte de en medio: lo que el libro escribiría, en números. Es el motivo de
   que leer y escribir sean dos clics, así que se lee como una ficha y no como un
   párrafo. */
.reporte-importacion {
    margin-top: var(--espacio);
    padding: var(--espacio);
    background: var(--fondo-elevado);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
}

.reporte-importacion h2 {
    margin: 0 0 0.25rem;
    font-size: 1.05rem;
}

.reporte-importacion h3 {
    margin: 1.2rem 0 0.4rem;
    font-size: 0.95rem;
}

.cifras {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.6rem var(--espacio);
    margin: var(--espacio) 0 0;
}

.cifras div {
    padding: 0.4rem 0;
    border-top: 1px solid var(--borde);
}

.cifras dt {
    color: var(--texto-tenue);
    font-size: 0.85em;
}

.cifras dd {
    margin: 0.1rem 0 0;
    font-size: 1.3em;
    font-weight: 600;
}

/* El número manda y el matiz acompaña: «310» grande, «12 reingresos» al lado y
   pequeño. Dos cifras del mismo tamaño serían dos cifras que compiten. */
.cifras dd .detalle {
    font-size: 0.62em;
    font-weight: 400;
}

.lista-simple {
    margin: 0;
    padding: 0;
    list-style: none;
}

.lista-simple li {
    padding: 0.2rem 0;
    border-top: 1px solid var(--borde);
}

.lista-simple li:first-child {
    border-top: none;
}

/* Decidir. La casilla de forzar y los dos botones, con aire alrededor: es el
   único lugar del programa donde un clic escribe tres mil filas. */
.decidir {
    margin-top: var(--espacio);
}

.casilla {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    margin: 0.6rem 0;
}

/* ---- la cola de revisión ---- */

.grupo-revision {
    margin-top: calc(var(--espacio) * 1.5);
}

.grupo-revision h2 {
    margin: 0 0 0.2rem;
    font-size: 1rem;
}

.grupo-revision .detalle {
    display: block;
    margin-bottom: 0.5rem;
}

.grupo-revision form {
    margin-bottom: 0.5rem;
}

.tabla-revision td {
    vertical-align: top;
}

/* Lo que el libro escribió, y nunca se edita. En monoespaciado para que se lea
   como lo que es: texto de una celda, con sus espacios y sus rarezas. */
.original {
    font-weight: 600;
}

.celda-libro {
    display: inline-block;
    margin-top: 0.2rem;
    padding: 0.05rem 0.3rem;
    background: var(--fondo-hundido);
    border-radius: var(--radio);
    font-size: 0.85em;
}

/* Un renglón ya revisado se apaga sin desaparecer: quitarlo de la vista al
   marcarlo se llevaría la única forma de deshacer un clic equivocado. */
.tabla-revision tr.resuelto {
    color: var(--texto-tenue);
}

.tabla-revision tr.resuelto .original {
    font-weight: 400;
}

.tabla-revision .renglon-forma {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    align-items: center;
}

.tabla-revision .renglon-forma input {
    min-width: 7rem;
    flex: 1 1 7rem;
}

.tabla-revision a.detalle {
    display: block;
    margin-top: 0.3rem;
}

/* El rechazo que reemplaza al renglón: htmx solo puede contestar con un `<tr>`
   aquí, así que el aviso viene dentro de una celda que ocupa la tabla entera. */
.aviso-renglon td {
    border-top: 1px solid var(--borde);
}

/* ---------------------------------------------------------------------------
   Respaldos (tarea 15)
   ------------------------------------------------------------------------ */

/* La verificación es parte del renglón y no una acción aparte, así que la celda
   trae la pastilla y debajo la frase completa. Sin el `display: block` las tres
   quedarían en una sola línea y la columna se llevaría el ancho de la tabla. */
.tabla-respaldos .detalle {
    display: block;
    margin-top: 0.25rem;
}

/* Un respaldo que no abre se queda en la lista: es evidencia sobre este disco, y
   borrarlo por su cuenta es como pasa dos veces lo mismo. Se marca, no se
   esconde. */
.tabla-respaldos tr.fallido code {
    color: var(--alerta);
}

/* Restaurar es lo único de esta pantalla que no se deshace apretando otra cosa,
   y la CSP no deja un confirm() del navegador — que además sería peor: una
   pregunta con el nombre del archivo dice más que «¿Está seguro?». */
.panel.confirmar {
    border-color: var(--alerta);
}

.panel.confirmar h2 {
    color: var(--alerta);
}

/* ---------------------------------------------------------------------------
   Configuración y cierre de aniversarios (tarea 16)
   ------------------------------------------------------------------------ */

/* Una tarjeta o un panel sueltos, apilados uno tras otro. Hasta aquí lo único que
   los separaba era el `gap` de la rejilla `.paneles`, y darle margen al `.panel`
   en general abriría un hueco entre los renglones de esa rejilla en el menú
   principal — por eso esto es una clase que se pide y no una regla sobre el
   elemento. Sin ella, «faltan por abonar» y «abonos que ya no coinciden» quedan
   pegados y se leen como una sola lista, que es exactamente lo que esa pantalla
   existe para no dejar creer. */
.separada {
    margin-top: var(--espacio);
}

/* --- La página de estilos (/estilos) ---------------------------------------

   Las muestras de color van por clase y no por un atributo style, porque el CSP
   lleva «style-src 'self'» y eso gobierna también style-src-attr: un
   style="background:…" en el markup queda bloqueado sin decir nada. Es la misma
   razón por la que las celdas del calendario se colorean por clase.

   Una muestra por token. Si se agrega un token a la paleta se agrega aquí, o la
   página de estilos deja de ser el inventario que dice ser. */

.muestra {
    display: inline-block;
    width: 3rem;
    height: 1.4rem;
    border: 1px solid var(--borde);
    border-radius: var(--radio-chico);
    vertical-align: middle;
}

.muestra-fondo { background: var(--fondo); }
.muestra-fondo-elevado { background: var(--fondo-elevado); }
.muestra-fondo-hundido { background: var(--fondo-hundido); }
.muestra-texto { background: var(--texto); }
.muestra-texto-tenue { background: var(--texto-tenue); }
.muestra-borde { background: var(--borde); }
.muestra-campo { background: var(--campo); }
.muestra-campo-borde { background: var(--campo-borde); }
.muestra-acento { background: var(--acento); }
.muestra-acento-tenue { background: var(--acento-tenue); }
.muestra-sobre-acento { background: var(--sobre-acento); }
.muestra-estructura { background: var(--estructura); }
.muestra-estructura-honda { background: var(--estructura-honda); }
.muestra-sobre-marca { background: var(--sobre-marca); }
.muestra-sobre-marca-tenue { background: var(--sobre-marca-tenue); }
.muestra-marca { background: var(--marca); }
.muestra-marca-tinta { background: var(--marca-tinta); }
.muestra-destacado { background: var(--destacado); }
.muestra-alerta { background: var(--alerta); }

/* --- El teléfono ----------------------------------------------------------

   La aplicación se diseñó, se midió y se corrigió a 1920×1080 y a 1366×768, y esa
   sigue siendo la prioridad: la usuaria captura ocho horas al día en un escritorio.
   Este bloque es para consultarla desde un teléfono, y **no cambia ni una
   declaración de las de arriba**. Esa es la regla que ordena la tarea entera: todo
   lo de aquí vive dentro del @media, así que «no afecta al escritorio» se comprueba
   midiendo las mismas rutas a 1920 y a 1366 antes y después y exigiendo las mismas
   cifras. Salieron idénticas, caja por caja.

   «ANGOSTA O BAJA», y la segunda mitad no es adorno: un teléfono acostado mide
   844×390 y por ancho entraría en el bloque de tableta de más arriba, quedándose con
   123px de riel sobre 390 de alto. Con la altura en la condición recibe el mismo
   trato que de pie.

   Medido a 390×844 antes de escribir esto, sobre 19 rutas: el documento medía 401px
   de ancho en una ventana de 390 —o sea que TODA pantalla del sitio se bamboleaba de
   lado—, el cromo se llevaba 291px de los 844 antes del primer dato, y la caja de la
   tabla de /empleados quedaba en 208: cinco renglones de trescientos doce. */
@media (max-width: 40rem), (max-height: 30rem) {
    /* La marca deja el texto y se queda la teja. El nombre del sistema lo dice el
       <title> y la miga; aquí eran 200px de los 390 y solo cabía un área y media de
       las trece. Con la teja sola se ven tres. No se toca el aria-label. */
    .riel {
        padding: 0.4rem 0.5rem;
        gap: 0.5rem;
    }

    .riel .marca-texto {
        display: none;
    }

    .riel .marca-teja {
        width: 32px;
        height: 32px;
    }

    /* 40px de alto para el dedo. En el escritorio la densidad es una decisión y se
       queda; aquí un blanco de 26px es un blanco que se falla. */
    .areas a {
        min-height: 2.5rem;
    }

    /* EL DESBORDE DE 11px ERA ESTE. `.sesion` —tema, nombre y «Salir»— medía 385
       donde caben 358, y como no puede encogerse por debajo de su contenido, empujaba
       el documento a 401px de ancho en las veintidós pantallas. `min-width: 0` la
       deja encoger y el nombre se recorta con puntos suspensivos, que es lo menos
       malo de las tres opciones (cabe entero, se esconde, o se recorta). */
    /* UN SOLO RENGLÓN. Con `flex-wrap: wrap` la sesión se iba abajo y la barra
       medía 105px de los 844 — el usuario lo dijo así: «abarca demasiado espacio
       vertical y se ve muy mal». Ahora el buscador es lo que cede, el tema se queda
       en tres iconos y «Salir» conserva su palabra, que es lo único aquí que no
       conviene adivinar. */
    .barra {
        flex-wrap: nowrap;
        gap: 0.5rem;
        padding: 0.4rem 0.6rem;
    }

    .buscador {
        min-width: 0;
    }

    .sesion {
        min-width: 0;
        flex: 0 0 auto;
        gap: 0.4rem;
    }

    /* El nombre es lo primero que sobra: quien está mirando el teléfono ya sabe
       quién es, y era lo único de la barra que se recortaba a «Claudia Za…». */
    .quien {
        display: none;
    }

    /* La palabra por el icono. El nombre del botón lo lleva el aria-label. */
    .tema-etiqueta {
        display: none;
    }

    .tema-icono {
        display: inline-block;
    }

    .tema button {
        padding: 0.4rem 0.55rem;
        font-size: 1rem;
        line-height: 1;
    }

    .contenido {
        padding: 0.5rem 0.75rem 1rem;
    }

    .migas {
        padding: 0.35rem 0.75rem 0;
    }

    /* Cada filtro se lleva su renglón. `min-width: 0` es lo que hace falta de verdad:
       un ítem flex no baja de su contenido por omisión, y el selector de reporte mide
       423px. Sin esto empuja la página entera, y con el `overflow: hidden` que traía
       `alto-fijo` ni siquiera se veía empujar: se recortaba el nombre del reporte y
       no había forma de leerlo. */
    .filtros > label,
    .filtros > .filtro,
    .reporte-barra > .filtros {
        flex: 1 1 100%;
        min-width: 0;
    }

    /* 16px y no menos: Safari de iOS ACERCA la página al enfocar un campo más chico
       y no la regresa, así que a partir del primer toque en un filtro el resto de la
       pantalla queda fuera. Aquí medían 13.2. */
    .filtros select,
    .filtros input {
        flex: 1 1 auto;
        min-width: 0;
        max-width: 100%;
        font-size: 16px;
    }

    .formulario input,
    .formulario select,
    .formulario textarea,
    .buscador input {
        font-size: 16px;
    }

    /* `.formulario` es una rejilla de una columna implícita `auto`, y una pista auto
       crece hasta su max-content sin que el contenedor la ate: en /usuarios/editar la
       columna se abría a 608px dentro de 358. */
    .formulario {
        grid-template-columns: minmax(0, 1fr);
    }

    .diagnostico {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Rutas de archivo. No traen espacios, así que no parten solas y desbordaban
       /configuracion a 650px y /respaldos a 379. */
    code {
        overflow-wrap: anywhere;
    }

    /* `inline-flex` y centrado, no solo `min-height`: con la altura sola el texto se
       queda pegado al borde de arriba de la caja. Se vio en «Quitar filtros». */
    .boton {
        display: inline-flex;
        min-height: 2.5rem;
        align-items: center;
        justify-content: center;
    }

    /* ⚠ EL TELÉFONO SUELTA `alto-fijo`, IGUAL QUE LO SUELTA EL PAPEL.

       Atar la caja a la ventana (tarea 06) existe para que la barra de desplazamiento
       de la tabla quede a la vista, y en un teléfono no hay barras que enseñar: se
       desplaza con el dedo. Lo que sí hay es poco alto, y después del cromo y de una
       barra de filtros de cuatro renglones la caja quedaba en 208px — cinco renglones
       de 312, una mirilla. Suelta, la página se desplaza como una página y la caja
       vuelve a sus 70vh: 591px, y el encabezado se queda pegado igual.

       Si alguien agrega mañana una regla a `.alto-fijo` sin liberarla aquí, el
       teléfono vuelve a la mirilla y nada lo dice. Por eso hay una prueba. */
    .armazon.alto-fijo {
        height: auto;
    }

    .alto-fijo .contenido {
        display: block;
        overflow: visible;
    }

    .alto-fijo .hoja-marco {
        display: block;
    }

    .alto-fijo .contenido > .tabla-alta,
    .alto-fijo .hoja-marco > .tabla-alta {
        max-height: 70vh;
    }

    .alto-fijo .desglose-envuelto {
        max-height: none;
    }
}

/* ============================================================================
   LA HOJA DE IMPRESIÓN VA HASTA ABAJO, Y ESO NO ES ORDEN: ES QUE FUNCIONE.

   Estaba a la mitad del archivo, y ahí `@media print { .tabla-alta { max-height:
   none } }` perdía contra `.tabla-alta { max-height: 70vh }`, que se declara más
   abajo — misma especificidad, gana la última. Resultado: /constancias imprimía sus
   562 renglones EN UNA SOLA PÁGINA, y llevaba así desde que existe la regla.

   Se descubrió imprimiendo a PDF y contando páginas, que es el criterio que la tarea
   04 dejó sin palomear. No se veía de ninguna otra forma: en pantalla todo estaba
   bien, y una regla de impresión que no gana no avisa.

   Toda regla nueva que se escriba después de este punto se imprime igual que se ve.
   Hay una prueba que exige que este bloque siga siendo lo último del archivo.
   ============================================================================ */
/* ---------------------------------------------------------------------------
   Impresión
   ---------------------------------------------------------------------------

   Esta usuaria imprime. El requisito de constancias salió de una foto de una hoja
   impresa rayada con marcador amarillo, así que lo que sale de la impresora es un
   entregable y no un accidente.

   Lo que se va son los controles —riel, buscador, migas, botones, filtros— porque
   en papel no se hace clic; lo que se queda es lo que se leía en pantalla. Los
   colores se fuerzan a imprimirse: sin esto el navegador vacía los fondos y los
   siete tipos de evento quedan del mismo gris. Las etiquetas los distinguirían de
   todos modos, y aun así una hoja a color se lee de un vistazo. */

@media print {
    /* `.barra` y no `.buscador`: escondiendo solo la caja de búsqueda, la tira de
       arriba se quedaba en el papel con el interruptor de tema, el nombre de quien
       imprimió y un botón de «Salir». Salió al imprimir la hoja de constancias a PDF
       y mirarla; en pantalla no hay nada que se vea mal. */
    .riel,
    .encabezado,
    .barra,
    .migas,
    .filtros,
    .modos,
    .acciones,
    .mes-selector,
    .vistos {
        display: none;
    }

    /* La barra del mes se queda porque lleva el título: una hoja impresa que no
       dice de qué mes es no sirve de nada. Lo que se va son sus flechas. */
    .mes-barra .boton {
        display: none;
    }

    body,
    .contenido,
    .contenido-suelto {
        margin: 0;
        padding: 0;
        background: #fff;
        color: #000;
    }

    .chip,
    .dia,
    .dia-domingo,
    .dia-nolaborable,
    .dia-festivo {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* Un día del calendario no cabe cuadrado en una hoja junto a sus chips: en
       papel manda el contenido, que es lo que se va a leer con el marcador en la
       mano. */
    .dia {
        aspect-ratio: auto;
        min-height: 4.5rem;
    }

    .agenda-dia,
    .rejilla {
        break-inside: avoid;
    }

    /* La hoja de constancias también se imprime: es la que hoy se raya con
       marcador amarillo. El recorte de 70vh es para una pantalla; en papel
       cortaría la lista a la mitad. */
    .tabla-alta {
        max-height: none;
        overflow: visible;
    }

    /* En papel no se hace clic ni se descarga nada. */
    .reporte-exportar,
    .desglose-cerrar,
    .hoja-plegar {
        display: none;
    }

    /* UNA TABLA ANCHA EN PAPEL NO SE DESPLAZA: SE RECORTA.

       En pantalla las celdas son `nowrap` y la caja se desplaza, que es lo correcto
       —los reportes son legítimamente anchos—. En una carta no hay a dónde
       desplazarse: el reporte general mide nueve columnas y la impresora se llevaba
       cuatro, sin decirlo. Dejándolas envolver, la tabla se acomoda al ancho del
       papel y el renglón crece hacia abajo, que es lo que hace una tabla impresa.

       Y la holgura del final se suelta: repartir el sobrante tiene sentido en un
       monitor de 1920, no en una hoja donde no sobra nada. */
    .tabla {
        font-size: 8pt;
    }

    .tabla th,
    .tabla td {
        padding: 0.15rem 0.3rem;
        white-space: normal;
    }

    .tabla-holgada th:last-child {
        width: auto;
    }

    /* Y el armazón de alto fijo se suelta entero, o el papel sale de una sola
       página: una ventana de 1080 con `overflow: hidden` imprime 1080 y recorta
       todo lo demás. Es el defecto más caro de este archivo, porque no se ve en
       pantalla —solo en la hoja que ya se imprimió—, y por eso hay una prueba que
       exige que este bloque nombre a `alto-fijo`. */
    .armazon.alto-fijo {
        height: auto;
    }

    .alto-fijo .columna,
    .alto-fijo .contenido,
    .alto-fijo .hoja-marco {
        display: block;
        overflow: visible;
    }

    .alto-fijo .contenido > .tabla-alta,
    .alto-fijo .hoja-marco > .tabla-alta,
    .alto-fijo .desglose-envuelto {
        max-height: none;
        overflow: visible;
    }

    /* El botón deja de parecer botón y se queda la palomita, que es lo único que
       la hoja tiene que decir. */
    .marca-boton {
        border: none;
        padding: 0;
    }

    .tabla thead {
        display: table-header-group;
    }

    /* La hoja impresa vuelve a ser una hoja impresa. En pantalla el encabezado y
       las dos primeras columnas se quedan quietos mientras lo demas se recorre; en
       papel no hay nada que recorrer, y una celda fija sobre el papel se encimaria
       con la de al lado. */
    .hoja-envuelta {
        max-height: none;
        overflow: visible;
    }

    .hoja thead th,
    .hoja .hoja-fija,
    .hoja-banda th,
    .hoja-banda th > span {
        position: static;
    }

    .hoja {
        font-size: 7pt;
    }

    /* Una celda viva es un enlace, y en papel un enlace subrayado es ruido: lo que
       se lleva la hoja son las cifras. */
    .hoja-celda:hover,
    .hoja-celda:focus-visible {
        background: none;
        text-decoration: none;
    }

    .brinco,
    .desglose-envuelto,
    .reporte-contexto {
        display: none;
    }

    /* En pantalla el nombre de la empresa y el del reporte van en un renglón para
       no gastar alto; en papel el encabezado es lo único que dice de qué es la
       hoja, y ahí se lee en dos. */
    .hoja-encabezado {
        display: block;
    }

    /* La banda abre un bloque de division; partirlo justo debajo deja gente sin
       encabezado que diga de cual es. */
    .hoja-banda {
        break-after: avoid;
    }
}
