/*
 * base.css — lo que define la página: tokens, tipografía y armazón.
 *
 * Era la primera mitad de `app.css`, que pasó el techo de líneas de
 * docs/marca-frontend.md §0. El corte no es por tamaño sino por pregunta: acá
 * va lo que DEFINE la página (de qué color es, con qué letra, dónde va cada
 * zona), en `componentes.css` lo que se pone DENTRO de ella y en
 * `navegacion.css` lo que la RODEA: la barra, la lateral y el menú de la
 * cuenta. Esa frase es lo que le dice al próximo dónde escribir una regla
 * nueva sin preguntar.
 *
 * Carga SIEMPRE, y SIEMPRE PRIMERO: los tokens de `:root` que declara acá los
 * usa todo lo demás, y la cascada los necesita ya definidos.
 */

/* --- Tipografía autohospedada (marca-frontend.md §3) -----------------------
 *
 * Desviación documentada respecto del §3: en vez de Regular + SemiBold como
 * dos archivos estáticos, se sirve el archivo VARIABLE de Plex Sans. Cubre
 * 400 y 600 (y cualquier peso intermedio) en 40 KB, contra ~50 KB que pesan
 * los dos estáticos por separado — menos bytes y menos peticiones en el
 * cuarto de máquinas, que es el criterio con que el §3 eligió dos pesos.
 */

@font-face {
    font-family: "IBM Plex Sans";
    src: url("../fuentes/IBMPlexSans-Variable-latin.d28498895ed7.woff2") format("woff2-variations");
    font-weight: 100 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC;
}

@font-face {
    font-family: "IBM Plex Mono";
    src: url("../fuentes/IBMPlexMono-Regular-latin.814fe1615d4d.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC;
}

/* --- Tokens (marca-frontend.md §6) --------------------------------------- */

:root {
    /* Superficies */
    --color-fondo: #f4f5f7;
    --color-superficie: #ffffff;
    --color-crema: #f2ede4;

    /* Azul hondo: cromo de la lateral de la app. Vivía solo en `publico.css`
     * (login y portada); ahora también lo usa la lateral de la app, así que
     * sube acá, que es lo que cargan las dos zonas. */
    --color-azul-hondo: #0f2537;
    /* Texto secundario sobre una superficie azul: crema con alfa, mismo
     * criterio que `--color-texto-suave` pero para fondo oscuro. Nació para
     * la lateral (azul hondo) y desde el 2026-09-05 también viste
     * `.filtros`/`.tabla thead th`/`.migas` sobre `--color-superficie-marca`
     * (azul más claro que el hondo): medido de nuevo ahí da 5,85:1 — sigue
     * sobrando AA (4,5:1) aunque el fondo sea más claro. */
    --color-crema-suave: rgba(242, 237, 228, 0.72);
    /* Hover/activo sobre una superficie azul: velo claro, no un tono nuevo.
     * Misma ampliación que la de arriba: azul hondo (lateral) o azul de
     * marca (filtros, migas). */
    --color-crema-velo: rgba(242, 237, 228, 0.12);
    /* Filete apenas visible sobre una superficie azul, misma familia que el
     * velo — únicamente decorativo (separadores, filetes de "activo"), por
     * eso no lleva medición de contraste: nunca es la única señal de nada. */
    --color-crema-filete: rgba(242, 237, 228, 0.18);

    /* Texto */
    --color-texto: #1f2430;
    --color-texto-suave: #5b6270;

    /* Bordes: decorativo y de control son cosas distintas (§2.2) */
    --color-borde: #d8dbe0;
    --color-borde-campo: #7d8593;

    /* Marca */
    --color-primario: #1c3d5a;
    --color-primario-hover: #14293d;
    /* Superficie pintada en el azul de marca: el fondo de `.filtros`,
     * `.tabla thead th` y `.migas` (marca-frontend.md §5.3.1/§5.4/§5.4.1,
     * 2026-09-05). Mismo valor que `--color-primario` —no es un tono
     * nuevo—, pero con nombre propio: "qué superficie se pinta de azul" es
     * una decisión de layout y "qué es interactivo" (botón, enlace, foco) es
     * otra, y no conviene que cambiar una mueva la otra sin querer. Encima
     * va texto de la familia `--color-crema*`: crema da 9,66:1, crema-suave
     * 5,85:1 — medidos con la fórmula de luminancia relativa de WCAG. */
    --color-superficie-marca: var(--color-primario);

    /* Cumplimiento: responde "¿cuándo vence esto?" */
    --color-exito: #15803d;        --color-exito-fondo: #e7f6ec;
    --color-advertencia: #b45309;  --color-advertencia-fondo: #fdf1de;
    --color-error: #b91c1c;        --color-error-fondo: #fbe9e9;
    --color-error-hover: #911616;
    --color-neutro: #4b5563;       --color-neutro-fondo: #e9eaec;

    /* Información: separado del primario */
    --color-info: #1d4ed8;         --color-info-fondo: #e8eefd;

    /* Origen/aprobación: responde "¿quién hizo esto?" */
    --color-propuesta: #0e6b76;    --color-propuesta-fondo: #e3f3f4;

    /* Tipografía */
    --fuente-ui: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --fuente-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Consolas, monospace;

    /* Velo del cajón de navegación en celular: oscurece el contenido que
     * queda detrás del menú abierto para que se lea como una capa encima y
     * no como parte de la pantalla (§5.5.1). */
    --color-velo: rgba(31, 36, 48, 0.5);

    /* Métrica */
    --radio: 6px;
    /* Esquinas de la lateral flotante: más redondeada que un control (§6),
     * porque es una losa completa y no una píldora. */
    --radio-lateral: 14px;
    --sombra: 0 1px 3px rgba(31, 36, 48, 0.1);
    /* La del cajón es otra sombra: tiene que separar una capa entera del
     * fondo, no levantar una tarjeta un milímetro. */
    --sombra-cajon: 0 0 2rem rgba(31, 36, 48, 0.28);
    --espacio: 1rem;
    --espacio-sm: 0.625rem;
    --espacio-lg: 2rem;
    --toque-minimo: 44px;
    --boton-ancho: 9.5rem;
    /* Sube de 1080 a 1440: la lateral ya no es una franja que compite por el
     * ancho de la pantalla —es una columna flotante angosta—, así que el
     * contenido puede estirarse más en una pantalla grande. */
    --ancho-contenido: 1440px;
    /* Ancho de la lateral en escritorio, y su riel colapsado (solo íconos). */
    --ancho-lateral: 17rem;
    --ancho-lateral-compacta: 4.75rem;
}

/* --- Base ---------------------------------------------------------------- */

* { box-sizing: border-box; }

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

body {
    margin: 0;
    font-family: var(--fuente-ui);
    font-size: 1rem;
    background: var(--color-fondo);
    /* Columna para que `.disposicion` se estire hasta abajo y la lateral
       llegue al borde inferior aun con una pantalla de poco contenido. */
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    color: var(--color-texto);
    line-height: 1.5;
    /* Un correo largo o una URL pegada en una observación no tienen dónde
     * cortar, y en 360 px estiraban la ficha entera hasta desbordar. */
    overflow-wrap: break-word;
}

h1, h2, h3 { line-height: 1.25; margin: 0 0 var(--espacio-sm); }
h1 { font-size: 1.5rem; font-weight: 600; }
h2 { font-size: 1.25rem; font-weight: 600; margin-top: var(--espacio-lg); }
h3 { font-size: 1.05rem; font-weight: 600; }

/* El subrayado pegado a la letra ensucia las tildes y los descendentes, y en
 * una tabla de enlaces —que es la mitad de las pantallas de la app— eso es
 * una reja de rayas. Separarlo un pelo no le quita la señal a nadie. */
a { color: var(--color-primario); text-underline-offset: 0.15em; }

/* Anillo de foco de dos colores (§2.1): el aro claro contrasta sobre azul y
 * el aro oscuro contrasta sobre página clara, así que no hay fondo del
 * sistema donde falle. */
:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-superficie),
                0 0 0 5px var(--color-primario);
}

/* Dato verificable: se compara, se dicta por teléfono o se copia a otro
 * sistema (§3). Junto con `body`, las dos únicas reglas que declaran familia. */
.mono {
    font-family: var(--fuente-mono);
    font-variant-numeric: tabular-nums;
    font-size: 0.95em;
}

/* --- Trama de puntos -------------------------------------------------------
 * El canvas de fondo que dibuja `trama.js`. Vivía en `publico.css` porque solo
 * la usaban las dos pantallas públicas (portada e ingreso); ahora también la
 * usa la lateral de la app —quieta, sin animación ambiental (§8.b)—, así que
 * sube a `base.css`, que es lo que cargan las tres. `base_publico.html`
 * también carga `base.css`, así que las públicas quedan posicionadas igual. */

.trama {
    position: absolute;
    inset: 0;
    z-index: -2;
    width: 100%;
    height: 100%;
    /* El canvas mide una fracción del alto real: cada punto suyo se sirve
     * como un cuadrado nítido, sin la interpolación que lo convertiría en un
     * degradado borroso. */
    image-rendering: pixelated;
}

/* `min(...)` y no `var(...)` a secas: `<main>` es celda de la reja de
 * `.disposicion` y su mínimo automático es el de su contenido, así que una
 * tabla de 800 px lo estiraba a 800 px y quien deslizaba era la PÁGINA
 * ENTERA, no el envoltorio de la tabla. En celular eso movía la barra, el
 * encabezado y los filtros hacia afuera de la pantalla. El tope de 100 % lo
 * devuelve al ancho de su celda y la tabla vuelve a deslizarse sola.
 *
 * `width: 100%` es obligatorio y NO es redundante con ese `max-width`:
 * `<main>` es item de la reja y `margin: 0 auto` le saca el `stretch`, así
 * que sin ancho declarado se encoge al de su contenido. Medido
 * el 2026-08-27 a 1280 px: la celda daba 1056 y `<main>` medía 508. El panel y
 * las tablas quedaban centrados en una franja angosta con dos zanjas vacías a
 * los lados, y la reja de `.cifras` armaba dos columnas donde caben cuatro. */
.contenedor {
    width: 100%;
    max-width: min(var(--ancho-contenido), 100%);
    margin: 0 auto;
    /* En celular el margen se achica: 16 px por lado son 32 px menos de tabla
     * en una pantalla de 360. Desde 40rem vuelve al espacio completo. */
    padding: var(--espacio-sm);
}

@media (min-width: 40rem) {
    .contenedor { padding: var(--espacio); }
}

/* Con la lateral al lado, 16 px dejan el título pegado a su filete y la
 * pantalla se lee como si el contenido empezara dentro del menú. El aire de
 * más solo entra desde 48rem, que es donde hay columna al costado: en celular
 * esos 32 px son tabla. El padding de arriba se queda en `--espacio`, no sube
 * a `--espacio-lg` como el resto: la lateral flotante arranca en
 * `top: var(--espacio)` (navegacion.css @media 48rem), y solo con el mismo
 * valor las migas quedan a la misma altura que el borde superior de la
 * losa azul de la lateral. */
@media (min-width: 48rem) {
    .contenedor { padding: var(--espacio-lg); padding-top: var(--espacio); }
}

/* El botón flotante del menú (`.menu-flotante`) es fijo y vive abajo a la
 * derecha en celular: sin este aire de más, tapa la última fila de una tabla
 * larga. Aparte y con `max-width` para apagarse justo donde se apaga el
 * botón (48rem) sin pelear con la cascada móvil-primero de arriba. */
@media (max-width: 47.9375rem) {
    .contenedor { padding-bottom: calc(var(--espacio-sm) + 3.5rem); }
}

/* --- Disposición de la app (lateral flotante, módulos al costado) ----------
 * El menú de módulos vivía en la barra superior. Con ocho encendidos la fila
 * ocupaba todo el ancho y empujaba la sesión a una segunda línea; en vertical
 * la lista crece sin competir con nada.
 *
 * La lateral es una COLUMNA A LA IZQUIERDA en las dos formas de pantalla,
 * desde el 2026-08-27 (§5.5.1), y desde ahora además flota: sin barra
 * superior que la recorte, es una losa azul hondo con esquinas redondeadas,
 * separada del borde de la ventana, con la trama de puntos de la landing y el
 * login de fondo. En celular sigue entrando como cajón por la izquierda sobre
 * el contenido; en escritorio es la columna fija, siempre visible.
 *
 * El <nav> va antes del <main> en el marcado, que es donde cae en pantalla en
 * las dos formas, así que no hace falta reordenar nada desde acá — y el foco
 * del teclado sigue el mismo camino que el ojo (WCAG 2.4.3).
 *
 * `flex` en el body y `flex: 1` acá para que la lateral llegue abajo aunque la
 * pantalla tenga poco contenido. `align-items: start` es lo que deja el
 * `position: sticky` de la lateral (navegacion.css, @media 48rem) funcionar:
 * sin esto un item de grid se estira a la altura de la celda más alta y un
 * elemento sticky dentro de una celda ya estirada no tiene contra qué
 * deslizarse. No afecta al cajón de celular, que es `position: fixed`. */

.disposicion {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    flex: 1;
}

/* --- Migas de pan ---------------------------------------------------------
 * Fondo azul de marca desde el 2026-09-05 (marca-frontend.md §5.4.1): antes
 * heredaba el gris de `body` sin declarar nada propio. Chip que se ajusta a
 * su contenido (`width: fit-content`) y no una franja de ancho completo —es
 * una migaja de texto corto, no un encabezado, y una barra azul de punta a
 * punta pelearía con el título de debajo por la misma atención. El padding y
 * el radio son los del resto del sistema (`--espacio-sm`, `--radio`), no
 * valores propios. */
/* Fila que junta el chip de migas con el botón del hub (`_menu_hub.html`,
 * incluido junto a `_migas.html` en `base.html`): `align-items: stretch` para
 * que ambos midan lo mismo de alto —el botón trae `min-height: var(--toque-minimo)`
 * de listado.css y estira al chip, sin perder el cuadrado de toque de 44px—,
 * `flex-wrap` para no romper en celular si no entran los dos, y el
 * `margin-bottom` que antes tenía `.migas` se muda para acá. */
.migas-fila {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: var(--espacio-sm);
    margin-bottom: var(--espacio-sm);
}

.migas {
    margin-bottom: 0;
    padding: 0.5rem var(--espacio-sm);
    background: var(--color-superficie-marca);
    border-radius: var(--radio);
    width: fit-content;
    max-width: 100%;
    font-size: 0.9rem;
}

.migas__lista {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

/* La barra separadora es decorativa: `aria-hidden` no aplica a un ::before,
 * pero el lector de pantalla anuncia la lista, no el separador. Por ser
 * decorativa no lleva medición de contraste (nunca es la única señal de
 * nada) — mismo filete apenas visible que usa la lateral para sus propios
 * separadores. */
.migas__paso + .migas__paso::before {
    content: "/";
    margin-right: 0.4rem;
    color: var(--color-crema-filete);
}

/* Texto y paso actual: familia crema sobre la superficie azul, mismo
 * criterio que `.lateral__enlace` (navegacion.css) sobre azul hondo — crema
 * suave para el paso de siempre (5,85:1), crema plena para el actual y para
 * el hover, que es la misma señal de "esto responde" que usa la lateral. */
.migas__paso { color: var(--color-crema-suave); }
.migas__paso a { color: var(--color-crema-suave); }
.migas__paso a:hover { color: var(--color-crema); }
.migas__paso[aria-current="page"] { color: var(--color-crema); font-weight: 600; }

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

.encabezado {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--espacio-sm) var(--espacio);
    margin-bottom: var(--espacio);
}

.encabezado__titulo { margin: 0; }

.encabezado__descripcion { margin: 0.2rem 0 0; color: var(--color-texto-suave); }

/* En celular las acciones toman el renglón completo debajo del título: con el
 * título al lado no queda ancho para un botón que además tiene piso de 9,5 rem
 * (ver `componentes.css`, filas de acciones). Desde 40rem vuelven a la derecha
 * del título, que es donde el §5.0 las pone. */
.encabezado__acciones {
    display: flex;
    flex-wrap: wrap;
    gap: var(--espacio-sm);
    width: 100%;
}

@media (min-width: 40rem) {
    .encabezado__acciones { width: auto; margin-left: auto; }
}

/* --- Mensajes de Django --------------------------------------------------- */

.lista-mensajes {
    list-style: none;
    margin: 0 0 var(--espacio);
    padding: 0;
    display: grid;
    gap: var(--espacio-sm);
}

.mensaje {
    padding: 0.75rem var(--espacio);
    border-radius: var(--radio);
    border: 1px solid transparent;
}

.mensaje--success { background: var(--color-exito-fondo); color: var(--color-exito); border-color: var(--color-exito); }
.mensaje--warning { background: var(--color-advertencia-fondo); color: var(--color-advertencia); border-color: var(--color-advertencia); }
.mensaje--error   { background: var(--color-error-fondo); color: var(--color-error); border-color: var(--color-error); }
.mensaje--info,
.mensaje--debug   { background: var(--color-info-fondo); color: var(--color-info); border-color: var(--color-info); }

/* Hub → pantalla se lee como bajar un nivel y no como recarga en blanco.
 * Cross-document, cero JS; sin soporte el navegador recarga como siempre.
 * Los pseudo-elementos ::view-transition-* NO los alcanza el `*` del bloque
 * de movimiento reducido de componentes.css, así que se apagan aparte. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: 200ms ease-in both salir-vista; }
::view-transition-new(root) { animation: 250ms cubic-bezier(0.2, 0, 0, 1) both entrar-vista; }
@keyframes salir-vista { to { opacity: 0; transform: translateY(-6px); } }
@keyframes entrar-vista { from { opacity: 0; transform: translateY(10px); } }
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}

