/* GDV — hoja de estilo única, escrita a mano.
 *
 * Sin framework, sin preprocesador y sin paso de compilación: lo que se lee acá
 * es lo que sirve el servidor. Un cambio de estilo es un cambio de este archivo,
 * revisable en el diff y sin un artefacto intermedio que pueda quedar viejo.
 *
 * Los **tokens de color** son la paleta GDV de `docs/GDV_DESIGN.md` (§4), en
 * dos temas: oscuro —el de siempre, y el que rige sin elección en un sistema
 * oscuro— y claro. La elección viaja en la cookie `tema`, que el servidor lee y
 * convierte en `data-tema` sobre `<html>` (ver `base.html`): la página llega ya
 * pintada del tema correcto. Sin cookie decide `prefers-color-scheme`, acá.
 * Están escritos como tripletes HSL sin la función alrededor —`210 11% 7%` y no
 * `hsl(210 11% 7%)`— justamente para poder pedirle una versión translúcida al
 * mismo token: `hsl(var(--destructive) / .12)` es el tinte del rojo sin declarar
 * un segundo color que pueda desincronizarse del primero. Cada triplete lleva al
 * lado el hex del documento del que sale.
 *
 * El criterio de fondo no cambió: esto es una herramienta de trabajo, no una
 * landing. Densidad antes que aire. No hay animaciones, ni degradados, ni
 * sombras que no sean la del panel desplegado, ni un solo icono que no diga algo
 * que el texto no diga.
 *
 * ===========================================================================
 * LOS CUATRO ANCHOS
 * ===========================================================================
 *
 * La hoja es **mobile-first**: la regla base es la del celular y las `@media`
 * agregan columnas hacia arriba. Hay exactamente tres cortes:
 *
 *       base          ≥ 640px        ≥ 1024px        ≥ 1440px
 *       celular       tablet         notebook        monitor
 *
 * CSS no admite `var()` adentro de una `@media`, así que esos tres números se
 * escriben literales. **En toda la hoja no hay otro ancho de corte**, con una
 * sola excepción anotada donde aparece: `@media (min-width: 1900px)`, para los
 * dos cheques por fila del formulario de carga.
 *
 * No hay ninguna `@media (max-width: …)` de layout. Las dos únicas `max-width`
 * de la hoja son de preferencia —`prefers-color-scheme` y
 * `prefers-reduced-motion`— y no hablan de ancho.
 *
 * **Los tokens no se redefinen adentro de una `@media`.** Es una restricción de
 * la suite y no una preferencia: `tests/test_pantallas_diseno.py` lee los
 * bloques `:root` con una expresión sobre el archivo entero, y un segundo
 * `:root` adentro de una `@media` pisaría al de arriba y dejaría la paleta
 * medio leída. Lo que cambia con el ancho —el relleno del contenido, el ancho
 * del panel— se escribe en la regla que lo usa, no en el token.
 *
 * ===========================================================================
 * LAS OCHO REGLAS QUE NO SON COSMÉTICAS
 * ===========================================================================
 *
 * 1. **Densidad primero.** Se tienen que ver muchas filas sin scrollear. La fila
 *    de datos ronda los 28px: tipografía de 15px con interlineado corto y 4px de
 *    padding vertical, sin márgenes decorativos en la página. El «espacio
 *    negativo generoso» del documento de diseño aplica a márgenes y tarjetas,
 *    nunca a meter menos filas por pantalla: esa decisión ya estaba tomada.
 * 2. **Objetivos táctiles de 44px** en botones y campos, sin excepciones en las
 *    acciones que están solas. La única que queda —la cruz que saca un alias de
 *    un chip— está explicada donde aparece.
 * 3. **Los importes van en Space Mono, alineados a la derecha y con
 *    `tabular-nums`.** Con ancho de dígito fijo, la longitud de la cifra *es* su
 *    magnitud: un importe grande se distingue de uno chico sin leerlo, y dos
 *    columnas de números se comparan renglón contra renglón. **Y van al cuerpo
 *    del texto que acompañan**: la mono no se achica para que entre una columna
 *    de más. Lo que decide qué columnas entran es la prioridad, no el cuerpo.
 * 4. **Los negativos van entre paréntesis** —los pone `formato.importe`— **y** en
 *    rojo. Dos señales independientes: el color solo no alcanza para quien no lo
 *    distingue.
 * 5. **Los estados se distinguen sin color**: además del tinte, el relleno, el
 *    trazo punteado y el tachado dicen lo mismo que la palabra que llevan dentro.
 * 6. **El dato pesa más que su rótulo.** El saldo domina sobre la palabra
 *    «Saldo», y el encabezado de una tabla es más tenue que los datos que
 *    encabeza, nunca al revés.
 * 7. **El texto tiene largo de línea y los datos no.** Todo lo que se lee de
 *    corrido lleva `--linea` (70ch); una tabla, una grilla de tarjetas o un
 *    formulario de asiento usan todo el ancho que haya. Una tabla de operaciones
 *    no es un párrafo, y en un monitor esa diferencia es un tercio de la
 *    pantalla.
 * 8. **Nada en versales.** La jerarquía la dan el peso y el color. Lo que está
 *    en mayúsculas es porque **es** un dato que se guarda así —un nombre del
 *    padrón, un código de cuenta, el «NO TOMAR» que escribe Nosis—, nunca porque
 *    lo pinte esta hoja.
 */

/* --- Tipografía: las dos familias, autoalojadas ------------------------- */

/* Servidas desde `static/fuentes/` y no desde fonts.googleapis.com. Una llamada
 * a un tercero en cada carga es una dependencia de red que no hace falta: en una
 * oficina con conexión mala se nota, y el día que Google no conteste la interfaz
 * tiene que verse igual. Es la misma razón por la que htmx está vendorizado.
 *
 * `font-display: swap`: mientras el archivo viaja se lee en la fuente del
 * sistema. Una pantalla en blanco esperando una tipografía es exactamente lo
 * contrario de lo que esta interfaz necesita.
 *
 * Los `unicode-range` son los de Google: el archivo «latin» alcanza para todo el
 * castellano y el «latin-ext» sólo se descarga si aparece un carácter que lo
 * pida. Son dos pedidos posibles, no dos seguros. */

@font-face {
  font-family: "DM Sans";
  src: url("fuentes/dm-sans-latin.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "DM Sans";
  src: url("fuentes/dm-sans-latin-ext.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Space Mono";
  src: url("fuentes/space-mono-400-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Mono";
  src: url("fuentes/space-mono-400-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Space Mono";
  src: url("fuentes/space-mono-700-latin.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Mono";
  src: url("fuentes/space-mono-700-latin-ext.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- Tokens -------------------------------------------------------------- */

:root {
  /* El tema oscuro, que es el de base: el de siempre, el del login —que no
   * conmuta— y el que rige cuando no hay cookie y el sistema es oscuro. Los
   * valores son los de GDV_DESIGN §4 tal cual (el hex va al lado); si hay que
   * cambiar la paleta se cambia acá y en ningún otro lado del archivo hay un
   * color escrito. */
  color-scheme: dark;
  --background: 210 10.5% 7.5%;        /* #111315 fondo general */
  --foreground: 220 14.3% 95.9%;       /* #F3F4F6 texto principal */
  --card: 214 12.7% 10.8%;             /* #181B1F superficie / tarjeta */
  --card-border: var(--border);
  --border: 215 11.1% 21.2%;           /* #30353C bordes */
  --sidebar: var(--card);
  --sidebar-border: var(--border);
  --popover: 216 13.5% 14.5%;          /* #20242A superficie elevada */
  /* El azul del documento es #2477D2 (48,2% de luminosidad): con blanco encima
   * queda en 4,52:1, sin margen. Mismo tono y saturación, un punto más oscuro,
   * y el botón principal pasa con 4,7. El hover, un punto más claro que el
   * primario: se enciende, y el blanco sigue llegando. */
  --primary: 211.4 70.7% 47%;          /* #2477D2, oscurecido hasta contrastar */
  --primary-hover: 212 77.5% 48%;      /* #3287E5, ídem */
  --primary-foreground: 0 0% 100%;
  --secondary: 215 12% 17%;
  --secondary-foreground: var(--foreground);
  --muted: var(--popover);
  --muted-foreground: 217 10.8% 67.5%; /* #A3AAB5 texto secundario */
  --accent: 216 13% 15.5%;
  --accent-foreground: var(--foreground);
  --destructive: 0 78.4% 63.7%;        /* #EB5A5A error */
  --success: 153 48.7% 44.3%;          /* #3AA877 éxito */
  --warning: 40 72.7% 55.5%;           /* #E0A83B advertencia */
  --enfasis: 39 86.6% 64.9%;           /* #F3BE58 amarillo de énfasis */
  --marca: var(--foreground);
  --input: 215 11% 30%;
  --ring: var(--primary-hover);
  --sombra: 220 40% 2%;
  /* El filo que dice «esta tabla sigue a la derecha». **No es `--sombra`**, y
   * por eso es un token propio: en el tema claro una sombra es más oscura que la
   * superficie, y en el oscuro no hay adónde bajar —la superficie está en 10,8 %
   * de luminosidad y la sombra en 2 %—. Medido sobre las capturas: en claro el
   * borde va de 255 a 179 (76 niveles) y en oscuro de 24 a 17, **siete niveles**,
   * o sea ninguna señal; y desde §12.12 la barra de scroll se apaga a partir de
   * 640, así que en oscuro no quedaba **nada** que dijera que la cartera tiene
   * seis columnas más. Acá el filo es más claro que la superficie, que es la
   * única dirección que queda: la señal es el contraste, no el color. */
  --sombra-borde: 215 11% 50%;

  /* Los `-text`: el mismo color usado como **texto sobre el fondo**, no como
   * relleno. Un azul o un rojo que rinde bien de relleno no siempre llega a
   * 4,5:1 como letra chica, así que estas variantes suben (acá) o bajan (en el
   * tema claro) la luminosidad del mismo tono hasta que contrasta, también
   * sobre los tintes translúcidos donde se usan —el chip azul, el badge verde—.
   * Los valores salen de calcular el contraste, no del ojo: hay un test que los
   * verifica en los dos temas. */
  --primary-text: 212 78% 62%;
  --destructive-text: 0 78% 72%;
  --success-text: 153 49% 53%;
  --warning-text: var(--warning);       /* en oscuro el ámbar ya contrasta */
  --enfasis-text: var(--enfasis);

  /* --- Medidas. No son colores y no salen del documento: salen de la mano y
   * del dedo que usan esto. --- */

  /* La unidad de aire. Todo margen y todo hueco de la hoja es un múltiplo. */
  --paso: 8px;

  /* Alto mínimo de un objetivo táctil, y el de la acción principal. Están acá y
   * no repetidos en cada regla para que subirlos sea una línea. 44px es el
   * mínimo que pide GDV_DESIGN §10. */
  --toque: 44px;
  --toque-grande: 48px;

  /* **Dos radios y no más.** El grande es de las cajas —tarjeta, marco, panel,
   * la hoja de «Más»— y el chico es de lo que se toca y de lo que se lee como
   * etiqueta —control, badge, chip, marca—. No hay píldoras: un badge es un
   * rectángulo redondeado, y lo que lo distingue de un botón es que no tiene
   * borde de control ni cursor. Si dos elementos se ven distintos, es porque
   * SON distintos. */
  --radio: 8px;
  --radio-chico: 4px;

  /* El largo de línea máximo del texto que se lee de corrido. Es la mitad de la
   * regla 7 del encabezado: lo lleva `.texto` y `.nota`, y **nada más**. Antes
   * había veintidós topes de ancho repartidos por el archivo —92ch, 68ch, 60ch,
   * 52ch, 46ch, 44ch, 40ch, 34ch, 24ch y un 480px— puestos pantalla por
   * pantalla, y varios caían sobre datos, que no son texto. */
  --linea: 70ch;

  /* El esqueleto. El alto de la cabecera está escrito porque lo necesitan dos
   * reglas que no se ven entre sí: la propia cabecera y la marca del panel
   * lateral, que tiene que quedar en su mismo renglón. Antes era implícito —44
   * del control más el relleno— y estaba escrito dos veces.
   *
   * **Eran tres**: el tercer uso era el `top` del `sticky` de la propuesta del
   * diálogo, que se fue con el panel fijo (ver el bloque del monitor, «EL
   * DIÁLOGO»). El token se queda igual y el contrato §12.1 lo justifica con ese
   * tercer uso, que ya no existe: hay que corregirlo ahí. */
  --cabecera: 56px;
  --barra: 56px;             /* la barra inferior de navegación, sólo celular */
  --lateral: 256px;          /* el panel de navegación expandido */
  --lateral-angosta: 64px;   /* el panel colapsado */

  /* La escala tipográfica. **Cinco pasos**, no ocho: cada uno tiene un trabajo y
   * se nombra por lo que hace, no por su tamaño. Los rangos son los de
   * GDV_DESIGN §5.
   *
   * Los tres que se fueron: `--t-menor` (12px) era `--t-rotulo` con otro
   * nombre; `--t-secundario` (13px) era un paso entre 12 y 15 que obligaba a
   * decidir de a un caso; `--t-cifra` (28px) era `--t-titulo` con otro nombre.
   * Con cinco, elegir es leer la lista. */
  --t-rotulo: 12px;    /* etiqueta de campo, encabezado de columna, pista, pie, badge */
  --t-dato: 15px;      /* celda de tabla, botón, navegación, nota */
  --t-cuerpo: 16px;    /* texto de corrido, y **todo campo de formulario**: por
                        * debajo de 16, iOS hace zoom al enfocar, y el zoom en la
                        * pantalla de carga deja media conversación fuera de cuadro */
  --t-seccion: 18px;   /* h2, la frase de la propuesta, el título de una tarjeta */
  --t-titulo: 28px;    /* h1, y la cifra de una tarjeta: 28 contra 12 es más del
                        * doble, y es lo que hace que el número domine al rótulo */

  --sans: "DM Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "Space Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
    "Liberation Mono", monospace;

  /* §14.F — los colores oficiales de Nosis, extraídos del HTML del propio
   * correo (`.h-pref.hAm/.hAz/.hRo/.hVe/.hNeu` en un adjunto real, y los cinco
   * de la situación del BCRA de un envío de CI). Son de Nosis y no del sistema
   * de diseño de GDV: **fijos en los dos temas, a propósito** —es lo que la
   * oficina ya tiene aprendido de mirar el correo, y un verde o un amarillo
   * que cambiara con el tema dejaría de ser reconocible—. Se documentan acá y
   * en el README, «Densidad y formato».
   *
   * El fondo es el que Nosis publica, tal cual, y no se toca nunca —es lo que
   * la gente reconoce—. El texto es el que Nosis declara, salvo donde no
   * llega a 4,5:1: ahí se ajustó **sólo el texto**, y se anota por qué en el
   * mismo renglón. `--situacion-4-texto` es el único caso: blanco sobre
   * `#FF0000` da 4,0:1, abajo del mínimo; negro da 5,25:1.
   */
  --situacion-1-fondo: 120 100% 25.1%;  /* #008000 */
  --situacion-1-texto: 0 0% 100%;       /* #FFFFFF */
  --situacion-2-fondo: 60 100% 50%;     /* #FFFF00 */
  --situacion-2-texto: 0 0% 0%;         /* negro */
  --situacion-3-fondo: 300 100% 50%;    /* #FF00FF */
  --situacion-3-texto: 0 0% 0%;         /* negro */
  --situacion-4-fondo: 0 100% 50%;      /* #FF0000 */
  --situacion-4-texto: 0 0% 0%;         /* negro y no blanco: ver la nota de arriba */
  --situacion-5-fondo: 0 100% 25.1%;    /* #800000 */
  --situacion-5-texto: 0 0% 100%;       /* #FFFFFF */
  /* La columna `SC` —Boletines Oficiales, cambios societarios— en el azul de
   * Nosis: `.h-pref.hAz` de un adjunto real (`background:#99f`,
   * `border-color:#009`), el mismo `#009` que usa `.cAz` como color de texto
   * en ese HTML. */
  --sc-fondo: 240 100% 80%;             /* #9999FF */
  --sc-texto: 240 100% 30%;             /* #000099 */
}

/* El tema claro (GDV_DESIGN §4), elegido con la cookie. Redefine sólo colores:
 * las medidas y la tipografía son las mismas en los dos temas. Los alias
 * —`--card-border`, `--ring` y compañía— no se repiten: un `var()` se resuelve
 * con el valor vigente, así que siguen al tema solos.
 *
 * **Este bloque tiene un gemelo** en el `@media (prefers-color-scheme: light)`
 * de abajo, para el que no eligió tema y usa un sistema claro. Tienen que
 * declarar exactamente lo mismo —hay un test que compara los dos bloques
 * token por token— porque son el mismo tema por dos puertas distintas. */
:root[data-tema="claro"] {
  color-scheme: light;
  --background: 43 30.4% 95.5%;        /* #F7F5F0 fondo general */
  --foreground: 215 29.3% 16.1%;       /* #1D2735 texto principal */
  --card: 0 0% 100%;                   /* #FFFFFF superficie / tarjeta */
  --border: 39 21.9% 87.5%;            /* #E6E1D8 bordes */
  --popover: 0 0% 100%;
  --primary: 210 79.5% 43.9%;          /* #176FC9 azul GDV interactivo */
  --primary-hover: 210 82.7% 36.3%;    /* #105CA9 azul GDV hover */
  --primary-foreground: 0 0% 100%;
  --secondary: 0 0% 100%;
  --muted: 40 22% 90%;
  --muted-foreground: 220 9% 41%;      /* #6B7280 oscurecido hasta 4,5:1 */
  --accent: 43 25% 91%;
  --destructive: 0 57.3% 49.6%;        /* #C73636 error */
  --success: 154 58.1% 32.7%;          /* #23845A éxito */
  --warning: 37 74.6% 44.7%;           /* #C7851D advertencia */
  --enfasis: 39 87% 60.8%;             /* #F2B544 amarillo de énfasis */
  --marca: 213 62.2% 24.9%;            /* #183B67 azul GDV principal */
  --input: 39 15% 72%;
  --sombra: 220 30% 15%;
  /* En claro el filo del desbordamiento **sí** es una sombra: hay adónde bajar. */
  --sombra-borde: var(--sombra);
  --primary-text: 210 79.5% 36%;
  --destructive-text: 0 57.3% 41%;
  --success-text: 154 58.1% 24%;
  --warning-text: 37 74.6% 31%;
  --enfasis-text: 39 87% 31%;
}

/* Sin cookie manda el sistema. El `:not([data-tema])` es lo que hace que la
 * elección explícita —incluido el login, que fija oscuro— le gane al sistema.
 * Es el gemelo textual del bloque de arriba: mismos tokens, mismos valores. */
@media (prefers-color-scheme: light) {
  :root:not([data-tema]) {
    color-scheme: light;
    --background: 43 30.4% 95.5%;        /* #F7F5F0 fondo general */
    --foreground: 215 29.3% 16.1%;       /* #1D2735 texto principal */
    --card: 0 0% 100%;                   /* #FFFFFF superficie / tarjeta */
    --border: 39 21.9% 87.5%;            /* #E6E1D8 bordes */
    --popover: 0 0% 100%;
    --primary: 210 79.5% 43.9%;          /* #176FC9 azul GDV interactivo */
    --primary-hover: 210 82.7% 36.3%;    /* #105CA9 azul GDV hover */
    --primary-foreground: 0 0% 100%;
    --secondary: 0 0% 100%;
    --muted: 40 22% 90%;
    --muted-foreground: 220 9% 41%;      /* #6B7280 oscurecido hasta 4,5:1 */
    --accent: 43 25% 91%;
    --destructive: 0 57.3% 49.6%;        /* #C73636 error */
    --success: 154 58.1% 32.7%;          /* #23845A éxito */
    --warning: 37 74.6% 44.7%;           /* #C7851D advertencia */
    --enfasis: 39 87% 60.8%;             /* #F2B544 amarillo de énfasis */
    --marca: 213 62.2% 24.9%;            /* #183B67 azul GDV principal */
    --input: 39 15% 72%;
    --sombra: 220 30% 15%;
    /* En claro el filo del desbordamiento **sí** es una sombra: hay adónde bajar. */
    --sombra-borde: var(--sombra);
    --primary-text: 210 79.5% 36%;
    --destructive-text: 0 57.3% 41%;
    --success-text: 154 58.1% 24%;
    --warning-text: 37 74.6% 31%;
    --enfasis-text: 39 87% 31%;
  }
}

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

* { box-sizing: border-box; }

/* El `color-scheme` —que pinta los controles nativos: el desplegable abierto,
 * la barra de scroll, el calendario de un `date`— vive en los bloques de tokens
 * de arriba: es del tema, no de la base. */
html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  /* 16px de base. Menos que esto se lee con esfuerzo en una notebook, y el
   * esfuerzo se paga en errores de lectura sobre columnas de números. Las tablas
   * bajan a 15px, que es donde se compra la densidad. */
  font: var(--t-cuerpo)/1.45 var(--sans);
  /* Las dos familias vienen con `tabular-nums` disponible; acá se pide de una
   * vez para todo el documento, así ninguna cifra queda con dígitos de ancho
   * variable por haberse olvidado una clase. */
  font-variant-numeric: tabular-nums;
}

a { color: hsl(var(--primary-text)); text-decoration: none; }
a:hover { text-decoration: underline; }

h1 {
  font-size: var(--t-titulo);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 var(--paso);
  /* Un título largo —«Cuentas corrientes», el nombre de un cliente— tiene que
   * poder cortar en un celular en vez de estirar la página. */
  overflow-wrap: break-word;
}
/* El título de una sección adentro de una pantalla: bastante más chico que el
 * `h1` y con aire arriba, que es lo que separa dos tablas seguidas sin dibujar
 * una línea. */
h2 {
  font-size: var(--t-seccion);
  font-weight: 600;
  letter-spacing: 0;
  margin: calc(var(--paso) * 2) 0 var(--paso);
}
/* El título de un bloque adentro de una sección —cada bloque del asiento, cada
 * sección del detalle de Nosis—. Es el escalón que faltaba: hasta acá esos
 * títulos se dibujaban con el cuerpo de un rótulo y en versales, y se leían
 * como etiquetas de campo en vez de como encabezados. */
h3, h4 {
  font-size: var(--t-dato);
  font-weight: 600;
  letter-spacing: 0;
  margin: var(--paso) 0 6px;
}

/* Lo monoespaciado que no es un importe: un código de cuenta, un número de
 * operación, un CUIT. **Sin `font-size`**: se dibuja al cuerpo del texto que lo
 * rodea. Achicarlo un 12% era lo que hacía que un código de cuenta adentro de
 * una celda se leyera más chico que el resto de la celda. */
code, .codigo, .num-plano { font-family: var(--mono); }
/* --- El esqueleto: la aplicación, el panel y la columna ------------------ */

/* Tres piezas y un orden que no cambia nunca: el panel de navegación, la
 * cabecera y el contenido. Lo que cambia con el ancho es **dónde está el
 * panel** —abajo y fuera de pantalla en un celular, al costado desde una
 * tablet—, y eso se escribe todo junto en «Los tres anchos», al final de esta
 * sección. Lo que sigue hasta ahí es la regla del celular, que es la base.
 *
 * Las dos áreas del contrato §3 son una grilla y no un `flex` porque una grilla
 * dice el ancho del panel **en el contenedor** —una pista— y no en el panel: el
 * riel de 64px, el panel de 256 y el celular sin panel son tres valores de la
 * misma declaración, y el `<aside>` no tiene que saber en cuál está.
 *
 * En celular la grilla tiene **una** columna: ahí el panel es la hoja de «Más»,
 * está `fixed`, y un hijo posicionado sale del flujo y deja de ser ítem de la
 * grilla. No hay pista que reservarle. */
.aplicacion {
  display: grid;
  /* `minmax(0, 1fr)` y nunca `1fr` (§12.2): una pista `1fr` es
   * `minmax(auto, 1fr)`, y el mínimo automático de una tabla con `nowrap` en
   * todas las celdas es el ancho de la tabla entera. Con eso, una pantalla con
   * una tabla ancha empuja el documento en vez de desplazarse adentro de su
   * marco, que es el desborde que este rediseño existe para matar. */
  grid-template-columns: minmax(0, 1fr);
  /* `dvh` y no `vh`: en un celular la barra del navegador entra y sale, y
   * `100vh` mide la ventana **sin** ella, o sea de más. Es el mismo motivo por
   * el que el marco del libro pasó a `dvh` (§12.1). */
  min-height: 100dvh;
}

/* La columna de la derecha: cabecera arriba, contenido abajo. El `min-width: 0`
 * es lo que deja que las tablas anchas scrolleen adentro de su marco en vez de
 * empujar el layout, y como acá además es ítem de grilla, sin él la pista
 * `minmax(0, 1fr)` no serviría de nada: el mínimo lo pondría el hijo. */
.columna {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* El panel de navegación. En celular **es la hoja de «Más»**: la misma casilla
 * `#menu-movil`, el mismo `<aside>` y el mismo lugar en el DOM que en
 * escritorio, posicionado abajo en lugar de al costado. No se mueve un solo
 * elemento del árbol, que es lo que permite que el `~` de la casilla lo siga
 * alcanzando (`app.html:15-17`).
 *
 * Cerrada va **fuera de pantalla y con `visibility: hidden`**. Lo segundo no
 * estaba en la hoja vieja y hace falta: con sólo el `transform`, los quince
 * enlaces del panel seguían en el orden de tabulación y se seguían anunciando a
 * un lector de pantalla aunque no se vieran. Es un agujero que se cierra sin
 * una línea de JavaScript. */
.lateral {
  position: fixed;
  inset: auto 0 0 0;          /* abajo, de lado a lado; `top: auto` es lo que la despega de arriba */
  z-index: 40;                /* por encima del telón (35) y de la barra (30) */
  min-width: 0;
  display: flex;
  flex-direction: column;
  /* Ochenta por ciento y no la pantalla entera: que se vea un pedazo de lo que
   * hay debajo es lo que dice que esto es una hoja y que se cierra tocando
   * afuera. Con el `overflow-y` que ya tenía, una navegación larga scrollea
   * adentro. */
  max-height: 80dvh;
  overflow-y: auto;
  background: hsl(var(--sidebar));
  border-top: 1px solid hsl(var(--sidebar-border));
  border-radius: var(--radio) var(--radio) 0 0;
  /* El área segura del teléfono: el gesto de inicio se come los últimos
   * píxeles, y sin esto el pie del panel —quién está adentro— queda debajo de
   * la barra del sistema. */
  padding-bottom: env(safe-area-inset-bottom, 0px);
  transform: translateY(100%);
  visibility: hidden;
}

/* Abierta por la casilla. La sombra es una de las dos únicas de la hoja: acá hay
 * algo que **flota** sobre el contenido, y es la señal de que se cierra.
 *
 * Sin `transition`: el único movimiento de la interfaz es el círculo adentro del
 * botón que se tocó. Una hoja que aparece de una es una hoja que aparece. */
#menu-movil:checked ~ .aplicacion .lateral {
  transform: none;
  visibility: visible;
  box-shadow: 0 -8px 32px hsl(var(--sombra) / 0.5);
}

/* El telón: el fondo que cierra al tocarlo. Nace apagado y lo prende la casilla;
 * es un `<label>` de la misma casilla y para un lector de pantalla no existe. */
.telon { display: none; }
#menu-movil:checked ~ .aplicacion .telon {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 35;
  background: hsl(var(--sombra) / 0.45);
}

/* --- La navegación del panel -------------------------------------------- */

.lateral-marca {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* El mismo alto que la cabecera, y por eso el token: la marca y el título de
   * la pantalla tienen que quedar en el mismo renglón cuando el panel está al
   * costado. Antes eran dos 56 escritos aparte que podían separarse. */
  min-height: var(--cabecera);
  padding: 0 14px;
  border-bottom: 1px solid hsl(var(--sidebar-border));
}

.marca {
  font-weight: 700;
  letter-spacing: 0.08em;
  color: hsl(var(--marca));
  /* «GDV» está en mayúsculas porque **es** la marca, no porque lo pinte esta
   * hoja: viene así del HTML. */
  font-size: var(--t-seccion);
}
.marca:hover { text-decoration: none; }

.navegacion {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--paso);
  overflow-y: auto;
  /* **Y que se vea que el menú sigue.** Las veintidós entradas piden 1.091px y
   * en una ventana de 844 el panel le deja 749: de `Socios` para abajo —el
   * padrón, las tasas, las cotizaciones, los ejemplos y los avisos— no hay nada
   * dibujado, y la barra de este contenedor es de superposición y no ocupa
   * ancho, así que **nada** decía que hubiera más. Medido a 1024 y a 1536: el
   * corte cae en el mismo lugar en el riel y en el panel expandido.
   *
   * Es la técnica de la sombra del borde de una tabla (§12.10) acostada: dos
   * tapas del color del panel pegadas a cada punta que viajan con el contenido
   * (`local`) y, debajo, dos sombras clavadas a la caja (`scroll`). Con el menú
   * arriba de todo, la tapa de arriba está sobre su sombra y no se ve nada; en
   * cuanto hay algo desplazado, aparece. Se apaga sola cuando no hay nada que
   * desplazar, que es lo que la hace segura de dejar en todos los anchos.
   *
   * Va en `background-image` y no en el atajo `background` a propósito: el
   * panel pinta su fondo en `.lateral` y acá sólo se agrega la señal. */
  /* La tapa arranca **opaca** los primeros ocho píxeles y recién ahí se
   * desvanece, que es el largo entero de la sombra: con la tapa desvaneciéndose
   * desde el borde —como está escrita la de las tablas— a mitad de camino la
   * tapa va al 75 % y la sombra al 17, y el resto se ve. Acá eso dejaba una
   * banda gris debajo de la marca **sin nada desplazado**, o sea una segunda
   * línea al lado de la que el borde de `.lateral-marca` ya dibuja. */
  background-image:
    linear-gradient(to bottom, hsl(var(--sidebar)) 8px, hsl(var(--sidebar) / 0) 16px),
    linear-gradient(to top, hsl(var(--sidebar)) 8px, hsl(var(--sidebar) / 0) 16px),
    linear-gradient(to bottom, hsl(var(--sombra-borde) / 0.35), hsl(var(--sombra-borde) / 0)),
    linear-gradient(to top, hsl(var(--sombra-borde) / 0.35), hsl(var(--sombra-borde) / 0));
  background-position: center top, center bottom, center top, center bottom;
  background-repeat: no-repeat;
  background-size: 100% 16px, 100% 16px, 100% 8px, 100% 8px;
  background-attachment: local, local, scroll, scroll;
}

/* Un enlace de la navegación y el rótulo de un grupo se dibujan igual: los dos
 * son una línea del menú, y que el padre de un submenú se viera distinto haría
 * pensar que es otra cosa. */
.navegacion a, .navegacion summary {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--toque);
  padding: 0 10px;
  border-radius: var(--radio-chico);
  color: hsl(var(--muted-foreground));
  white-space: nowrap;
  font-size: var(--t-dato);
}
.navegacion a:hover, .navegacion summary:hover {
  background: hsl(var(--accent));
  color: hsl(var(--foreground));
  text-decoration: none;
}
.navegacion .actual {
  background: hsl(var(--primary) / 0.14);
  color: hsl(var(--primary-text));
  font-weight: 600;
  /* El elemento activo no depende sólo del color de fondo: lleva su barra. Es un
   * `inset`, o sea una línea dibujada, no una sombra. */
  box-shadow: inset 3px 0 0 hsl(var(--primary-text));
}

/* El rótulo de una entrada. Se acota acá y no en el panel: con `nowrap` en la
 * línea entera, una entrada de nombre largo estiraría el panel —o el riel de
 * 64px— en vez de cortarse. */
.rotulo-nav {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* El submenú de «Cheques»: cuatro vistas del mismo objeto —el stock, los que
 * falta identificar, el precio y quién los libra— bajo un rótulo. Es un
 * `<details>`: se abre y se cierra sin JavaScript, igual que el menú de usuario
 * de la cabecera. El servidor decide si llega abierto (`app.html`), así que no
 * hay pliegue después de cargar.
 *
 * El `<details>` no lleva `display` propio a propósito: cambiarle el modo de
 * caja es la forma conocida de que el navegador deje de esconder lo de adentro
 * cuando está cerrado, y el submenú se vería siempre abierto. El aire entre el
 * rótulo y las hijas lo pone el margen de `.submenu`. */
.navegacion summary {
  cursor: pointer;
  /* Sin el triángulo del navegador: la flecha propia es la que gira, y las dos
   * juntas serían dos marcas diciendo lo mismo. */
  list-style: none;
  user-select: none;
}
.navegacion summary::-webkit-details-marker { display: none; }

/* La flecha, al final de la línea y girada cuando el grupo está abierto. Sin
 * `transition`: el giro es instantáneo, como todo lo demás. */
.flecha-nav {
  margin-left: auto;
  display: inline-flex;
  color: hsl(var(--muted-foreground));
}
.grupo-nav[open] .flecha-nav { transform: rotate(90deg); }

/* Las hijas, indentadas hasta debajo del rótulo del padre: 10 de relleno + 18 de
 * icono + 10 de hueco es donde arranca el texto de arriba. */
.submenu { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.submenu a { padding-left: 38px; }

/* Un icono de navegación o de la cabecera: trazo de 2px, tamaño fijo. Se
 * dimensiona acá y no en el SVG para que el HTML no cargue medidas. */
.icono { inline-size: 18px; block-size: 18px; flex: 0 0 auto; }

/* El corte entre el trabajo diario y la configuración (GDV_DESIGN §6). Una
 * línea con aire, no un título: lo que separa ya lo dicen las entradas. */
.separador-nav {
  margin: var(--paso) 4px;
  border-top: 1px solid hsl(var(--sidebar-border));
}

/* Las cuatro entradas que en celular ya están en la barra de abajo —Cargar,
 * Caja, Libro, Cuentas corrientes— no se repiten adentro de la hoja de «Más».
 * Una hoja cuyas primeras cuatro líneas son las cuatro que uno acaba de ver
 * enseña a bajar la vista para nada.
 *
 * Es una clase y no `:nth-child(-n+4)` por una razón que no se ve: el
 * resolvedor de `tests/estilos.py` manda a la bolsa de «no sé leer esto»
 * cualquier selector con un `+` o un `~` en cualquier lugar, y una regla ahí
 * adentro que declare `display` deja sin poder concluir a **todo** test que
 * pregunte por `display` —hay uno, sobre los campos del e-cheq, que lo hace sin
 * filtrar por selector—. La clase la pone la plantilla: son cuatro rutas fijas.
 *
 * Desde 640 no hay barra, así que la hoja vuelve a ser el panel entero y las
 * cuatro tienen que estar. */
.navegacion .en-barra { display: none; }

@media (min-width: 640px) {
  .navegacion .en-barra { display: flex; }
}

/* El contador de lo que no se vio, al final de su entrada del menú. **Vacío no
 * se dibuja**: un contador que siempre marca algo deja de leerse, que es la
 * misma regla de los contadores de la caja. Por eso el `<span>` llega
 * literalmente vacío cuando no hay nada, y no con un cero.
 *
 * Es uno de los tres redondeos de verdad que el contrato §2 exceptúa: un
 * contador de un dígito **es** un círculo, y con 4px de radio sería un
 * cuadradito con las puntas limadas. */
.contador-nav {
  margin-left: auto;
  padding: 0 6px;
  border: 1px solid hsl(var(--destructive-text) / 0.8);
  border-radius: 999px;
  background: hsl(var(--destructive) / 0.12);
  color: hsl(var(--destructive-text));
  font-family: var(--sans);
  font-size: var(--t-rotulo);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}
.contador-nav:empty { display: none; }

/* El usuario al pie del panel. Informa quién está adentro; salir vive en el
 * menú de la cabecera. */
.lateral-pie {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid hsl(var(--sidebar-border));
  color: hsl(var(--muted-foreground));
}
/* El nombre de quien está adentro es un dato que se lee, no un rótulo: va al
 * cuerpo de dato. (`--t-secundario`, el paso de 13px que tenía, no existe más.) */
.lateral-pie .quien { font-size: var(--t-dato); color: hsl(var(--muted-foreground)); }

/* El conmutador de tema adentro de la hoja de «Más» (§2e del plan). En celular
 * la cabecera no lo dibuja —no hay renglón— y el plan lo mandaba acá; hasta esta
 * vuelta no había llegado, así que en un teléfono el tema no se podía elegir.
 *
 * Va **arriba** del pie y no abajo: el pie dice quién sos, que es lo último de
 * la hoja, y un control activo debajo de un dato pasivo se lee como parte del
 * dato.
 *
 * Los dos botones con su rótulo al lado del icono, y no dos iconos pelados: acá
 * hay ancho de sobra —la hoja mide el 84 % de la pantalla— y un sol solo es
 * ambiguo entre «está claro» y «poné claro». Con la palabra no lo es. */
.tema-en-hoja {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  border-top: 1px solid hsl(var(--sidebar-border));
}
.tema-en-hoja .rotulo-tema {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
/* `form.tema-en-hoja` y no `.tema-en-hoja` a secas: la regla de los controles de
 * icono de la cabecera nombra también a estos botones y **viene después en el
 * archivo**, así que a igualdad de peso (0,1,1) ganaba ella y estas tres
 * declaraciones estaban muertas —el botón cargaba los 44px de ancho mínimo del
 * botón-icono aunque acá lleva rótulo—. Con la etiqueta pesa (0,1,2) y gana. */
form.tema-en-hoja button {
  gap: 6px;
  padding: 0 10px;
  min-width: 0;
  font-size: var(--t-rotulo);
}
.tema-en-hoja button.actual {
  background: hsl(var(--primary) / 0.14);
  border-color: hsl(var(--primary-text) / 0.5);
  color: hsl(var(--primary-text));
}

/* El rol, al lado del nombre. Sin versales y sin píldora: la jerarquía la dan el
 * peso y el color, y un badge es un rectángulo redondeado como cualquier otro. */
.rol {
  margin-left: 5px;
  padding: 1px 6px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  font-size: var(--t-rotulo);
}

/* --- La barra inferior de navegación (celular) --------------------------- */

/* Cinco entradas fijas abajo, y no un panel que se desliza desde la esquina de
 * arriba. El panel deslizante es el default de cualquier sistema interno y es
 * peor para el pulgar en las dos direcciones: hay que subir a la esquina
 * superior izquierda para abrirlo y después bajar hasta la entrada que se
 * buscaba. Las cuatro pantallas que se usan de pie —Cargar, Caja, Libro,
 * Cuentas— son casi toda la navegación de un celular y entran en una barra
 * abajo, donde el pulgar ya está. La quinta es «Más», que abre la hoja con el
 * resto.
 *
 * Cuesta 56px de una pantalla de 844, menos que los 150 que ocupaba la cabecera
 * de tres renglones que esta misma decisión achica. Desde 640 no existe.
 *
 * **Va en el marcado como hermana posterior de `#menu-movil`, afuera de
 * `.aplicacion`**, que es de donde la alcanza el `~` del foco de más abajo. Es
 * la misma condición que ya cumplen el `<aside>` y el telón, y no es una
 * preferencia de orden: metida adentro de `.columna`, la barra se dibuja igual
 * —está `fixed`— pero el anillo de foco de «Más» deja de aparecer, en silencio y
 * sin que nada lo verifique. */
.barra-inferior {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 30;
  display: flex;
  min-height: var(--barra);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: hsl(var(--sidebar));
  border-top: 1px solid hsl(var(--sidebar-border));
}

/* Las cuatro entradas y el `<label>` de «Más» se dibujan igual: son la misma
 * cosa para el dedo, y que la quinta se viera distinta haría pensar que hace
 * otra cosa. Cinco columnas iguales —`flex: 1 1 0`— para que el ancho del
 * objetivo no dependa del largo de la palabra. */
.entrada-barra, .abrir-mas {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--toque);
  color: hsl(var(--muted-foreground));
  font-size: var(--t-rotulo);
  text-align: center;
  cursor: pointer;
  user-select: none;
}
.entrada-barra:hover, .abrir-mas:hover {
  color: hsl(var(--foreground));
  text-decoration: none;
}
/* Dónde estoy parado. En la barra no hay lugar para la barrita lateral del
 * panel, así que la señal es el color del primario más el peso. */
.barra-inferior .actual { color: hsl(var(--primary-text)); font-weight: 600; }

/* El foco **hacia adentro**: la barra está pegada al borde de la pantalla y un
 * anillo por fuera se corta contra el borde del viewport. */
.entrada-barra:focus-visible, .abrir-mas:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: -2px;
}

/* «Más» acciona la casilla clipeada, que es la que abre la hoja. La casilla no
 * está sacada del tabulador —está clipeada—, así que el foco se dibuja sobre el
 * `<label>` que la representa, que es lo que se ve. Es el mismo mecanismo que
 * los cinco interruptores de la pantalla de carga. */
.abrir-mas { position: relative; }
#menu-movil:focus-visible ~ .barra-inferior .abrir-mas {
  outline: 2px solid hsl(var(--ring));
  outline-offset: -2px;
}

/* El punto de «hay algo sin ver», sobre el icono de «Más». Es **un** punto y no
 * dos contadores: en la barra no entran los de Novedades y los de Avisos por
 * separado, así que se suman en una sola señal y el número se lee adentro.
 *
 * Con 8px de lado, `--radio-chico` (4px) **es** la mitad del lado: da un círculo
 * exacto sin pedir la excepción de los `999px`.
 *
 * `color: transparent` y `overflow: hidden` porque el `<span>` viaja con el
 * número adentro —es lo que le permite al poller de avisos reemplazarlo *out of
 * band* cada treinta segundos y apagarlo sin JavaScript—: el dígito no se
 * dibuja, pero deja al elemento no-vacío, y `:empty` es lo que apaga el punto
 * cuando no hay nada. Un `<span>` que llegara siempre sin contenido quedaría
 * apagado para siempre. */
/* El punto rojo sobre «Más»: hay algo sin ver. Es uno solo para los dos
 * contadores —novedades y avisos— porque la barra tiene cinco entradas y no
 * entra un número al lado de cada una; el número exacto está en el panel, que se
 * abre justo desde acá.
 *
 * **El número no está en el texto del elemento, está en un atributo**, y eso no
 * es un rodeo: el punto mide ocho píxeles y no hay forma de dibujar un número
 * adentro, así que la primera versión lo escondía con `color: transparent`. Eso
 * deja un texto que el verificador de contraste de la suite no puede evaluar
 * —«no sé leer el color transparent»— y con razón: un texto invisible no tiene
 * contraste que medir. Con el número en `data-cuantas` no hay texto que
 * esconder, el elemento queda vacío de verdad y la regla de abajo lo prende o lo
 * apaga leyendo el atributo.
 *
 * `aria-hidden` en la plantilla: para quien no ve la pantalla, el dato viaja en
 * el rótulo de las entradas del panel, que sí llevan su contador con número. */
.punto-pendiente {
  position: absolute;
  top: 6px;
  left: calc(50% + 4px);
  inline-size: 8px;
  block-size: 8px;
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive));
  display: none;
}
.punto-pendiente:not([data-cuantas=""]) { display: block; }

/* --- La cabecera --------------------------------------------------------- */

/* Un renglón, siempre: el título de la pantalla a la izquierda y a la derecha
 * las puntas con las que se opera. En celular es lo único que queda arriba
 * —abajo está la barra—, y es lo que reemplaza a los tres renglones de hoy.
 *
 * `sticky` porque el título es la única señal de en qué pantalla se está una vez
 * que el `h1` se fue para arriba. */
.cabecera {
  display: flex;
  align-items: center;
  gap: 4px var(--paso);
  min-height: var(--cabecera);
  padding: 0 10px;
  background: hsl(var(--sidebar));
  border-bottom: 1px solid hsl(var(--sidebar-border));
  position: sticky;
  top: 0;
  z-index: 20;
}

/* El título cede antes de empujar a los controles fuera de la pantalla: es el
 * único de la fila que se puede recortar sin perder una función, y además está
 * repetido en el `h1` de abajo.
 *
 * **En el celular cede envolviendo y no recortándose**, que es lo único que
 * entra en 390: la cabecera son el título, las dos plazas y el avatar, y el
 * título se quedaba con ~125px. Con puntos suspensivos eso era «Cotizaciones y
 * ci…» —y «Historial de arq…» en el arqueo—; envolviendo, «Cotizaciones y
 * cierre» se lee entero en dos renglones de 12 y no cuesta un píxel de alto,
 * porque al lado ya hay dos renglones de plazas adentro de los 56 de la
 * cabecera. El `overflow-wrap` es el seguro para una pantalla más angosta que
 * las tres medidas: antes de salirse de su caja y pisar los números, una palabra
 * se parte.
 *
 * Desde 640 vuelven el renglón único y los puntos suspensivos, junto con el
 * `min-width: 16ch` de más abajo: ahí el ancho alcanza y un título de dos
 * renglones sería alto comprado por nada. */
.titulo-cabecera {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.2;
  font-weight: 600;
  font-size: var(--t-dato);
}

/* Los controles de icono de la cabecera: abrir el menú, colapsar el panel, y las
 * dos caras del tema. Todos con el objetivo táctil entero. */
.abrir-menu, .cerrar-menu, .colapsar, .cambiar-tema button, .tema-en-hoja button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--toque);
  min-width: var(--toque);
  padding: 0 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radio-chico);
  color: hsl(var(--muted-foreground));
  cursor: pointer;
}
.abrir-menu:hover, .cerrar-menu:hover, .colapsar:hover, .cambiar-tema button:hover,
.tema-en-hoja button:hover {
  background: hsl(var(--accent));
  color: hsl(var(--foreground));
}

/* **La hamburguesa no se dibuja en ningún ancho.** En celular la navegación está
 * abajo y «Más» abre la misma hoja; desde 640 el panel está siempre a la vista.
 * El `<label>` se conserva en el marcado porque un test exige los cuatro
 * controles de la cabecera en toda pantalla entera, y porque acciona la misma
 * casilla desde donde esté: no sobra, no se ve. */
.abrir-menu { display: none; }

/* La cruz de cerrar vive adentro de la hoja y es de celular: desde 640 el panel
 * no se cierra, está. */
.cerrar-menu { display: inline-flex; }

/* El botón de colapsar nace con `hidden` y lo muestra `gdv.js`: un botón que no
 * hace nada es peor que ninguno. Y no existe abajo de 1024: en celular el panel
 * se abre y se cierra, y en tablet ya está colapsado, así que no hay nada que
 * elegir. */
.colapsar { display: none; }

/* El conmutador de tema: dos botones, uno por tema, y el elegido marcado. Dos y
 * no un toggle porque sin cookie el tema lo decide el sistema y el servidor no
 * sabe cuál se está viendo: «cambiar al otro» no tendría de dónde arrancar.
 *
 * **En celular no se dibuja**: el renglón no da para el título, las cotizaciones,
 * dos botones de tema y el usuario, y de los cuatro es el único cuya función
 * tiene otra puerta —sin cookie manda `prefers-color-scheme`, que en un teléfono
 * es justamente la elección que la persona ya hizo en el sistema—. El menú de
 * usuario se queda porque salir no tiene otra puerta. */
.cambiar-tema { display: none; margin-left: auto; gap: 2px; }
.cambiar-tema button.actual {
  background: hsl(var(--primary) / 0.14);
  border-color: hsl(var(--primary-text) / 0.5);
  color: hsl(var(--primary-text));
}

/* El menú de usuario, con el cierre de sesión adentro. Un `<details>` con el
 * panel posicionado: se abre y se cierra sin JavaScript. */
.menu-usuario { position: relative; }
.menu-usuario summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--toque);
  padding: 0 10px;
  border-radius: var(--radio-chico);
  cursor: pointer;
  color: hsl(var(--muted-foreground));
  font-size: var(--t-dato);
  white-space: nowrap;
  user-select: none;
}
.menu-usuario summary::-webkit-details-marker { display: none; }
.menu-usuario summary:hover { background: hsl(var(--accent)); color: hsl(var(--foreground)); }
.menu-usuario[open] summary { background: hsl(var(--accent)); color: hsl(var(--foreground)); }

/* El nombre al lado del avatar. Aparece recién en la notebook: hasta ahí queda
 * el icono, que sigue diciendo quién es por el `title` y por el panel de abajo. */
.quien-cabecera { display: none; font-size: var(--t-dato); }

/* El desplegable **flota**: es la segunda y última sombra de la hoja. El ancho
 * mínimo en `ch` y no en píxeles porque lo que tiene que entrar es un nombre de
 * usuario más «Salir», que son caracteres. */
.menu-desplegado {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  min-inline-size: 22ch;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
  box-shadow: 0 8px 24px hsl(var(--sombra) / 0.35);
  z-index: 30;
}
.menu-desplegado .quien { font-size: var(--t-dato); }
.menu-desplegado form { margin: 0; }
/* Adentro del panel, Salir es una fila del menú: ancho completo y con borde, que
 * suelto en la cabecera no necesitaba. */
.menu-desplegado .salir {
  width: 100%;
  justify-content: flex-start;
  border-color: hsl(var(--border));
}

/* --- La barra de cotizaciones (§13) -------------------------------------- */

/* Integrada a la cabecera, arriba de todas las pantallas: es contexto de
 * mercado, y la cabecera es lo único que está siempre a la vista.
 *
 * Las dos puntas con las que se opera —la compra de Buenos Aires y la venta de
 * Rosario— van en el amarillo de énfasis, en negrita y subrayadas; las otras
 * dos, en el gris de lo secundario. El amarillo es exactamente para esto
 * (GDV_DESIGN §4: «énfasis puntuales e indicadores relevantes») y son tres
 * señales para una sola distinción, dos de ellas legibles en blanco y negro:
 * cuál mira quien está por cerrar una operación no puede depender de distinguir
 * dos colores.
 *
 * En celular las dos plazas se apilan una debajo de la otra dentro del mismo
 * renglón de cabecera —dos líneas de 12px entran en los 56px—, y **lo único que
 * se esconde son las dos puntas de contexto** (§12.11): son las que no deciden
 * nada. La antigüedad se queda, siempre y en todos los anchos. */
.barra-cotizaciones {
  /* Ni crece ni empuja, **y en el celular tampoco encoge**. El sobrante del
   * renglón se lo lleva el título, que es el único de la fila que sabe ceder sin
   * perder una función —envuelve, y de todos modos está repetido en el `h1` de
   * abajo—.
   *
   * El `0 1 auto` que había acá decía «encoger sí, envolver es el último
   * recurso», y a 390 el último recurso pasaba igual: al repartir el faltante
   * entre los dos, la barra quedaba unos 30px por debajo de lo que mide una
   * plaza y `Buenos Aires 1.530` se llevaba el renglón dejando el `recién`
   * huérfano en el de abajo —la antigüedad separada de su número, que es
   * justamente la lectura que §12.11 no quiere—. Sin encoger, la plaza entra
   * entera y el que envuelve es el título, que sabe hacerlo. Desde 640 vuelve a
   * encoger: ahí el faltante es de píxeles y no de renglones. */
  flex: 0 0 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  padding: 0 var(--paso);
}
.barra-cotizaciones .plaza {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--paso);
  min-width: 0;
}
.barra-cotizaciones .donde {
  font-size: var(--t-rotulo);
  font-weight: 600;
  color: hsl(var(--muted-foreground));
}
.barra-cotizaciones .punta { display: inline-flex; align-items: baseline; gap: 6px; }
/* «compra» / «venta». En celular se esconde: con una sola punta por plaza a la
 * vista, el rótulo repite una constante del negocio —cuál es la operativa sale
 * de `blue.PUNTA_OPERATIVA` y es la misma todos los días— y esos veinte píxeles
 * son la diferencia entre que el título de la pantalla se lea o se corte. */
.barra-cotizaciones .cual {
  display: none;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
.barra-cotizaciones .precio {
  font-family: var(--mono);
  font-size: var(--t-dato);
  color: hsl(var(--foreground));
}
/* Las dos de contexto: fuera del celular. Es lo único que §12.11 deja esconder. */
.barra-cotizaciones .contexto { display: none; }
.barra-cotizaciones .opera .cual { color: hsl(var(--enfasis-text)); }
.barra-cotizaciones .opera .precio {
  color: hsl(var(--enfasis-text));
  font-weight: 700;
  border-bottom: 2px solid hsl(var(--enfasis));
}
.barra-cotizaciones .contexto .precio { color: hsl(var(--muted-foreground)); }

/* La antigüedad va **siempre**, no sólo cuando el dato está viejo: un número sin
 * antigüedad se lee como actual. Pasado el umbral se pinta de ámbar y el HTML
 * agrega «sin actualizar», que es la señal que no depende del color. */
.barra-cotizaciones .cuando {
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
.barra-cotizaciones .vieja .cuando { color: hsl(var(--warning-text)); font-weight: 600; }
.barra-cotizaciones .vieja .precio {
  color: hsl(var(--muted-foreground));
  border-bottom: 2px dashed hsl(var(--warning));
}
.barra-cotizaciones .sin-dato {
  font-size: var(--t-rotulo);
  font-style: italic;
  color: hsl(var(--muted-foreground));
}

/* --- El canal en página (§15.G.1) ---------------------------------------- */

/* Aterriza debajo de `#avisos` y no adentro: aquél es la respuesta a lo que
 * acaba de apretar quien está mirando, y esto es algo que pasó en otro lado.
 * Compartir el hueco haría que un aviso del blue tapara la confirmación de un
 * guardado, o al revés. */
.aviso-notificaciones { display: block; margin: 0; }
.aviso-notificaciones:empty { display: none; }

/* Un panel, y por eso el radio grande: lo dice su propio nombre (§2, las trece
 * cajas que pasan de `--radio-chico` a `--radio`). El tope de ancho se lo pone
 * la clase de texto que lleva en el HTML y no una `max-width` propia: es la
 * mitad de la regla 7 y hay un solo lugar donde se escribe. */
.panel-avisos {
  margin: 0 0 var(--paso);
  padding: 8px 10px;
  border: 1px solid hsl(var(--border));
  border-left: 3px solid hsl(var(--primary));
  border-radius: var(--radio);
  background: hsl(var(--card));
  font-size: var(--t-dato);
  line-height: 1.45;
}
.lista-avisos { list-style: none; margin: 0; padding: 0; }
/* El separador va en cada renglón menos el primero, y no con `+`: el resolvedor
 * de `tests/estilos.py` no sabe leer los combinadores de hermano y una regla que
 * cae en esa bolsa deja sin poder concluir a todo test que mire esa propiedad.
 * `:first-child` sí lo entiende, y dibuja lo mismo. */
.lista-avisos .aviso { padding: 3px 0; border-top: 1px solid hsl(var(--border) / 0.6); }
.lista-avisos .aviso:first-child { border-top: none; }
.lista-avisos .titulo-aviso { font-weight: 700; }
/* En celular cada aviso es **un renglón**: el título y su «Ver». El detalle se
 * lee entero en `/notificaciones`, que es a donde lleva el enlace; acá arriba, en
 * una pantalla de 390, cuatro avisos con detalle son media pantalla antes de la
 * primera fila de lo que se vino a mirar. */
.lista-avisos .detalle-aviso { display: none; margin-left: 6px; color: hsl(var(--muted-foreground)); }
.lista-avisos .aviso.advertencia .titulo-aviso { color: hsl(var(--warning-text)); }
.lista-avisos .aviso.critica .titulo-aviso { color: hsl(var(--destructive-text)); }
/* El escalón de arriba de crítica no se dibuja con versales: se dibuja con la
 * barra roja al costado del renglón, que es la misma señal que usan la fila sin
 * ver y la novedad retenida, y que se ve en blanco y negro. */
.lista-avisos .aviso.critica_urgente {
  padding-left: var(--paso);
  box-shadow: inset 3px 0 0 hsl(var(--destructive));
}
.lista-avisos .aviso.critica_urgente .titulo-aviso { color: hsl(var(--destructive-text)); }
.panel-avisos form { margin: var(--paso) 0 0; }
.panel-avisos button { padding: 0 12px; }

/* --- La grilla del contenido -------------------------------------------- */

/* `<main>` es **la** grilla de la aplicación: una columna en el celular, dos en
 * la tablet, seis en la notebook y doce en el monitor. Los bloques no dicen
 * nunca en qué columna van; dicen qué **son** —una clase de zona— y la familia
 * de la pantalla decide cuántas columnas ocupa cada zona en cada ancho.
 *
 * Las zonas se ubican con `grid-column: span N` y **no** con
 * `grid-template-areas` (§12.3): ocho pantallas tienen más de una tabla hermana
 * de primer nivel —`/resultados` tiene seis— y un nombre de área no se puede
 * usar dos veces. Con `span`, un área es repetible por construcción.
 *
 * El relleno escala con el ancho y el hueco no: 8px en vertical y 16 en
 * horizontal en los cuatro anchos, porque el aire entre dos bloques es una
 * medida de lectura y no de pantalla.
 *
 * Ojo con el selector, que es de tipo y llega a **todo** `<main>`: `/login` y la
 * página de error también traen uno (`login.html:9`, `error.html:4`), y no son
 * de esta parte. No las rompe porque `.centrado` —parte 10— declara su propio
 * `display` y su propio `padding` y le gana por especificidad (0,1,0 contra
 * 0,0,1), no por venir después. O sea que el día que alguien le saque el
 * `display: flex` a `.centrado`, la pantalla de acceso se vuelve una grilla con
 * 80px de aire abajo para una barra que ahí no existe.
 *
 * El `env()` va con su respaldo en `0px` a propósito: sin él, un navegador que
 * no conozca la variable invalida el `calc()` entero y `main` se queda sin
 * ningún relleno —los cuatro lados—, no sólo sin el de abajo. */
main {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--paso) calc(var(--paso) * 2);
  /* Lo que la barra inferior tapa, más el área segura del teléfono, más el aire
   * de siempre al pie. Sin esto, la última fila de cualquier tabla queda debajo
   * de la barra y no hay forma de llegar a ella. */
  padding: 12px 12px calc(var(--barra) + env(safe-area-inset-bottom, 0px) + 24px);
}

/* **Un bloque sin clase de zona ocupa el ancho entero.** Es el caso por defecto,
 * es el de la mayoría de las pantallas, y tiene que funcionar sin que nadie
 * escriba nada: el `h1`, el hueco de avisos y el panel de novedades que
 * `app.html` pone en todas las pantallas caen acá.
 *
 * El `min-width: 0` es la otra mitad de §12.2: sin él, un ítem con una tabla
 * ancha adentro le pone a la pista un mínimo del ancho de la tabla y el
 * documento se estira. Va en el ítem porque el `minmax(0, 1fr)` de la pista no
 * alcanza solo. */
main > * {
  grid-column: 1 / -1;
  min-width: 0;
}
/* **Un `<button>` que cuelga directo de `<main>` es un ítem de la grilla, y un
 * ítem de grilla se estira a su pista.** «Permitir avisos en este navegador»
 * —el único de la aplicación que está fuera de todo formulario y de todo
 * contenedor, en `notificaciones.html`— medía 1.240px a 1536 contra los 307 de
 * su texto, porque la regla de arriba le da las doce columnas y nadie le dijo
 * dónde plantarse. `justify-self` y no un `width`: la caja del botón sigue
 * siendo la de su contenido en los cuatro anchos, y con `start` queda donde
 * empieza el texto de la pantalla. */
main > button { justify-self: start; }

/* Las diecisiete zonas. En el celular **todas** ocupan el ancho entero: en una
 * columna no hay nada que repartir. Lo que sigue en «Los tres anchos» es
 * solamente dónde alguna familia decide partir la fila. */
.zona-cabecera, .zona-principal, .zona-secundario, .zona-acciones,
.zona-historial, .zona-filtros, .zona-resumen, .zona-tabla, .zona-pie,
.zona-campos, .zona-ayuda, .zona-conversacion, .zona-propuesta,
.zona-contadores, .zona-saldos, .zona-detalle, .zona-notas {
  grid-column: 1 / -1;
  min-width: 0;
}

/* Un listado usa el ancho entero en los cuatro anchos, y se dice acá en vez de
 * dejarlo librado al default: **la tabla es la pantalla**. Los filtros son una
 * fila que envuelve sola, el resumen es una fila de casilleros, el pie es el
 * paginado y su nota. Partir cualquiera de los cuatro deja la tabla más angosta
 * para ganar una columna que nadie pidió. */
main.familia-listado .zona-filtros,
main.familia-listado .zona-resumen,
main.familia-listado .zona-tabla,
main.familia-listado .zona-pie { grid-column: 1 / -1; }

/* **En una columna, el orden del documento es el orden de lectura, y en la ficha
 * de un cliente estaba al revés de la importancia.** El bloque secundario va
 * después del principal en el HTML para que en el monitor caiga a la derecha
 * (`ficha_cliente.html` lo explica ahí); en el celular eso deja las cuatro
 * cifras —el saldo, que es a lo que se abre una ficha— debajo de diez pares de
 * datos: pasaron de y≈530 a y≈930, dos pantallas de scroll.
 *
 * Se arregla con `order` y no moviendo el HTML, que es lo que deja intacto el
 * orden de tabulación en los anchos donde el reparto es de dos columnas. Y en el
 * celular tampoco lo rompe: en esta pantalla la `dl` principal **no tiene ningún
 * control** —los alias son `<span>`, no enlaces—, así que lo único enfocable que
 * cambia de lugar no cambia de lugar, y el foco sigue yendo migas → chips del
 * bloque secundario → las dos acciones del pie, que es exactamente lo que se ve.
 *
 * Se mueve lo mínimo: **la ficha baja**, y con ella las acciones para que no se
 * le adelanten. Todo lo demás —el `h1`, el hueco de avisos, el panel de
 * novedades— se queda en `order: 0` y en el orden en que está escrito.
 *
 * **Lo que sube es el bloque de cifras y no la zona entera, y ésa es la
 * corrección de un intento anterior.** La primera versión de esta regla mandaba
 * abajo a la ficha y con eso subía `div.zona-secundario` completo: las cuatro
 * cifras, **y detrás de ellas** las cuatro relaciones y el párrafo del garante.
 * `Tipo`, `Alias`, `CUIT`, `Teléfono` y `Dirección` —la identidad del cliente—
 * quedaron ~280px más abajo que antes del rediseño, terceras en la pantalla y
 * detrás de seis renglones que explican una distinción que no es la que uno vino
 * a buscar. Subir el saldo estaba bien; arrastrar la mitad de la ficha con él,
 * no.
 *
 * Se arregla con `display: contents` sobre el envoltorio: las cifras, las
 * relaciones y la nota del garante pasan a ser ítems de la grilla de `<main>`
 * por su cuenta, y ahí el `order` puede repartirlos uno por uno. Los tres se
 * nombran completos —el `> *` de al lado les devuelve el ancho entero, porque
 * `main > *` mira el DOM y no alcanza a los hijos de un elemento sin caja—. El
 * envoltorio vuelve a ser un bloque desde 1024, que es donde **sí** tiene que
 * dibujar una caja: ahí es la columna de contexto de dos pistas.
 *
 * En un navegador sin `display: contents` no se rompe nada: el envoltorio sigue
 * siendo un bloque, el `order` de sus hijos no aplica y queda el orden del
 * documento, que es el de antes de este arreglo.
 *
 * `dl.zona-principal` y no `.zona-principal` a secas: de las tres fichas con
 * bloque secundario, ésta es la única cuyo principal es una lista de pares. En
 * las dos de Nosis el principal es un `<div>` que **sí** tiene enlaces adentro
 * (el firmante, el cliente), así que ahí adelantar las cifras descalzaría el
 * foco de lo que se ve, y además la plantilla dice con todas las letras que en
 * el celular las cifras son «el renglón que sigue». Por lo mismo el
 * `display: contents` va sobre `div.zona-secundario`: en las dos de Nosis la
 * zona **es** la `<section class="tarjetas">`, y disolverla ahí dejaría a cada
 * tarjeta suelta en la grilla, sin la suya. */
main.familia-ficha > div.zona-secundario { display: contents; }
main.familia-ficha > div.zona-secundario > * { grid-column: 1 / -1; min-width: 0; }
main.familia-ficha > dl.zona-principal,
main.familia-ficha > div.zona-secundario > .datos-clave,
main.familia-ficha > div.zona-secundario > .nota,
main.familia-ficha > .zona-acciones { order: 1; }

/* --- Los tres anchos ----------------------------------------------------- */

/* Acá está todo lo que cambia con el ancho, junto y en orden: 640, 1024 y 1440,
 * y ningún otro número en toda la sección. Está junto a propósito —y no repartido
 * pegado a cada regla— porque el esqueleto cambia **como una pieza**: la barra
 * de abajo se va, el panel vuelve al costado y el relleno crece en el mismo
 * movimiento, y leerlos separados es lo que hacía que la hoja vieja tuviera
 * cuatro cortes distintos sin que nadie pudiera decir por qué. */

/* TABLET (≥640) — se va la barra de abajo y vuelve el panel, colapsado. */
@media (min-width: 640px) {
  /* La barra de abajo y la hoja son de celular y nada más. */
  .barra-inferior { display: none; }
  .cerrar-menu { display: none; }

  /* Dos áreas: el riel del panel y el resto. El panel arranca **colapsado** y
   * **se queda así hasta 1440**: a este ancho 256px de navegación son un tercio
   * de la pantalla al lado de una tabla que necesita todo, y a 1024 son 193 de
   * los 920 que le quedan al contenido —la cuenta entera, con las ocho tablas
   * que se caían, está en el bloque de `min-width: 1024`—. Los iconos con su
   * `title` siguen llevando a cada pantalla, que es lo que la navegación tiene
   * que hacer. */
  .aplicacion { grid-template-columns: var(--lateral-angosta) minmax(0, 1fr); }

  /* El `<aside>` deja de ser hoja y vuelve a ser panel. `sticky` con su propio
   * scroll para que una navegación larga no obligue a scrollear la pantalla
   * entera para llegar a «Ejemplos», y `align-self: start` porque sin él el ítem
   * se estira hasta el alto de la fila y un elemento tan alto como su contenedor
   * nunca tiene contra qué pegarse. */
  .lateral {
    position: sticky;
    inset: auto;
    top: 0;
    align-self: start;
    height: 100dvh;
    max-height: none;
    transform: none;
    visibility: visible;
    border-top: none;
    border-right: 1px solid hsl(var(--sidebar-border));
    border-radius: 0;
    padding-bottom: 0;
    z-index: auto;
  }
  /* La casilla sigue existiendo —es la misma de siempre— y puede llegar marcada
   * desde el celular al rotar el teléfono o al agrandar la ventana. Acá no abre
   * nada: se apagan las dos reglas que la escuchan, con su misma especificidad y
   * más abajo en el archivo. */
  #menu-movil:checked ~ .aplicacion .lateral { box-shadow: none; }
  #menu-movil:checked ~ .aplicacion .telon { display: none; }

  /* El riel: sin rótulos, todo centrado. Es el mismo dibujo que el colapso por
   * cookie del monitor, y desde acá hasta 1440 es el estado por defecto y no una
   * elección: `:root.lateral-expandida` (bloque de 1024) es la que lo deshace
   * para quien lo quiera ancho en la notebook. */
  .rotulo-nav,
  .lateral-pie .quien { display: none; }
  /* El `relative` es el marco de referencia de las dos cosas que en el riel se
   * van a una esquina —el contador de la entrada y la flecha del grupo—. Se
   * queda puesto también en el panel ancho, donde no cuesta nada: ahí las dos
   * vuelven al renglón y no hay nada absoluto que ubicar. */
  .navegacion a, .navegacion summary { justify-content: center; padding: 0; position: relative; }

  /* **La flecha del grupo vuelve, y fuera del flujo.** Estaba escondida junto
   * con el rótulo, y el motivo escrito era que en el renglón dejaba al icono
   * descentrado; sacándola del flujo eso no pasa, así que se recupera lo único
   * que dice que «Cheques» no es una pantalla sino siete. Sin ella, en el riel
   * un grupo cerrado es un icono más entre quince y un grupo abierto son ocho
   * entradas sueltas.
   *
   * Doce y no dieciocho píxeles: es una marca **sobre** otro dibujo y no un
   * dibujo, y en una celda de 47 el icono de siempre le comería la esquina. */
  .grupo-nav .flecha-nav {
    display: inline-flex;
    position: absolute;
    right: 3px;
    bottom: 5px;
    margin-left: 0;
  }
  .grupo-nav .flecha-nav .icono { inline-size: 12px; block-size: 12px; }

  /* Y las hijas cuelgan de un filete, que es la otra mitad de lo mismo: la
   * flecha dice que el grupo abre y el filete dice cuáles son las que abrió.
   *
   * Un `box-shadow` y no un `border-left`: el borde le sacaría dos píxeles al
   * ancho de las hijas y las correría respecto de la columna de iconos, que es
   * justo el defecto que la regla del contador de más abajo viene a arreglar.
   * La sombra no ocupa lugar.
   *
   * Y el color es `--input` y no `--sidebar-border`, que es el de las otras
   * líneas del panel: aquél está en 87,5 % de luminosidad sobre blanco y a
   * tamaño real no se ve. Una señal que hay que ampliar para encontrar no es
   * una señal. */
  .submenu { box-shadow: inset 2px 0 0 hsl(var(--input)); }
  /* Sin ancho para indentar: las hijas se distinguen por el filete, que no
   * gasta ancho, y no por la sangría, que en 48px es todo lo que hay. */
  .submenu a { padding-left: 0; }
  .lateral-pie { justify-content: center; }
  .lateral-marca { justify-content: center; padding: 0; }
  .marca { font-size: var(--t-rotulo); letter-spacing: 0.04em; }
  /* Con el rótulo escondido el contador **sale del renglón y se apoya sobre el
   * hombro del icono**. En flujo era un hermano más adentro de un enlace
   * centrado, así que lo que el navegador centraba era el par icono+contador y
   * no el icono: las dos entradas que lo llevan —Novedades y Avisos— dibujaban
   * el suyo catorce píxeles a la izquierda de la columna de las otras quince
   * (medido a 1024 con el panel en el riel: x=8,5 contra x=22,5). Absoluto no
   * ocupa lugar y el icono vuelve a la columna, que es lo único que alinea una
   * barra de iconos sin rótulos.
   *
   * El marco de referencia es el `position: relative` del enlace, quince líneas
   * más arriba. */
  .contador-nav { position: absolute; top: 3px; right: 2px; margin-left: 0; padding: 0 4px; }

  /* La cabecera muestra las cuatro puntas y el conmutador de tema. Y con eso el
   * de la hoja se apaga: dos conmutadores del mismo tema en la misma pantalla
   * son uno de más, y el de la hoja existe sólo porque en celular el de arriba
   * no está. */
  .cambiar-tema { display: flex; }
  .tema-en-hoja { display: none; }

  /* **Una plaza por renglón, también acá: la barra sigue siendo una columna.**
   * Hasta ahora, de 640 para arriba pasaba a `flex-direction: row`, y ése es el
   * defecto que se comía el título de las cuarenta pantallas. El mecanismo, que
   * no se ve en el selector: una caja de flex que envuelve **pide su ancho sin
   * envolver**. En fila, el tamaño base de esta barra es el de las dos plazas
   * una al lado de la otra —unos 780px— aunque después se dibuje en dos
   * renglones de 400. La cabecera reparte contra ese número, no contra lo que se
   * ve: a 1536 quedaban 290px en blanco adentro de la barra y el título salía
   * recortado igual («Ediciones de cheques por apro…», medido sobre
   * `ediciones_1536_claro.png`), y a 1024 la barra no entraba, envolvía en
   * cuatro renglones y el título se caía a dos caracteres («C..», «Cli…»).
   *
   * En columna el ancho que pide es el de **una** plaza, que es lo que de verdad
   * ocupa, así que lo que sobra se lo lleva el título, que es el único de la fila
   * que sabe recortarse. Y de paso cumple lo que la regla del `min-width` de
   * abajo venía prometiendo: los cuatro precios quedan uno debajo del otro y se
   * comparan de un vistazo, cosa que en fila pasaba sólo cuando la barra
   * envolvía por casualidad. */
  .barra-cotizaciones { flex: 0 1 auto; gap: 3px; }
  .barra-cotizaciones .plaza { gap: 4px 12px; }
  /* Y el nombre de la plaza al mismo ancho en las dos: es lo que alinea
   * «compra» con «compra» y los dos precios uno debajo del otro. */
  .barra-cotizaciones .donde { min-width: 11ch; }
  .barra-cotizaciones .cual { display: inline; }
  .barra-cotizaciones .contexto { display: inline-flex; }

  /* **El piso del título.** Ceder no es desaparecer: con `min-width: 0` el
   * título se recortaba hasta dos letras y lo que quedaba en la cabecera era el
   * contexto de mercado sin el nombre de la pantalla en la que se está parado.
   * Dieciséis caracteres son el nombre más corto que sigue distinguiendo dos
   * pantallas («Cheques en cart…» de «Cheques sin ide…»); lo que falte lo cede
   * la barra, que envuelve y no pierde ningún dato al hacerlo (§12.11: lo que se
   * esconde de las cotizaciones se decide por regla de negocio, no por sobra de
   * ancho).
   *
   * Sólo desde 640: en el celular la barra no envuelve —muestra una punta por
   * plaza— y el renglón de 56px de la cabecera es una de las ganancias del
   * rediseño; un piso ahí lo pondría en riesgo por un título que igual se lee
   * entero en el `h1` de abajo. */
  .titulo-cabecera {
    min-width: 16ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Vuelve el detalle de cada aviso: acá el renglón entra entero. */
  .lista-avisos .detalle-aviso { display: inline; }

  /* Dos columnas y el relleno del escalón siguiente. Ninguna zona se parte
   * todavía: a 640 la mitad de la pantalla son 300px, que no alcanzan para una
   * tabla ni para un formulario. Las dos columnas están para lo que las usa por
   * su cuenta —las tarjetas, los casilleros, los chips—, que traen su propia
   * grilla adentro de su zona. */
  main {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    padding: 16px 16px 24px;
  }
}

/* NOTEBOOK (≥1024) — el panel **sigue en el riel**, y acá aparece la elección. */
@media (min-width: 1024px) {
  /* **El panel no se expande acá: se expande a 1440, y esto es lo que más ancho
   * le devolvió a la notebook en toda la ronda.** Expandido se lleva
   * `--lateral` —256px— y el relleno de `main` otros 40, así que en una ventana
   * de 1024 al contenido le quedaban **727px** (medidos, `despues/medidas.json`)
   * y sobre esos 727 se caía la última columna de ocho tablas distintas: el
   * campo donde se tipea el conteo del arqueo, la diferencia del arqueo hecho,
   * la hora de la última captura de cotizaciones, los centavos del nominal del
   * cotizador. Con el riel de 64px el contenido pasa a **920px, un 27 % más**, y
   * con eso entran las que se caían por poco y las demás pierden menos.
   *
   * Lo que se paga: en la notebook la navegación son iconos y no rótulos. Cada
   * icono lleva su `title` —está en `app.html`, en los tres tipos de entrada—,
   * el submenú de «Cheques» se sigue abriendo con un clic y el contador de
   * novedades se sigue viendo, apretado contra el icono por la regla del bloque
   * de 640. O sea que la navegación no pierde ninguna función: pierde los
   * rótulos, y los recupera quien quiera con el botón de al lado del título.
   *
   * **Esto ya se arregló mal una vez, y conviene que se lea acá**: la ronda
   * anterior dejó el panel expandido y subió `p3` a 1440. Eso tapaba la mitad
   * del problema —la columna que sobraba dejaba de dibujarse— y abría otra: la
   * `p3` no quedaba ni en la fila ni en el `<details class="mas">`, que se
   * apagaba en 640, así que entre esos dos anchos no había ningún gesto para
   * llegar a ella. Subirle el corte a `p3` sin devolverle el ancho a la tabla no
   * alcanza. Acá se hacen las dos cosas: el ancho vuelve por el riel y el `más`
   * vuelve a dibujarse hasta 1440.
   *
   * La cookie manda en los dos sentidos y en los dos anchos: `gdv.js` pone
   * `lateral-expandida` o `lateral-colapsada` en el `<html>` según lo que el
   * panel esté midiendo en ese momento, y `base.html` la vuelve a poner desde la
   * cookie `lateral` en la página siguiente, así el ancho no salta al cargar.
   * Sin JavaScript no hay clase, el panel queda como lo dejan estas `@media`, y
   * el botón —que nace `hidden`— no se dibuja: no hay un control que no haga
   * nada. */
  :root.lateral-expandida .aplicacion { grid-template-columns: var(--lateral) minmax(0, 1fr); }
  :root.lateral-expandida .rotulo-nav,
  :root.lateral-expandida .lateral-pie .quien { display: inline; }
  /* La flecha vuelve al renglón: con el rótulo al lado señala el final de la
   * línea, que es donde una flecha de desplegar se busca. Es el deshacer de la
   * esquina del riel, y por eso van las tres declaraciones y no sólo el
   * `display`. */
  :root.lateral-expandida .flecha-nav { display: inline-flex; position: static; margin-left: auto; }
  :root.lateral-expandida .flecha-nav .icono { inline-size: 18px; block-size: 18px; }
  :root.lateral-expandida .navegacion a,
  :root.lateral-expandida .navegacion summary { justify-content: flex-start; padding: 0 10px; }
  /* Y el filete del submenú se apaga: con la sangría y el rótulo, las hijas ya
   * se leen como hijas. */
  :root.lateral-expandida .submenu { box-shadow: none; }
  :root.lateral-expandida .submenu a { padding-left: 38px; }
  :root.lateral-expandida .lateral-pie { justify-content: flex-start; }
  :root.lateral-expandida .lateral-marca { justify-content: space-between; padding: 0 14px; }
  :root.lateral-expandida .marca { font-size: var(--t-seccion); letter-spacing: 0.08em; }
  :root.lateral-expandida .contador-nav { position: static; margin-left: auto; padding: 0 6px; }

  /* Recién acá aparece el botón: es donde el panel tiene dos estados posibles.
   * Nace con `hidden` y lo saca `gdv.js`; la regla del atributo hace falta
   * porque el `display` de la regla de arriba le ganaría. */
  .colapsar { display: inline-flex; }
  .colapsar[hidden] { display: none; }

  /* Y el nombre al lado del avatar. */
  .quien-cabecera { display: inline; }

  main {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    padding: 20px 20px 24px;
  }

  /* FICHA: los datos a la izquierda y las cifras y relaciones a la derecha, 4 y
   * 2. La cabecera de datos clave, las acciones y el historial siguen a lo
   * ancho: son una fila de pares, una fila de botones y una lista.
   *
   * Una ficha cuyo `principal` sea una tabla ancha —el asiento de una operación,
   * que son seis controles por fila— **no lleva la clase de zona** y cae en el
   * default de ancho completo: dos tablas de seis columnas no entran en 1000px,
   * y eso está medido (§12.7). */
  main.familia-ficha .zona-principal { grid-column: span 4; }
  main.familia-ficha .zona-secundario { grid-column: span 2; }

  /* Y se deshace el `order` del celular: acá la grilla ubica los ítems en el
   * orden del documento y adelantar el bloque secundario lo mandaría a la
   * columna de la izquierda, que es el espejo de lo que la ficha pide.
   *
   * El envoltorio vuelve a dibujar su caja, que es lo que lo convierte en la
   * columna de contexto de dos pistas; con eso sus hijos dejan de ser ítems de
   * la grilla y el `order` que llevan escrito deja de significar nada, así que
   * no hay que devolvérselo uno por uno. */
  main.familia-ficha > div.zona-secundario { display: block; }
  main.familia-ficha > dl.zona-principal,
  main.familia-ficha > .zona-acciones { order: 0; }

  /* Y las tarjetas que caigan en esa zona van a **una** columna. La zona son 2
   * de 6 —unos 330px cuando esto se midió, con el panel expandido; hoy, con el
   * panel en el riel hasta 1440, son unos 300 y el argumento sólo se refuerza— y
   * la grilla de tarjetas le metía tres adentro: un importe de once dígitos en
   * Space Mono a 28px mide 204px y se derramaba, estirando el documento a 1067px
   * en una ventana de 1024. Está medido con el navegador, no deducido: es el
   * mismo derrame que en la cartera a 390, una pista más abajo. */
  /* Los dos selectores y no uno: en la ficha de un cliente las tarjetas están
   * **adentro** de la zona, y en las dos pantallas de Nosis la `<section>` es la
   * zona y las tarjetas a la vez. Con sólo el descendiente, esas dos seguían con
   * tres columnas en 330px y el importe se derramaba: el documento medía 1067px
   * en una ventana de 1024. Medido con el navegador las dos veces. */
  main.familia-ficha .zona-secundario .tarjetas,
  main.familia-ficha .zona-secundario .tarjetas.compactas,
  main.familia-ficha .tarjetas.zona-secundario,
  main.familia-ficha .tarjetas.compactas.zona-secundario {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Y lo mismo con los pares rótulo/dato: dos por renglón adentro de 330px son
   * 165px por par, y un chip de alias —«HOCHNADEL LOURDES», que no corta— mide
   * más que eso y se derramaba. Un par por renglón. */
  main.familia-ficha .zona-secundario .datos-clave {
    grid-template-columns: minmax(0, 1fr);
  }

  /* FORMULARIO: campos y ayuda, mitad y mitad. La ayuda de un formulario es
   * texto y se acota sola a 70ch; lo que gana la mitad es que se lea **al lado**
   * del campo que explica y no tres pantallas más abajo. Las acciones al pie, a
   * lo ancho y alineadas a la izquierda. */
  main.familia-formulario .zona-campos { grid-column: span 3; }
  main.familia-formulario .zona-ayuda { grid-column: span 3; }
}

/* MONITOR (≥1440) — acá nace expandido el panel, y cambia lo que entra adentro. */
@media (min-width: 1440px) {
  /* **El panel expandido empieza acá y no en 1024**, y el número sale de una
   * resta: expandido se lleva 256px de panel más 40 de relleno, así que la
   * ventana que le deja 1024px reales al contenido es 1024 + 256 + 40 = 1320, y
   * de los tres cortes que el §1 del contrato permite el primero que la pasa es
   * éste. A 1440 el contenido son 1144px y a 1536 son 1240 (medidos): ahí
   * mostrar los rótulos no le saca la última columna a ninguna tabla, que es lo
   * que sí pasaba a 1024 con 727. El motivo largo, con las ocho tablas, está
   * arriba en el bloque de 1024.
   *
   * Es el mismo cálculo que decide dónde entra `p3` —«los cortes con el
   * descuento ya hecho»—, y ahora las dos cosas caen en el mismo escalón: a
   * 1440 el panel se abre **y** entran las `p3`, o sea que el `<details
   * class="mas">` se apaga justo cuando ya no esconde nada. */
  .aplicacion { grid-template-columns: var(--lateral) minmax(0, 1fr); }

  /* Se deshace el riel: vuelven los rótulos. */
  .rotulo-nav, .lateral-pie .quien { display: inline; }
  /* Calificada con `.grupo-nav` y no `.flecha-nav` a secas: la del riel pesa
   * (0,2,0) y una regla de (0,1,0) no le gana por estar más abajo. Lo mismo el
   * tamaño del icono, que allá lo baja a doce. */
  .grupo-nav .flecha-nav { display: inline-flex; position: static; margin-left: auto; }
  .grupo-nav .flecha-nav .icono { inline-size: 18px; block-size: 18px; }
  .navegacion a, .navegacion summary { justify-content: flex-start; padding: 0 10px; }
  .submenu { box-shadow: none; }
  .submenu a { padding-left: 38px; }
  .lateral-pie { justify-content: flex-start; }
  .lateral-marca { justify-content: space-between; padding: 0 14px; }
  .marca { font-size: var(--t-seccion); letter-spacing: 0.08em; }
  .contador-nav { position: static; margin-left: auto; padding: 0 6px; }

  /* Y la cookie lo vuelve a colapsar, que es el otro sentido de la elección: el
   * de acá esconde lo que a 1024 se muestra. Van después de las de arriba a
   * propósito —pesan (0,3,0) contra (0,1,0) y ganarían igual, pero el orden dice
   * cuál es la excepción de cuál—, y no hace falta repetirlas en el bloque de
   * 1024: ahí el riel ya es el estado por defecto y `lateral-colapsada` no
   * tendría nada que apagar. */
  :root.lateral-colapsada .aplicacion { grid-template-columns: var(--lateral-angosta) minmax(0, 1fr); }
  :root.lateral-colapsada .rotulo-nav,
  :root.lateral-colapsada .lateral-pie .quien { display: none; }
  :root.lateral-colapsada .navegacion a,
  :root.lateral-colapsada .navegacion summary { justify-content: center; padding: 0; }
  /* Las tres del riel otra vez —flecha en la esquina, icono chico y filete—:
   * acá el panel vuelve a ser una barra de iconos y las necesita igual. */
  :root.lateral-colapsada .flecha-nav {
    display: inline-flex;
    position: absolute;
    right: 3px;
    bottom: 5px;
    margin-left: 0;
  }
  :root.lateral-colapsada .flecha-nav .icono { inline-size: 12px; block-size: 12px; }
  :root.lateral-colapsada .submenu { box-shadow: inset 2px 0 0 hsl(var(--input)); }
  :root.lateral-colapsada .submenu a { padding-left: 0; }
  :root.lateral-colapsada .lateral-pie { justify-content: center; }
  :root.lateral-colapsada .lateral-marca { justify-content: center; padding: 0; }
  :root.lateral-colapsada .marca { font-size: var(--t-rotulo); letter-spacing: 0.04em; }
  :root.lateral-colapsada .contador-nav { position: absolute; top: 3px; right: 2px; margin-left: 0; padding: 0 4px; }

  main { grid-template-columns: repeat(12, minmax(0, 1fr)); }

  /* La ficha pasa a mitad y mitad: es lo que hace que la regla espejo (§3.8) se
   * pueda **leer** en vez de sólo listarse —cada línea de caja al lado de su
   * reflejo en la cuenta de la contraparte, en el mismo renglón—. Con 4 y 2 el
   * reflejo quedaba en diagonal. */
  main.familia-ficha .zona-principal { grid-column: span 6; }
  main.familia-ficha .zona-secundario { grid-column: span 6; }

  /* Y con la zona al doble de ancho, las tarjetas vuelven a ser dos por renglón.
   * La regla de 1024 las manda a **una** columna con un motivo medido —la zona
   * son 2 de 6, unos 330px, y un importe de once dígitos a 28px se derramaba—,
   * pero ese motivo se termina justo acá: a este ancho la zona son 6 de 12, o
   * sea unos 610px en un monitor de 1536, y el mismo importe mide 218. Sin esta
   * línea las cuatro cifras de la ficha de un cliente quedaban en **una columna
   * de tarjetas de 610px de ancho para un `0,00`**, con 340px de hueco al lado.
   * Dos y no tres: una tarjeta de cifra lleva un pie de dos renglones y a 200px
   * el pie es más alto que el número. */
  main.familia-ficha .zona-secundario .tarjetas,
  main.familia-ficha .zona-secundario .tarjetas.compactas,
  main.familia-ficha .tarjetas.zona-secundario,
  main.familia-ficha .tarjetas.compactas.zona-secundario {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* El mismo reparto del formulario, con el doble de columnas. */
  main.familia-formulario .zona-campos { grid-column: span 6; }
  main.familia-formulario .zona-ayuda { grid-column: span 6; }

  /* EL DIÁLOGO a dos columnas: la conversación y el cuadro de texto a la
   * izquierda, la propuesta a la derecha. La propuesta es la ancha porque es la
   * que tiene tablas.
   *
   * **Y ya no va fija con scroll adentro, que es la corrección de esta tanda.**
   * La idea era buena y el resultado no: `position: sticky` con
   * `max-height: 100dvh` y `overflow-y: auto` dejaba la propuesta de una compra
   * de cheques cortada en el título «Cuentas de capital», y del otro lado del
   * corte quedaban la suma que tiene que dar cero, los cheques que entran, el
   * aviso ámbar y **las tres salidas** —`Confirmar`, `Dejar pendiente`,
   * `Cancelar`—. Sin barra dibujada y sin nada que dijera que seguía. La prueba
   * de que no se veía no admite interpretación: a 1536,
   * `cargar_cheques_1536.png` y `cargar_propuesta_1536.png` son **el mismo
   * archivo byte a byte** (md5 `38471bc7…`, en los dos temas): abrir el panel de
   * carga de cheques no cambiaba un píxel de lo que se ve.
   *
   * Y no alcanzaba con dibujar la barra. Un panel `sticky` **más alto que la
   * ventana** no tiene salida buena: o se le pone scroll propio —y entonces las
   * tres salidas viven detrás de un gesto adentro de una caja que nadie sabe que
   * scrollea— o se lo deja crecer, y entonces el `sticky` lo clava por el `top` y
   * su parte de abajo no se alcanza **nunca**, ni scrolleando la página. Las dos
   * esconden lo mismo. Un panel largo que se recorre con el scroll de siempre no
   * esconde nada, y es lo que queda acá.
   *
   * Lo que se pierde está dicho: con una conversación larga la propuesta deja de
   * quedar a la vista mientras se lee lo de arriba. En las capturas la columna
   * izquierda está vacía desde y≈600, así que hoy no hay tal conversación larga;
   * el día que la haya, lo que corresponde es fijar **la fila de salidas** —que
   * es lo que se está por apretar— y no el panel entero, y eso se escribe en
   * `cargar.html`, que es donde está esa fila.
   *
   * `align-self: start` se queda: sin él el ítem se estira al alto de la fila.
   *
   * **Y el reparto es 4 y 8, no 5 y 7, porque el asiento no entraba en 7.** Es
   * la corrección de esta tanda y sale de medir, no de gustos. La tabla del
   * asiento pide **unos 680px**: sus siete columnas son el código de cuenta
   * (`CAJA.ARS.EFECTIVO`, 17 caracteres monoespaciados que no envuelven desde
   * 640), la moneda, dos importes de catorce dígitos, el `TC`, el detalle
   * acotado a 20ch y el rótulo `Resultado`. Con 7 de 12 le tocan 717px de zona,
   * que menos el relleno del bloque son **654 de marco**: se cortaban las dos
   * últimas letras de `Resultado` en `Caja` y las cuatro en `Cuentas
   * corrientes`, con la sombra de desborde puesta (`cargar_propuesta_1536` y
   * `cargar_cheques_1536`; a 1440 el marco es todavía más chico, 628). Con 8 de
   * 12 son 821 de zona y ~759 de marco a 1536, y ~724 a 1440: entra en los dos.
   *
   * **La causa no era el aire de celda de §12.15**, que es lo que este defecto
   * parecía: `.propuesta table.datos th, td { padding-left/right: 6px }` pesa
   * (0,2,2) y le gana al `padding: 4px 10px` de `table.datos th, td` (0,1,2),
   * así que el asiento nunca recuperó los diez del monitor. Verificado con
   * `tests/estilos.py` a 1536. Lo que le falta al asiento no es relleno de
   * menos: es ancho de columna, y la única forma de dárselo es acá.
   *
   * Lo que se paga: la conversación baja de 507 a 403px a 1536 y de 443 a 371 a
   * 1440. Adentro no hay ninguna cifra —son los comprobantes, lo que se dictó y
   * el cuadro de corregir con sus dos botones—, y es la mitad que en las
   * capturas queda vacía desde y≈600. La propuesta es la ancha porque es la que
   * tiene tablas, que es lo que este bloque ya decía. */
  main.familia-dialogo .zona-conversacion { grid-column: span 4; }
  main.familia-dialogo .zona-propuesta {
    grid-column: span 8;
    align-self: start;
  }

  /* TABLERO: los detalles se emparejan. `/resultados` tiene seis tablas hermanas
   * y `/cotizaciones` cuatro; a este ancho entran de a dos, y es exactamente lo
   * que el monitor tiene de más. Los contadores, los saldos, lo principal y las
   * notas siguen a lo ancho: son una fila de chips, una fila de casilleros, la
   * tabla del día y texto. */
  main.familia-tablero .zona-detalle { grid-column: span 6; }
}
/* --- Tablas: los marcos, la cascada, la poda y los badges --------------- */

/* Sesenta y cinco tablas en cuarenta y dos plantillas: ésta es la sección que
 * decide si el sistema se puede usar de pie. El rediseño le cambia tres
 * cosas y le deja el resto como estaba:
 *
 * 1. **La tabla ya no muestra siempre todas sus columnas.** Cada celda declara
 *    su prioridad —`p1`, `p2`, `p3`— y el ancho decide cuáles entran. Lo que se
 *    esconde en un celular no se pierde: se abre en la fila.
 * 2. **La que no se poda se desplaza, y se nota.** Primera columna fija y una
 *    sombra en el borde que dice que hay más a la derecha.
 * 3. **El encabezado deja de ser fijo.** Estaba declarado para las 65 tablas y
 *    no hacía nada en 64. Ver la nota de `thead th`.
 *
 * Y una que no cambia y es la más importante de todas: **el orden de los
 * selectores es el orden de la especificidad**, de menor a mayor. Acá vivió el
 * peor defecto que tuvo este archivo y está contado dos veces más abajo. */

/* --- Los dos marcos ----------------------------------------------------- */

/* `.tabla-marco` es una caja —borde, fondo y radio— y `.tabla-scroll` es sólo el
 * desplazamiento, para las tablas que ya están adentro de una caja: las cuatro
 * de la propuesta del diálogo y el asiento de un ejemplo del corpus. Lo que
 * comparten es lo único que no se negocia: **el que scrollea es el marco y no la
 * página**. Las celdas no se aprietan —van con `nowrap`—, así que lo que sobra
 * se desplaza y nada se vuelve ilegible.
 *
 * **Los dos son `position: relative`, y no es sólo por la sombra.**
 * `.solo-lectores` —la casilla clipeada de los formularios de archivar— es
 * `position: absolute`, y sin ningún ancestro posicionado se ubicaba contra la
 * página: en `/novedades/seguimiento/{cuit}` y `/novedades/cuit/{cuit}` quedaba
 * en x = 845 y estiraba el documento a 846px en una ventana de 390. Es la causa
 * 7 del diagnóstico, y se arregla acá: con el marco posicionado, la casilla se
 * ubica adentro del marco, donde mide 1×1 y no arrastra a nadie. */
.tabla-marco {
  position: relative;
  /* `min-width: 0` en cada eslabón de la cadena, y no es de más: medido con el
   * navegador, un «(ganancia)» del bloque de resultado de la propuesta estiraba
   * el documento de /cargar a 418px en una ventana de 390. Una caja con
   * `overflow-x` **no** se achica sola cuando su antepasado es un ítem de
   * grilla: hereda un mínimo automático del ancho de su contenido, y el
   * `minmax(0, 1fr)` de la pista no alcanza. Es §12.2 aplicada hacia abajo. */
  min-width: 0;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
.tabla-scroll { position: relative; min-width: 0; }

/* **La barra de scroll visible es la regla base y se apaga desde 640.** Hasta
 * ahora era al revés —vivía en una `@media (max-width: 760px)`—, y mobile-first
 * la invierte: en el teléfono la barra queda siempre a la vista, porque una
 * tabla que sobra por derecha sin barra se lee como una tabla cortada y no como
 * una que se desplaza. De 640 para arriba vuelve a aparecer sólo cuando hace
 * falta, que es lo que corresponde con un mouse.
 *
 * **Y la señal de «hay más a la derecha», sin JavaScript.** Son cuatro fondos:
 * dos tapas del color de la superficie pegadas a cada borde y, debajo, dos
 * sombras. Las tapas van con `background-attachment: local` —viajan con el
 * contenido— y las sombras con `scroll` —se quedan pegadas al marco—: mientras
 * hay contenido escondido de un lado, la tapa de ese lado se fue con él y la
 * sombra queda a la vista; cuando se llegó al final, la tapa vuelve a su borde y
 * la sombra desaparece debajo. Nadie tiene que calcular nada.
 *
 * El color de tapa es `hsl(var(--card))` en los dos marcos (contrato §12.10):
 * en `.tabla-marco` es su propio fondo y en `.tabla-scroll` es el de la caja que
 * lo contiene, que es la única que hay. El extremo transparente se escribe
 * `hsl(var(--card) / 0)` y no `transparent`, porque `transparent` es negro con
 * alfa cero y ensucia el degradado con un gris en el medio.
 *
 * **El filo va en `--sombra-borde` y no en `--sombra`**, que es la corrección de
 * que en el tema oscuro esta señal no se percibía: siete niveles de 255. El
 * porqué del token está donde se declara, arriba, con los números medidos.
 *
 * **Lo que queda abierto y no se toca acá**: tres relevamientos leyeron tres
 * cosas distintas sobre *cuándo* aparece el filo —que se dibuja aunque no haya
 * nada más a la derecha, que no se dibuja donde sí lo hay, y que funciona—, y
 * las tres pueden ser ciertas a la vez porque `.tabla-marco` tiene fondo y
 * `.tabla-scroll` no, y la técnica de las dos tapas depende de tenerlo. Eso se
 * zanja con una medición, no con una corrección a ciegas: lo único que estaba
 * fuera de disputa —y es lo que se arregla acá— es que en oscuro no se veía.
 *
 * Ojo con el orden: `background-image` va **después** de la regla de
 * `.tabla-marco` de arriba a propósito. Un `background:` corto —el de allá, y el
 * `background: none` que `.bloque-asiento` y `.tarjeta-seguimiento` le ponen a
 * sus marcos— reinicia la imagen; declarar la imagen por su nombre largo y más
 * abajo deja las dos cosas convivir, y deja que esas dos apaguen la sombra
 * entera con una sola declaración, que es lo que quieren. */
.tabla-marco,
.tabla-scroll {
  overflow-x: scroll;
  overscroll-behavior-x: contain;
  scrollbar-color: hsl(var(--input)) transparent;
  background-image:
    linear-gradient(to right, hsl(var(--card)), hsl(var(--card) / 0)),
    linear-gradient(to left, hsl(var(--card)), hsl(var(--card) / 0)),
    linear-gradient(to right, hsl(var(--sombra-borde) / 0.35), hsl(var(--sombra-borde) / 0)),
    linear-gradient(to left, hsl(var(--sombra-borde) / 0.35), hsl(var(--sombra-borde) / 0));
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 20px 100%, 20px 100%, 10px 100%, 10px 100%;
  background-attachment: local, local, scroll, scroll;
}
.tabla-marco::-webkit-scrollbar,
.tabla-scroll::-webkit-scrollbar { height: 10px; }
.tabla-marco::-webkit-scrollbar-thumb,
.tabla-scroll::-webkit-scrollbar-thumb {
  background: hsl(var(--input));
  /* Uno de los tres redondeos que quedan: un pulgar de 10px de alto con 999 de
   * radio es un semicírculo de verdad, no una píldora decorativa. */
  border-radius: 999px;
}

@media (min-width: 640px) {
  .tabla-marco,
  .tabla-scroll { overflow-x: auto; }
}

/* --- La tabla ----------------------------------------------------------- */

/* Sin `color`: la tabla hereda el del documento, que ya es `--foreground`, y
 * declararlo acá no agregaría nada pero sí rompería algo. Una regla de
 * contenedor con dos elementos adentro pesa más que la clase de una celda, así
 * que `table.datos { color: … }` le gana a `.neg` y un importe negativo pierde
 * el rojo. Lo mismo vale para el `tfoot`: el color de un dato lo decide el dato
 * —`.neg`, `.ganancia`— y no la caja donde está. */
table.datos {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-dato);
  line-height: 1.3;
}

table.datos th,
table.datos td {
  padding: 4px 6px;
  border-bottom: 1px solid hsl(var(--border));
  white-space: nowrap;
}
/* **El aire lateral de la celda es mobile-first como todo lo demás.** Diez
 * píxeles por lado son veinte por columna, y con cuatro o cinco columnas `p1` son
 * cien de los 366 que tiene el marco de un celular: es el ancho de una columna de
 * importes gastado en el aire que las separa. En la regla base van seis.
 *
 * **Los diez vuelven a 1440 y no a 640, y eso cambió después de medir.** Estaban
 * puestos «desde la tablet, donde el ancho sobra», y el ancho no sobra: hasta
 * 1440 el panel es el riel y el contenido son 544px a 640 y 920 a 1024, y con el
 * cuerpo de 15px cada tabla se ensanchó un 15 % sin que nadie rehiciera el
 * presupuesto de columnas. Ocho pantallas perdían su última columna a 1024 —el
 * campo del conteo del arqueo, la `Diferencia` del arqueo hecho, `Faltantes` en
 * el historial, `BRL` a mitad de número en socios, la hora de la última captura
 * de cotizaciones, el `Saldo` de la valuación—, y ocho píxeles por columna son
 * entre 40 y 64 por tabla: no alcanzan solos, pero son los primeros que se
 * pagan por nada. A 1440 el contenido son 1144px y ahí sí sobra.
 *
 * El precedente está en la hoja desde antes: `.propuesta table.datos` ya baja a
 * seis a 1536 por el mismo motivo, y con el mismo número. */
@media (min-width: 1440px) {
  table.datos th,
  table.datos td { padding: 4px 10px; }
}
/* **La alineación va sólo en el `th`, y es la corrección de un defecto viejo.**
 * Mientras la regla de arriba decía `text-align: left` para `th` **y** `td`,
 * pesaba (0,1,2) y le ganaba a `.num` (0,1,0): ninguna columna de importes de
 * ninguna tabla de la aplicación estaba alineada a la derecha. Quedaban
 * monoespaciadas y desalineadas, que es lo peor de las dos cosas —la
 * monoespaciada existe justamente para que las cifras se comparen por su largo—.
 * El `td` ya viene alineado a la izquierda del navegador; el `th` no, así que
 * necesita la regla, y con dos elementos de especificidad `.num` le gana.
 *
 * La regla de la sección entera sale de acá: **se cuenta la especificidad, no se
 * mira el orden.** Cada vez que una clase de celda tiene que ganarle a una regla
 * de contenedor, se la califica con el contenedor y se dice por qué. */
table.datos th { text-align: left; }

/* **En el celular el encabezado de una tabla podable envuelve.** Es un rótulo de
 * dos o tres palabras —«Con saldo desde», «Razón social», «Costo transf.»— y en
 * una línea mide más que el dato que titula: en `/cuentas` el `<th>` de «Con
 * saldo desde» pedía 136px y la fecha de abajo 102, así que era el rótulo y no el
 * dato el que decidía el ancho de la columna y el que empujaba el saldo fuera del
 * marco. Dos renglones de rótulo se pagan **una vez por tabla**; una columna de
 * más afuera se paga en cada fila.
 *
 * Sólo en las podables: son las que tienen un presupuesto de ancho que cerrar en
 * 366px. Las `ancha` se desplazan y no ganan nada con esto, y el encabezado del
 * libro de caja es `sticky` —dos renglones ahí le comen alto al día—. Desde 640
 * vuelve al `nowrap` de `table.datos th`. Pesa (0,2,3). */
table.datos.podable thead th { white-space: normal; }
@media (min-width: 640px) {
  table.datos.podable thead th { white-space: nowrap; }
}

/* El encabezado es una **etiqueta**, no un dato: más chico, más tenue y sin
 * negrita fuerte. Lo que tiene que saltar de una tabla es lo que dice, no cómo
 * se llaman sus columnas. Es la regla 6 y se aplica en las dos direcciones: el
 * `th` va en `--muted-foreground` y la celda de datos en `--foreground`, nunca
 * al revés.
 *
 * **Acá ya no hay `position: sticky`, y ésa es la decisión del contrato §12.1.**
 * El `sticky` se mide contra el contenedor de scroll, y el contenedor de scroll
 * es el marco: un `overflow-x` convierte al elemento en contenedor de scroll en
 * los **dos** ejes, y un marco sin alto acotado nunca desplaza nada por dentro,
 * así que no había qué fijar. Estaba declarado para las 65 tablas y no hacía
 * nada en 64. La única que sí tiene el alto acotado es el libro de caja, y por
 * eso su `thead` fijo —y el `inset` que le sostiene la línea de abajo mientras
 * las filas pasan por debajo— se declara allá, con su marco, donde se puede leer
 * junto con el alto que lo hace posible. Y `--cabecera` no lo arreglaba: el
 * `top` se mide contra el marco, no contra la ventana. */
table.datos thead th {
  background: hsl(var(--card));
  padding-top: 6px;
  padding-bottom: 6px;
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
/* «Papeles», «Tipo de cambio», «Resultado asignado»: el `th` de una columna
 * numérica se alinea a la derecha como su columna, pero **no** se escribe en
 * Space Mono. La monoespaciada está para que los dígitos midan lo mismo; en un
 * rótulo de dos palabras no hay dígitos que alinear y sólo lo hace más ancho.
 *
 * La alineación va repetida acá y no alcanza con `.num`: el `table.datos th` de
 * arriba lleva una clase adentro —`.datos`— y por eso pesa (0,1,2) contra el
 * (0,1,0) de `.num`. Es exactamente la trampa que dejó sin alinear a todas las
 * columnas de importes de la aplicación, y la única forma de no volver a caer en
 * ella es contar la especificidad, no mirar el orden. */
table.datos th.num { text-align: right; font-family: var(--sans); }

table.datos tbody tr:nth-child(even) { background: hsl(var(--muted) / 0.35); }
table.datos tbody tr:hover { background: hsl(var(--accent)); }

table.datos tfoot th,
table.datos tfoot td {
  border-top: 2px solid hsl(var(--border));
  border-bottom: none;
  font-weight: 600;
  background: hsl(var(--card));
}
/* El rótulo de un total sigue siendo un rótulo. */
table.datos tfoot th { color: hsl(var(--muted-foreground)); }

/* --- Los datos de una celda --------------------------------------------- */

/* Los importes. Space Mono, a la derecha y con `tabular-nums`: con el dígito de
 * ancho fijo, dos cifras alineadas se comparan por su largo, sin leerlas.
 *
 * **Sin `font-size`.** Hasta acá `.num` se dibujaba al 88% de la celda para que
 * entrara una columna más, y era la decisión al revés: la mono va al cuerpo del
 * texto que acompaña (regla 3 del encabezado del archivo), y lo que decide qué
 * columnas entran es la prioridad de columna, no achicar la letra. */
.num {
  text-align: right;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Negativo: paréntesis (los pone el servidor) más color más un trazo de peso.
 * Tres señales, y las dos primeras se leen en blanco y negro. */
.neg { color: hsl(var(--destructive-text)); font-weight: 500; }

/* El bloque de resultado (§7): ganancia o pérdida, y **no** por el signo del
 * importe —acá una ganancia se guarda negativa (§4.8), así que `.neg` pintaría
 * de rojo cada ganancia—. `gdv.enums.es_ganancia` decide cuál de las dos es, y
 * la plantilla pone la clase que corresponde. El color nunca es la única
 * señal: la palabra «ganancia»/«pérdida» va siempre al lado, en
 * `.sentido-resultado`, que hereda el color de la celda por `currentColor`. */
.ganancia { color: hsl(var(--success-text)); font-weight: 500; }
.perdida { color: hsl(var(--destructive-text)); font-weight: 500; }
.sentido-resultado { font-style: italic; }

.destacado { font-weight: 600; }
/* Rótulos y calificadores, no datos: van tenues porque acompañan a la celda que
 * están al lado, no porque valgan menos que ella. La fecha **sí** es un dato y
 * por eso queda en el color del texto, sólo en monoespaciada para que una
 * columna de fechas se lea alineada.
 *
 * `.secundario` va al cuerpo del dato y no a uno intermedio: de los cinco pasos
 * que quedan, el que le toca a «texto secundario» es `--t-dato`. Lo que lo
 * distingue del dato que acompaña es el color, no el tamaño. Y `.fecha` pierde
 * su `0.86em`: hereda, como toda la monoespaciada. */
.vacio, .secundario, .moneda { color: hsl(var(--muted-foreground)); }
.secundario { margin-left: 6px; font-size: var(--t-dato); }
.moneda { font-size: var(--t-rotulo); }
.fecha { font-family: var(--mono); }

/* Las columnas que llevan texto libre y no un dato de una palabra: envuelven y
 * tienen tope de ancho, al revés que el resto de la tabla. Sin tope, una nota
 * larga empuja las columnas numéricas fuera de la pantalla; sin `normal`, la
 * fila se hace del ancho de la nota.
 *
 * **Estos topes no son los que el plan saca.** Los que se van son los que
 * acotaban **texto que se lee de corrido** y ahora los da `--linea` en un solo
 * lugar; éstos acotan **una columna de una tabla**, que es otra cosa: es lo
 * único que impide que una nota de trescientos caracteres se coma el ancho de
 * los importes. Lo mismo vale para el tope de `td.alias`, que vive con el
 * padrón.
 *
 * **`td.fila-mas` sale de esta lista y vuelve desde 640**, que es la regla de
 * abajo. Entró acá para que la `dl` de pares de la fila expandida pudiera
 * envolver, y eso hoy lo declara el panel sobre sí mismo —`table.datos
 * details.mas`, unas líneas más abajo, que pesa (0,2,2) y le gana al `nowrap` de
 * la celda—: lo único que seguía haciendo era envolver el texto **propio** de la
 * celda que hospeda el panel.
 *
 * En casi todas las tablas esa celda es un importe o una fecha y no envuelve
 * nunca. Donde envolvía era en el archivo de novedades, y en el celular cobraba
 * caro: con tres columnas `p1` de `nowrap` adelante, la del título se dibuja en
 * su ancho **mínimo** —unos 170px— y el título se parte en cuatro renglones. La
 * fila medía **131px contra los 29** de antes del rediseño mostrando las mismas
 * tres columnas, y los otros dos renglones y medio los ponía esto y no el
 * `summary` (medido en `novedades_archivo_390_claro.png`).
 *
 * **Calificadas con `table.datos`, y no es adorno.** El `white-space: nowrap` de
 * la celda pesa (0,1,2) y una clase sola pesa (0,1,0): sin la calificación estas
 * reglas no llegan y las columnas siguen en una línea. Es exactamente la misma
 * trampa de especificidad que tenía sin alinear a todos los importes de la
 * aplicación, en otra propiedad. */
.descripcion, .notas { max-width: 24ch; }
/* Cuarenta caracteres son unos 330px y el marco del celular tiene 366: en el
 * mayor —que es `ancha` y no se poda, así que ninguna columna se esconde— esa
 * sola celda empujaba `Importe` y `Saldo` fuera de la pantalla, que son las dos
 * por las que se abre un mayor. En el celular el tope baja al de `td.detalle`, y
 * desde la tablet vuelve a los 40, que es donde una descripción se lee entera. */
@media (min-width: 640px) {
  .descripcion, .notas { max-width: 40ch; }
}
table.datos .descripcion,
table.datos .notas,
table.datos td.alias,
table.datos td.detalle { white-space: normal; }
td.detalle { max-width: 24ch; }
/* **Y la celda del panel envuelve desde 640 y no antes**, que es la mitad
 * mobile-first de lo de arriba. De 640 para arriba la columna tiene ancho de
 * verdad —a 1024 el título del archivo de novedades se dibuja en unos 200px y
 * envuelve en dos renglones, que es lo que hace que las siete columnas entren en
 * los 920 del marco sin desplazar nada— y sacarle el `normal` ahí ensancharía la
 * tabla hasta empujar `Estado` fuera del marco: se ganarían veinte píxeles de
 * alto y se perdería una columna, que es el cambio al revés.
 *
 * En el celular no hay ancho que repartir: la columna cae en su mínimo, envolver
 * es partir el título en cuatro y lo que sobra se alcanza desplazando el marco,
 * que es lo que una tabla ancha hace en un teléfono. */
@media (min-width: 640px) {
  table.datos td.fila-mas { white-space: normal; }
}

/* **El panel de la fila expandida envuelve siempre, esté en la celda que esté y
 * sea cual sea el ancho.** Es lo que hace que la celda que lo hospeda pueda
 * quedarse con el `nowrap` de la tabla —en el celular todas, y en cualquier
 * ancho la de acciones, que es la que tiene más de un control y con el `normal`
 * heredado apilaba los cinco botones de `/padron` uno por renglón—. El que
 * envuelve es la lista de pares, que es la que lo necesita: adentro hay razones
 * sociales y detalles largos. Pesa (0,2,2) y le gana a ese `nowrap` (0,1,2). */
table.datos details.mas { white-space: normal; }

/* **El panel de la fila se dibuja con la letra del documento, no con la de la
 * celda que lo hospeda.** `fila-mas` va en la última celda `p1` en el orden del
 * documento (§12.13) y ésa es, en varias tablas, una `.num` o una `.fecha`: las
 * dos declaran `font-family: var(--mono)` y `.num` además alinea a la derecha.
 * Adentro del panel eso no dice nada —son pares rótulo/dato, prosa corta— y
 * dibuja «Vigente hasta» o «Costo transf.» en Space Mono, contra el borde
 * derecho, que es la forma de un importe. Pesa (0,2,2) y le gana a `.num`
 * (0,1,0). Es el hermano de `table.datos td.fila-acciones details.mas`, más
 * abajo, que arreglaba sólo la mitad de la alineación y sólo en la celda de
 * acciones. */
table.datos td.fila-mas details.mas {
  font-family: var(--sans);
  text-align: left;
}

/* En el celular la primera columna de una tabla podable **envuelve**: es la que
 * lleva el nombre —cliente, firmante, razón social— y con el `nowrap` de
 * `table.datos td` una razón social de treinta caracteres se lleva los 366
 * enteros y empuja fuera del marco a las dos o tres columnas `p1` que la
 * acompañan, que son las que traen el dato. Es la única que puede envolver sin
 * perder nada: las demás columnas `p1` son fechas, importes y controles, y ésas
 * sí se leen en una línea o no se leen. Desde 640 vuelve al `nowrap`, porque ahí
 * el ancho alcanza y una tabla con filas de dos renglones se lee peor.
 *
 * Pesa (0,3,3) —el `:first-child` cuenta como una clase— y le gana al (0,1,2) de
 * `table.datos td`. Va sobre `tbody` y no sobre la tabla entera para no alcanzar
 * al `<th>` del encabezado ni al del pie, que son rótulos y no datos. */
table.datos.podable tbody td:first-child { white-space: normal; }
/* Salvo cuando esa primera celda **es una fecha**, que es el caso de la cartera:
 * `05/09/2026` tiene oportunidad de corte después de cada barra y una fecha
 * partida en dos renglones deja de leerse como una fecha. Y no hace falta que
 * envuelva: no tiene ni un espacio y mide siempre lo mismo. Pesa (0,4,3) y le
 * gana a la de arriba. */
table.datos.podable tbody td.fecha:first-child { white-space: nowrap; }
@media (min-width: 640px) {
  table.datos.podable tbody td:first-child { white-space: nowrap; }
}

tr.anulada td, tr.baja td { color: hsl(var(--muted-foreground)); }
tr.anulada .descripcion { text-decoration: line-through; }

/* --- La prioridad de columna -------------------------------------------- */

/* Diecisiete tablas de listado declaran `podable` —las que quedaron del contrato
 * §12.5 más las que la mirada fue encontrando sin ninguna estrategia de celular—
 * y cada `th` y cada `td` de una columna llevan la misma clase de prioridad.
 *
 * **El número de acá se vence.** Ya se venció tres veces: la lista cerrada del
 * contrato decía nueve, después dieciséis, y hoy son diecisiete. Manda el
 * comando, no el párrafo:
 * `grep -c "class=\"datos[^\"]*podable" src/gdv/web/templates -r`.
 *
 * **Eran nueve las del §12.5 y son ocho: `/cartera/ediciones` se fue con la
 * misma regla que ya había sacado a la cola de pendientes y al catálogo de
 * bancos.** Su fila entera es un formulario —dos salidas y el campo del motivo
 * del rechazo—, así que no había columna que podar y la poda no la ayudaba en
 * nada: pasó a `papel tarjeta-siempre`, que es la sección de más abajo.
 *
 *   p1  se ve siempre —lo que identifica la fila, el número que se vino a
 *       mirar, y **las acciones**: un «Aprobar» que no se alcanza en el celular
 *       es la falla más grave que tiene hoy el listado;
 *   p2  desde 640 —lo que califica: estado, fecha secundaria, quién;
 *   p3  desde **1440** —lo que se consulta de vez en cuando: notas, costo de
 *       transferencia, el tipo del movimiento. El número no es 1024 y el porqué
 *       está abajo, en la regla. **Los alias salieron de esta lista**: esa
 *       columna es un `<form>` de «+ alias» con un botón de borrado por chip, y
 *       una columna que contiene un control nunca es `p3` —a 1440 el control
 *       aparece recién en el monitor y desde la notebook no se puede hacer la
 *       tarea—. Es `p2`, con las demás.
 *
 * **Sin clase es `p2`**, y eso está escrito en el `:not(.p1)` de la primera
 * regla y en el `:not(.p3)` de la segunda: una columna nueva se esconde en el
 * celular por omisión, en vez de romperlo por olvido. El día que alguien agregue
 * una columna al libro sin tocar esta hoja, el celular sigue entero.
 *
 * **Sólo adentro de `table.datos.podable`.** Una tabla sin esa clase muestra
 * siempre todas sus columnas: el reparto entre socios, la valuación de
 * posiciones, la lista de socios, los cierres y las paridades llevan `ancha` y
 * **no llevan `podable`**, así que ninguna regla les esconde una celda. Se
 * desplazan, que es lo que se pide de una tabla que es toda números y donde los
 * guiones también dicen algo.
 *
 * **Dos correcciones a lo que este mismo párrafo decía antes**, porque las dos
 * mandaban a buscar en el lugar equivocado: el mayor **sí** lleva `podable`
 * desde §12.5 —lleva las dos clases, como `resultado_clase`—, y la grilla de
 * Nosis no entra en esta cuenta porque no es `table.datos`: es
 * `<table class="grilla-nosis">`, con su propio armado, y lo dice su parcial.
 *
 * **Y la tercera lista, la que no existía, es la que costó los defectos.** El
 * contrato §6 cerró nueve podables y cinco anchas sobre unas sesenta y cinco
 * `table.datos`: todo lo que no entró en ninguna de las dos se recortaba contra
 * el marco sin prioridades, sin `más` y sin columna quieta. No era un error de
 * implementación sino un agujero del inventario, y se cierra repartiendo esas
 * tablas entre los dos mecanismos que ya existen, sin inventar ninguno:
 *
 *   podable  el detalle de una clase de resultado, las cuatro tablas de
 *            `/resultados` que no son el reparto ni la valuación, las
 *            conversaciones costosas de `/ejemplos`, la serie de tasas y los
 *            últimos avisos de `/notificaciones`;
 *   ancha    la tabla de preferencias de `/notificaciones` —tres columnas de
 *            casillas: todas son el control, así que no hay nada que podar—, las
 *            de cierres y paridades de `/cotizaciones`, el historial de un CUIT
 *            y las tres del detalle de un seguimiento. Las seis últimas las
 *            saca de las podables el contrato §6 por su nombre, así que la
 *            elección era ésta o ninguna.
 *
 * **La inmunidad de `ancha` es por omisión y no está declarada, y hay dos tablas
 * que llevan las dos clases**: `parciales/mayor_tabla` y `resultado_clase`. En
 * ellas estas reglas **sí** podan, que es lo que §12.13 quiere para las columnas
 * de bucle, que reciben la prioridad por índice.
 *
 * **No son «el libro», que es de donde salía la confusión**: bajo ese nombre hay
 * dos tablas distintas y ninguna lleva las dos clases. La de la pantalla de
 * inicio (`caja.html`) es `ancha libro-del-dia` **sin** `podable`, y la de
 * `/libro` (`parciales/libro_tabla`) es `podable` **sin** `ancha`. Lo que sigue
 * vale para la segunda: las reglas del libro que
 * esconden una columna por su cuenta —`.quieta`, y `.movimientos-de-la-fila` de
 * 640 para arriba— pesan (0,2,1) y (0,3,1) contra los (0,3,2) de acá, así que
 * pierden. Quien escriba la parte del libro las tiene que calificar hasta pasar
 * ese peso; si no, las reglas de este bloque le devuelven a la pantalla columnas
 * que el libro había apagado a propósito.
 *
 * Se escribe `th` y `td` y no un `:not(.p1)` suelto: sin el tipo, el selector
 * alcanzaría a cada `span` de adentro de cada celda y escondería medio listado.
 *
 * Las reglas pesan todas lo mismo —(0,3,2)—, así que lo que las ordena es el
 * lugar en el archivo: primero la que esconde, y después, en cada `@media`, la
 * que devuelve. Mobile-first en una línea. */
table.datos.podable th:not(.p1),
table.datos.podable td:not(.p1) { display: none; }

/* **Una celda con `colspan` no es una columna, así que la poda no la toca.** Sin
 * esto, la fila entera de edición del padrón y la de firmantes —un `<td
 * colspan="8">` con el formulario adentro— se van de la pantalla en el celular,
 * que es exactamente lo que prohíbe la tercera regla dura del contrato §6: lo
 * que se edita no se esconde. Lo mismo con el renglón de «no hay nada» de un
 * listado vacío, que es la única cosa que esa pantalla tiene para decir.
 *
 * Pesa lo mismo que la regla de arriba —(0,3,2): un atributo cuenta como una
 * clase— y por eso va justo después: lo que las ordena es el lugar en el
 * archivo. De 640 para arriba no hace falta, porque el `:not(.p3)` ya la
 * devuelve; está igual en la regla base, que es donde la celda se perdía. */
table.datos.podable th[colspan],
table.datos.podable td[colspan] { display: table-cell; }

/* `.p2` va escrita aunque el `:not(.p3)` de abajo ya la incluya, y no es
 * redundancia gratuita: es el nombre público del contrato §6, y una clase que
 * ningún selector nombra es —para el test que recorre el HTML buscando clases
 * sin regla— una clase sin estilo. Además dice en el propio selector las dos
 * cosas que entran acá: la columna que declaró `p2` y la que no declaró nada. */
@media (min-width: 640px) {
  table.datos.podable th.p2,
  table.datos.podable td.p2,
  table.datos.podable th:not(.p3),
  table.datos.podable td:not(.p3) { display: table-cell; }
}
/* **`p3` entra a 1440 y no a 1024, y el número está elegido con el ancho de la
 * tabla y no con el de la ventana.** Una `@media` mide la ventana; lo que decide
 * si una columna entra es lo que le queda a la tabla, y las dos cosas se separan
 * justo acá. Con `p3` prendida en `min-width: 1024` el archivo de novedades
 * pedía 1266px, el libro devolvía `Movimientos` y empujaba `Editar`/`Aprobar`
 * fuera del marco, y la cartera —que pide 1460— mostraba dos caracteres de
 * nominal: la notebook, donde se trabaja, era el peor de los tres anchos.
 *
 * CSS no sabe preguntar por el ancho del contenedor con una `@media`, así que la
 * cuenta se hace acá y una sola vez: con el panel expandido la ventana que le
 * deja 1024px a la tabla es 1024 + 256 + 40 = 1320, y de los tres cortes que el
 * contrato §1 permite el primero que la pasa es **1440** (1144px de tabla, que
 * es el ancho para el que estas columnas se pensaron; a 1536 son 1240, los
 * mismos 1239 que mide `medidas.json`).
 *
 * **Se reevaluó bajarla a 1024 con el panel colapsado, y no da.** Colapsar el
 * panel hasta 1440 (bloque de `min-width: 1024`) le devolvió al contenido 193px
 * —de 727 a 920—, que era la razón por la que `p3` había subido. Pero 920 no
 * alcanza para las tablas que la motivaron: el archivo de novedades sigue
 * pidiendo 1266, la cartera 1460, el libro 1190 y el padrón 1186. Bajarla
 * devolvería las mismas columnas cortadas por 250 o 500px, así que se queda acá
 * y el tramo de 640 a 1439 lo cubre el `<details class="mas">`, que ahora se
 * dibuja hasta 1440 —la regla está unas líneas más abajo, con su medición—.
 *
 * `p2` no se mueve: entra a 640, donde el panel es el riel de
 * `--lateral-angosta` (64px) y la tabla tiene 544px, que es lo que ese escalón
 * siempre quiso decir. */
@media (min-width: 1440px) {
  table.datos.podable th.p3,
  table.datos.podable td.p3 { display: table-cell; }
}

/* **Y una tabla angosta puede traer sus `p3` a la notebook, si lo declara.** El
 * 1440 de arriba sale de las tablas que lo motivaron —el archivo de novedades
 * pide 1266px, la cartera 1460, el libro 1190, el padrón 1186— y no es una
 * propiedad de `p3`: es el ancho que necesitan **ésas**. La serie de tasas mide
 * unos 750px con sus seis columnas puestas, así que entra holgada en los 920 que
 * hay a 1024, y hasta esta ronda pagaba el número de las otras: dibujaba cuatro
 * columnas cortas en 920px, mandaba `La fijó` y `Cuándo` detrás de un clic y le
 * sumaba el `summary` a cada fila —28px de fila pasaron a 72, medido en
 * `tasas_1024_claro.png`—.
 *
 * Se declara tabla por tabla y no se adivina: una `@media` mide la ventana y lo
 * que decide si la columna entra es lo que le queda a la tabla, que es la misma
 * separación que explica el bloque de arriba. El día que alguien le ponga esta
 * clase a otra tabla, lo que hay que medir es la tabla entera contra los 920px
 * de marco que hay a 1024. Va en la `<table>` y es la mitad de una afirmación:
 * la otra mitad —si a 1024 se ven todas, a 1024 no hay nada que desplegar— la
 * escribe la misma palabra en la sección que sigue. */
@media (min-width: 1024px) {
  table.datos.podable.entera-desde-1024 th.p3,
  table.datos.podable.entera-desde-1024 td.p3 { display: table-cell; }
}

/* --- La fila que se expande --------------------------------------------- */

/* Lo que la poda esconde no se pierde: la última celda `p1` en el orden del
 * documento lleva un `<details class="mas">` y adentro los pares rótulo/dato de
 * las columnas ocultas. Funciona sin JavaScript, sobrevive al reemplazo de fila
 * de HTMX y —a diferencia de mostrar las celdas escondidas con `:has()`— lo
 * puede leer el resolvedor de la suite, que es lo que decide que las
 * afirmaciones de esta hoja se puedan seguir verificando.
 *
 * El `<summary>` es un objetivo táctil de 44px enteros: es el control que abre
 * la fila y en un celular se toca con el pulgar en movimiento. El foco lo pone
 * la regla general de `summary:focus-visible`, con los demás controles.
 *
 * Va junto con `details.movimientos`, que es el otro plegado de una tabla —el
 * asiento de la propuesta y el de cada ejemplo del corpus— porque **es el mismo
 * control**: se abre una cosa que estaba plegada dentro de una fila. Aquélla no
 * tenía ninguna regla y el único control que abría el asiento del corpus medía
 * lo que mide su texto y ni siquiera cambiaba el cursor. */
details.mas > summary,
details.movimientos > summary {
  display: flex;
  align-items: center;
  min-height: var(--toque);
  cursor: pointer;
  font-size: var(--t-dato);
  color: hsl(var(--primary-text));
  list-style: none;
}
/* `list-style: none` apaga el triángulo en Firefox; en WebKit el marcador es un
 * pseudoelemento propio y con el `summary` en `display: flex` queda de ítem de
 * la fila, corriendo el texto. Es la misma línea que la hoja ya escribe dos
 * veces para los `summary` de la navegación, y acá importa más: iOS es la
 * pantalla para la que existe todo este rediseño. */
details.mas > summary::-webkit-details-marker,
details.movimientos > summary::-webkit-details-marker { display: none; }

/* **El `más` se dibuja en todo ancho donde alguna columna esté escondida, y se
 * apaga recién cuando se ven todas.** En la tabla que usa las tres prioridades
 * —`p2` entra en 640 y `p3` en 1440— eso es: hasta 1439 se dibuja, desde 1440
 * no. Es el caso por defecto; las dos tablas que se ven enteras antes lo dicen
 * en su `<table>` y están más abajo. Se esconde **el `<details>` y no
 * su celda**: la celda es una `p1` que sigue llevando su dato. El costo —los
 * valores de `p2` y `p3` van dos veces en el HTML de cada fila— está aceptado en
 * el plan §2d.
 *
 * **Antes se apagaba en 640, y eso dejó una columna en ninguna parte.** Con `p3`
 * entrando a 1440, entre 640 y 1439 una `p3` no estaba en la fila **ni** en este
 * panel: el `<details>` se había apagado y la columna todavía no entraba. Se
 * midió en cinco pantallas a 1024 y en todas la columna perdida era un dato y no
 * una nota —`USDT` y sus `200,00` en `/cuentas`, `Movimientos` en el libro,
 * `Detalle` en el resultado por clase, `Plazo` y `Descuento` en el cotizador,
 * `Días` en intereses—, y no había ningún gesto que las trajera: antes del
 * rediseño estaban fuera de la ventana, pero se llegaba desplazando.
 *
 * Lo que se probó antes y no alcanzó: **decidir a mano qué columna es nota y
 * cuál es plata**. No alcanza porque la prioridad de las columnas de bucle sale
 * del índice (`cuentas_tabla.html`, §12.13 del contrato), así que la cuarta
 * moneda de un saldo cae en `p3` sin que nadie lo decida, y la lista de qué es
 * nota cambiaría cada vez que alguien agregue una moneda.
 *
 * Lo que cuesta esta versión, dicho porque no se ve en el selector: entre 640 y
 * 1439 el panel ofrece **dos veces** cada `p2` —ya está en la fila— y le suma el
 * `min-height: var(--toque)` del `summary` a cada fila. Es lo que se paga por no
 * perder ninguna columna, y **sólo se paga donde hay algo escondido**. Eso no es
 * lo mismo que 1440 en todas las tablas, y decirlo así fue lo que dejó a los
 * últimos avisos de `/notificaciones` ofreciendo a 1024 un «más» que al abrirse
 * mostraba `Cuándo`, que está escrito dos columnas a la izquierda, y que era el
 * único control de esa tabla. Las dos formas que faltaban se declaran en la
 * `<table>`, porque son propiedades de esa tabla y no de la hoja:
 *
 *   `entera-desde-640`   la tabla no tiene ninguna columna `p3`, así que desde
 *                        640 se ve entera. Debajo de 640 el panel sí trae algo
 *                        —las `p2`—, así que el `<details>` se emite igual: lo
 *                        que se apaga es de 640 para arriba.
 *   `entera-desde-1024`  sus `p3` entran en la notebook y se dibujan desde 1024
 *                        (la regla está arriba, con la medición), así que el
 *                        panel se apaga en el mismo escalón.
 *
 * Y una tabla puede no emitir el `<details>` en ningún ancho, que es una
 * decisión de la plantilla y no de acá: las cuatro de `/resultados` esconden una
 * `p2` —`Sin aprobar`— y no la ofrecen, porque es exactamente `Total` menos
 * `Aprobado` y el `summary` costaría mil píxeles de scroll para mostrar un
 * guión. Está escrito en `resultados.html`, donde se decidió.
 *
 * **Lo que esta regla no arregla, y conviene no confundir: la tabla que a 1440
 * sigue sin entrar en su marco.** La cartera pide 2.277px en los 1.240 del
 * monitor, así que seis de sus quince columnas quedan fuera de la ventana con el
 * `más` ya apagado. No se le devuelve el `más` y es a propósito: a 1536 esas
 * seis columnas **están dibujadas** —lo que falta no es un gesto que las traiga
 * sino ancho—, y volver a ofrecerlas plegadas costaría el `summary` en las trece
 * filas, unos 570px de página, para mostrar de nuevo lo que la fila ya tiene y
 * en desorden respecto de sus columnas. Ahí el trabajo lo hace el marco:
 * `.tabla-marco` se desplaza y lo dice con la sombra del borde derecho —la barra
 * siempre visible es de la regla base y a ese ancho ya se apagó (§12.12)—.
 * O sea que el `más` se apaga cuando la tabla deja de esconder con
 * `display: none`, que no es lo mismo que «cuando se ve todo».
 *
 * **Y no se arregla poniéndolo al lado de los botones.** Un `display:
 * inline-block` en la celda de acciones le ahorraría esos 44px a la fila —esa
 * celda ya mide 44 por sus controles—, pero `td.fila-acciones` lleva `nowrap`,
 * así que el `más` le sumaría su ancho a la celda: unos 45px de tabla en las
 * mismas nueve pantallas donde falta ancho, que es la moneda cara. El alto es la
 * barata y se paga con eso. */
@media (min-width: 640px) {
  table.datos.podable.entera-desde-640 details.mas { display: none; }
}
@media (min-width: 1024px) {
  table.datos.podable.entera-desde-1024 details.mas { display: none; }
}
@media (min-width: 1440px) {
  details.mas { display: none; }
}

/* --- Los pares rótulo/dato ---------------------------------------------- */

/* `dl.datos-clave` es lo que reemplaza a las líneas de metadatos con puntos
 * medios —«Compra cheque · 05/09/2026 · MELLADO → MELLADO JULIAN»—, y resuelve
 * de paso el problema que tenían: un segmento que no se dibujaba dejaba un punto
 * huérfano en el medio del renglón, y por eso el separador había terminado en un
 * `::before`. Acá no hay separador que sobre porque no hay separador: lo que
 * separa un par del siguiente es el hueco de la grilla, que sólo existe entre
 * cosas que existen. El par sin dato no se emite y listo.
 *
 * El `<div>` por par es obligatorio y es el ítem de la grilla: es lo que impide
 * que el rótulo quede en una columna y su dato en la otra. Y lleva
 * `min-width: 0` porque un ítem de grilla sin eso mide su `min-content`, que con
 * un nombre del padrón o un CUIT desborda la columna en vez de cortarse.
 *
 * Sirve en los tres lugares donde hace falta y por eso no tiene variantes:
 * adentro del `<details>` de una fila, como cabecera de una ficha —las cuatro
 * que nunca fueron tablas: diez pares con el dato a 1200px del rótulo; tres se
 * llaman `table.datos.ficha` y la cuarta hace lo mismo sin la clase, así que se
 * las busca por lo que son y no por cómo se llaman— y como línea de metadatos
 * suelta. Lo único que cambia entre los tres es cuántas columnas entran, y eso
 * lo decide el ancho.
 *
 * Y la regla que va con el componente aunque se cumpla en la plantilla: **el
 * `<dd>` lleva el valor como texto plano, nunca una copia del marcado de la
 * celda**. Repetir un elemento con clase dentro de la misma fila hace que
 * `Nodo.uno(clase=…)` de la suite encuentre dos y reviente, y una celda que
 * contiene un control no se duplica ni siquiera resumida: dos formularios que
 * postean a la misma ruta en la misma fila no los atrapa ningún test. Por eso
 * una columna que se edita es `p1` y no se esconde nunca. */
.datos-clave {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px calc(var(--paso) * 2);
  align-content: start;
  margin: 6px 0;
}
.datos-clave > div { min-width: 0; }

/* Un par del panel que sólo vale en el celular.
 *
 * El panel de una fila podable trae **todas** las columnas escondidas, y cuáles
 * están escondidas depende del ancho: `p2` vuelve a la fila a los 640 y `p3` a
 * los 1024. Para casi todas las tablas eso no importa, porque el panel entero se
 * apaga en el mismo corte en que la tabla deja de esconder. Importa en el mayor
 * de un socio, donde `Saldo` es la única `p2` que vuelve a los 640 mientras el
 * panel sigue vivo hasta los 1440 por las otras dos: sin esta clase, entre 640 y
 * 1439 el panel repetiría un número que la fila ya tiene dos columnas más a la
 * derecha, que es exactamente lo que se le reprocha al «más» de Avisos.
 *
 * Se apaga con `display` y no sacándolo de la plantilla porque cuál se dibuja lo
 * decide el ancho, y el ancho no lo sabe el servidor. */
@media (min-width: 640px) {
  .datos-clave > div.solo-angosto { display: none; }
}
/* El rótulo es la etiqueta y el dato es el dato: la regla 6 otra vez, la misma
 * del `thead`. Sin versales —la jerarquía la dan el peso y el color— y el rótulo
 * arriba, que es lo que deja que el dato se lea en una barrida vertical. */
.datos-clave dt {
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
/* El `margin-inline-start: 40px` que el navegador le pone a un `<dd>` es de un
 * glosario, no de una ficha: acá correría cada dato media pantalla a la derecha. */
.datos-clave dt { min-width: 0; overflow-wrap: break-word; }
/* Un chip adentro de un par puede ser más ancho que su columna —un nombre del
 * padrón entero— y es `nowrap`, así que no corta y se derrama. Acá sí corta: un
 * chip de dos renglones se lee igual, y un nombre recortado con puntos
 * suspensivos no. */
.datos-clave dd .chip { white-space: normal; }
.datos-clave dd {
  margin: 0;
  min-width: 0;
  font-size: var(--t-dato);
  overflow-wrap: break-word;
}
/* **El importe de un par no se alinea a la derecha**, y es el gemelo que faltaba
 * del que la ficha del cheque ya tiene escrito (`.datos-cheque .num`). En una
 * columna de números la derecha es lo que los hace comparables por su largo; en
 * un par rótulo/dato lo único que hace es mandar el número contra el margen
 * derecho de su celda y dejarlo a media pantalla de su rótulo, que es como se
 * veían la tasa, la comisión y el costo de la ficha del cliente y los pares de
 * las dos pantallas de Nosis. La monoespaciada de `.num` se queda: un importe se
 * sigue leyendo por su largo. Pesa (0,2,1) contra el (0,1,0) de `.num`, así que
 * gana sin depender del orden. */
.datos-clave dd.num { text-align: left; }

/* Dos, tres y cuatro columnas. El número no sale de la estética sino del par más
 * largo que la lista tiene que poder mostrar entero —«Cliente» con una razón
 * social del padrón—: a 390 dos pares por renglón ya lo obligan a cortar en dos
 * líneas, y por eso no hay un cuarto escalón a 1440. Las pistas van en
 * `minmax(0, 1fr)` por §12.2: con `1fr` a secas el mínimo es automático y un
 * CUIT o un nombre largo ensancharían la fila en vez de cortarse. */
@media (min-width: 640px) {
  .datos-clave { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .datos-clave { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- Las tablas anchas: primera columna fija ---------------------------- */

/* Las que son todas números y no se podan. Se desplazan, y lo que queda quieto
 * es la columna que dice de qué fila se trata: sin eso, tres columnas a la
 * derecha uno ya no sabe qué está mirando, que es el defecto que tiene hoy el
 * mayor con cinco monedas.
 *
 * **Quiénes son, después de cerrar el inventario.** A las cinco del contrato §6
 * —el libro de caja, la grilla de Nosis, el mayor con varias monedas, el reparto
 * entre socios y la valuación de posiciones— se suman seis que el §6 sacó de las
 * podables **por su nombre** y dejó sin la otra mitad: las de cierres y
 * paridades de `/cotizaciones`, el historial de novedades de un CUIT y las tres
 * del detalle de un seguimiento. En tres de esas seis la última celda es el
 * formulario de archivar con su motivo obligatorio, y «lo que se edita no se
 * esconde» (§6, regla 3) las deja sin poda posible.
 *
 * Y una séptima que no es numérica y entra igual: **la tabla de preferencias de
 * `/notificaciones`**. Sus tres columnas son el aviso y sus dos casillas, o sea
 * que todas son el control con el que se viene a esa pantalla; podar una es
 * dejar la pantalla sin su función.
 *
 * **Y el inventario ya no son siete: son catorce, y la cuenta de arriba quedó
 * vieja el mismo día que se escribió.** La lista que sirve es la que devuelve
 * `grep -c "class=\"datos[^\"]*ancha" src/gdv/web/templates -r`; el párrafo de
 * arriba vale por el criterio —qué hace que una tabla sea ancha— y no por el
 * número. De la grilla de Nosis, además, hay que sacarla: no es `table.datos`
 * sino `<table class="grilla-nosis">`, con su propio armado.
 *
 * **Cinco de las catorce llevan además `papel`, y `ancha` sola no les
 * alcanzaba.** Las tres que terminan en el formulario de archivar y la de
 * preferencias tienen un control en la última celda, y desplazarse alcanza para
 * leer pero no para hacer: a 390 esa celda arranca a 600 o 900px del borde de un
 * marco de 366, sin ninguna señal de que ahí haya algo que hacer. Con `papel` la
 * fila se apila hasta 640 y el control queda al pie de la tarjeta; de 640 para
 * arriba mandan estas reglas y la columna quieta vuelve. Las otras tres —las de
 * cierres y paridades y la de los papeles de un firmante— son de lectura y se
 * quedan con `ancha` sola.
 *
 * **El límite conocido dejó de ser una nota y pasó a ser el tope de abajo.** Una
 * columna quieta más ancha que el marco no deja lugar para nada más, y en la
 * valuación de posiciones de `/resultados` eso ya había pasado: medido sobre
 * `resultados_390_claro.png`, la primera celda dice «Efectivo en dólares
 * CAJA.USD.EFECTIVO» en 292px de los 360 del marco, y la de «Cuenta corriente
 * DISTRIBUIDORA NORTE SA CC.DISTRIBUIDORA.NORTE.SA» se corta **contra el borde
 * del marco**, o sea que pasa de 360. Con la columna quieta ocupando el ancho
 * entero, desplazarse no descubre nada: las cuatro columnas de importes de esa
 * tabla no se alcanzaban de ninguna manera en un teléfono. Es la causa de «la
 * valuación no muestra un solo importe», que no era la poda —esa tabla no se
 * poda a propósito— sino esto.
 *
 * El fondo propio es obligatorio, no decorativo: una celda `sticky` sin fondo
 * deja pasar por debajo las celdas que se están desplazando. `--card` es el
 * fondo del marco, o sea el de una fila impar: es el piso sobre el que se
 * apoyan todas.
 *
 * El `inset` del borde derecho **no es una sombra**: es la línea que separa la
 * columna quieta de las que se mueven, y va como `box-shadow` porque un `border`
 * en una celda `sticky` se corre con el colapso de bordes de la tabla. */
table.datos.ancha th:first-child,
table.datos.ancha td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: hsl(var(--card));
  box-shadow: inset -1px 0 0 hsl(var(--border));
}

/* **Y el cebreado le tiene que llegar.** El fondo opaco de arriba tapaba la
 * franja de `tbody tr:nth-child(even)`, que se pinta en el `<tr>`: la fila par
 * quedaba partida en dos —blanca hasta la primera columna y gris de ahí en
 * adelante—, medido a píxel en `mayor_1536_claro` (fila 248,247,244 contra celda
 * 255,255,255) y en `socios_1536_oscuro` (26,30,35 contra 24,27,31). En el
 * reparto de `/resultados` se lee como **dos filas distintas**. El contrato
 * §12.10 pedía «con fondo» y no decía cuál; es éste: el de su fila.
 *
 * Va como `background-image` y no como `background` porque el color de la fila
 * par es translúcido —`--muted / 0.35` sobre el fondo del marco— y la celda
 * necesita las **dos** capas: abajo el `--card` opaco de la regla de arriba, que
 * es lo que impide que las celdas que se desplazan se vean por debajo, y encima
 * la misma franja que pinta el `<tr>`. Un degradado de un solo color es la forma
 * de escribir «una capa lisa» en `background-image`. Componer los dos colores en
 * uno solo no es una opción: `color-mix()` está prohibido en esta hoja.
 *
 * `:not(.papel)` **no es de más**, y es lo único de estas dos reglas que no se
 * ve en el selector: en el celular una tabla `.papel` no es una tabla —cada fila
 * es una tarjeta y la primera celda es su título, sin `sticky` y con
 * `background: none`—, así que ahí la franja del `<tr>` ya se ve entera y esta
 * capa la pintaría **dos veces**, dejando el título de las tarjetas pares más
 * oscuro que el resto de su tarjeta. Desde 640 vuelven a ser tablas con su
 * columna quieta y ahí sí la necesitan: la regla está en el bloque de 640, más
 * abajo, nombrando a `.papel`.
 *
 * Pesa (0,5,4) contra el (0,3,2) de la regla de arriba: gana por especificidad y
 * no por orden. */
table.datos.ancha:not(.papel) tbody tr:nth-child(even) > th:first-child,
table.datos.ancha:not(.papel) tbody tr:nth-child(even) > td:first-child {
  background-image: linear-gradient(
    hsl(var(--muted) / 0.35), hsl(var(--muted) / 0.35)
  );
}
/* Y lo mismo con la fila señalada por el mouse, que también se pinta en el
 * `<tr>` y también quedaba cortada en la columna quieta. Acá el color es opaco,
 * así que esta capa lo tapa entero y no se compone con nada. Las tablas `.papel`
 * entran también: en el celular no hay mouse que señale ninguna fila. */
table.datos.ancha tbody tr:hover > th:first-child,
table.datos.ancha tbody tr:hover > td:first-child {
  background-image: linear-gradient(hsl(var(--accent)), hsl(var(--accent)));
}

/* Desde 640 la tabla `.papel` vuelve a ser una tabla y su columna quieta vuelve
 * a pintar `--card` opaco (ver «el formulario en la fila», más abajo), así que
 * ahí sí le hace falta la franja. Pesa (0,5,4) y le gana a la regla que le
 * devuelve el fondo, que pesa (0,4,3). */
@media (min-width: 640px) {
  table.datos.ancha.papel tbody tr:nth-child(even) > th:first-child,
  table.datos.ancha.papel tbody tr:nth-child(even) > td:first-child {
    background-image: linear-gradient(
      hsl(var(--muted) / 0.35), hsl(var(--muted) / 0.35)
    );
  }
}

/* **El tope de la columna quieta, en el celular.** Veinticuatro caracteres, que
 * es el mismo número con el que `.descripcion` y `.notas` acotan una columna de
 * texto a este ancho: unos 205px de los 360 que mide el marco a 390, y por eso
 * ése y no otro. La cuenta es al revés de como se lee: lo que tiene que entrar
 * en lo que sobra es **una columna de importes**, y la más ancha de la
 * aplicación —`(121.000.000,00)` en Space Mono con el relleno de celda— mide
 * unos 156. Un tope más grande deja una tabla en la que desplazarse no alcanza a
 * ver un número entero nunca, que es de lo que se salió.
 *
 * Va con `white-space: normal` porque un tope sin permiso para envolver no
 * acota nada: la celda se saldría de su caja en vez de partirse. Pesa (0,4,3) y
 * le gana al `nowrap` de `table.datos td`, que pesa (0,1,2), y también al
 * `normal` de la primera columna de una podable (0,3,3), que dice lo mismo.
 *
 * **`tbody td` y no `th`.** En las anchas el encabezado y el rótulo del pie son
 * rótulos cortos —«Socio», «Cuenta», «Valuado»— y no deciden el ancho de nada.
 * La única donde la primera celda de cada fila **es** un `<th scope="row">` es
 * la de preferencias de `/notificaciones`, y esa tabla se resolvió por otro lado:
 * lleva `papel`, así que a 390 no es una tabla que se desplaza sino una tarjeta
 * por aviso, y el tope de acá —que empieza por `:not(.papel)`— no la alcanza ni
 * le hace falta. El día que un `th` de cualquiera de las otras decida el ancho,
 * el tope tiene que alcanzarlo también.
 *
 * Desde 640 se va entero: el marco ahí mide 600 o más y una tabla con la primera
 * celda partida en tres renglones se lee peor que una que se desplaza. */
table.datos.ancha:not(.papel) tbody td:first-child {
  max-width: 24ch;
  white-space: normal;
}
/* Las dos que se leen en un renglón o no se leen, y las dos son primera columna
 * de una tabla ancha: la fecha del mayor, de los cierres y de las paridades
 * —`02/01/2026` tiene corte después de cada barra y partida deja de ser una
 * fecha, que es lo que ya dice la regla gemela de las podables— y el `#op` del
 * libro de caja, que tiene su propia regla de `nowrap` diez secciones más abajo y
 * su badge ya baja de renglón solo. Ninguna de las dos llega al tope: 90 y 40px
 * contra 205. Pesan (0,4,3), lo mismo que la de arriba, y ganan por venir
 * después. */
table.datos.ancha tbody td.fecha:first-child,
table.datos.ancha tbody td.op:first-child { white-space: nowrap; }

/* **Y el dato de al lado del nombre baja a su propio renglón**, que es lo que
 * hace entrar a la primera columna sin llegar al tope. En `/socios` y en el
 * reparto de `/resultados` la celda dice «Alexis Gattelet agattelet» en un solo
 * renglón y mide 203px de los 360 del marco —medido sobre `socios_390_claro.png`,
 * con la línea de la columna quieta en x=216—: el nombre abajo del nombre la
 * deja en unos 132 y son 71px que se le devuelven a los importes, que es la mitad
 * de una columna de plata. Es la misma decisión que ya toman `.sentido-saldo`
 * debajo del saldo y el badge «En revisión» debajo del `#op` del libro, y por el
 * mismo motivo medido: en el celular lo que califica va debajo de lo que
 * califica, no al lado.
 *
 * El `overflow-wrap` es para el código de cuenta que la valuación de posiciones
 * pone acá —`CC.DISTRIBUIDORA.NORTE.SA`—: no tiene un solo espacio donde cortar,
 * así que sin `anywhere` el tope de arriba no lo alcanza y la columna quieta
 * vuelve a medir lo que mide el código. Es el mismo recurso, con la misma
 * explicación, que `.propuesta table.datos tbody td.codigo`.
 *
 * Pesa (0,4,3) contra el (0,1,0) de `.secundario`. */
table.datos.ancha tbody td:first-child .secundario {
  display: block;
  margin-left: 0;
  overflow-wrap: anywhere;
}

@media (min-width: 640px) {
  table.datos.ancha:not(.papel) tbody td:first-child {
    max-width: none;
    white-space: nowrap;
  }
  table.datos.ancha tbody td:first-child .secundario {
    display: inline;
    margin-left: 6px;
    overflow-wrap: normal;
  }
}

/* --- Los estados -------------------------------------------------------- */

/* La palabra ya dice cuál es el estado; lo que agrega el badge es poder barrer
 * una columna sin leerla. Por eso cada familia se distingue además del color por
 * su **forma**: relleno para lo cerrado, punteado para lo que espera a alguien,
 * trazo grueso para lo que salió mal y tachado para lo que no cuenta. Un balance
 * se tiene que poder leer en blanco y negro, y hay un test que lo verifica
 * estado por estado: que la señal de forma la ponga una regla **del estado** y
 * que sea la que gana. Por eso los grupos de abajo no se consolidan aunque dos
 * se parezcan: consolidar es cómo un estado termina distinguiéndose sólo por el
 * tono.
 *
 * Lo único que cambia del badge es el radio: era una píldora de 999px y ahora es
 * un rectángulo redondeado como cualquier otra etiqueta. Lo que lo distingue de
 * un botón no es la forma sino que no tiene borde de control ni cursor. */
.estado {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--radio-chico);
  border: 1px solid hsl(var(--border));
  background: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
  font-size: var(--t-rotulo);
  font-weight: 500;
  line-height: 1.35;
  white-space: nowrap;
}

/* Cerrado y a favor: relleno. `e-vendido` y `e-acreditado` son las dos formas en
 * que un papel termina bien —se colocó, o se le acreditó al cliente—; sin regla
 * propia caían al gris genérico y en la cartera no se distinguían de un cheque
 * que todavía no pasó nada. */
.estado.e-aprobada,
.estado.e-en_cartera,
.estado.e-vendido,
.estado.e-acreditado {
  border-color: hsl(var(--success-text) / 0.55);
  background: hsl(var(--success) / 0.3);
  color: hsl(var(--success-text));
  font-weight: 600;
}

/* Esperando a alguien. El punteado es la señal de «esto todavía no cerró», y se
 * ve igual sin color: es lo que distingue una fila que hay que atender hoy.
 *
 * §12 — una propuesta espera a alguien igual que una operación en revisión, así
 * que se ve igual. Lo que las distingue no es el color sino la pantalla en la
 * que aparecen, y ahí el texto lo dice: una propuesta todavía no está en ninguna
 * cuenta corriente. Y `e-depositado`, que es la misma espera del otro lado del
 * mostrador: el papel está en el banco y todavía no se sabe si acredita. */
.estado.e-en_revision,
.estado.e-propuesta,
.estado.e-recibido,
.estado.e-depositado {
  border-style: dashed;
  border-color: hsl(var(--warning) / 0.6);
  background: hsl(var(--warning) / 0.12);
  color: hsl(var(--warning-text));
  font-weight: 600;
}

/* Salió mal: trazo grueso. */
.estado.e-rechazado,
.estado.e-incobrable {
  border-width: 2px;
  border-color: hsl(var(--destructive-text) / 0.7);
  background: hsl(var(--destructive) / 0.25);
  color: hsl(var(--destructive-text));
  font-weight: 600;
}

/* Ya no cuenta: tachado, que se lee sin color y sin peso. `e-rechazada` es la
 * propuesta que alguien contestó que no —§12—, y no `e-rechazado`, que es el
 * cheque que rebotó: son dos cosas distintas y se ven distinto. */
.estado.e-anulado,
.estado.e-anulada,
.estado.e-rechazada {
  color: hsl(var(--muted-foreground));
  background: transparent;
  border-style: dotted;
  text-decoration: line-through;
}

/* El papel que volvió por donde vino. No es un final malo ni uno bueno —el
 * cheque se devolvió, o se repuso por otro—, así que se queda **sin relleno**,
 * que es lo que lo separa del badge de base: aquél sí lo tiene. Es una señal de
 * forma y no de tono, y por eso esta regla no se junta con ninguna otra aunque
 * el color sea el mismo gris que el de lo anulado. */
.estado.e-devuelto, .estado.e-repuesto {
  color: hsl(var(--muted-foreground));
  background: transparent;
}

/* --- Las marcas --------------------------------------------------------- */

/* Las marcas son la familia de al lado de los estados: no dicen en qué estado
 * está una fila sino qué le falta o qué le pasó. Todas comparten el mismo
 * tratamiento —cuerpo de rótulo, radio chico, sin versales— y se distinguen
 * entre sí por el trazo y el color, nunca por el tamaño de la letra.
 *
 * Las versales se fueron de las seis que las tenían: un «SIN COMPLETAR» al lado
 * de un nombre del padrón competía con el nombre, que está en mayúsculas porque
 * **es** un dato. Ahora se distingue lo que grita de lo que se guarda así.
 *
 * §9 — el cliente que entró para que una operación pudiera asentarse y que nadie
 * completó todavía. Punteada como `.marca-baja` —las dos son «esto no es una
 * fila normal» y las dos se tienen que leer sin color— y en ámbar y no en rojo,
 * porque no es un error: es trabajo pendiente. El mismo ámbar de `.aviso`. */
.marca-provisorio {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px dotted hsl(var(--warning-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.18);
  color: hsl(var(--warning-text));
  font-size: var(--t-rotulo);
  white-space: nowrap;
}

/* §4.4 — la tercera de la familia: a esta ficha le falta el CUIT, el teléfono o
 * la dirección. Ámbar y punteada como `.marca-provisorio` y `.marca-falta`,
 * porque las tres dicen lo mismo en el fondo —esto es trabajo pendiente, no un
 * error— y eso se tiene que leer sin color.
 *
 * **Clase propia y no una de las otras dos**, por el mismo motivo que está
 * escrito abajo en `.marca-falta`: aquélla dice «este cliente entró al vuelo y
 * nadie lo completó» y hay un test que verifica que su texto sea exactamente
 * ése. Dos significados bajo la misma clase es cómo una regla termina pintando
 * algo que no le toca. `.marca-provisorio` y ésta nunca salen juntas en una fila
 * —`Cliente.incompleto` excluye al provisorio—, así que compartir el aire no las
 * confunde.
 *
 * Lo único que la separa de verdad de las otras dos es el `white-space`: su
 * texto es una lista de largo variable —«falta CUIT, teléfono, dirección»— y con
 * `nowrap` ensancharía la fila del padrón sin techo. La lista de lo que falta es
 * el dato: recortarla dejaría la marca diciendo menos que la ficha. */
.marca-sin-datos {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px dotted hsl(var(--warning-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.18);
  color: hsl(var(--warning-text));
  font-size: var(--t-rotulo);
  white-space: normal;
}

/* §9 — las dos formas de resolver un provisorio, debajo de su nombre en el
 * padrón. Sólo se dibuja en las filas que lo son, así que en un padrón normal
 * esta regla no alcanza a nada. Vive acá, con la marca que la abre: es lo que se
 * hace con una fila marcada, y separarlas deja la marca diciendo un problema
 * cuya solución se dibuja en otra parte del archivo.
 *
 * El tope de ancho es el de una columna y no el de un texto: sin él, un panel
 * con un `<select>` de clientes adentro de la primera celda del padrón le da el
 * ancho a la columna y empuja al resto de la tabla. */
.resolver-provisorio {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 6px;
  max-width: 44ch;
  margin-top: 6px;
  padding: var(--paso) 10px;
  background: hsl(var(--warning) / 0.1);
  border: 1px solid hsl(var(--warning) / 0.45);
  border-radius: var(--radio-chico);
  white-space: normal;
}
.resolver-provisorio .por-que {
  flex: 1 1 100%;
  margin: 0;
  font-size: var(--t-dato);
  line-height: 1.4;
}
.resolver-provisorio form { display: flex; align-items: flex-end; gap: 6px; margin: 0; }
.resolver-provisorio button { min-height: var(--toque); padding: 0 12px; }
.fusionar-cliente { flex: 1 1 100%; flex-wrap: wrap; }
/* El rótulo del desplegable, sin versales como todo el resto: lo que lo separa
 * del dato es el cuerpo y el color, que es la regla 8 del encabezado. */
.fusionar-cliente label {
  flex: 1 1 100%;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
.fusionar-cliente select { flex: 1 1 16ch; min-width: 0; }

/* §4.9 — lo que le falta a un papel para poder venderse, en la cola de
 * pendientes y en la cartera.
 *
 * **Es una clase propia y no `marca-provisorio`**, aunque se vean igual:
 * aquélla dice una cosa concreta —«este cliente entró al vuelo y nadie lo
 * completó»— y hay un test que verifica que su texto sea exactamente ése. Dos
 * significados bajo la misma clase es cómo una regla termina pintando algo que
 * no le toca. */
.marca-falta {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px dotted hsl(var(--warning-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.18);
  color: hsl(var(--warning-text));
  font-size: var(--t-rotulo);
  white-space: nowrap;
}

/* Punteada además de roja, como los badges de estado: «baja» y «anulada» son lo
 * que ya no cuenta, y eso se tiene que leer en blanco y negro. */
.marca-baja {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px dotted hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.22);
  color: hsl(var(--destructive-text));
  font-size: var(--t-rotulo);
}

/* §9 y §13 — cómo terminó una conversación costosa, en la lista de
 * `/ejemplos`. Cancelada es lo mismo que «de baja» —nada que contar— y lleva
 * el mismo tratamiento; la que costó pero cerró en una operación es neutra, no
 * un error, así que usa el chip de siempre y no el rojo. */
.marca-cancelada {
  padding: 1px 6px;
  border: 1px dotted hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.22);
  color: hsl(var(--destructive-text));
  font-size: var(--t-rotulo);
}
.marca-costosa {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--radio-chico);
  background: hsl(var(--primary) / 0.2);
  color: hsl(var(--primary-text));
  font-size: var(--t-rotulo);
  white-space: nowrap;
}

/* La marca de «sin identificar» en la cartera: enlaza a la cola donde se
 * completa, porque un aviso que no dice adónde ir se lee y no se resuelve.
 * Rayada y no punteada —es la única de la familia que se toca—.
 *
 * **Y sin objetivo táctil propio**, que es una excepción y va dicha: 44px acá le
 * sumarían dieciséis píxeles a cada fila que tenga un papel sin identificar, y
 * en la cartera ésas son muchas. Va pegada al número del cheque, que sí es un
 * enlace de fila, y a la misma cola se llega desde «Pendientes» en la
 * navegación. Es la segunda excepción declarada de la regla 2 del encabezado,
 * junto con la cruz que saca un alias de un chip. */
.pendiente {
  display: inline-block;
  padding: 2px 8px;
  border: 1px dashed hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.2);
  color: hsl(var(--destructive-text));
  font-size: var(--t-rotulo);
  white-space: nowrap;
  text-decoration: none;
}
.pendiente:hover { text-decoration: underline; }
/* En el celular la marca va **debajo** del número del cheque, no al lado: la
 * celda es `p1` y con la marca en el mismo renglón mide número más marca —unos
 * 150px de los 366— y el nominal, que es la otra columna que la cartera vino a
 * mostrar, quedaba cortado contra el borde (`380.(`). Debajo, la celda mide lo
 * que mide la marca sola. El `width: max-content` es lo que impide que la caja
 * rayada se estire a lo ancho de la columna al pasar a bloque. Desde 640 vuelve
 * al renglón, que es donde estaba bien. */
table.datos td .pendiente { display: block; width: max-content; margin-top: 2px; }
@media (min-width: 640px) {
  table.datos td .pendiente { display: inline-block; width: auto; margin-top: 0; }
}

/* `.rol` —«admin», «lector», al lado del nombre al pie del panel— es de esta
 * familia y lleva este mismo tratamiento, pero su regla vive con el panel, que
 * es donde se dibuja. Está dicho acá para que no se la busque dos veces: una
 * marca escrita en dos lugares es una marca que mañana cambia en uno solo. */

/* El chip: un alias, un banco, una tasa. Un dato que pertenece a otro dato y que
 * viene de a varios, así que se dibuja en el tinte primario para que el grupo se
 * lea de un vistazo. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 8px;
  border-radius: var(--radio-chico);
  background: hsl(var(--primary) / 0.2);
  color: hsl(var(--primary-text));
  font-size: var(--t-rotulo);
  white-space: nowrap;
}
/* Adentro de un chip, el calificador **no** va en `--muted-foreground`, que es
 * el gris calibrado contra el fondo de la página: sobre el tinte azul del chip
 * cae a 4,41:1 en el tema claro. Va en el mismo azul del chip y se distingue por
 * el tamaño, que es lo que la regla 5 pide igual —lo que distingue tiene que
 * leerse sin color— y que además contrasta. Lo destapó la muestra de
 * `test_pantallas_diseno` el día que entró a ella un firmante con un banco. */
.chip .secundario {
  margin-left: 0;
  color: hsl(var(--primary-text));
  font-size: var(--t-rotulo);
}

/* §4.5 — el chip de un alias que quedó con varios pegados adentro: «TAMANTINI,
 * DEGRANDE, DE GRANDE» es **uno** y ninguna de sus partes se puede buscar. Se
 * tiñe de la advertencia —no del azul del chip normal— porque lo que dice no es
 * «acá hay un alias» sino «esto hay que revisarlo», y al lado de la cruz de
 * quitar aparece un «partir» que lo ofrece. El color no está solo: el botón de
 * más lo dice con una palabra. */
.chip.pegado {
  background: hsl(var(--warning) / 0.18);
  color: hsl(var(--warning-text));
}

/* --- Acciones de fila --------------------------------------------------- */

/* Los 44px también acá, y cuestan menos de lo que parece: la fila con acciones
 * medía 42px —un control de 34 más los 4+4 de la celda—, así que subir el
 * control al objetivo táctil y bajar el relleno de esa celda a 1 la deja en 46.
 * Cuatro píxeles por fila es un precio que se paga; el que no se paga es el de
 * un botón de «eliminar» de 34px al que hay que apuntar. Las filas **sin**
 * acciones siguen en 28.
 *
 * Todo lo que dimensiona va calificado con `td.`, y no es un detalle: la clase
 * se usaba también **fuera** de una fila —el «Guardar el conteo» del arqueo
 * colgaba de un `<div class="fila-acciones">` debajo de la tabla— y sin la
 * calificación esta regla le ganaba a `.principal` y lo dejaba a la altura de un
 * «editar». Aquel botón ya no está acá: es la acción de la pantalla y pasó al
 * `.campo.acciones` que usan los demás formularios, porque la alineación a la
 * derecha —lo único que esta clase comparte fuera de la celda— lo mandaba a
 * 1.100px del último campo. La calificación se queda igual: es lo que hace que
 * el día que alguien vuelva a poner esta clase fuera de una fila no se lleve
 * puesto el tamaño de su botón.
 *
 * Y la columna de acciones es `p1` **siempre**, por la regla del contrato §6: un
 * «Aprobar» que no se alcanza en el celular es la falla más grave del listado. */
.fila-acciones { text-align: right; white-space: nowrap; }
/* **La misma regla, calificada, y existe sólo para ganarle a otra.** La celda de
 * acciones es además la última `p1` de la fila, así que lleva `fila-mas`
 * (§12.13), y `table.datos td.fila-mas { white-space: normal }` —hoy adentro de
 * la `@media` de 640— pesa (0,1,2) contra los (0,1,0) de la línea de arriba: el
 * `nowrap` no llegaba **justo** a la única celda que tiene más de un control, y
 * los cinco botones de `/padron` —y el `Editar`/`Aprobar` del libro— se apilaban
 * uno por renglón, cada uno cortado contra el borde. Ésta pesa lo mismo que
 * aquélla (0,1,2) y está después en el archivo, que es lo que las ordena, así
 * que gana en los dos anchos. El `<details>` de adentro vuelve a envolver por
 * `table.datos details.mas`, que pesa (0,2,2) y le gana a ésta. */
table.datos td.fila-acciones { white-space: nowrap; }
/* Y el panel se lee a la izquierda aunque la celda esté alineada a la derecha:
 * son pares rótulo/dato en una grilla, y una `dl` con los rótulos contra el
 * margen derecho se lee como una columna de números. */
table.datos td.fila-acciones details.mas { text-align: left; }
/* **Calificado con `table.datos`, y ésa es la corrección de una regla que nunca
 * anduvo.** Estaba escrita `td.fila-acciones`, que pesa (0,1,1), contra
 * `table.datos th, table.datos td { padding: … }`, que pesa (0,1,2): el relleno
 * vertical de esta celda nunca bajó a uno y la cuenta del comentario de arriba
 * —«la deja en 46»— no pasaba. Medido con el navegador sobre la fila del padrón:
 * el `padding-top` calculado daba 4px y la fila con acciones medía 97; con la
 * regla calificada da 1px y mide 91. Es la misma trampa de especificidad que ya
 * está anotada dos veces en `table.datos td.alias`, en otra propiedad.
 *
 * **Y el relleno de la derecha baja a cuatro, por el mismo motivo que el
 * vertical**: el último control ya trae sus ocho píxeles adentro, así que los
 * diez de la celda son aire duplicado contra el borde de la tabla, que es donde
 * más caro sale —esta columna es siempre la última—. Son seis de los 55 que le
 * faltaban a `clientes` a 1536 para entrar entero en su marco. El de la
 * izquierda se queda: ése es el aire que separa esta columna de la anterior. */
table.datos td.fila-acciones {
  padding-top: 1px;
  padding-bottom: 1px;
  padding-right: 4px;
}
.fila-acciones form { display: inline-flex; }
/* **Ocho píxeles de aire por lado en todos los anchos, y los doce de la tablet
 * se fueron después de medirlos.** Estaban puestos «desde 640, donde el ancho
 * sobra», y el ancho no sobra justo donde esta celda es más larga. Con el
 * `nowrap` que la causa 1 le devolvió, la celda pide todo su ancho de una sola
 * pieza: a 1536 los cinco controles de `clientes` medían 390px y la tabla se iba
 * 55px fuera de su marco con `eliminar` cortado contra el borde (`elim⎢`), y en
 * `firmantes` la columna entera arrancaba más allá del marco y no se veía
 * **ninguna** acción. Medido con el navegador sobre las dos tablas reales: los
 * cuatro píxeles por lado son cuarenta en los cinco controles de `clientes` y
 * veinticuatro en los tres de `firmantes` —el «más» no cuenta: está apagado
 * desde 640—, y los dos de `margin-left` diez y seis más. La celda de `clientes`
 * pasó de 390 a 340px y la de `firmantes` de 241 a 211.
 *
 * **El objetivo táctil no se toca**: son los 44px de `min-height`, que siguen
 * acá y son los que mide un dedo. Lo que se achica es el aire, que es lo único
 * de esta celda que no informa.
 *
 * **Lo que no vale, y ya se probó una vez**: dejar que los controles se apilen.
 * Eso es exactamente lo que arreglaba la causa 1 —cinco botones en escalera, uno
 * por renglón, cada uno cortado contra el borde— y volver a eso para ganar ancho
 * cambia un defecto por el que ya se pagó. */
td.fila-acciones button, td.fila-acciones a {
  display: inline-flex;
  align-items: center;
  min-height: var(--toque);
  padding: 0 8px;
  margin-left: 2px;
  font-size: var(--t-dato);
  border-radius: var(--radio-chico);
}
td.fila-acciones a {
  border: 1px solid transparent;
  color: hsl(var(--primary-text));
}
td.fila-acciones a:hover {
  border-color: hsl(var(--border));
  background: hsl(var(--accent));
  text-decoration: none;
}
/* Aprobar es la acción que congela un asiento: aun en una fila lleva el color
 * primario, porque es la que hay que encontrar y la que no se deshace sola. Lo
 * que no se lleva es el alto extra de la principal, que ahí sí rompería la
 * densidad de la tabla. `td.` y no `.fila-acciones` a secas por lo mismo de
 * arriba: el «Guardar el conteo» del arqueo no está en una celda y le
 * corresponden los 48px enteros. */
td.fila-acciones button.principal {
  min-height: var(--toque);
  padding: 0 14px;
  font-size: var(--t-dato);
}

/* El plegado de una tabla de movimientos —`details.movimientos`, la propuesta
 * del asistente y cada ejemplo del corpus— es la otra acción que vive adentro de
 * una fila, y se dibuja con el `summary` de «La fila que se expande»: es el
 * mismo control y no dos parecidos. */
/* --- Formularios y controles --------------------------------------------- */

/* **El ancho de un campo es el ancho de su dato.** Es la corrección más visible
 * de todo el rediseño y la que más veces está anotada en el diagnóstico: hoy el
 * cotizador dibuja un campo de importe de 1200px con la fecha en el renglón de
 * abajo (`cotizador_1536`), el arqueo pone «Guardar el conteo» a 1200px del
 * último campo y las tasas dejan dos campos de 170px con el botón «Fijar» a
 * 900px de distancia. La causa es siempre la misma línea escrita catorce veces:
 * `flex: 1 1 140px`, que reparte el sobrante entre todos los campos por igual.
 * Un importe, una fecha y un CUIT no miden lo mismo y no hay ancho de pantalla
 * que los haga medir lo mismo.
 *
 * Entonces acá no hay ni un `flex-basis` en píxeles. El campo **no se estira**:
 * mide lo que mide su control, el control mide su dato en `ch` —diecisiete
 * caracteres un importe, quince un CUIT, seis una tasa— y lo único que crece
 * con lo que sobra es el texto libre, que lleva `.ancho`: un nombre, una
 * dirección, unas notas, un motivo, una razón social.
 *
 * Y es una sola tabla de anchos, escrita por **lo que el campo recibe** y no por
 * el formulario en el que está: un importe mide diecisiete caracteres en el
 * arqueo, en el cotizador, en la carga de cheques y en el alta de un cliente.
 * Las once reglas por contenedor que hoy dicen lo mismo, peor, desaparecen.
 *
 * FORMULARIO es un componente y no una familia (contrato §12.4): el
 * `<details class="alta"> > <form class="formulario-alta">` aparece ocho veces
 * en siete pantallas de tres familias distintas. Nada de lo que sigue cuelga de
 * `main.familia-formulario`; todo funciona en cualquier pantalla. */

/* --- El campo: rótulo arriba, control, ayuda abajo ----------------------- */

/* La etiqueta va **arriba** del campo y no adentro: un placeholder que hace de
 * etiqueta desaparece al escribir, justo cuando hay que verificar que lo que se
 * tipeó fue a donde se creía.
 *
 * `flex: 1 1 100%` es **un campo por línea en el celular**, que es la regla
 * base: a 390px, dos campos en una fila son dos campos de 150px donde no se lee
 * de qué son. Desde 640 el campo pasa a medir su dato y los campos envuelven
 * solos —está abajo, en «El ancho de cada campo»—. */
.campo {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 100%;
  /* La otra mitad del §12.2: un ítem de una fila flexible sin esto le pone al
   * renglón el mínimo de su contenido y estira el formulario entero. */
  min-width: 0;
}

/* El rótulo de un campo. **Sin versales** —regla 8 del encabezado—: lo que lo
 * separa del dato son el cuerpo y el color, que es lo mismo que hace el
 * encabezado de una tabla. Alcanza a las etiquetas de veinticinco plantillas, y
 * todas miden menos de veintiséis caracteres y ya están en Sentence case: no
 * hay ninguna que dependa de las mayúsculas para leerse.
 *
 * `.rotulo-campo` es el mismo rótulo donde no hay un `<label>` que ponerle —el
 * tipo de papel en la cola de pendientes, la razón social de la unificación—, y
 * va en la misma regla porque **es la misma cosa**: escribirla dos veces es
 * cómo mañana cambia una sola. */
.campo label, .rotulo-campo {
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}

/* La ayuda de un campo: debajo del control, en el cuerpo de un rótulo. No es
 * texto de corrido y no lleva tope de línea: mide lo que mide su campo. */
.campo .pista { font-size: var(--t-rotulo); color: hsl(var(--muted-foreground)); }

/* --- Los controles ------------------------------------------------------- */

/* `font: inherit` y no una familia propia: un `<select>` con la letra del
 * sistema al lado de un `<input>` con la del documento es lo que hace que un
 * formulario se vea armado con piezas de dos lugares. */
input, select, button, textarea { font: inherit; color: inherit; }

/* La caja común de todo lo que se escribe. `--t-cuerpo` (16px) y no `--t-dato`:
 * por debajo de 16 iOS hace zoom al enfocar, y el zoom en la pantalla de carga
 * deja media conversación fuera de cuadro. Es la razón por la que la escala
 * tiene un paso de 16 aparte del de 15.
 *
 * `inline-size: 100%` es la mitad de «un campo por línea en el celular»: el
 * control llena el renglón que le dio `.campo`. Desde 640 lo pisa la tabla de
 * anchos por dato. */
input[type="text"], input[type="search"], input[type="password"],
input[type="date"], input[type="number"], select, textarea {
  min-height: var(--toque);
  inline-size: 100%;
  padding: 0 10px;
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--input));
  border-radius: var(--radio-chico);
  font-size: var(--t-cuerpo);
  min-width: 0;
}
textarea { padding: 8px 10px; line-height: 1.45; resize: vertical; }
input::placeholder, textarea::placeholder { color: hsl(var(--muted-foreground) / 0.75); }

/* Los campos que reciben un número —importes, nominales, tipos de cambio,
 * tasas, comisiones, cantidades— van en Space Mono, y los que son cifra además
 * a la derecha: con ancho de dígito fijo la longitud del número **es** su
 * magnitud, y dos importes tipeados uno debajo del otro se comparan sin leerlos.
 * El CUIT y el número de cheque también son monoespaciados y **no** van a la
 * derecha: son identificadores que se cotejan carácter por carácter contra un
 * papel, no cantidades que se suman. */
input[data-importe],
input[name="importe"],
input[name="nominal"],
input[name="tipo_cambio"],
input[name="notacion"],
input[name="costo_transferencia"],
input[name="tasa"],
input[name="tasa_propia"],
input[name="tasa_default"],
input[name="comision_default"],
input[name="cantidad"] {
  text-align: right;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
input[type="date"],
input[name="cuit"],
input[name="cuit_firmante"],
input[name="numero"] {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* `input[type=file]` no entra en la caja de arriba: el navegador lo dibuja con
 * su propio botón adentro y forzarle el alto deja ese botón flotando en el
 * medio. Lo que sí hace falta es que llegue al objetivo táctil y que no se vea
 * como una isla clara sobre el fondo oscuro. */
input[type="file"] {
  min-height: var(--toque);
  padding: 8px;
  font-size: var(--t-dato);
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--input));
  border-radius: var(--radio-chico);
  /* El único control cuyo ancho lo escribe el usuario y no la hoja: adentro va
   * el nombre del archivo elegido, que no tiene largo máximo. Al quedar afuera
   * del `inline-size: 100%` de la caja de arriba, sin este tope un adjunto con
   * nombre largo empuja la fila y devuelve el desborde a 390. */
  max-inline-size: 100%;
}

/* Las casillas y los radios son el gesto central de unificar y de aprobar
 * intereses, y quedaban en los ~13px que dibuja el navegador. No entran en la
 * regla de arriba —un `min-height` sobre una casilla la estira sin agrandar el
 * cuadradito— así que se dimensionan explícitamente. `accent-color` es lo que
 * las pinta con el primario sin reemplazarlas por un control dibujado a mano,
 * que necesitaría JavaScript.
 *
 * El `:not` es por las casillas clipeadas que abren los cinco interruptores sin
 * JavaScript: sin él esta regla —que pesa más que `.solo-lectores`— las devolvía
 * a la pantalla como un cuadradito suelto al lado del botón. */
input[type="checkbox"]:not(.solo-lectores),
input[type="radio"]:not(.solo-lectores) {
  width: 18px;
  height: 18px;
  accent-color: hsl(var(--primary-text));
  cursor: pointer;
}

/* Clipeado, no sacado del tabulador: es la casilla que abre cada panel sin
 * JavaScript y el rótulo que sólo lee el lector de pantalla. Se queda en el
 * recorrido del teclado —de ahí el `:focus-visible` de más abajo, que dibuja el
 * foco sobre el `<label>` que la representa— y mide 1×1 para no ocupar lugar.
 * `position: absolute` **contra el ancestro posicionado que le toque**: es la
 * causa 7 del diagnóstico, y se arregla en los marcos, no acá. */
.solo-lectores {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}

/* El foco, en todo lo que se toca con el teclado, y siempre visible: sin esto,
 * quien tabula por un formulario de doce campos no sabe en cuál está.
 * `:focus-visible` y no `:focus` para que el anillo no aparezca al hacer clic
 * con el mouse, que es cuando estorba y no informa. */
input:focus-visible, select:focus-visible, button:focus-visible, a:focus-visible,
textarea:focus-visible, summary:focus-visible, label:focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 1px;
}
input:focus, select:focus, textarea:focus { border-color: hsl(var(--ring)); }

/* --- El ancho de cada campo, desde 640 ----------------------------------- */

/* Desde 640 el campo deja de ocupar el renglón y **mide lo que mide su dato**.
 * Los campos envuelven solos: no hay número de columnas escrito en ningún lado,
 * porque el que decide cuántos entran es el ancho de los datos y no una grilla.
 *
 * Los anchos van en `ch` y no en píxeles porque lo que se acota son caracteres:
 * el día que el cuerpo de un campo cambie, el campo del CUIT sigue midiendo
 * quince caracteres. Las medidas salen del dato, una por una:
 *
 *   17ch  un importe con separadores de miles y dos decimales
 *   16ch  una fecha: diez caracteres de dato más el calendario que el navegador
 *         dibuja **adentro** de la caja (con doce justos se come el año)
 *   15ch  un CUIT con sus dos guiones
 *   12ch  un número de cheque
 *   10ch  los términos del cotizador: `5+2.5`, `96+2.5`
 *    6ch  una tasa, una comisión, un costo de transferencia, una cantidad de
 *         papeles — todos son dos dígitos y una coma
 *   26ch  lo que se tipea en un buscador: un pedazo de un nombre o de un alias
 *
 * Todas estas reglas pesan lo mismo —(0,1,1)—, así que lo que las ordena es el
 * lugar en el archivo: primero la que devuelve el ancho a `auto`, y después la
 * tabla, campo por campo. */
@media (min-width: 640px) {
  .campo { flex: 0 1 auto; }

  /* **El `textarea` no está en esta lista, y es a propósito.** Un `textarea` es
   * texto libre: no tiene ancho de dato que devolverle, y `inline-size: auto`
   * sobre uno no lo achica a su contenido sino que lo manda al `cols` del HTML
   * —veinte caracteres por omisión, y los tres `textarea` de la aplicación
   * escriben `rows` y ninguno escribe `cols`—. O sea que devolverle el `auto`
   * desde 640 dejaba el cuadro de «¿Qué falta?» más angosto en la notebook que
   * en el celular. Se queda con el `inline-size: 100%` de la caja de arriba, en
   * todos los anchos, y lo que decide su ancho real es el campo que lo contiene. */
  input[type="text"], input[type="search"], input[type="password"],
  input[type="date"], input[type="number"], select { inline-size: auto; }

  /* Un desplegable de clientes tiene opciones de sesenta caracteres y sin tope
   * le da ese ancho a la fila entera. El tope es del control; la opción larga se
   * sigue leyendo entera al desplegarlo, que es cuando importa. */
  select { max-inline-size: 26ch; }

  input[data-importe],
  input[name="importe"],
  input[name="nominal"],
  input[name="tipo_cambio"] { inline-size: 17ch; }
  input[type="date"] { inline-size: 16ch; }
  input[name="cuit"], input[name="cuit_firmante"] { inline-size: 15ch; }
  input[name="numero"] { inline-size: 12ch; }
  input[name="notacion"] { inline-size: 10ch; }
  input[name="tasa"],
  input[name="tasa_propia"],
  input[name="tasa_default"],
  input[name="comision_default"],
  input[name="costo_transferencia"],
  input[name="cantidad"] { inline-size: 6ch; }
  input[type="search"] { inline-size: 26ch; }

  /* Lo único que se estira. Un nombre, una dirección, unas notas, un motivo o
   * una razón social no tienen largo previsible, así que se llevan lo que sobre
   * de la fila. Los 24ch son de dónde arranca, no lo que mide. */
  .campo.ancho { flex: 1 1 24ch; }
}

/* El control de un campo ancho llena su campo, en cualquier pantalla: es lo que
 * hace que «estirarse» quiera decir algo. Va afuera de la `@media` porque no
 * cambia con el ancho, y pesa (0,2,1), que es lo que le deja ganarle a la tabla
 * de anchos por dato de arriba.
 *
 * Los dos `:not` no son cautela: son la razón social de la unificación. Ahí el
 * `<div class="campo ancho opciones-razon">` tiene adentro **radios**, y
 * `input[type="radio"]:not(.solo-lectores)` —el cuadradito de 18px— pesa
 * exactamente lo mismo, (0,2,1), así que a igualdad ganaba el que viene después
 * en el archivo, que es éste: el punto de elegir la razón social salía dibujado
 * a todo el ancho del panel. Sacarlos del selector cuesta dos negaciones y
 * evita que el ancho de un campo de texto le llegue a una casilla. */
.campo.ancho input:not([type="checkbox"]):not([type="radio"]),
.campo.ancho select, .campo.ancho textarea {
  inline-size: 100%;
  max-inline-size: none;
}

/* --- Los botones --------------------------------------------------------- */

/* Un botón se toca, así que se dimensiona para el dedo y no para el texto.
 *
 * Las cuatro variantes de GDV_DESIGN §8, como clases reutilizables:
 *
 * - **primario** es `button.principal`: relleno azul GDV, la acción que escribe.
 * - **secundario** es el `button` a secas: fondo neutro con borde visible.
 * - **outline** es `button.secundario`: transparente, para lo de baja prioridad.
 * - **destructivo** es `button.peligro` (y `button.enlace`, que es el mismo con
 *   el fondo transparente): el rojo aparece al apuntarle, y lo irreversible
 *   confirma antes.
 *
 * Los nombres de clase son los que el HTML ya usa; renombrarlos sería tocar
 * cuarenta plantillas para que el CSS se lea más parecido al documento. */
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--toque);
  padding: 0 16px;
  background: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  cursor: pointer;
  white-space: nowrap;
  font-size: var(--t-dato);
}
button:hover {
  border-color: hsl(var(--primary-text) / 0.7);
  color: hsl(var(--primary-text));
}
/* `progress` y no `not-allowed`: acá un botón se deshabilita mientras el pedido
 * está en vuelo —lo hace htmx con `hx-disabled-elt`—, así que el cursor dice
 * «esperá», que es lo que está pasando, y no «no se puede», que sería mentira. */
button[disabled] { opacity: 0.5; cursor: progress; }

/* La acción principal —Confirmar, Guardar, Aprobar, Calcular— es más grande y va
 * en el color primario: es la que se busca con la vista y la única que escribe
 * algo que no se deshace solo. Ocho píxeles más de alto, más relleno horizontal
 * y el relleno de color: las tres cosas juntas, porque una sola se pierde. */
button.principal {
  min-height: var(--toque-grande);
  padding: 0 24px;
  background: hsl(var(--primary));
  border-color: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
  font-size: var(--t-cuerpo);
  font-weight: 600;
}
button.principal:hover {
  background: hsl(var(--primary-hover));
  border-color: hsl(var(--primary-hover));
  color: hsl(var(--primary-foreground));
}

/* Las secundarias se ven, pero no compiten: mismo alto, sin relleno de color. */
button.secundario {
  background: transparent;
  color: hsl(var(--muted-foreground));
}
button.secundario:hover { color: hsl(var(--primary-text)); }

/* Destructivo: el rojo aparece al apuntarle y no antes. Un botón rojo fijo en
 * una fila de acciones se vuelve parte del paisaje y deja de avisar nada.
 *
 * `.enlace` es esta misma variante con el fondo transparente, y va acá y no en
 * la pantalla: lo que **no** hace es medir menos ni dibujarse como un enlace.
 * Es una salida, y las salidas de esa pantalla se ven todas como salidas.
 *
 * Son dos botones y no uno, y el segundo no es una salida: «Descartar y empezar
 * de cero» del diálogo, y el «+ Otro cheque» de la fila de acciones del
 * formulario de carga, que agrega y no borra nada. Que ese herede el rojo al
 * apuntarle es lo que la hoja de hoy ya hace, y **se conserva tal cual**: el
 * encargo es escribir las cuatro variantes como están, y arreglarlo pide
 * cambiarle la clase en la plantilla —a `.secundario`—, que es una decisión de
 * quien las escriba y no de esta parte. Queda anotado acá para que se vea. */
button.peligro, button.enlace { color: hsl(var(--muted-foreground)); }
button.enlace { background: transparent; text-decoration: none; }
button.peligro:hover, button.enlace:hover {
  border-color: hsl(var(--destructive-text));
  color: hsl(var(--destructive-text));
  background: hsl(var(--destructive) / 0.18);
}

/* Salir no es una acción del trabajo, pero se toca igual: mantiene los 44px
 * —que en la barra no cuestan nada, porque el resto de los controles ya los
 * mide— y baja el peso con el color y el cuerpo. */
.salir {
  min-height: var(--toque);
  padding: 0 12px;
  background: transparent;
  border-color: transparent;
  color: hsl(var(--muted-foreground));
  font-size: var(--t-dato);
}
.salir:hover {
  border-color: hsl(var(--destructive-text));
  color: hsl(var(--destructive-text));
  background: hsl(var(--destructive) / 0.18);
}

/* El botón que cierra el choque de un alta: «Usar ese». Está en el HTML desde
 * siempre y no tenía **ninguna** regla (contrato §12.13); hoy no falla sólo
 * porque su parcial no entra en la muestra del test. Va del mismo alto y del
 * mismo cuerpo que `.es-otra-persona`, que es la otra mitad de la decisión: las
 * dos salidas del choque pesan lo mismo porque elegir mal cuesta un cliente
 * duplicado en el padrón, y eso no lo arregla ningún botón más grande. */
.usar-existente {
  min-height: var(--toque-grande);
  padding: 0 20px;
  font-size: var(--t-cuerpo);
}

/* --- Los cinco `<label>` que hacen de botón ------------------------------ */

/* Los cinco interruptores sin JavaScript —dejar pendiente, el alta de un
 * cliente, asociarlo a uno existente, cargar los cheques ahora y «es otra
 * persona»— son un `<label>` de una casilla clipeada. Un `<label>` no hereda
 * **nada** de `button`, así que la forma va escrita entera; lo que sí se puede
 * es escribirla **una vez** y no cinco, que es lo que estaba pasando: cinco
 * copias del mismo bloque de trece declaraciones, repartidas por el archivo.
 *
 * `.boton` viaja con ellos y es la sexta cara de lo mismo: un `<a>` que lleva a
 * otra pantalla y que está en una fila de acciones —«Cotizarlos», al lado de
 * «Cargar sólo el total»—. Un enlace tampoco hereda nada de `button`, y un
 * enlace dibujado como texto en una fila de botones se lee como una nota al
 * pie. Sigue siendo un `<a>`: no escribe nada, lleva a otro lado.
 *
 * `user-select: none` porque son `<label>`: sin eso, dos toques seguidos —el que
 * abre y el que cierra— dejan la palabra seleccionada en azul. */
.abrir-pendiente,
.abrir-cliente-nuevo,
.abrir-cliente-asociar,
.abrir-cheques,
.abrir-banco-nuevo,
.es-otra-persona,
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--toque);
  padding: 0 16px;
  background: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  cursor: pointer;
  white-space: nowrap;
  font-size: var(--t-dato);
  user-select: none;
}
/* Cuatro de los cinco están en una fila de salidas al lado de un `button` de
 * 48px, y una salida más chica que su hermana dice que es la opción de segunda:
 * van al alto y al cuerpo de la acción principal. El quinto —«Dejar pendiente»—
 * recibe esa medida de la fila del diálogo, que es donde vive. */
.abrir-cliente-nuevo,
.abrir-cliente-asociar,
.abrir-cheques,
.es-otra-persona,
.boton {
  min-height: var(--toque-grande);
  padding: 0 20px;
  font-size: var(--t-cuerpo);
}
.abrir-pendiente:hover,
.abrir-cliente-nuevo:hover,
.abrir-cliente-asociar:hover,
.abrir-cheques:hover,
.es-otra-persona:hover,
.boton:hover {
  border-color: hsl(var(--primary-text) / 0.7);
  color: hsl(var(--primary-text));
}
/* Abierto se nota en el botón y no sólo en lo que apareció abajo: es lo que dice
 * que ese panel salió de acá y que volver a tocarlo lo cierra. */
.interruptor-pendiente:checked + .abrir-pendiente,
.interruptor-alta:checked + .abrir-cliente-nuevo,
.interruptor-asociar:checked + .abrir-cliente-asociar,
.interruptor-cheques:checked + .abrir-cheques,
.interruptor-banco:checked + .abrir-banco-nuevo {
  border-color: hsl(var(--primary-text));
  color: hsl(var(--primary-text));
  background: hsl(var(--primary) / 0.2);
}
/* La casilla está clipeada pero no sacada del tabulador: el foco se dibuja sobre
 * el `<label>`, que es lo único que hay para mirar. */
.interruptor-pendiente:focus-visible + .abrir-pendiente,
.interruptor-alta:focus-visible + .abrir-cliente-nuevo,
.interruptor-asociar:focus-visible + .abrir-cliente-asociar,
.interruptor-cheques:focus-visible + .abrir-cheques,
.interruptor-banco:focus-visible + .abrir-banco-nuevo {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 1px;
}

/* --- La fila de campos --------------------------------------------------- */

/* **Una** forma para todos los formularios de la aplicación: una fila que
 * envuelve, con los campos alineados por arriba y separados por el paso.
 *
 * `align-items: flex-start` y no `end`, que es lo que había: con los campos
 * pegados abajo, un campo con ayuda debajo del control **sube** su control y
 * deja las etiquetas a alturas distintas —se ve en `clientes_1536`, con el alta
 * desplegada—. Alineados por arriba, los rótulos quedan todos en el mismo
 * renglón y los controles caen alineados, porque el campo nunca es más angosto
 * que su rótulo. */
form.filtros, .filtros > form, .buscador,
.formulario-alta, .formulario-fila, .campos-del-asiento {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--paso) 10px;
}
.formulario-alta, .formulario-fila { margin-top: var(--paso); }
/* Adentro del `<details>` de los filtros el formulario ya está dentro de la
 * caja, y el margen de arriba lo separaría del `<summary>` que lo abrió. Vale
 * igual para el `<nav>` de chips de `/novedades`, que es el mismo panel con otro
 * contenido adentro. */
.filtros > form,
.filtros > nav { margin: 0; }

/* El casillero de un formulario que en vez de un control lleva botones. En el
 * celular ocupa el renglón entero y sus botones se estiran: la acción de un
 * formulario largo se toca con el pulgar sin apuntar. Desde 640 vuelve a medir
 * lo que miden sus botones y se apoya abajo, alineado con los controles —de ahí
 * el `align-self`, que es lo que el `flex-start` de la fila le sacó—. */
.campo.acciones {
  flex-direction: row;
  align-items: center;
  gap: 10px;
}
.campo.acciones button, .campo.acciones a { flex: 1 1 auto; }

@media (min-width: 640px) {
  .campo.acciones { flex: 0 0 auto; align-self: flex-end; }
  .campo.acciones button, .campo.acciones a { flex: 0 0 auto; }
}

/* El alta plegada: ocho pantallas la usan y es donde vive casi toda la carga de
 * datos del sistema. La caja es un panel —borde, fondo de superficie y el radio
 * grande— y el `<summary>` es un objetivo táctil entero: lo que se toca para
 * abrirla es la línea, no la palabra. */
.alta {
  padding: 10px 12px;
  margin-bottom: var(--paso);
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
/* **Y dice que se abre.** En `display: flex` el triángulo no se dibuja —el
 * marcador sólo existe con `display: list-item`—, así que con el color del texto
 * corriente y `font-weight: 600` lo que quedaba era un encabezado. El
 * relevamiento lo reportó como «un encabezado "Nuevo cliente" que no se abre»,
 * que es exactamente lo que se ve. El color de acción es la misma señal que usan
 * los otros dos plegados de la hoja —`details.mas` y `details.movimientos`—, así
 * que no hay un control nuevo: hay uno que ahora se distingue del texto.
 *
 * `list-style: none` y el marcador de WebKit apagados por lo mismo que allá: en
 * WebKit el marcador es un pseudoelemento propio y con el `summary` en flex se
 * mete como ítem de la fila corriendo el texto. */
.alta summary {
  display: flex;
  align-items: center;
  min-height: var(--toque);
  cursor: pointer;
  font-weight: 600;
  font-size: var(--t-dato);
  color: hsl(var(--primary-text));
  list-style: none;
}
.alta summary::-webkit-details-marker { display: none; }
/* Lo que el rótulo de un plegado no puede dejar de decir. En el diálogo de carga
 * es «se interpretan junto con el texto»: elegir el comprobante entero o el
 * recorte del importe es una decisión distinta según eso, y se toma **antes** de
 * abrir el panel. */
.pista-summary {
  margin-left: 8px;
  font-size: var(--t-rotulo);
  font-weight: 400;
  color: hsl(var(--muted-foreground));
}

/* La fila de una tabla que se está editando: el fondo dice cuál es, y el texto
 * envuelve porque adentro hay un formulario y no una celda de datos. */
tr.editando td { background: hsl(var(--primary) / 0.14); white-space: normal; }

/* --- Los filtros --------------------------------------------------------- */

/* **En el celular los filtros se pliegan.** Hoy los diez de la cartera miden
 * 750px apilados antes del primer cheque y los cuatro del libro, 350px: una
 * pantalla entera de controles antes del primer dato, en la pantalla donde lo
 * que se busca es el dato. Pasan a un `<details class="filtros">` cuyo
 * `<summary>` dice cuántos hay puestos, y desde 640 el `<summary>` no se dibuja
 * y el contenido está siempre a la vista: la casilla de plegar no tiene sentido
 * donde los filtros entran.
 *
 * **La caja no es la fila.** `.filtros` es sólo el panel; la fila de campos es
 * el `<form>` de adentro. Es lo que deja que la misma clase sirva para las dos
 * formas del marcado —el `<form class="filtros">` de hoy y el
 * `<details class="filtros">` con el formulario adentro— sin que el plegado
 * dependa de cómo el navegador arma la caja de un `<details>`.
 *
 * Y alcanza a las cinco pantallas que filtran con `form.buscador` más
 * `span.filtros-chips` y no con `.filtros` (contrato §12.9) —cuentas, clientes,
 * firmantes, archivo de novedades y unificar—: el `<details>` es el mismo, el
 * formulario de adentro es el buscador, y no hace falta ninguna regla más. */
.filtros {
  padding: 10px 12px;
  margin-bottom: var(--paso);
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
details.filtros > summary {
  min-height: var(--toque);
  padding-top: 10px;
  padding-bottom: 10px;
  cursor: pointer;
  font-size: var(--t-dato);
  font-weight: 600;
  color: hsl(var(--primary-text));
  /* **El marcador es el del navegador y no uno dibujado.** El defecto que había
   * que arreglar era que a 390 esto se dibujaba como una caja de 366×68 con la
   * palabra «Filtros» en azul y ni un píxel más: un rótulo, no un control. Se
   * arregló con un triángulo propio hecho con bordes sobre un `::after`, y eso
   * costó caro por un motivo que no se ve: `tests/estilos.py` no sabe leer un
   * pseudoelemento, así que manda la regla entera a la bolsa de «no puedo
   * asegurarlo», y **cualquier test que pregunte por `border-*` deja de poder
   * concluir** —cayó uno de cotizaciones que no tiene nada que ver con esto—.
   * Es la regla 3 del contrato §11, y la pagamos para aprenderla.
   *
   * El marcador nativo es un triángulo, gira solo al abrir, no depende de qué
   * fuente esté instalada y no cuesta una línea de CSS. Lo único que hay que
   * hacer es **no apagarlo**, y con `display: list-item` se dibuja también donde
   * el `display: flex` de arriba se lo llevaría puesto. */
  display: list-item;
  list-style-position: inside;
}
details.filtros[open] > summary { margin-bottom: var(--paso); }

/* Que el contenido **esté escondido mientras el `<details>` está cerrado** se
 * escribe acá y no se deja en manos del navegador, y es la única forma de que
 * el plegado funcione: la fila de campos lleva `display: flex`, y una regla de
 * autor le gana siempre a la hoja del navegador —que es la que esconde el
 * contenido de un `<details>` cerrado—, con cualquier especificidad. Sin esta
 * línea los filtros se ven plegados y desplegados al mismo tiempo.
 *
 * **Y el `<nav>` junto con el `<form>`**: en `/novedades` los filtros no son un
 * formulario sino tres grupos de chips que son enlaces —ahí filtrar es navegar—,
 * así que sin nombrar al `<nav>` esa pantalla tenía el `<summary>` y el panel
 * abierto debajo. Era la única de las que filtran que no plegaba nada, y le
 * costaba 320px de chips antes de la primera tarjeta. */
details.filtros:not([open]) > form,
details.filtros:not([open]) > nav { display: none; }

/* Desde 640 el plegado deja de existir: el `<summary>` no se dibuja —la casilla
 * de plegar no tiene sentido donde los filtros entran— y el formulario está a la
 * vista **aunque el `<details>` siga cerrado**, que es lo que hace que abrir la
 * misma pantalla en la notebook no dependa de lo que se tocó en el celular.
 *
 * Son dos declaraciones porque los navegadores esconden el contenido de un
 * `<details>` de dos maneras: los viejos con `display: none` sobre los hijos y
 * los nuevos con `content-visibility` sobre `::details-content`, que es un
 * pseudoelemento y no se puede alcanzar de otra forma. Es la única regla de esta
 * parte que el resolvedor de la suite no sabe leer, y no declara ninguna
 * propiedad que un test mire. */
@media (min-width: 640px) {
  details.filtros > summary { display: none; }
  details.filtros:not([open]) > form,
  details.filtros:not([open]) > nav { display: flex; }
  details.filtros::details-content { content-visibility: visible; }
}

/* El buscador de una pantalla de listado: el campo, su botón y —en cinco de
 * ellas— los chips del filtro, todo en el mismo formulario. En formularios
 * separados, tocar un chip mandaría lo suyo y borraría lo que se había buscado.
 *
 * `.filtros-padron` y `.filtros-archivo` son ese mismo buscador con chips. Lo
 * único suyo es que envuelven, y va escrito aunque el buscador ya lo traiga: son
 * las dos variantes donde envolver no es una comodidad sino la única salida
 * —cuatro controles que miden su dato y no se achican—, y el día que el buscador
 * a secas deje de envolver, éstas tienen que seguir haciéndolo.
 *
 * Es la única fila de campos alineada **al medio** y no por arriba: acá no hay
 * rótulos apilados sobre controles sino una línea de controles al lado del otro
 * —«Buscar», el campo, el botón y los chips—, y arriba dejaría la palabra
 * «Buscar» flotando contra el techo de un campo de 44px. La segunda mitad del
 * selector es para cuando el buscador es el formulario de adentro del
 * `<details>`, donde si no le gana la regla de la fila de campos. */
.buscador { margin: var(--paso) 0; }
.buscador, .filtros > form.buscador { align-items: center; }
.buscador label { font-size: var(--t-rotulo); color: hsl(var(--muted-foreground)); }
.filtros-padron, .filtros-archivo { flex-wrap: wrap; }
.filtros-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: center;
}

/* «Limpiar» y «Este año» son enlaces, no botones, y estaban al lado de un botón
 * de 44px midiendo el alto de su propio texto. Se tocan igual que el botón. */
.limpiar {
  display: inline-flex;
  align-items: center;
  min-height: var(--toque);
  padding: 0 10px;
  font-size: var(--t-dato);
}

/* --- Los chips que filtran ----------------------------------------------- */

/* Cuatro nombres para el mismo control: el chip con una casilla adentro
 * (`.chip-filtro`), el chip que es un enlace de filtro rápido (`.filtro-rapido
 * a`), el del índice de novedades (`.chip-indice`) y el candidato que se elige
 * de un toque (`.chip-boton`). Los cuatro miden 44px de alto, llevan el radio
 * chico de los controles y **no son píldoras**: un `999px` decía que eran
 * etiquetas, y una etiqueta no se toca.
 *
 * `white-space: nowrap` porque un chip partido en dos renglones deja de leerse
 * como una unidad. */
.chip-filtro, .filtro-rapido a, .chip-indice, .chip-boton {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--toque);
  padding: 0 12px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  font-size: var(--t-dato);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  user-select: none;
}
.chip-filtro:hover, .filtro-rapido a:hover, .chip-indice:hover, .chip-boton:hover {
  border-color: hsl(var(--primary-text) / 0.7);
}
/* Los controles que viven **adentro** de un chip —el desplegable de tipo y las
 * dos fechas del archivo de novedades— no llenan el renglón: el chip los envuelve
 * y mide lo que ellos midan. */
.chip-filtro select, .chip-filtro input[type="date"] { inline-size: auto; }
/* Y la casilla va sin el margen del navegador: los 3px que trae de fábrica se
 * suman al `gap` del chip y descentran el tilde respecto de su palabra. */
.chip-filtro input { margin: 0; }

/* Prendido se ve prendido **sin leer la casilla y sin depender del color**: el
 * relleno, el borde más grueso y la negrita dicen lo mismo tres veces. Con tres
 * filtros al lado, el único tilde chico es justo lo que no se mira al volver a
 * la pantalla.
 *
 * El `inset` no es una sombra: es la segunda línea del borde, dibujada adentro
 * para que el chip no cambie de tamaño al prenderse. */
.chip-filtro:has(input:checked) {
  border-color: hsl(var(--primary-text));
  box-shadow: inset 0 0 0 1px hsl(var(--primary-text));
  background: hsl(var(--primary) / 0.2);
  color: hsl(var(--primary-text));
  font-weight: 600;
}

/* La fila de filtros rápidos: las monedas del mayor y las dos salidas de la
 * ficha de un cliente. Es una fila de chips y envuelve, que en el celular es lo
 * único que hace falta para que siete monedas entren. */
.filtro-rapido {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin: 0 0 var(--paso);
  font-size: var(--t-dato);
}
/* En el color de enlace y no en gris: los mismos recuadros son el filtro de
 * moneda del mayor —donde el que no está elegido igual **navega**— y las dos
 * salidas de la ficha de un cliente, que no son un filtro sino dos enlaces. En
 * gris, ahí no se leían como algo que se puede tocar.
 *
 * El borde se apaga pero **no se saca**: el `1px solid` de la regla de arriba se
 * queda ocupando lugar, que es lo que hace que prenderse no corra al chip de al
 * lado un píxel. */
.filtro-rapido a { border-color: transparent; color: hsl(var(--primary-text)); }
.filtro-rapido a:hover {
  background: hsl(var(--accent));
  color: hsl(var(--accent-foreground));
  text-decoration: none;
}
/* Un candidato es un botón con forma de chip: la decisión es siempre del
 * usuario —el sistema no vincula solo—, así que tiene que parecer un botón y no
 * una etiqueta. */
.chip-boton {
  border-color: hsl(var(--primary-text) / 0.7);
  background: hsl(var(--primary) / 0.14);
  color: hsl(var(--primary-text));
}
.chip-boton:hover { background: hsl(var(--primary) / 0.3); }
/* El chip del índice de novedades no es un enlace de los que se leen como
 * enlace: es una categoría que además navega, y va en el color del texto sobre
 * la superficie, como una columna más del índice. */
.chip-indice {
  background: hsl(var(--card));
  color: hsl(var(--foreground));
}
/* El elegido, en las dos familias de chips: relleno **y** negrita. Sin la
 * negrita, «todas» y «crítica» se ven igual para quien no distingue el tinte, y
 * el índice estaría recortado sin que nada lo diga. */
.filtro-rapido a.actual {
  background: hsl(var(--primary) / 0.2);
  border-color: hsl(var(--primary-text) / 0.6);
  color: hsl(var(--primary-text));
  font-weight: 600;
}
.chip-indice.puesto {
  background: hsl(var(--primary));
  border-color: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
  font-weight: 700;
}

/* --- Los campos de un asiento, que no filtran nada ------------------------ */

/* La ficha de una operación y el ejemplo manual llevaban `.filtros` en el grupo
 * «Fecha contable / Descripción / Motivo de la corrección», que **no filtra
 * nada**: son los campos del asiento que se está corrigiendo (contrato §12.8).
 * Con los filtros plegados en el celular, esa clase dejaría los campos de la
 * corrección escondidos detrás de un «Filtros · 0» en la única pantalla donde se
 * corrige un asiento. Se llaman por lo que son y **no se pliegan**: la caja es
 * la misma y el `<details>` no existe. */
.campos-del-asiento {
  padding: 10px 12px;
  margin-bottom: var(--paso);
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
/* --- Tarjetas de cifras -------------------------------------------------- */

/* Una tarjeta de cifra es **un número con su explicación**: el resultado del
 * período, el saldo de un cliente, las cajas descuadradas de un arqueo. Eso es
 * lo que se queda acá. Lo que se fue son los dos usos que nunca fueron eso: los
 * siete contadores del inicio —que son enlaces a una lista y no necesitan un pie
 * de dos renglones— y los saldos de la caja —que son siete números del mismo
 * tipo y se comparan entre sí—. Cada uno tiene ahora su componente, abajo.
 *
 * **Se acabaron los `auto-fit`.** `repeat(auto-fit, minmax(230px, 1fr))` no
 * decidía nada: el número de columnas era el ancho de la ventana dividido 230,
 * así que a 1536 salían cinco y dos huérfanas, a 1024 tres más tres más uno, y a
 * 390 una por fila —los siete contadores del inicio medían 700px de scroll antes
 * de que apareciera el libro—. Ahora las columnas son una decisión por ancho: 1,
 * 2, 3 y 4; las compactas 2, 3, 4 y 6.
 *
 * **Y las pistas son `minmax(0, 1fr)`, siempre** (§12.2). Una pista `1fr` es
 * `minmax(auto, 1fr)`, y el mínimo automático de una tarjeta con un importe de
 * once dígitos en Space Mono es el ancho de ese importe: es exactamente lo que
 * derramaba la tarjeta compacta de la cartera y estiraba el documento a 428px en
 * una ventana de 390. Con el `minmax(0, …)` de la pista y el `min-width: 0` del
 * ítem, la grilla mide lo que hay y ninguna tarjeta la estira. Lo que sobra
 * adentro de una tarjeta es harina de otro costal y se resuelve donde se
 * origina: haciendo que la cifra entre (ver `.compactas`, más abajo). */
.tarjetas {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--paso);
  margin: 0 0 calc(var(--paso) * 1.5);
}

/* Las compactas arrancan en **dos** y no en una, y por eso llevan su regla base
 * y no sólo las tres de más abajo: una tarjeta compacta es un número corto con
 * un rótulo corto —los seis del arqueo, los cuatro de una operación— y a una por
 * fila en el celular esa sección mide lo mismo que la de tarjetas grandes sin
 * decir más. Es además el ancho que da por supuesto la regla del cuerpo de la
 * cifra de acá abajo, que baja un escalón porque «la columna es la mitad de un
 * teléfono»: sin esta línea la columna era el teléfono entero y el escalón
 * sobraba. */
.tarjetas.compactas { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* `.pendientes` es el grupo que cuenta trabajo que espera: los de la caja y los
 * de las dos colas de pendientes. Va pegado a lo que resume —la tabla de abajo
 * es la misma cosa contada fila por fila—, y por eso lleva la mitad del aire al
 * pie que una fila de tarjetas suelta. */
.tarjetas.pendientes { margin-bottom: var(--paso); }

.cifra {
  display: flex;
  flex-direction: column;
  gap: 1px;
  /* La otra mitad de §12.2, la que va en el ítem: sin esto la pista se agranda
   * hasta el ancho de la cifra más larga y la grilla deja de tener el ancho que
   * dice tener. */
  min-width: 0;
  padding: 10px 14px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}

/* Una tarjeta que **es** un enlace: el recuadro entero lleva a su lista. Un
 * contador con un «ver» al lado obliga a apuntarle a un texto de treinta píxeles
 * con el pulgar; así el objetivo es la tarjeta. El foco lo pone la regla general
 * de `a:focus-visible`, con el resto de los controles. */
a.cifra { text-decoration: none; color: inherit; }
a.cifra:hover {
  border-color: hsl(var(--border));
  background: hsl(var(--accent));
  text-decoration: none;
}

/* El rótulo es la pregunta y el valor es la respuesta: 12px tenues contra 28px
 * en el color del texto. Antes los dos pesaban casi lo mismo y había que leer la
 * tarjeta entera para saber qué decía.
 *
 * **Sin versales.** El rótulo se distingue por el cuerpo y por el color, que es
 * la regla 8 del encabezado del archivo: en mayúsculas competía con los nombres
 * del padrón, que están en mayúsculas porque **son** un dato guardado así. */
.cifra .rotulo {
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
.cifra .valor {
  font-size: var(--t-titulo);
  font-weight: 700;
  line-height: 1.1;
  text-align: left;
  letter-spacing: -0.02em;
  color: hsl(var(--foreground));
}
/* Una tarjeta con un saldo negativo también va en rojo. `.cifra .valor` pesa
 * (0,2,0) y le gana a `.neg`, así que sin esta línea el único lugar donde un
 * importe negativo se ve en el color del texto normal sería justamente el más
 * grande de la pantalla. */
.cifra .valor.neg { color: hsl(var(--destructive-text)); }
.cifra .pie {
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
  line-height: 1.35;
  margin-top: 3px;
}
/* Un dato que es texto y no una cifra —quién contó— en el lugar del valor. A
 * 28px un nombre propio ocupa dos renglones y compite con la tabla de abajo. */
.cifra .valor.chico { font-size: var(--t-seccion); font-weight: 600; }

/* El rojo es la señal de que algo se quedó atrás, y no aparece si no pasó.
 * Acompañado del texto del pie y de una barra a la izquierda: el color solo no
 * alcanza para quien no lo distingue, igual que con los importes negativos. */
/* Sin calificar por `.pendientes`: la misma marca la usa la tarjeta «Con
 * diferencia» del arqueo (`arqueo_uno.html`), que no está adentro de esa
 * sección y por eso no se pintaba de nada — un arqueo con cajas descuadradas se
 * veía igual que uno cuadrado. */
.cifra.alerta {
  border-color: hsl(var(--destructive-text) / 0.6);
  border-left-width: 4px;
  background: hsl(var(--destructive) / 0.16);
}
.cifra.alerta .valor,
.cifra.alerta .pie,
.cifra.alerta .rotulo { color: hsl(var(--destructive-text)); }

/* Y el `hover` no le puede sacar la marca. `a.cifra:hover` pesa (0,2,1) y le
 * gana a `.cifra.alerta` (0,2,0) —un elemento más—, así que sin esta regla la
 * única tarjeta de la pantalla que se veía **sin** su rojo era justamente la que
 * el dedo está por tocar: el borde volvía a `--border` y el tinte a `--accent`.
 * Un poco más de rojo y no menos, que es lo que un hover tiene que decir. */
a.cifra.alerta:hover {
  border-color: hsl(var(--destructive-text));
  background: hsl(var(--destructive) / 0.24);
}

/* **La tarjeta compacta baja la cifra un escalón, y es lo que la hace compacta.**
 * A 28px, `97.195.886,00` mide 218px en Space Mono y no entra en la mitad de un
 * celular de 390: es el derrame de `cartera_390`. El `minmax(0,…)` de la pista
 * evita que ese importe **agrande la columna**, pero no lo hace desaparecer: lo
 * que sobra sigue dibujándose encima de la tarjeta de al lado y sigue contando
 * para el ancho desplazable de la página, porque una tarjeta no clipea —clipear
 * un importe es esconder dígitos, que es peor que desbordar—. Lo único que
 * cierra el caso es que la cifra **entre**: a 18px mide 140 y sobra aire.
 *
 * No contradice la regla 3. Lo que decide qué entra es cuántas columnas hay y no
 * achicar la letra, y acá la decisión ya está tomada: la columna es la mitad de
 * un teléfono, y `--t-seccion` es el cuerpo de un título de tarjeta, que es
 * exactamente lo que esta cifra es.
 *
 * **Y por eso `compacta` quiere decir «acá el valor es un importe largo», no
 * «acá hay pocos números».** El escalón vale en los cuatro anchos y no sólo en
 * el celular, y está medido: la columna de una compacta mide 176px a 640, 224 a
 * 1024, 184 a 1440 y 200 a 1536 —cuatro y seis columnas—, así que un importe de
 * 218px a 28px **no entra en ninguno de los cuatro**. Subir el escalón desde
 * 1024 fue lo primero que se probó para devolverle el cuerpo a la cifra del
 * arqueo y no da: devuelve el derrame de la cartera en la notebook y en el
 * monitor.
 *
 * Lo que se hizo en su lugar es sacar del grupo a la sección que no tenía nada
 * que hacer acá: el resultado de un arqueo son **conteos** —un `1`, un `3`— y
 * un nombre, no importes, y con `compactas` la cifra que dice si el arqueo dio
 * se dibujaba a 18px, del tamaño de la línea que tiene debajo, en los tres
 * anchos. `arqueo_uno.html` usa `tarjetas` a secas y lo dice ahí. Si mañana
 * vuelve a hacer falta agrupar de a seis cifras cortas, lo que corresponde es un
 * nombre para eso y no volver a meterlas acá.
 *
 * Pesa (0,4,0) y le gana al `.valor.chico` de arriba (0,3,0), que pide el mismo
 * cuerpo: las dos reglas dicen 18px y no se contradicen. */
.tarjetas.compactas .cifra .valor { font-size: var(--t-seccion); }

/* La cifra que necesita más ancho que un contador: el resultado del período y el
 * acumulado son importes largos con una explicación abajo, no un número de dos
 * dígitos. Ocupa **dos columnas de la grilla** en vez de retocar el tamaño de
 * todas las pistas con un `:has()`, que era un parche encima de otro parche —y
 * que el resolvedor de la suite no sabe leer—. En el celular no hay dos columnas
 * que ocupar, así que la regla empieza en 640.
 *
 * Es una decisión **de la tarjeta** y no de la fila, y eso se ve en la notebook,
 * que tiene tres columnas: una sección donde todas las tarjetas son anchas entra
 * de a una por renglón. Donde eso no se quiera, lo que sobra es el `ancha` —las
 * cinco fuentes de `/cotizaciones` la llevan y muestran una cotización corta con
 * `.valor.chico`, no un importe largo— y se saca en la plantilla, que es donde
 * está el dato que decide. */
@media (min-width: 640px) {
  .tarjetas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tarjetas.compactas { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cifra.ancha { grid-column: span 2; }
}
@media (min-width: 1024px) {
  .tarjetas { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .tarjetas.compactas { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* **Lo que este reparto deja abierto, anotado acá para que no se arregle a la
 * ligera: la sección que tiene menos tarjetas que columnas deja el hueco.** En
 * el monitor se ve en el resultado del arqueo —tres tarjetas en cuatro columnas,
 * 310px vacíos a la derecha, `arqueo_resultado_1536_claro.png`— y en otras tres
 * secciones que usan la misma clase: el mayor tiene dos tarjetas, la cuenta de
 * un socio tres y el detalle de un resultado **una**.
 *
 * No se arregla haciendo que la fila se reparta entre las que hay —un `flex` con
 * `grow`, o el `auto-fit` que esta sección ya sacó— porque entonces la única
 * tarjeta del detalle de un resultado se dibuja de 1.240px de ancho para un
 * importe, que es peor que el hueco. Y tampoco con un número de columnas por
 * sección: el arqueo mismo tiene **tres o cuatro** según se hayan contado
 * e-cheqs, así que cualquier número fijo deja hueco en uno de los dos casos.
 *
 * La salida que queda es que la sección declare cuántas tarjetas trae, como las
 * tablas declaran `entera-desde-1024` —una propiedad del bloque y no de la
 * hoja—, y eso es un nombre público: entra por el contrato, no por acá. */
@media (min-width: 1440px) {
  .tarjetas { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .tarjetas.compactas { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

/* --- Los contadores: una fila de chips ----------------------------------- */

/* Los siete pendientes del inicio dejan de ser siete tarjetas con pie. Un
 * contador no es una cifra con explicación: es **un número, una palabra y un
 * enlace**. El pie —«3 de días anteriores, sin aprobar»— pasa al `title` del
 * chip y a la pantalla que el chip abre, que es donde se puede hacer algo con
 * él. En un celular la cuenta es directa: siete tarjetas con pie medían 700px de
 * scroll antes de que apareciera el libro, que es lo que esta pantalla viene a
 * mostrar; siete chips de a dos por fila miden poco más de 200.
 *
 * Flex y no grilla, a propósito: la cantidad de chips cambia por pantalla —siete
 * en el inicio, cuatro en novedades— y una grilla de columnas fijas le dejaría
 * huecos a la de cuatro. Con `flex-basis` en porcentaje, dos por fila en el
 * celular es una cuenta y no una tabla de casos. */
.contadores {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  margin: 0 0 calc(var(--paso) * 1.5);
}

/* El chip: el número y el rótulo **en el mismo renglón**, alineados por la línea
 * de base. Es lo que lo distingue de una tarjeta y lo que lo hace medir un solo
 * objetivo táctil de alto en vez de tres renglones.
 *
 * Grilla de dos pistas y no flex: la primera es `auto` —el ancho del número, que
 * es lo que tiene que mandar— y la segunda `minmax(0, 1fr)`, que es la que se
 * queda con lo que sobra y deja que el rótulo se recorte en vez de estirar el
 * chip. Los dos ítems llevan `min-width: 0` (§12.2); en el número no es adorno:
 * sin él, el mínimo automático de la pista `auto` es el ancho del número y un
 * contador de cuatro dígitos volvería a empujar la fila.
 *
 * `align-content: center` y no `align-items: center`: el número y el rótulo se
 * alinean entre sí por la base —que es lo que hace que un 7 de 28px y una
 * palabra de 12 se lean como una sola cosa— y el conjunto se centra en los 44px
 * del chip. */
.chip-contador {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  align-content: center;
  gap: 0 6px;
  /* El chip es además un ítem de la fila de arriba, y §12.2 vale igual acá: sin
   * esto su mínimo automático es el ancho del número más el del rótulo entero, y
   * en el monitor —donde entran todos en una fila y no envuelven— eso es lo que
   * volvería a estirar el documento. */
  min-width: 0;
  min-height: var(--toque);
  padding: 4px 10px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio-chico);
  color: inherit;
  text-decoration: none;
  /* Dos por fila en el celular: la mitad menos el hueco. El `1 1` es lo que hace
   * que el último de una fila impar se estire y no quede una tarjeta a medias. */
  flex: 1 1 calc(50% - var(--paso));
}
.chip-contador:hover {
  border-color: hsl(var(--border));
  background: hsl(var(--accent));
  text-decoration: none;
}
/* El número manda sobre su rótulo: 28 contra 12 es más del doble, que es la
 * regla 6 escrita en números. La monoespaciada la pone `.num` desde la
 * plantilla, como en cualquier otra cifra del sistema. */
.chip-contador .valor {
  min-width: 0;
  font-size: var(--t-titulo);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
/* El rótulo es de una palabra o dos y se recorta con puntos suspensivos en vez
 * de envolver: un chip que crece a dos renglones deja de ser un chip. Lo que se
 * pierde al recortar lo dice el `title`, que además es donde vive ahora el pie
 * explicativo que la tarjeta tenía escrito. */
.chip-contador .rotulo {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
/* **Un chip cuyo valor es texto y no un número.** Los cuatro de `/novedades` no
 * cuentan nada: dicen una fecha («01/09/2026»), un estado del envío y si la
 * casilla se pudo leer («no se pudo leer»). A los 28px y en negrita del contador
 * eso son tres o cuatro palabras que miden más que el chip entero, y como la
 * primera pista de la grilla es `auto` se llevaba el ancho completo: a 390 dos
 * de los cuatro quedaban **sin rótulo**, con la fecha sola y nada que dijera de
 * qué fecha se estaba hablando.
 *
 * Va al cuerpo de una sección —que es exactamente lo que `.cifra .valor.chico`
 * ya hace con el mismo caso en la tarjeta— y se recorta como el rótulo, así que
 * las dos pistas ceden y ninguna se come a la otra. Pesa (0,3,0) contra el
 * (0,2,0) de la regla de arriba, así que no depende del orden. */
.chip-contador .valor.chico {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-seccion);
  font-weight: 600;
}
/* La marca de alerta del chip **es la barra de la izquierda**, no un icono. El
 * chip no tiene pie donde escribir «3 de días anteriores», así que la señal que
 * acompaña al color tiene que estar en la forma: cuatro píxeles de borde a la
 * izquierda se leen en blanco y negro, igual que en la tarjeta. */
.chip-contador.alerta {
  border-color: hsl(var(--destructive-text) / 0.6);
  border-left-width: 4px;
  background: hsl(var(--destructive) / 0.16);
}
.chip-contador.alerta .valor,
.chip-contador.alerta .rotulo { color: hsl(var(--destructive-text)); }
/* Lo mismo que en la tarjeta, y acá hoy sale gratis: `.chip-contador.alerta`
 * pesa lo mismo que `.chip-contador:hover` y le gana por estar escrito después.
 * Se escribe igual, con un peso que no depende del orden, para que la marca no
 * se apague el día que alguien reordene las dos reglas de arriba. */
.chip-contador.alerta:hover {
  border-color: hsl(var(--destructive-text));
  background: hsl(var(--destructive) / 0.24);
}

@media (min-width: 640px) {
  .chip-contador { flex-basis: calc(33.33% - var(--paso)); }
}
@media (min-width: 1024px) {
  .chip-contador { flex-basis: calc(25% - var(--paso)); }
}
/* En el monitor entran todos en una fila, sean cuatro o siete: se apaga el
 * envoltorio y cada chip pide lo suyo.
 *
 * **`auto` y no `0`, que es lo que había.** Con la base en cero los siete se
 * repartían el renglón en partes exactamente iguales —unos 172px cada uno— y
 * entonces «Clientes sin datos», que entra de sobra, recibía lo mismo que el
 * rótulo más largo, que no entraba: el recorte a 1536 era **evitable** y lo
 * causaba el reparto, no la falta de ancho. Con `auto` cada uno arranca del
 * ancho de su contenido y lo que sobra se reparte con el `flex-grow` que ya
 * llevan, así que el largo se lleva lo que necesita y el corto no lo retiene. */
@media (min-width: 1440px) {
  .contadores { flex-wrap: nowrap; }
  .chip-contador { flex-basis: auto; }
}

/* --- Los casilleros: los saldos ------------------------------------------ */

/* Los siete saldos de la caja, los totales de un listado. Un saldo no es una
 * cifra con explicación: es **un número comparable con los seis de al lado**, y
 * lo que necesita es rótulo arriba, cifra abajo, sin pie y **todos del mismo
 * ancho** —si no miden lo mismo, la comparación es de a uno—.
 *
 * Grilla y no flex, justamente por eso: `1fr` reparte en partes iguales y un
 * `flex-basis` con envoltorio le da a la última fila todo lo que sobra.
 *
 * Las columnas son 2, 3, 4 y 6, y no siete de una en el monitor: con siete, cada
 * casillero mide 156px y un `97.195.886,00` a 18px pide 160 con su relleno. El
 * séptimo saldo cae a un segundo renglón a propósito; que se derrame el importe
 * es exactamente la causa que este rediseño viene a matar. */
.casilleros {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--paso);
  margin: 0 0 calc(var(--paso) * 1.5);
}
.casillero {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  padding: 6px 10px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
/* El rótulo de un casillero es el código del activo —`EFECTIVO`, `USDT`— y no se
 * envuelve: en una fila de siete, un rótulo de dos renglones descalza las siete
 * cifras. Lo que se recorta lo dice el `title` de la plantilla. */
.casillero .rotulo {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
/* Un escalón menos que la cifra de una tarjeta, por lo mismo que en la tarjeta
 * compacta: son siete en una fila y a 28px el importe no entra en su casillero.
 * Sigue dominando a su rótulo —18 contra 12, con el peso y el color— que es lo
 * que la regla 6 pide. */
.casillero .valor {
  font-size: var(--t-seccion);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: hsl(var(--foreground));
  /* A la izquierda, como en la tarjeta y al revés que en una celda de tabla: el
   * rótulo y su cifra comparten el borde y se leen como una sola cosa. Pesa
   * (0,2,0) y le gana al `text-align: right` de `.num` (0,1,0), que es lo que
   * corresponde en una columna de importes y no acá: lo que hace comparables a
   * dos casilleros es que midan lo mismo, no que estén alineados por la derecha. */
  text-align: left;
}
/* Igual que en la tarjeta: `.casillero .valor` pesa (0,2,0) y sin esta línea un
 * saldo negativo sería el único importe de la pantalla sin el rojo. */
.casillero .valor.neg { color: hsl(var(--destructive-text)); }

@media (min-width: 640px) {
  .casilleros { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .casilleros { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 1440px) {
  .casilleros { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

/* --- Las dos cifras: lo aprobado y lo que falta aprobar ------------------ */

/* Va **debajo** del importe firme y en el cuerpo de un rótulo: es una salvedad
 * sobre ese número, no otro número. Al lado, en la misma línea, las dos cifras se
 * leerían como una columna de dos importes y habría que averiguar cuál manda. */
.provisorio {
  display: block;
  font-family: var(--mono);
  font-size: var(--t-rotulo);
  font-variant-numeric: tabular-nums;
  color: hsl(var(--muted-foreground));
  white-space: nowrap;
}

/* --- Una celda con posiciones por moneda y su valuación ------------------ */

/* El reparto entre socios. Cada celda dice **primero cuánto hay de cada moneda y
 * después cuánto vale en pesos**, y el orden es el argumento: lo de arriba es lo
 * que efectivamente hay —500.000 dólares son dólares— y lo de abajo es una
 * lectura derivada que depende de un tipo de cambio. Antes esta celda tenía una
 * sola cifra que sumaba las cinco monedas.
 *
 * En columna y no en línea, por lo mismo que `.provisorio`: dos importes al lado
 * del otro se leen como dos columnas y hay que averiguar cuál manda. */
.montos { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }

/* El código de moneda va **antes** del número y con su ancho fijo, así que la
 * columna de importes queda alineada aunque los códigos midan distinto. */
.posicion { display: block; white-space: nowrap; }
/* 5ch y no 4,5: cuatro de las cinco monedas miden tres letras y `USDT` mide
 * cuatro, y el `ch` se mide sobre la fuente del propio código —el cuerpo de un
 * rótulo— que es más chica que la del importe de al lado. El `padding` garantiza
 * la separación sin depender de cuánto rinda la fuente. */
.posicion .moneda {
  display: inline-block;
  inline-size: 5ch;
  padding-inline-end: 4px;
  text-align: left;
}

/* La valuación en pesos: separada por una línea, no por un espacio. La línea es
 * lo que dice que lo de abajo es de otra clase que lo de arriba —una conversión
 * y no una tenencia— sin gastar una palabra en decirlo. */
.valuado {
  display: block;
  margin-top: 2px;
  padding-top: 2px;
  border-top: 1px solid hsl(var(--border));
  font-size: var(--t-rotulo);
  white-space: nowrap;
}
/* **`min-inline-size` y no `inline-size`, que es lo que encimaba el rótulo con
 * su número.** El ancho fijo existe para que los importes de las filas queden
 * alineados entre sí, y con «en ARS» —seis caracteres— funciona; pero el mismo
 * `<span>` escribe «parcial en ARS», que son catorce, y con la caja clavada en
 * nueve el texto se derramaba y el importe arrancaba igual a los 9ch: se leía
 * `parcial en AR$120.000.000,00`, las dos cosas una encima de la otra, en los
 * tres anchos. Con el nueve de piso, la fila que dice «parcial» corre su número
 * lo que haga falta y las demás siguen alineadas, que es donde la alineación
 * valía algo. El `padding` garantiza la separación en el caso largo sin
 * depender de cuánto rinda la fuente —es el mismo recurso que `.posicion
 * .moneda` de acá arriba— y no cuesta ancho en el corto, porque con
 * `box-sizing: border-box` los cuatro píxeles van adentro de los nueve. */
.valuado .rotulo-valuado {
  display: inline-block;
  min-inline-size: 9ch;
  padding-inline-end: 4px;
  text-align: left;
  font-family: var(--sans);
  color: hsl(var(--muted-foreground));
}
/* «no disponible» no es un importe: sin mono, sin alinear, y tenue. Nunca 0,00,
 * que sería afirmar que eso no vale nada. */
.valuado.sin-valuar { font-family: var(--sans); color: hsl(var(--muted-foreground)); }

/* --- El libro de caja del día (§4.6) ------------------------------------- */

/* La hoja CAJA, con lo que la planilla no podía hacer. Es la pantalla que se
 * mira más veces por día, así que la densidad manda: filas más bajas que en
 * cualquier otra tabla, y un día normal —treinta o cuarenta movimientos— tiene
 * que entrar en una notebook sin scrollear la página. */
.libro-caja { margin-top: calc(var(--paso) * 2); }
.cabecera-libro {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px var(--paso);
  margin-bottom: 6px;
}
.cabecera-libro h2 { margin: 0; }
/* El selector de día: un formulario `GET`, así que anda sin JavaScript. Las
 * flechas son enlaces al día anterior y al siguiente, dibujadas como botones
 * porque en esta pantalla son la acción más frecuente. */
.selector-dia {
  display: flex;
  align-items: center;
  gap: 4px;
}
/* Con el token y no con el 44 escrito a mano que había acá: era el único de la
 * hoja, y un objetivo táctil escondido en píxeles es el que nadie sube el día
 * que se decida subirlos. */
.flecha-dia, .ir-a-hoy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--toque);
  min-height: var(--toque);
  padding: 0 var(--paso);
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  text-decoration: none;
  font-size: var(--t-dato);
}
.flecha-dia:hover, .ir-a-hoy:hover { border-color: hsl(var(--primary-text) / 0.7); }
.estado-libro { font-size: var(--t-dato); color: hsl(var(--muted-foreground)); }
.exportar-csv {
  margin-left: auto;
  font-size: var(--t-dato);
}

/* **El único marco con alto acotado de la interfaz** (§12.1), y es lo que hace
 * que el `sticky` del `thead` haga algo: `sticky` se mide contra el contenedor
 * de scroll, y un marco que crece con su tabla no desplaza nada por dentro. Por
 * eso el encabezado fijo se declara acá y no en `table.datos`, donde estaba
 * escrito para las 65 tablas y no servía en 64.
 *
 * **En `dvh` y no en `calc(100vh - 330px)`.** Dos cosas estaban mal en esa
 * cuenta: `100vh` es el alto de la ventana **como si la barra del navegador no
 * estuviera**, así que en un celular daba de más y el marco terminaba más alto
 * que lo que se ve —la tabla se desplazaba en los dos ejes y el pie quedaba
 * fuera—; y los 330px eran el alto de los siete contadores de arriba, que ya no
 * son siete tarjetas. Una fracción de `dvh` no tiene ninguna de las dos deudas:
 * dice «como mucho dos tercios largos de lo que hay», y sigue a la barra del
 * navegador cuando aparece y cuando se va.
 *
 * El piso también en `dvh`: es lo que evita que un día de dos movimientos deje un
 * marco de dos renglones con el encabezado pegado a los totales.
 *
 * Y va `overflow-y` y no `overflow`: el atajo reiniciaría el `overflow-x` del
 * marco y con él la barra de scroll siempre visible del celular, que es una
 * decisión de la sección de tablas. */
.marco-libro {
  max-height: 70dvh;
  min-height: 30dvh;
  /* **`scroll` y no `auto` en el celular**, que es la mitad que faltaba de esta
   * decisión. El tope se queda (§12.1) y con él el `<thead>` fijo, que es lo que
   * justifica el único marco acotado de la interfaz; lo que no se puede es que
   * el marco corte la tabla **sin decirlo**. A 390 el tope son 591px y la fila
   * `Salidas` del pie cae por debajo del corte: la barra siempre a la vista es lo
   * que dice que el libro sigue, con el mismo criterio y el mismo dibujo con que
   * la barra horizontal lo dice de las columnas.
   *
   * (La otra mitad de que `Salidas` no entre son las dos bandas en blanco del
   * pie, que se comen 290 de esos 591px. Eso no es de acá: es el `colspan` del
   * pie de `caja.html`.)
   *
   * Desde 640 vuelve a `auto`, igual que la horizontal: con un mouse, una barra
   * que aparece cuando hace falta es lo que corresponde. */
  overflow-y: scroll;
}
/* La barra vertical, del mismo grosor que la horizontal de los marcos. El color
 * y el pulgar redondo los pone la regla de `.tabla-marco`, que también alcanza a
 * éste. */
.marco-libro::-webkit-scrollbar { width: 10px; }

@media (min-width: 640px) {
  .marco-libro { overflow-y: auto; }
}

/* La densidad del libro: el relleno y el interlineado, no el cuerpo de la letra.
 * Sin `font-size`, entonces —la celda se dibuja al cuerpo de cualquier otra
 * celda—, porque achicarla un escalón es comprar una columna con la legibilidad
 * de la columna que se compró (regla 3).
 *
 * **Y va nombrada `table.datos.libro-del-dia`, que es la corrección de un
 * defecto que nadie vio porque nadie lo podía ver.** Esto decía
 * `.libro-del-dia th`, que pesa (0,1,1), contra el `table.datos td` de la
 * sección de tablas, que pesa (0,1,2): el relleno apretado del libro **nunca
 * llegó a ninguna celda**, y lo mismo le pasaba al cuerpo más chico, que era
 * `.libro-del-dia` (0,1,0) contra `table.datos` (0,1,1). La tabla más mirada del
 * sistema se dibujaba igual que todas las demás mientras el comentario de al
 * lado explicaba por qué era más densa. Es la misma trampa que dejó sin alinear
 * a todos los importes de la aplicación: se cuenta la especificidad, no se mira
 * el orden. */
table.datos.libro-del-dia th,
table.datos.libro-del-dia td { padding: 2px var(--paso); line-height: 1.25; }

/* El encabezado fijo, en sus dos renglones: los rótulos de columna y el saldo
 * inicial. El saldo inicial vive en el `thead` porque es lo que tiene que quedar
 * a la vista mientras las filas se desplazan por debajo, junto con el nombre de
 * cada columna.
 *
 * El relleno vertical va repetido acá **como dos propiedades largas** aunque el
 * atajo de la regla de arriba ya lo resuelva en el navegador: `table.datos thead
 * th` declara `padding-top` y `padding-bottom` por separado, y el resolvedor de
 * la suite no expande atajos —compara nombre de propiedad contra nombre de
 * propiedad—, así que sin estas dos líneas contestaría 6px donde el navegador
 * dibuja 2. Un test que mienta a favor es peor que no tenerlo.
 *
 * El fondo es obligatorio y no decorativo: una celda `sticky` sin fondo deja
 * pasar por debajo las filas que se desplazan. */
table.datos.libro-del-dia thead th,
table.datos.libro-del-dia thead td {
  position: sticky;
  top: 0;
  z-index: 3;
  padding-top: 2px;
  padding-bottom: 2px;
  background: hsl(var(--card));
}
/* El segundo renglón cuelga del primero, así que su `top` es el alto del primero
 * y no cero. Se escribe con la escala —el rótulo, su interlineado, los dos
 * rellenos y la línea— y no con el 26 medido a ojo que había acá: si mañana
 * cambia el cuerpo de un rótulo, el saldo inicial sigue pegado donde va. El
 * `z-index` menor es el seguro: si la cuenta quedara corta por medio píxel, el
 * renglón de arriba tapa al de abajo y no al revés. */
.libro-del-dia thead tr.saldo-inicial th,
.libro-del-dia thead tr.saldo-inicial td {
  top: calc(var(--t-rotulo) * 1.25 + 5px);
  z-index: 2;
  box-shadow: inset 0 -1px 0 hsl(var(--border));
}
/* La línea de abajo del encabezado va con `inset` y no con `border` porque el
 * borde de una celda `sticky` se corre con el colapso de bordes de la tabla.
 * **No es una sombra**: es una línea. Y la celda de la esquina es la única fija
 * en los dos ejes a la vez —le llega el `left` de la primera columna de una
 * tabla ancha—, así que lleva las dos líneas: la de abajo y la que separa la
 * columna quieta de las que se mueven. */
.libro-del-dia thead tr.saldo-inicial th:first-child {
  box-shadow: inset 0 -1px 0 hsl(var(--border)), inset -1px 0 0 hsl(var(--border));
}
/* Y las dos esquinas necesitan que les devuelvan su plano. `table.datos.ancha
 * th:first-child` pesa (0,3,2) —**el `:first-child` cuenta como una clase**— y
 * le gana a las dos reglas de arriba, así que la celda de la esquina se quedaba
 * con el `z-index: 1` de la primera columna fija, el mismo que tienen las celdas
 * del cuerpo; y a igualdad de plano manda el orden del documento, o sea que las
 * filas se desplazaban **por encima** del encabezado fijo, que es exactamente lo
 * que el encabezado fijo viene a evitar.
 *
 * Las dos reglas están calificadas con `.ancha` a propósito: es la única
 * situación en la que el problema existe. Sin esa clase no hay primera columna
 * fija, no hay a quién ganarle, y las reglas de arriba alcanzan solas. */
table.datos.ancha.libro-del-dia thead th:first-child { z-index: 3; }
table.datos.ancha.libro-del-dia thead tr.saldo-inicial th:first-child { z-index: 2; }
.libro-del-dia tr.saldo-inicial td,
.libro-del-dia tr.saldo-final td { font-weight: 700; }
.libro-del-dia tr.totales-libro td { font-weight: 500; }

/* **El pie deja de ser `sticky`** (§12.1). Era lo que tapaba la última fila del
 * día —se ve en `inicio_1024_claro.png`, con el saldo final encima del último
 * movimiento—, y lo que ganaba no valía eso: los totales son el final, y a un
 * final se llega scrolleando. El fondo, el borde y el peso del `tfoot` los pone
 * la regla general de `table.datos`, que es la misma para las 65 tablas. */

.libro-del-dia td.hora {
  color: hsl(var(--muted-foreground));
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.libro-del-dia td.op { white-space: nowrap; }
/* El badge «En revisión» va pegado al número de operación y con el relleno
 * apretado: en esta tabla la fila mide dos píxeles de relleno, y un badge con el
 * alto que tiene en el resto de la interfaz sería el que decide el alto de la
 * fila. El cuerpo es el del badge de cualquier tabla; lo único que cambia es
 * cuánto aire lleva alrededor. */
.libro-del-dia td.op .estado { margin-left: 4px; padding: 0 6px; font-size: var(--t-rotulo); }
/* **En el celular el badge baja a un segundo renglón.** Al lado del número, la
 * celda mide `#12` más «En revisión» —unos 142px de los 366 del marco— y era el
 * primero de los tres empujones que dejaban la celda de movimientos arrancando en
 * x≈390, o sea la pantalla de la caja sin un solo importe a la vista. Debajo, la
 * celda mide lo que mide el badge y se pagan quince píxeles de alto en las filas
 * que lo llevan, que son las que están en revisión y no todas. Desde 640 vuelve
 * al renglón del número. */
.libro-del-dia td.op .estado { display: block; width: max-content; margin-left: 0; }
@media (min-width: 640px) {
  .libro-del-dia td.op .estado { display: inline-block; width: auto; margin-left: 4px; }
}
/* **Y la hora se va del celular.** De las cuatro columnas que quedan con la tabla
 * `compacta` es la única que no contesta ninguna de las tres preguntas del libro
 * —qué operación, qué fue, por cuánto—: las filas ya vienen en orden de hora, y
 * la hora exacta está en la ficha de la operación, a un toque del `#`. Sin
 * sacarla no entra la celda de movimientos, y una caja sin importes no es una
 * caja. Vuelve desde 640, junto con las columnas de activo.
 *
 * El `<th>` lleva la clase igual que el `<td>` —`caja.html` se la puso— porque un
 * encabezado que se queda sin su columna deja la tabla corrida un lugar. Las
 * celdas con `colspan` del pie no se tocan: una columna que no se dibuja no ocupa
 * lugar, así que un `colspan` que la incluye sigue alineado. */
.libro-del-dia th.hora,
.libro-del-dia td.hora { display: none; }
/* En el celular la descripción es **un renglón con puntos suspensivos**, y el
 * texto entero está en el `title`. Sin esto, «Compra de cheque a HOCHNADEL
 * LOURDES con endoso a…» son tres renglones por fila y el día entra en un tercio
 * de las filas. Desde 640 vuelve a envolver con su tope de columna: ahí el
 * ancho alcanza y lo que importa es leerla.
 *
 * **Doce caracteres y no veintidós**: veintidós son 176px y eran el tercero de
 * los tres empujones que dejaban la celda de movimientos fuera de la pantalla. Lo
 * que se pierde acá se recupera a un toque —el `#` lleva a la ficha— y lo que se
 * gana es la columna de importes, que es a lo que se entra a esta pantalla.
 *
 * Las dos reglas pesan (0,2,1), lo mismo que el `white-space: normal` que la
 * sección de tablas le da a `.descripcion`, así que lo que las ordena es el
 * lugar en el archivo. Es la misma mecánica de la poda por prioridad: primero lo
 * del celular, después lo que el ancho devuelve. */
.libro-del-dia td.descripcion {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 12ch;
}
/* Entradas y salidas en la misma columna, con signo **y** color: el signo se
 * lee en blanco y negro, y el color hace que la columna se lea de un vistazo. */
.libro-del-dia td.movimiento.entrada { color: hsl(var(--success-text)); }
.libro-del-dia td.movimiento.salida { color: hsl(var(--destructive-text)); }
.libro-del-dia td.entrada { color: hsl(var(--success-text)); }
.libro-del-dia td.salida { color: hsl(var(--destructive-text)); }
.libro-del-dia td.sin-movimiento { color: hsl(var(--muted-foreground)); }
/* La operación en revisión, además del badge: el punteado del lado izquierdo es
 * la misma señal que en el resto de las tablas. La segunda línea es la que trae
 * la primera columna fija de una tabla ancha y que esta regla —más específica—
 * pisaría: sin repetirla, la fila en revisión sería la única sin el corte entre
 * la columna quieta y las que se desplazan. */
.libro-del-dia tbody tr.en-revision > td:first-child {
  box-shadow: inset 3px 0 0 hsl(var(--warning)), inset -1px 0 0 hsl(var(--border));
}

/* **Las columnas de activo en el celular** (plan §2c). El libro es una tabla
 * ancha y no se poda por prioridad: sus columnas son las que tiene el día y no
 * las puede numerar nadie a mano. Lo que sí sabe la plantilla es cuáles se
 * movieron, y con eso alcanza:
 *
 * `.quieta` es la columna de un activo que hoy no se movió. Un día normal mueve
 * dos o tres cajas: escondiendo las quietas, esas dos o tres entran al lado del
 * número de operación y de la descripción, que es lo que antes no pasaba —a 390
 * el libro mostraba `Op.`, `Hora` y `Descripción`, o sea **ninguna columna de
 * dinero** en la pantalla que se mira treinta veces por día—. */
.libro-del-dia th.quieta,
.libro-del-dia td.quieta { display: none; }

/* Y si se movieron más de tres, esconderlas de a una no alcanza: la plantilla
 * marca la tabla `compacta` y en el celular se van **todas** las columnas de
 * activo. En esta tabla «columna de activo» y «columna `num`» son lo mismo: la
 * hora, la operación y la descripción son las tres únicas que no llevan `num`, y
 * las de activo las genera un bucle que se lo pone a todas. */
.libro-del-dia.compacta th.num,
.libro-del-dia.compacta td.num { display: none; }

/* Lo que las reemplaza: una celda por fila con la lista «activo importe», que la
 * plantilla ya trae rendida. Existe siempre en el HTML y se dibuja sólo donde
 * hace falta —en el celular y con la tabla compacta—, porque en cualquier otro
 * caso diría dos veces lo mismo que las columnas de al lado. Envuelve, que es lo
 * único que puede hacer una lista de tres renglones adentro de una tabla que va
 * toda en una línea. */
.libro-del-dia th.movimientos-de-la-fila,
.libro-del-dia td.movimientos-de-la-fila { display: none; }
.libro-del-dia.compacta th.movimientos-de-la-fila,
.libro-del-dia.compacta td.movimientos-de-la-fila {
  display: table-cell;
  white-space: normal;
  max-width: 22ch;
}

/* **Las tres filas del pie dejan de ser filas de la tabla y pasan a ser un
 * renglón cada una, y eso es lo que hace entrar a `Salidas`.** El marco del
 * libro corta en `70dvh` —591px a 390, §12.1— y la fila `Salidas` caía por
 * debajo del corte. La barra siempre a la vista dice que abajo queda algo, pero
 * la mitad que faltaba es por qué el pie ocupa tanto: en el pie, las dos
 * columnas de la izquierda —la descripción y la hora— **no tienen nada que
 * decir**, y sin embargo se llevan sus ~128px, así que la lista «activo importe»
 * se dibuja en los 145 que sobran y `EFECTIVO 45.412.142,83` —190px— entra en
 * dos renglones en vez de uno. Ocho ítems para seis monedas en `Saldo final`,
 * cinco para tres en `Entradas`: unos 290 de los 591 del marco, gastados en
 * partir renglones que entran.
 *
 * Con la fila en `flex` el pie sale de la grilla de columnas de la tabla y la
 * lista se lleva todo lo que el rótulo no usa. Es el mismo molde que usa la
 * `.papel` para convertir una fila en tarjeta, y con el mismo cuidado: `tfoot`
 * en `block` para que el `<tr>` que dejó de ser fila no quede colgando de un
 * grupo de filas.
 *
 * **No se toca el `colspan` de la plantilla**, y no por comodidad: `caja.html`
 * explica —en la fila del saldo inicial— que un `colspan` escrito a mano contra
 * un número de columnas que cambia con el ancho es la clase de calce que se
 * rompe sin que nadie lo vea, y acá el número de columnas lo pone el día. Lo que
 * esta regla necesita es exactamente lo contrario: que las columnas dejen de
 * importar.
 *
 * Sólo con `compacta`, que es el único caso en que la lista se dibuja: sin ella
 * el pie tiene sus columnas de importes y es una tabla de verdad. Desde 640
 * vuelve a serlo. */
.libro-del-dia.compacta tfoot { display: block; }
.libro-del-dia.compacta tfoot tr {
  display: flex;
  align-items: baseline;
  gap: 0 var(--paso);
}
/* La celda vacía de la descripción no reserva nada: en el pie no dice nada, y su
 * ancho es justamente lo que se está recuperando. La de la hora ya está apagada
 * para toda la tabla, unas líneas más arriba. */
.libro-del-dia.compacta tfoot th.descripcion { display: none; }
/* Y la lista se lleva lo que queda del renglón. `max-width: none` porque los
 * 22ch de arriba son el tope que la lista necesita **en el cuerpo**, donde
 * comparte el ancho con la descripción de cada operación; en el pie no hay
 * descripción con la que competir. Pesa (0,4,3) contra el (0,3,2) de aquélla. */
.libro-del-dia.compacta tfoot td.movimientos-de-la-fila {
  flex: 1 1 0;
  max-width: none;
}

/* Desde la tablet entra el ancho: vuelven la hora y todas las columnas de activo
 * —las quietas también, porque un guión en una columna también dice algo— y se va
 * la lista por fila. Las reglas pesan lo mismo que las de arriba y ganan por
 * estar después, que es cómo se escribe mobile-first sin una sola `max-width`. */
@media (min-width: 640px) {
  .libro-del-dia th.hora,
  .libro-del-dia td.hora,
  .libro-del-dia th.quieta,
  .libro-del-dia td.quieta,
  .libro-del-dia.compacta th.num,
  .libro-del-dia.compacta td.num { display: table-cell; }
  /* Y el pie vuelve a ser el pie de una tabla: acá están las columnas de activo,
   * cada total cae debajo de la suya y la lista por fila se apaga. */
  .libro-del-dia.compacta tfoot { display: table-footer-group; }
  .libro-del-dia.compacta tfoot tr { display: table-row; }
  .libro-del-dia.compacta tfoot th.descripcion { display: table-cell; }
  .libro-del-dia.compacta th.movimientos-de-la-fila,
  .libro-del-dia.compacta td.movimientos-de-la-fila { display: none; }
  .libro-del-dia td.descripcion {
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    max-width: 34ch;
  }
}

.pie-libro { margin-top: 6px; }
.descuadre-libro { color: hsl(var(--destructive-text)); }

/* --- Arqueo (§4.10) ------------------------------------------------------ */

/* La fila **es** un formulario, como en la edición de un asiento: son seis
 * renglones y no doscientos, así que el objetivo táctil manda sobre la densidad.
 * Los campos miden lo que miden sus datos —un importe diecisiete caracteres, una
 * cantidad de papeles cuatro— y no todos lo mismo.
 *
 * **Éste es el precedente que el resto de los formularios copia** (§2b del plan):
 * el ancho de un campo se escribe en `ch` y sale del dato que entra, no de un
 * `flex-basis` en píxeles que después se estira con lo que sobre. Los tres de
 * acá son los que estaban bien desde el principio y por eso no se tocan. */
.conteo table.datos td { padding: 4px 6px; }
.conteo table.datos input {
  min-height: var(--toque);
  text-align: right;
  font-family: var(--mono);
}
.conteo input[name="conteo"] { width: 17ch; }
.conteo input[name="cantidad"] { width: 6ch; }
.conteo input[name="cambio"] { width: 10ch; }
.conteo .fila-acciones { margin-top: var(--paso); }

/* **El nombre de la caja va debajo de su código, y eso es presupuesto de
 * columna, no tipografía.** Las tres tablas del arqueo abren con el código y el
 * nombre en la misma celda —`CAJA.ARS.CHEQUES Cartera de cheques (a valor
 * nominal)`— y, con el `white-space: nowrap` que heredan de `table.datos td`,
 * esa columna medía 435px: más que las tres columnas de importes juntas, y es la
 * única que no lleva un número. En una notebook eso se pagaba en la punta
 * derecha: la tabla del conteo pedía 1.137px y la del arqueo hecho 1.228 sobre
 * los 727 que dejaba el panel expandido, y lo que se caía afuera era el campo
 * donde se tipea el conteo —lo único que esa pantalla hace— y la `Diferencia`,
 * que es el número por el que se abre la otra. Apilado, la celda mide el más
 * largo de los dos renglones —unos 250px— y le devuelve ~185 a las columnas de
 * la derecha, que con los 920px del panel colapsado alcanzan para que entren.
 * A 390 cierra además el corte de `Cartera de cheques (a valor n` contra el
 * marco.
 *
 * Desde 1440 vuelven al mismo renglón, con su `margin-left` de vuelta: ahí la
 * tabla tiene 1.144px o más y el código con el nombre al lado se lee de un
 * tirón, que es como se leía antes de todo esto.
 *
 * **No se toca `.secundario` en general, y no es timidez**: es una clase de toda
 * la hoja —está en el padrón, en la cartera, en «De dónde vino»— y apilarla en
 * todas alargaría cada fila de listados donde el ancho no es lo que falta. La
 * clase va en el `<td>` de las tres plantillas del arqueo; el precedente de
 * hacerlo así son `.ediciones-del-cheque .secundario` y `.candidatos-peso
 * .secundario`, que ya apilan por su cuenta. */
td.caja-contada .secundario {
  display: block;
  margin-left: 0;
}
@media (min-width: 1440px) {
  td.caja-contada .secundario {
    display: inline;
    margin-left: 6px;
  }
}
/* --- El diálogo de carga (§9): la pantalla que se usa parado -------------- */

/* `/cargar` es **la** pantalla: por acá entra toda operación al sistema, y se
 * usa de pie, con una mano, con el celular y con un cliente enfrente esperando.
 * Todo lo que sigue está decidido con esa escena delante, y por eso es la
 * sección donde más se nota que la hoja es mobile-first: la regla base es la de
 * los 390px de ancho y lo que agrega ancho está abajo, en su `@media`.
 *
 * Cuatro cosas que valen para la sección entera:
 *
 * 1. **Se fue el `#asistente { max-width: 68ch }`.** Era el tope que dejaba la
 *    mitad derecha de un monitor en blanco justo en la pantalla más importante.
 *    Lo que se acota con `--linea` es el texto que se lee de corrido, y lo hace
 *    la clase que existe para eso: una propuesta con cuatro tablas adentro no es
 *    texto, y una conversación tampoco se acota dos veces.
 * 2. **Las tres salidas se ven las tres, del mismo tamaño y en la misma fila.**
 *    Confirmar asienta, Cancelar cierra sin asentar y Dejar pendiente no cierra
 *    nada: ninguna se deduce de las otras dos, así que ninguna se dibuja más
 *    chica. Lo único que distingue a Confirmar es el color, no el tamaño.
 * 3. **Los cinco interruptores sin JavaScript se conservan tal cual.** Cada
 *    panel de esta pantalla lo abre una casilla clipeada con su `<label>`
 *    haciendo de botón, y lo que lo muestra es un `.interruptor-x:checked ~
 *    .panel`. El resolvedor de la suite **descarta en silencio** las reglas de
 *    estado, así que si una de éstas se rompe ningún test dice una palabra: no
 *    se tocan, y el `<label>` tiene que seguir siendo hermano **anterior** de su
 *    panel en el DOM. La forma del botón se escribe una sola vez, con los otros
 *    cuatro, en la sección de formularios.
 * 4. **El aire acá no es decoración.** El cuadro de texto es grande, la
 *    propuesta se lee sin acercar la vista y dos salidas nunca quedan pegadas:
 *    en el ancho de un pulgar, dos botones juntos se aprietan por error, y de
 *    los tres el único que tira trabajo a la basura es «Cancelar». */

/* --- El armazón de la pantalla ------------------------------------------- */

/* `#asistente` es la caja que HTMX reemplaza entera en cada vuelta, y no tiene
 * que dibujar nada: `display: contents` la saca del layout y deja que sus hijos
 * sean ítems de la grilla de `<main>` directamente. Sin esto las dos zonas de la
 * familia —`.zona-conversacion` y `.zona-propuesta`, que reparten las columnas a
 * partir de 1440— quedarían anidadas adentro de un `<div>` y sus `grid-column`
 * no alcanzarían a ninguna pista: se verían las dos a lo ancho, en una columna,
 * en cualquier monitor.
 *
 * El reparto en sí —5fr para la conversación, 7fr para la propuesta, y la
 * propuesta `sticky` bajo la cabecera con su propio desplazamiento— vive con el
 * resto del esqueleto, junto a las demás familias, que es donde se puede leer al
 * lado de la ficha y del formulario. Acá está sólo lo que lo habilita.
 *
 * **Las clases de zona las pone la plantilla sólo cuando hay una propuesta.**
 * Sin propuesta no hay dos columnas que repartir —hay una conversación y un
 * cuadro de texto— y todo cae en el ancho entero, que es el default de `<main>`
 * y es lo correcto: partir la pantalla en dos para dejar siete columnas vacías
 * sería el mismo defecto que el `max-width` que se acaba de sacar, con otra
 * forma. */
#asistente { display: contents; }

/* La frase que explica por qué existe un panel, arriba de sus campos. Aparece en
 * los seis paneles de esta pantalla —dejar pendiente, el alta, asociar, el
 * choque, los cheques— y en dos más de otras: es **una** cosa y por eso es una
 * sola regla. Va al cuerpo del dato y no al de un rótulo: es una frase que se
 * lee, no una etiqueta que se saltea. */
.por-que { margin: 0 0 4px; font-size: var(--t-dato); }

/* --- Las dos salidas de antes de la propuesta ---------------------------- */

/* Mientras no hay propuesta las salidas son dos: descartar lo escrito, o dejarlo
 * esperando una definición. Las dos son salidas de verdad y por eso se dibujan
 * iguales —mismo alto, misma forma, mismo cuerpo—: mientras una fue un renglón
 * de texto subrayado y la otra un botón, la pantalla estaba diciendo que sólo
 * una de las dos era una opción real.
 *
 * **Orden: descartar primero, dejar pendiente después.** Sin propuesta, dejar
 * pendiente es la que **salva** el trabajo y descartar es la que lo tira, así
 * que la que salva queda última en el orden de lectura y más cerca del pulgar, y
 * la destructiva queda antes y más callada.
 *
 * `position: relative` para que la casilla clipeada del botón de pendiente se
 * posicione contra esta fila y no contra la página: es la causa 7 del
 * diagnóstico —un `position: absolute` sin ancestro posicionado estira el
 * documento— y se defiende en cada uno de los cuatro contenedores que tienen
 * una casilla adentro. */
.salidas {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--paso);
  margin-bottom: var(--paso);
}
.descartar { margin: 0; }
/* En el celular las dos se apilan a ancho completo, con la que salva el trabajo
 * abajo, que es donde queda el pulgar. Se escribe con `flex-basis: 100%` sobre
 * una fila que envuelve y **no** con `flex-direction: column`: en columna el eje
 * principal es el vertical y ese mismo `100%` pasaría a medir **alto**, que es
 * lo que dejaba al panel de campos pidiendo la pantalla entera. */
.salidas > form:not(.dejar-pendiente),
.salidas .abrir-pendiente { flex: 1 1 100%; }
.salidas .descartar button { width: 100%; }

@media (min-width: 640px) {
  /* Con lugar, las dos vuelven a una fila alineada a la derecha: son las salidas
   * de emergencia de la pantalla —se buscan cuando se las busca— y no compiten
   * con el cuadro de texto, que está abajo. */
  .salidas { justify-content: flex-end; }
  .salidas > form:not(.dejar-pendiente),
  .salidas .abrir-pendiente { flex: 0 1 auto; }
  .salidas .descartar button { width: auto; }
}

/* --- Dejar pendiente ------------------------------------------------------ */

/* §9 — dejar la conversación esperando que un socio decida algo. Es una de las
 * tres salidas y se dibuja como tal: un control del mismo peso que los otros
 * dos, en la misma fila, y los dos campos obligatorios abriéndose **debajo de la
 * fila entera**. Estuvo plegada adentro de un `<details>` con forma de renglón
 * de texto y el resultado fue que no la encontraba nadie.
 *
 * `flex: 1 1 100%` es lo que la baja a su propio renglón en vez de dejarla
 * adentro de la columna del botón que la abrió. Y nace `display: none`: la
 * muestra su casilla, tres líneas más abajo. */
.dejar-pendiente {
  flex: 1 1 100%;
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 12px 14px;
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
}
/* **Interruptor 2 de 5.** No se toca: el resolvedor de la suite descarta las
 * reglas de estado y si esto se rompe no falla nada. El `~` alcanza a un hermano
 * **posterior** de la casilla, que es justamente lo que permite que el botón
 * viva en la fila de las tres salidas y el panel caiga debajo de las tres. */
.interruptor-pendiente:checked ~ .dejar-pendiente { display: flex; }
/* Las dos preguntas del panel son frases y no rótulos de campo —«¿A quién le
 * estás preguntando?»—, así que van al cuerpo del dato y no al de doce píxeles
 * que le toca a una etiqueta de una palabra. */
.dejar-pendiente label {
  margin-top: 4px;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}
.dejar-pendiente button { align-self: flex-start; margin-top: 6px; }
/* El pie que dice qué **no** pasa al dejar pendiente: no se asienta nada y no se
 * toca ningún saldo. Es una pista y va al cuerpo de una pista. */
.dejar-pendiente .pista {
  margin: 6px 0 0;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

/* --- La conversación ------------------------------------------------------ */

/* Sin globitos de chat: son dos interlocutores y alcanza con el margen y el
 * color para saber quién dijo qué. */
.dialogo {
  list-style: none;
  margin: 0 0 calc(var(--paso) * 1.5);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--paso);
}
.dicho p { margin: 0; font-size: var(--t-cuerpo); line-height: 1.45; }
.dicho.operador p {
  padding: 9px 12px;
  background: hsl(var(--primary) / 0.16);
  border-radius: var(--radio);
  /* Lo que escribió el operador se muestra tal cual, saltos de línea incluidos:
   * es el texto que va a quedar como `prompt_original` (§3.5). */
  white-space: pre-wrap;
}
/* El turno del sistema **repite la frase de la propuesta**, y eso está bien: son
 * dos cosas distintas —lo que se dijo y lo que se decide—. Lo que las distingue
 * es el tamaño: acá `--t-dato`, porque es el eco de algo ya dicho; abajo, en la
 * propuesta, `--t-seccion`, porque es lo que se está por confirmar. Hasta acá
 * las dos se dibujaban con el mismo peso y había que leerlas para saber cuál era
 * cuál. */
.dicho.sistema p { padding: 2px 0; font-size: var(--t-dato); }

/* §9 — lo que le pasó a la conversación: que se dejó pendiente, que la retomó
 * otro. No lo dijo ni el operador ni el parser, así que no se puede dibujar como
 * ninguno de los dos: va centrado, chico y en cursiva, que es la forma en que se
 * lee un rótulo de tiempo en medio de un diálogo. */
.dicho.nota p {
  padding: 4px 0;
  font-size: var(--t-rotulo);
  font-style: italic;
  color: hsl(var(--muted-foreground));
  text-align: center;
}

/* Un turno que falló por un error de la API o de la red. Se sigue viendo —lo que
 * el operador escribió no se pierde— pero apagado y con la leyenda al pie: ese
 * texto no llegó al modelo y no forma parte del diálogo, así que dibujarlo igual
 * que el resto sería decir que se interpretó. El color no alcanza solo, por eso
 * además está escrito. */
.dicho.fallido.operador p {
  background: hsl(var(--muted) / 0.5);
  color: hsl(var(--muted-foreground));
}
.dicho.fallido .marca-fallido {
  margin-top: 3px;
  font-size: var(--t-rotulo);
  color: hsl(var(--destructive-text));
}

/* §4.11 — con qué comprobantes fue **este** mensaje. Va pegado abajo del texto y
 * no en la lista de arriba porque contesta una pregunta del diálogo: dos semanas
 * después, mirando de dónde salió un número, lo que hace falta saber es en qué
 * momento entró la foto, antes o después de la propuesta que se confirmó. */
.con-adjuntos {
  margin-top: 3px;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

/* La conversación vacía: la invitación a escribir y un ejemplo de qué escribir.
 * El ejemplo va en monoespaciada porque es una cita literal de lo que se tipea,
 * no una frase del sistema. */
.dialogo .vacio p { font-size: var(--t-cuerpo); }
.dialogo .ejemplo {
  margin-top: 6px;
  font-family: var(--mono);
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* Las opciones de una pregunta ambigua: un toque cada una, en columna para que
 * no haya que apuntar entre dos botones pegados. */
.opciones { display: flex; flex-direction: column; gap: 6px; margin-top: var(--paso); }
.opciones form { margin: 0; }
/* Y los candidatos del cliente que no está en el padrón, que son lo mismo con
 * otro nombre: una lista de clientes, un toque cada uno, y la conversación
 * sigue. Comparten el selector para que compartan la forma; si fueran dos
 * reglas, la segunda se despegaría de la primera en el primer retoque. */
.opciones button.opcion,
.candidatos-cliente button.opcion {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  width: 100%;
  min-height: var(--toque-grande);
  min-width: 0;
  text-align: left;
  padding: 8px 12px;
  font-size: var(--t-cuerpo);
  /* Dos renglones adentro de un botón: el nombre arriba y el detalle abajo. Sin
   * esto el `nowrap` de todo botón deja al detalle de un cliente saliéndose de
   * la pantalla en un celular. */
  white-space: normal;
}
.opciones .etiqueta,
.candidatos-cliente .etiqueta { display: block; font-weight: 600; }
.opciones .detalle,
.candidatos-cliente .detalle {
  display: block;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* --- El cliente que no está en el padrón (§9) ----------------------------- */

/* Va pegado a la pregunta que lo dejó abierto, entre el diálogo y el cuadro de
 * texto. Se dibuja como una tarjeta y no como un aviso suelto porque no es un
 * aviso: es una decisión que hay que tomar para poder seguir, y las tres salidas
 * viven adentro.
 *
 * En ámbar y no en rojo. No pasó nada malo —el parser hizo lo que tenía que
 * hacer— y no hay nada roto: falta una decisión. El rojo de esta pantalla está
 * reservado para lo que falló. */
.cliente-inexistente {
  position: relative;
  margin-bottom: calc(var(--paso) * 1.5);
  padding: 12px 14px;
  background: hsl(var(--warning) / 0.1);
  border: 1px solid hsl(var(--warning) / 0.5);
  border-left: 4px solid hsl(var(--warning));
  border-radius: var(--radio);
}
.cliente-inexistente .no-esta {
  margin: 0;
  font-size: var(--t-seccion);
  line-height: 1.3;
}
/* El nombre **tal como se tipeó**, en mono y entre comillas: es una cita de lo
 * que escribió el operador, no una etiqueta del sistema, y la diferencia importa
 * cuando lo que hay que decidir es justamente qué significa ese texto. */
.cliente-inexistente .tipeado {
  font-family: var(--mono);
  font-weight: 700;
}
.cliente-inexistente .tipeado::before { content: "«"; }
.cliente-inexistente .tipeado::after { content: "»"; }
.cliente-inexistente > .por-que {
  margin: 4px 0 0;
  color: hsl(var(--muted-foreground));
}

/* Las tres salidas, del mismo alto y el mismo cuerpo que las tres del diálogo:
 * ninguna se deduce de las otras dos —una escribe el padrón, otra lo escribe
 * marcado y la tercera no crea a nadie—, así que ninguna se dibuja más chica.
 * `flex-wrap` y `position: relative` son de los dos paneles, que caen en su
 * propio renglón debajo de la fila entera —el mismo truco de «Dejar pendiente»,
 * con la casilla clipeada posicionándose contra esta caja—. */
.salidas-cliente {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: center;
  margin-top: var(--paso);
}
/* En el celular las tres se apilan a ancho completo. El `<form>` del alta entra
 * en la misma regla y le viene bien: es un panel y también quiere el renglón
 * entero. */
.salidas-cliente > form,
.salidas-cliente > label { flex: 1 1 100%; }
.salidas-cliente > form > button {
  width: 100%;
  min-height: var(--toque-grande);
  padding: 0 20px;
  font-size: var(--t-cuerpo);
}

@media (min-width: 640px) {
  /* Con lugar vuelven a la fila. El `:not` deja afuera al panel del alta, que
   * sigue ocupando el renglón entero en cualquier ancho. */
  .salidas-cliente > form:not(.alta-cliente),
  .salidas-cliente > label { flex: 0 1 auto; }
  .salidas-cliente > form > button { width: auto; }
}

/* El alta que chocó contra un cliente que ya estaba (§9). En su propio renglón,
 * arriba del panel del alta que sigue abierto con lo escrito: la decisión que se
 * ofrece —usar ese, o es otra persona— es sobre ese formulario. El borde es el
 * del aviso entero, para que se lea como parte de él y no como otro cartel. */
.choque-alta {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: center;
  margin: 0;
  padding: 10px 12px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--warning) / 0.5);
  border-radius: var(--radio);
}
.choque-alta > .ya-existe {
  flex: 1 1 100%;
  margin: 0;
  font-size: var(--t-cuerpo);
}
.choque-alta > form { flex: 1 1 100%; margin: 0; }
.choque-alta > form > button { width: 100%; }
.choque-alta > .es-otra-persona { flex: 1 1 100%; }
.choque-alta > .pista {
  flex: 1 1 100%;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

@media (min-width: 640px) {
  /* Las dos salidas del choque, una al lado de la otra: elegir mal cuesta un
   * cliente duplicado en el padrón, así que se ven las dos juntas y del mismo
   * tamaño. La pista sigue en su renglón, debajo de las dos. */
  .choque-alta > form { flex: 0 1 auto; }
  .choque-alta > form > button { width: auto; }
  .choque-alta > .es-otra-persona { flex: 0 1 auto; }
}

/* Lo que se le dice a quien no tiene nivel para dar de alta: por qué falta un
 * botón, y que las otras dos salidas siguen siendo suyas. Sin esto, la pantalla
 * mostraría dos opciones donde hay tres y nadie sabría que falta una. */
.sin-nivel {
  flex: 1 1 100%;
  margin: 0;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* Los dos paneles. `flex-basis: 100%` para que caigan en su propio renglón,
 * abajo de la fila entera de botones y no adentro de la columna de uno. Cada uno
 * lo abre **su** casilla: el `~` alcanza a todos los hermanos posteriores, así
 * que con una clase compartida la del alta abriría también el de asociar. */
.alta-cliente,
.asociar-cliente {
  flex: 1 1 100%;
  display: none;
  min-width: 0;
  padding: 12px 14px;
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
}
/* **Interruptores 3 y 4 de 5.** Ver la nota del 2: no se tocan, y el resolvedor
 * de la suite no los ve. Los `display` de los dos son distintos a propósito
 * —`flex` el del alta, que adentro reparte campos; `block` el del buscador— y
 * hay un test que lee los dos valores sobre el texto de la hoja. */
.interruptor-alta:checked ~ .alta-cliente { display: flex; }
.interruptor-asociar:checked ~ .asociar-cliente { display: block; }

.alta-cliente {
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: flex-start;
}
.alta-cliente > .por-que,
.asociar-cliente > .por-que { flex: 1 1 100%; }
.alta-cliente > button { flex: 1 1 100%; }
/* Lo opcional, plegado: esto se completa parado frente a un cliente y lo que
 * hace falta para seguir son el nombre y el alias. Nada se pierde —adentro están
 * todos los campos del ABM— y nada estorba. */
.mas-datos { flex: 1 1 100%; min-width: 0; }
.mas-datos summary {
  cursor: pointer;
  padding: 6px 0;
  font-size: var(--t-dato);
  min-height: var(--toque);
  display: flex;
  align-items: center;
  gap: 6px;
}
.campos-opcionales {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso) 10px;
  padding-top: 6px;
}

/* El buscador del panel de asociar. Es un `GET` de verdad: sin JavaScript navega
 * a `/cargar?cliente_buscar=…` y el servidor devuelve la pantalla con este mismo
 * panel abierto. */
.buscador-cliente {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: var(--paso) 0;
}
/* Sin versales —regla 8—: lo que separa al rótulo de su campo son el cuerpo y el
 * color, igual que en el encabezado de una tabla. */
.buscador-cliente label {
  flex: 1 1 100%;
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
.buscador-cliente input { flex: 1 1 14ch; min-width: 0; }
.buscador-cliente button { flex: 0 0 auto; }

.candidatos-cliente {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.candidatos-cliente form { margin: 0; }
.candidatos-cliente .sin-candidatos {
  padding: 6px 0;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* --- La propuesta --------------------------------------------------------- */

/* Lo que se está por escribir en el libro: la caja que hay que poder verificar
 * de un vistazo. Desde 1440 es la columna ancha de las dos —8 de 12, porque la
 * tabla del asiento pide unos 680px— y **no** va fija: el `position: sticky` que
 * tuvo se sacó porque un panel más alto que la ventana dejaba las tres salidas
 * del otro lado del corte. El porqué entero está en `.zona-propuesta`, en el
 * esqueleto; acá sólo la corrección, para que este comentario no siga diciendo
 * que se queda quieta. */
.propuesta {
  padding: 14px 16px;
  min-width: 0;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-left: 4px solid hsl(var(--primary));
  border-radius: var(--radio);
  margin-bottom: calc(var(--paso) * 1.5);
}
/* La frase es lo que se verifica sin leer la tabla, así que es lo más grande de
 * la caja: `--t-seccion`, el escalón de un `h2`. Eran 21px sueltos, un tamaño
 * que no existía en ningún otro lado de la hoja. */
.propuesta .frase { margin: 0; font-size: var(--t-seccion); line-height: 1.35; font-weight: 500; }
/* «Compra cheque · 05/09/2026 · MELLADO → MELLADO JULIAN» dejó de ser una línea
 * con puntos medios y es una `dl.datos-clave` (contrato §5): pares rótulo/dato,
 * y el par que no tiene dato no se emite, con lo cual el punto huérfano —el
 * motivo por el que el separador había terminado en un `::before`— no existe
 * más. Acá sólo queda el aire que la separa de la frase. */
.propuesta .quien-es { margin: var(--paso) 0 0; }
/* Lo que se tipeó y a quién resolvió. Iba con `nowrap` para que el par no se
 * partiera en dos renglones; adentro de un `<dd>` de 165px en un celular eso lo
 * saca de la caja, y el par ya no se puede confundir con otro porque cada uno es
 * su propio ítem de la lista. Envuelve, y desde 640 —donde entra— vuelve a
 * leerse en un renglón. */
.propuesta .resuelto { white-space: normal; }

@media (min-width: 640px) {
  .propuesta .resuelto { white-space: nowrap; }
}

/* §9 — de dónde salió cada dato: del texto o de un comprobante.
 *
 * A la vista y no plegada, a diferencia de la tabla de movimientos. La tabla se
 * pliega porque la frase la resume; esto no se puede plegar porque es
 * exactamente lo que la frase **no** dice: «entraron $850.000» se lee igual si
 * ese número lo escribió una persona o lo leyó una máquina de una foto, y
 * confirmar sin saber cuál de las dos cosas fue es el agujero que esta lista
 * cierra.
 *
 * Cada renglón es una línea propia y no una fila de tabla: son tres o cuatro y
 * se leen de corrido, y en un celular una tabla de tres columnas se desplaza.
 *
 * **El origen se lee sin color**: lo dice la palabra al final de cada renglón.
 * El borde izquierdo es refuerzo, no el dato.
 *
 * Calificada con `.propuesta` a propósito: `.procedencia` es también el badge de
 * origen de un cierre de cotizaciones (contrato §12.8), que se llama
 * `.procedencia-cierre` desde el rediseño. Con el contenedor delante, el día que
 * alguien se olvide de renombrar el badge éste no se convierte en una columna. */
.propuesta .procedencia {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: var(--t-dato);
}
.propuesta .procedencia li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  padding-left: var(--paso);
  border-left: 3px solid hsl(var(--border));
}
/* El borde de la izquierda es lo único que distingue las tres procedencias sin
 * leer, y las tres se declaran: dejar una con el borde por defecto haría que el
 * día que cambie el token de `--border` el trío deje de leerse como trío.
 *
 * El saldo (§9) va con `--enfasis`, y no con el `--primary` del comprobante: son
 * dos fuentes que no son el texto, pero una la leyó el modelo en una foto y la
 * otra el sistema en la base, y se verifican contra cosas distintas. Como en las
 * otras dos, el borde refuerza y no informa: «leído el …» al final del renglón
 * lo dice en palabras. */
/* Calificadas con `.procedencia li` porque tienen que ganarle a esa regla de
 * contenedor (0,2,1), que pone el borde entero: escritas como `.propuesta
 * .de-comprobante` pesaban (0,2,0), perdían, y las tres filas salían con el
 * mismo borde gris —se vio en las capturas de §9, con el saldo—. */
.propuesta .procedencia li.de-comprobante { border-left-color: hsl(var(--primary)); }
.propuesta .procedencia li.de-texto { border-left-color: hsl(var(--border)); }
.propuesta .procedencia li.de-saldo { border-left-color: hsl(var(--enfasis)); }
.propuesta .dato-nombre { color: hsl(var(--muted-foreground)); }
/* El valor es el número que hay que verificar, así que va en la familia con la
 * que se comparan números en toda la aplicación. */
.propuesta .dato-valor { font-family: var(--mono); }
.propuesta .dato-fuente { color: hsl(var(--muted-foreground)); }

/* El plegado de los movimientos. El `<summary>` —su alto táctil, su color y su
 * cursor— es el mismo control que abre una fila de tabla y se dibuja con ella,
 * en la sección de tablas: es la misma pieza y no dos parecidas. */
.propuesta details { margin-top: var(--paso); min-width: 0; }

/* El título de cada bloque del asiento —Caja, Cuentas corrientes, Cuentas de
 * capital, Resultado—. Es un `<h4>` y se dibuja como un `<h4>`: el cuerpo y el
 * peso ya se los da la base. Se dibujaba en versales y con doce píxeles, o sea
 * con la forma de una etiqueta de campo, y así encabezaba una tabla leyéndose
 * como un rótulo de columna. Acá queda sólo el aire. */
.propuesta .titulo-bloque-movimientos { margin: var(--paso) 0 4px; }
.propuesta .titulo-bloque-movimientos:first-child { margin-top: 4px; }

/* El nombre del cliente y el saldo que le queda, arriba de su propia tabla. Es
 * el número que se quiere ver antes de confirmar, así que va en Space Mono como
 * cualquier importe y no como el nombre que lo antecede. */
.propuesta .grupo-cuenta-corriente {
  margin: 10px 0 0;
  font-size: var(--t-dato);
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: baseline;
}
.propuesta .nombre-cliente { font-weight: 500; }
/* La cifra en sí no lleva ninguna regla propia: `.num` (mono, tabular-nums) y
 * `.neg` (rojo cuando corresponde) son las reglas globales de cualquier importe,
 * y alcanzan. Ponerle acá un color de más le habría ganado a `.neg` por
 * especificidad y un saldo negativo hubiera dejado de leerse en rojo. */
.propuesta .saldo-resultante { color: hsl(var(--muted-foreground)); }

/* --- La tabla de movimientos de la propuesta ----------------------------- */

/* Las cuatro tablas del asiento son `table.datos` como cualquier otra tabla de
 * la aplicación —el mismo cuerpo, el mismo encabezado tenue, los mismos
 * importes— y viven adentro de un `.tabla-scroll`, que es el marco sin caja:
 * la caja ya la pone `.propuesta`.
 *
 * **A 390 dejan de ser tablas.** Siete columnas —cuenta, moneda, importe,
 * detalle, TC, a la referencia y clase— en 350px son siete columnas de cincuenta
 * píxeles donde no se lee ninguna. Lo que se ve es lo que identifica el
 * movimiento y lo que se vino a verificar: **la cuenta a la izquierda y el
 * importe a la derecha**, con el **detalle en una segunda línea a lo ancho**. La
 * moneda, el tipo de cambio, la columna «a la referencia» y la clase de
 * resultado vuelven a los 640, que es donde entran.
 *
 * Se hace con la fila convertida en grilla de dos columnas y no con un
 * `<details>` por fila como en los listados: acá la tabla **ya** está plegada
 * adentro de «Ver los N movimientos», y plegar dos veces lo mismo es esconder el
 * asiento detrás de dos toques justo antes de confirmarlo.
 *
 * El encabezado no se dibuja a 390: con dos columnas —un código de cuenta en
 * monoespaciada y un importe alineado a la derecha— el rótulo cuesta un renglón
 * por tabla y no dice nada que la celda no diga. Desde 640 vuelve, que es donde
 * hay siete columnas que sí hay que nombrar. */
.propuesta table.datos { display: block; }
.propuesta table.datos thead { display: none; }
.propuesta table.datos tbody,
.propuesta table.datos tfoot { display: block; }
.propuesta table.datos tbody tr {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 var(--paso);
  padding: 4px 0;
  border-bottom: 1px solid hsl(var(--border));
}
/* §12.2: todo ítem de grilla lleva `min-width: 0`. Sin él, una cuenta larga
 * —`CAJA.ARS.CHEQUES`— le pone a su pista el ancho del texto y la fila empuja al
 * documento entero, que es exactamente el desborde que el rediseño existe para
 * matar. El borde de la celda se va porque ahora lo lleva la fila. */
.propuesta table.datos tbody td { min-width: 0; border-bottom: none; }
/* **La cuenta envuelve, y corta por donde sea.** `min-width: 0` deja que la
 * pista se achique; lo que no achica es el texto, y toda celda de `table.datos`
 * va con `nowrap`. Medido a 390: la pista mide 148px, `CAJA.ARS.EFECTIVO` pide
 * 163 y un `CC.` de razón social —`CC.TRANSPORTES.DEL.SUR.SRL`, que es como
 * `clientes.codigo_de_cuenta` arma el código— pide 254, con la fila entera en
 * 303. O sea que el código se sale de su columna y se acuesta encima del
 * importe, que es el número que se vino a verificar.
 *
 * `anywhere` y no `break-word` —que es lo que llevan el `h1` y el `<dd>` de los
 * pares—: un código de cuenta no tiene un solo espacio donde cortar, así que la
 * regla que corta entre palabras no corta nunca. Se parte por donde caiga, que
 * en dos renglones de monoespaciada se sigue leyendo entero; salirse de la caja,
 * no. Desde 640 vuelven las siete columnas y con ellas el `nowrap` de siempre.
 *
 * **Y el `nowrap` de 640 no se baja a la base, aunque lo pida quien vea
 * `CC.MELLADO.JULI / AN` en una captura de 390.** Ya se propuso una vez, con el
 * argumento de que «la regla que impide partir el código a mitad de palabra vive
 * en la `@media` de 640, o sea que no alcanza al único ancho donde falta ancho».
 * Está al revés: el `nowrap` vive a 640 **porque** de ahí para arriba sobra
 * ancho, y bajarlo no crea ninguno. Lo que crea es el desborde de arriba, con
 * los números medidos: 254px de código en una pista de 148, encima del importe.
 * Un código partido en dos renglones se lee entero; uno acostado sobre la cifra
 * que se vino a verificar, no. Y no hay tercera opción: ningún valor de
 * `overflow-wrap` ni de `word-break` prefiere cortar en el punto —el algoritmo
 * de línea trata `X.Y` como una sola palabra—, así que «que corte en los puntos»
 * no se puede pedir desde la hoja. */
.propuesta table.datos tbody td.codigo {
  white-space: normal;
  overflow-wrap: anywhere;
}
/* El detalle, en el renglón de abajo y a lo ancho de los dos. */
.propuesta table.datos tbody td.detalle {
  grid-column: 1 / -1;
  max-width: none;
  padding-top: 0;
  color: hsl(var(--muted-foreground));
}
/* Las cuatro columnas que esperan a los 640. Se escriben `th` y `td` y no una
 * clase suelta: sin el tipo, el selector alcanzaría a cada `span` de adentro de
 * cada celda. */
.propuesta th.moneda, .propuesta td.moneda,
.propuesta th.tc, .propuesta td.tc,
.propuesta th.a-la-referencia, .propuesta td.a-la-referencia,
.propuesta th.clase-resultado, .propuesta td.clase-resultado { display: none; }

/* El total del asiento: el rótulo a la izquierda y la cifra contra el borde
 * derecho, en el mismo renglón. La última celda del `<tfoot>` está vacía —es la
 * columna de la clase, que a este ancho no existe— y sin sacarle el relleno
 * dibujaría una caja de veinte píxeles al lado del total. */
.propuesta table.datos tfoot tr {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 var(--paso);
}
/* «Suma a la referencia (tiene que dar 0)» es el rótulo y el número es el dato:
 * el `th` cede el ancho y su texto va pegado a la cifra que rotula. La
 * alineación va calificada con `.propuesta` y con la tabla porque
 * `table.datos th { text-align: left }` pesa (0,1,2) y le empataría por orden;
 * acá se cuenta la especificidad y no el lugar en el archivo. */
.propuesta table.datos tfoot th {
  flex: 1 1 12ch;
  min-width: 0;
  text-align: right;
  /* **Y envuelve, que es lo que le faltaba.** Con el `nowrap` que hereda de
   * `table.datos th` y el `min-width: 0` de acá arriba, el rótulo cedía por
   * debajo de su propio texto en vez de partirse: a 390 se leía «Suma a la
   * referencia (tiene que dar» y **se perdía el «0)»**, que es justamente el
   * número que la frase existe para nombrar. Con `normal` se parte en dos
   * renglones y la cifra del total se queda donde estaba. Pesa (0,1,4) contra el
   * (0,1,2) del `nowrap` de la tabla. Vale en todos los anchos porque sólo actúa
   * cuando no hay lugar: desde 640 el `tfoot` vuelve a ser una fila de tabla, el
   * `th` lleva `colspan="5"` y no envuelve nada. */
  white-space: normal;
}
.propuesta table.datos tfoot td { flex: 0 1 auto; min-width: 0; }
.propuesta table.datos tfoot td:last-child { padding: 0; }
/* Una suma distinta de cero es un asiento que el motor va a rechazar. Se marca
 * acá para que se vea **antes** de tocar Confirmar, no después. Pesa (0,2,2) y
 * por eso le gana al color de rótulo del `tfoot`, que pesa (0,1,3). */
.propuesta tfoot tr.descuadre td,
.propuesta tfoot tr.descuadre th { color: hsl(var(--destructive-text)); }

/* A este ancho la tabla no desborda —no hay ninguna columna a la derecha que
 * alcanzar— así que la barra de scroll siempre visible, que es la regla base de
 * los marcos, dibujaría una barra que no desplaza nada. La sombra de «hay más»
 * **no hace falta apagarla**: se dibuja con dos tapas `background-attachment:
 * local` que sólo se corren cuando hay contenido escondido, así que sin desborde
 * se apaga sola. Es la ventaja de esa técnica sobre una clase puesta a mano. */
.propuesta .tabla-scroll { overflow-x: visible; }

/* Y con el marco sin desplazamiento, la celda de resultado tiene que poder
 * cortar. `table.datos td` es `nowrap` —lo que hace que una columna de importes
 * se lea en línea— y la celda del resultado lleva dos cosas: el importe y la
 * palabra que dice de qué lado está, «(ganancia)». Juntas y sin poder cortar
 * medían 148px de contenido en una celda de una tarjeta de 303, y **estiraban el
 * documento entero a 418px en una ventana de 390**: la página se desplazaba de
 * costado y el gesto de scroll enganchaba para el lado equivocado.
 *
 * La palabra baja a su propio renglón, debajo del número. Es además como se lee
 * mejor: el importe es el dato y la palabra lo califica. Desde 640 vuelve a la
 * misma línea, que es donde entra. Está medido con el navegador, no deducido. */
.propuesta .sentido-resultado { display: block; }

@media (min-width: 640px) {
  /* Y vuelve a ser una tabla, con sus siete columnas y su marco que se desplaza
   * si hace falta. */
  .propuesta table.datos { display: table; }
  .propuesta table.datos thead { display: table-header-group; }
  .propuesta table.datos tbody { display: table-row-group; }
  .propuesta table.datos tfoot { display: table-footer-group; }
  .propuesta table.datos tbody tr,
  .propuesta table.datos tfoot tr { display: table-row; padding: 0; border-bottom: none; }
  .propuesta table.datos tbody td { border-bottom: 1px solid hsl(var(--border)); }
  /* Con la columna propia el código entra entero, y una tabla de siete columnas
   * con una celda que envuelve descalza las filas entre sí. */
  .propuesta table.datos tbody td.codigo {
    white-space: nowrap;
    overflow-wrap: normal;
  }
  .propuesta table.datos tbody td.detalle {
    max-width: 20ch;
    padding-top: 4px;
    color: inherit;
  }
  /* **El presupuesto de ancho de las siete columnas, y es la deuda que dejó el
   * salto de 13 a 15px.** La tabla del asiento no vive en la pantalla sino en la
   * columna de la propuesta —el ancho entero hasta 1440, y ocho de doce de ahí
   * para arriba: unos 860px de marco a 1024 y 759 a 1536, descontando el relleno
   * del bloque; los 654 que tenía con siete de doce son los que dejaban a
   * `Resultado` cortado, y por eso el reparto de la familia dice ocho—, y con el
   * cuerpo nuevo la fila pasó a pedir 767: la columna `Resultado` quedó fuera
   * del marco en los dos anchos,
   * cuando **antes entraban las siete**. La tipografía no se toca —la decisión
   * es correcta y está justificada en el contrato §2—; lo que se ajusta es el
   * presupuesto, y en una tabla de siete columnas el aire es lo primero que
   * sobra: seis píxeles por lado en vez de diez son 56 sobre siete columnas,
   * casi el ancho entero de la que se estaba perdiendo, y el detalle acotado a
   * veinte caracteres aporta los que faltan. Los seis son además los mismos que
   * la regla base de `table.datos` usa en el celular, así que el número no es
   * nuevo. Pesa (0,2,2) contra el (0,1,2) de `table.datos th/td`. */
  .propuesta table.datos th,
  .propuesta table.datos td { padding-left: 6px; padding-right: 6px; }
  .propuesta th.moneda, .propuesta td.moneda,
  .propuesta th.tc, .propuesta td.tc,
  .propuesta th.a-la-referencia, .propuesta td.a-la-referencia,
  .propuesta th.clase-resultado, .propuesta td.clase-resultado { display: table-cell; }
  .propuesta .tabla-scroll { overflow-x: auto; }
  .propuesta .sentido-resultado { display: inline; }
}

/* --- Los cheques que entran, y los términos ------------------------------- */

/* La lista de papeles que entran con la operación. Era **una línea
 * monoespaciada con cinco puntos medios** —«GALICIA 00012345 Físico · nominal
 * 3.500.000,00 · fecha de pago 15/09/2026 · entra a 3.245.000,00 (En cartera) ·
 * en Depositado en Macro»— que a 390 envolvía en tres renglones y no se podía
 * leer de ninguna manera. Ahora cada cheque es un ítem con su `dl.datos-clave`
 * adentro: nominal, fecha de pago, a cuánto entra y en qué estado son cuatro
 * datos distintos, y el paréntesis que ataba los dos últimos se va con el resto.
 *
 * Calificada con `.propuesta`: `.cheques` es también el contenedor de las filas
 * del cotizador, que es un `flex` en columna con seis píxeles de hueco. Sin el
 * contenedor delante, aquella regla le da la forma a ésta. */
.propuesta .cheques {
  list-style: none;
  margin: var(--paso) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--paso);
}
.propuesta .cheques > li {
  min-width: 0;
  padding-left: var(--paso);
  border-left: 3px solid hsl(var(--border));
}
/* «Términos: 5+2.5 (interés más comisión)»: el pie de la propuesta. Igual que
 * arriba, calificado con el contenedor porque `.terminos` es además la fila de
 * campos del cotizador; el `display: block` es lo que deshace ese `flex` y está
 * escrito acá desde antes del rediseño, con este mismo motivo. */
.propuesta .terminos {
  display: block;
  margin: 6px 0 0;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* --- Las tres salidas del diálogo ---------------------------------------- */

/* Confirmar, Dejar pendiente y Cancelar, en ese orden y en la misma fila.
 *
 * **Mismo peso visual entre las tres.** Las tres son salidas y ninguna se deduce
 * de las otras dos —confirmar asienta, cancelar cierra sin asentar, dejar
 * pendiente no cierra nada—, así que las tres miden lo mismo de alto, tienen la
 * misma forma y el mismo cuerpo de letra. Lo único que las distingue es el
 * color: Confirmar lleva el primario porque es la que escribe en el libro, y lo
 * lleva **sin** medir más que las otras. Mientras una de las tres fue un renglón
 * de texto plegado, la pantalla afirmaba que las salidas eran dos.
 *
 * **Cómo se apilan en un celular.** Una columna, las tres del ancho de la
 * pantalla y en el orden en que están en el DOM: Confirmar, Dejar pendiente,
 * Cancelar. Cancelar va última y con el doble de separación arriba. En el ancho
 * de un pulgar, dos botones pegados se aprietan por error, y de los tres el
 * único que tira trabajo a la basura es ése: la separación no es aire, es lo que
 * evita que el envión del dedo que iba a «Dejar pendiente» termine cancelando la
 * operación. Las dos que se quieren tocar quedan arriba y juntas.
 *
 * Se apilan con `flex-basis: 100%` sobre una fila que envuelve y no con
 * `flex-direction: column`, por lo mismo que en `.salidas`: en columna ese mismo
 * `100%` mediría **alto**, y el panel de «Dejar pendiente» —que lo necesita para
 * caer debajo de la fila entera— pediría el alto del contenedor.
 *
 * `flex-wrap` y `position: relative` son de ese panel: sus dos campos caen en el
 * renglón de abajo, y la casilla clipeada que los abre se posiciona contra esta
 * fila y no contra la página. */
.decidir {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  margin-top: calc(var(--paso) * 1.5);
  align-items: center;
}
.decidir form { margin: 0; }
/* El `:not` deja afuera al panel de campos, que también es un `<form>` de esta
 * fila pero no es una salida: su botón «Dejar pendiente» es el que **manda** el
 * formulario, y ahí adentro vale el alto normal de un control. */
.decidir > form:not(.dejar-pendiente),
.decidir .abrir-pendiente { flex: 1 1 100%; }
.decidir > form:not(.dejar-pendiente) > button { width: 100%; }
.decidir form:not(.dejar-pendiente) > button,
.decidir .abrir-pendiente {
  min-height: var(--toque-grande);
  font-size: var(--t-cuerpo);
  padding: 0 20px;
}
.decidir .cancelar { margin-top: var(--paso); }

@media (min-width: 640px) {
  .decidir > form:not(.dejar-pendiente),
  .decidir .abrir-pendiente { flex: 0 1 auto; }
  .decidir > form:not(.dejar-pendiente) > button { width: auto; }
  /* Confirmar se estira con lo que sobra: es la única de las tres que se busca
   * sin mirar, y en una pantalla ancha eso es ancho, no alto. El botón llena su
   * formulario, que es lo que hace que ese ancho de más se pueda tocar. */
  .decidir > form:first-child:not(.dejar-pendiente) { flex: 1 1 12ch; }
  .decidir > form:first-child:not(.dejar-pendiente) > button { width: 100%; }
  /* En fila ya no hace falta separarla: el envión del dedo es un problema del
   * pulgar y no del mouse. */
  .decidir .cancelar { margin-top: 0; }
}

/* --- Los cheques que entran sin identificar (§4.9, §9) -------------------- */

/* En ámbar y con el mismo borde izquierdo que el aviso del cliente inexistente,
 * y por la misma razón: no pasó nada malo —un cheque entra sin banco y sin
 * número todos los días— pero falta una decisión que hay que tomar acá. El rojo
 * de esta pantalla sigue reservado para lo que falló.
 *
 * Va **adentro** de `.propuesta`, entre lo que hay que verificar y la fila que
 * decide, así que el margen inferior lo separa de los botones y no de la
 * pantalla. */
.cheques-a-cargar {
  margin: var(--paso) 0;
  padding: 12px 14px;
  background: hsl(var(--warning) / 0.1);
  border: 1px solid hsl(var(--warning) / 0.5);
  border-left: 4px solid hsl(var(--warning));
  border-radius: var(--radio);
}
.cheques-a-cargar .sin-identificar {
  margin: 0;
  font-size: var(--t-seccion);
  line-height: 1.3;
}
.cheques-a-cargar > .por-que { margin: 4px 0 0; color: hsl(var(--muted-foreground)); }

/* Las dos salidas, del mismo alto y el mismo cuerpo, igual que las tres del
 * cliente inexistente: ninguna se deduce de la otra. `position: relative` y
 * `flex-wrap` son del panel, que cae en su propio renglón debajo de las dos —el
 * mismo truco de la casilla clipeada—. */
.salidas-cheques {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: center;
  margin-top: var(--paso);
}
.salidas-cheques > form,
.salidas-cheques > label { flex: 1 1 100%; }
.salidas-cheques > form > button {
  width: 100%;
  min-height: var(--toque-grande);
  padding: 0 20px;
  font-size: var(--t-cuerpo);
}

@media (min-width: 640px) {
  .salidas-cheques > form:not(.cargar-cheques),
  .salidas-cheques > label { flex: 0 1 auto; }
  .salidas-cheques > form > button { width: auto; }
}

/* --- El formulario de cheques -------------------------------------------- */

/* El panel: un `<fieldset>` por cheque. `flex-basis: 100%` para que caiga en su
 * propio renglón, debajo de los dos botones y no adentro de la columna de uno. */
.cargar-cheques {
  flex: 1 1 100%;
  display: none;
  min-width: 0;
  padding: 12px 14px;
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
}
/* **Interruptor 5 de 6.** Ver la nota del 2. */
.interruptor-cheques:checked ~ .cargar-cheques { display: block; }
.cargar-cheques > .por-que { margin: 0 0 var(--paso); color: hsl(var(--muted-foreground)); }

/* **Interruptor 6 de 6** — §4.19: el banco que falta, dado de alta sin salir del
 * formulario de cheques. Mismo panel y mismo mecanismo que el alta de cliente
 * del diálogo: la casilla clipeada, el `<label>` haciendo de botón y el `~` que
 * muestra el formulario hermano. Va afuera del `<form>` de los cheques porque un
 * formulario no anida otro, así que es hermano y no descendiente. */
.alta-banco {
  flex: 1 1 100%;
  display: none;
  min-width: 0;
  margin-top: var(--paso);
  padding: 12px 14px;
  background: hsl(var(--popover));
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
}
.interruptor-banco:checked ~ .alta-banco { display: flex; flex-wrap: wrap; gap: var(--paso) 10px; }
.alta-banco > .por-que { flex: 1 1 100%; margin: 0 0 var(--paso); color: hsl(var(--muted-foreground)); }

/* Un cheque por renglón. Es una grilla de una sola pista para poder pasar a dos
 * sin tocar nada más que el `grid-template-columns`, que es lo que hace la única
 * `@media` de 1900 de toda la hoja, al final de esta sección. */
.filas-cheque {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--paso);
}
/* Un `<fieldset>` por cheque y no una fila de tabla. Siete campos no entran en
 * una fila de celular, y una tabla que se desplaza al costado obliga a tipear el
 * número de un cheque sin ver de cuál es. Así, cada papel es un bloque que se
 * apila solo en pantalla angosta y se acomoda en columnas cuando hay lugar.
 *
 * `min-width: 0` porque es ítem de grilla (§12.2): sin él, el `<datalist>` de
 * bancos y los nombres largos de un firmante le dan el ancho a la pista. */
.fila-cheque {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso) 10px;
  min-width: 0;
  margin: 0;
  padding: 10px 12px 12px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
}
/* «Cheque 1», «Cheque 2»: sin versales, como todo rótulo desde el rediseño. */
.fila-cheque legend {
  padding: 0 6px;
  font-size: var(--t-rotulo);
  font-weight: 600;
  color: hsl(var(--muted-foreground));
}
/* §9 — la fila que el guardado rechazó. El borde y el tinte hacen lo que el
 * texto de arriba no puede con nueve cheques en pantalla: decir **cuál**.
 *
 * Borde de 2px y no sólo color de fondo: el tinte solo desaparece en un monitor
 * mal calibrado, y ésta es la marca que decide a qué recuadro volver. El rótulo
 * de al lado del número la repite en palabras, por lo mismo que la barra de
 * 4px de `.error`: en blanco y negro tiene que seguir leyéndose. */
.fila-cheque.con-error {
  border-width: 2px;
  border-color: hsl(var(--destructive-text) / 0.8);
  background: hsl(var(--destructive) / 0.07);
}
.fila-cheque.con-error legend { color: hsl(var(--destructive-text)); }
.fila-cheque .marca-error {
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.2);
  color: hsl(var(--destructive-text));
  font-weight: 600;
}
/* El error **repetido** al pie del formulario, junto al botón que se apretó: el
 * de cheques y el del arqueo, que son los dos que miden varias pantallas.
 *
 * Lleva su propia clase y no `.error`, y no es cosmética: «una pantalla, un
 * error» es un invariante que los tests verifican (`tests/html.py`, `uno`), y
 * esto **no es un segundo error** sino el mismo dicho donde está el dedo.
 * Pintarlo igual es todo lo que tiene que compartir.
 *
 * Pegado a los botones —`margin-bottom` chico— porque lo que tiene que quedar
 * claro es que contesta a ese botón, y no que es un cartel más de la página. */
.error-al-pie { margin-bottom: 6px; }
/* **Un campo por línea a 390** lo da `.campo` con su `flex: 1 1 100%`, que es la
 * regla base de todo formulario: acá no hace falta decir nada. */

@media (min-width: 640px) {
  /* **Cuatro campos por fila.** Es la única forma del sistema en la que el
   * ancho del campo **no** sale del ancho de su dato, y tiene motivo: acá se
   * tipean cinco o seis papeles seguidos mirando el montón que se tiene en la
   * mano, y lo que hace rápido ese trabajo es que el importe del cheque 3 esté
   * donde estaba el del cheque 2. Con anchos por dato eso pasa igual mientras
   * los campos sean los mismos, y deja de pasar en cuanto uno de los `<input>`
   * de una fila crece —el banco, que se estira— y arrastra al resto del renglón.
   *
   * Cuatro y no seis: son importe, fecha, banco y número, que es lo que se lee
   * del frente del papel de un vistazo; el CUIT y el firmante caen al renglón de
   * abajo solos. Pesa (0,2,0) y por eso le gana al `flex: 0 1 auto` que la
   * sección de formularios le pone a `.campo` desde este mismo ancho. */
  /* **Y ningún campo por debajo del ancho de su dato.** Los cuatro por fila son
   * un porcentaje de la columna de la propuesta, y esa columna no mide lo mismo
   * a 1024 que a 1536: un cuarto de la de 1024 son unos 110px y el importe
   * formateado —`$ 2.000.000,00`— pide diecisiete caracteres, así que perdía los
   * centavos (`$ 2.000.000,`). Los diecisiete son los mismos del contrato §2c y
   * los mismos que la tabla de anchos por dato de la sección de formularios le
   * da a un importe; lo que faltaba era que llegaran hasta acá, donde el ancho
   * lo decide el reparto y no el dato.
   *
   * Con el piso puesto, la fila envuelve a dos columnas donde no entran cuatro,
   * y eso **no rompe lo que el reparto compra**: el importe del cheque 3 sigue
   * cayendo donde cayó el del cheque 2, que es lo único que hace rápido tipear
   * seis papeles seguidos. Es la excepción declarada al `min-width: 0` de §12.2:
   * acá el mínimo no sale del contenido —que es lo que aquella regla evita— sino
   * de una medida escrita, y el contenedor envuelve en vez de desbordar. */
  .fila-cheque .campo { flex: 1 1 calc(25% - var(--paso)); min-width: 17ch; }
  .fila-cheque .campo.ancho { flex: 1 1 calc(50% - var(--paso)); }
  /* Y el control llena su campo, que es lo que hace que las cuatro columnas
   * quieran decir algo. Calificado con `.campo` —(0,2,1)— para ganarle a la
   * tabla de anchos por dato de la sección de formularios, que pesa (0,1,1).
   *
   * **Los dos `:not` no son cautela: son la casilla de «E-cheq».** Es un
   * `.campo` más de la fila —`.casilla-echeq`, con su `<input type="checkbox">`
   * adentro— y este selector pesa exactamente lo mismo (0,2,1) que el
   * `input[type="checkbox"]:not(.solo-lectores)` de la sección de formularios,
   * que es el que le da los 18×18: a igualdad gana el que viene después en el
   * archivo, y éste viene después. Sin las negaciones, el cuadradito de tildar
   * «E-cheq» salía de 90px de ancho a 640 y de 148 a 1024, con 18 de alto. Es la
   * misma trampa que allá se anota sobre `.campo.ancho`, en la otra pantalla que
   * tiene una casilla adentro de un campo. */
  .fila-cheque .campo input:not([type="checkbox"]):not([type="radio"]),
  .fila-cheque .campo select { inline-size: 100%; max-inline-size: none; }
}

/* «Guardar» va primero en el DOM —es el botón por defecto del formulario, así
 * que un Enter en un campo guarda y no agrega una fila— y `order` lo manda a la
 * derecha, que es donde termina el recorrido de la mano.
 *
 * **A 390 las dos acciones van fijas abajo, apoyadas sobre la barra de
 * navegación.** Con cinco cheques el formulario mide más de cuatro mil píxeles
 * de alto: «Guardar los cheques» quedaba al final de esa página y para agregar
 * la fila siguiente había que scrollear hasta el fondo, tocar, y volver a subir.
 * Fijas, las dos están siempre debajo del pulgar, que es donde tienen que estar
 * en el único formulario largo que se completa parado.
 *
 * El `bottom` cuenta la barra inferior más el área segura del teléfono: apoyadas
 * **sobre** la barra y no debajo de ella. El margen negativo a los costados las
 * lleva hasta los bordes del panel, para que el formulario no se vea pasar por
 * el costado de la banda al scrollear.
 *
 * El `env()` va con su respaldo en `0px`, igual que los tres del esqueleto y por
 * el mismo motivo: un navegador que no conozca la variable invalida el `calc()`
 * **entero**, y entonces no queda un `bottom` de más o de menos sino ninguno.
 * Con `bottom: auto` la banda deja de pegarse y los dos botones vuelven al final
 * de una página de cuatro mil píxeles, que es justo el defecto que esta regla
 * existe para arreglar, y sólo en el teléfono, que es donde importa.
 *
 * Las dos en **dos columnas iguales** y no en una fila que envuelve: medido a
 * 390, «+ Otro cheque» y «Guardar los cheques» piden siete píxeles más de los
 * que hay, así que una fila se parte en dos renglones de botones y la banda se
 * come el doble de pantalla. Con dos pistas y el rótulo envolviendo —«Guardar
 * los / cheques»— la banda es siempre un renglón, y de alto fijo: en una
 * pantalla que se usa con una mano, que las dos acciones estén siempre en el
 * mismo lugar vale más que el renglón único del rótulo. */
.acciones-cheques {
  position: sticky;
  bottom: calc(var(--barra) + env(safe-area-inset-bottom, 0px));
  z-index: 10;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--paso);
  margin: var(--paso) -14px -12px;
  padding: var(--paso) 14px;
  background: hsl(var(--popover));
  border-top: 1px solid hsl(var(--border));
}
/* `min-width: 0` porque son ítems de grilla (§12.2), y `white-space: normal`
 * porque un botón va con `nowrap` en toda la aplicación y acá eso es justamente
 * lo que le impide entrar en su columna. */
.acciones-cheques button { min-width: 0; white-space: normal; }
/* **Y el relleno lateral del principal baja de 24 a 12 acá adentro**, que es lo
 * que hace verdad el «Guardar los / cheques» que la regla de arriba da por
 * hecho al aceptar que el rótulo envuelva —la banda siempre fue un renglón; el
 * rótulo era el que se partía en tres y no en dos, y por eso la banda medía
 * medio centímetro más que lo escrito—. Medido sobre
 * `cargar_cheques_390_claro.png`: la columna mide 129px y `button.principal`
 * gasta 24 por lado, o sea **48 de relleno contra 79 de rótulo**; con 79 no
 * entra «Guardar los» —el rótulo pide 87 en su primera línea— y se dibuja
 * «Guardar / los / cheques» en **tres** renglones, cuando lo que esta regla
 * promete son dos. Con doce por lado quedan 103 y la primera línea entra.
 *
 * El relleno no dibuja nada en esta banda: el botón ocupa su columna entera, así
 * que lo único que hace es comerle ancho al rótulo, y el objetivo táctil lo da
 * el `min-height`. Desde 640 el botón vuelve a medir lo que mide su rótulo y le
 * vuelven los 24, abajo. Pesa (0,2,0) contra el (0,1,1) de `button.principal`,
 * que es la cuenta de siempre: dos clases le ganan a una clase y un tipo. */
.acciones-cheques .principal { min-height: var(--toque-grande); padding: 0 12px; }
.acciones-cheques .agregar-fila { order: -1; }

@media (min-width: 640px) {
  /* Desde acá el formulario entra en pantalla y la banda fija deja de tener
   * sentido: vuelve a ser el pie del panel, con «Guardar» a la derecha y cada
   * botón midiendo lo que mide su rótulo, en un renglón. */
  .acciones-cheques {
    position: static;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    margin: var(--paso) 0 0;
    padding: 0;
    background: none;
    border-top: none;
  }
  .acciones-cheques button { white-space: nowrap; }
  /* Y con el botón midiendo su rótulo, el relleno vuelve a ser el de cualquier
   * acción principal de la aplicación: acá sí dibuja, porque es lo que separa la
   * palabra del borde de un botón que ya no ocupa media banda. */
  .acciones-cheques .principal { padding: 0 24px; }
  .acciones-cheques .agregar-fila { margin-right: auto; }
}

/* **La única `@media` por encima de 1440 de toda la hoja, y va con su motivo.**
 * Dos cheques por fila piden 1100px de columna. En un monitor de 1536 la
 * propuesta mide unos 820 —es la columna de 8 de 12, y adentro tiene todavía el
 * relleno del aviso ámbar y el del panel—, así que a ese ancho la segunda fila
 * de campos se parte y se tipea peor que con un cheque por fila. Recién a partir
 * de 1900 la columna da los 1100, y ahí sí: con seis papeles en la mano, dos
 * `<fieldset>` por renglón son la mitad de scroll.
 *
 * No hay ningún otro corte en 1900 y no tiene que haberlo: éste existe porque
 * se midió una columna concreta, no porque haya un breakpoint de monitor grande. */
@media (min-width: 1900px) {
  .filas-cheque { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- El cuadro de texto --------------------------------------------------- */

/* Grande y último, donde queda el pulgar. Sigue disponible con una propuesta en
 * pantalla: corregir también es una forma de contestarle, y se corrige
 * escribiendo. */
.escribir { display: flex; flex-direction: column; gap: 4px; }
/* La etiqueta se ve, y sin versales: un `placeholder` que hace de etiqueta
 * desaparece al escribir, que es justo cuando hay que verificar qué se tipeó. */
.escribir label {
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
.escribir .pista { font-size: var(--t-rotulo); color: hsl(var(--muted-foreground)); margin: 0; }
.escribir textarea {
  /* **`--t-cuerpo` y no 17px.** Eran 17 sueltos por el zoom que iOS hace al
   * enfocar un campo de menos de 16, y 16 ya lo evita: el paso de la escala
   * existe justamente para esto, y un tamaño suelto en la pantalla más
   * importante es el que después se copia a las demás.
   *
   * `font-variant-numeric` escrito acá aunque el documento entero ya lo pida:
   * los controles heredan su tipografía con `font: inherit`, y el atajo `font`
   * **resetea** todo lo que no nombra, `tabular-nums` incluido. Adentro de este
   * cuadro es donde se tipean los importes. */
  font-variant-numeric: tabular-nums;
  /* Cinco renglones y no cuatro: la operación real —«MELLADO ENTREGA 2 CHEQUES
   * … Y RETIRA EFVO …»— ocupa cuatro en un celular, y con el cuadro justo del
   * tamaño del texto no se ve lo que se escribió antes de mandarlo. Se calcula
   * del cuerpo y del interlineado para que siga siendo cinco el día que la
   * escala cambie. */
  min-height: calc(var(--t-cuerpo) * 1.45 * 5 + 24px);
}

/* La fila de abajo del cuadro: el micrófono, lo que está pasando, e interpretar.
 * El micrófono queda a la izquierda porque es una forma de escribir en el cuadro
 * y no una acción sobre la pantalla; la acción principal, a la derecha.
 *
 * En el celular se apila y los dos controles ocupan el ancho: `align-self:
 * stretch` y no `flex-start`, porque adentro de una fila `stretch` estira el
 * alto y no el ancho, y el botón terminaba midiendo su texto. */
.acciones-escribir {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--paso);
  margin-top: 4px;
}
.escribir button {
  align-self: stretch;
  min-height: var(--toque-grande);
  font-size: var(--t-cuerpo);
  padding: 0 28px;
}

@media (min-width: 640px) {
  .acciones-escribir { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .escribir button { align-self: flex-start; }
}

/* §8 y §9 — los dos caminos de carga de cheques, arriba del cuadro de texto.
 * Mismo panel que el bloque del cliente inexistente y el de los cheques a
 * cargar: son de la misma familia —lo que se puede hacer con esta operación,
 * pegado a la pregunta que lo dejó abierto— y dibujarlos distinto sería decir
 * que son cosas distintas.
 *
 * Reusa `.salidas-cheques` para la fila de acciones, que es la misma que usa el
 * formulario de cheques; lo único propio es el marco. */
.caminos-cheques {
  margin-bottom: var(--paso);
  padding: 10px 12px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
/* El total y la cantidad, en fila desde la tablet y apilados en el celular, que
 * es lo que hace cualquier formulario de esta hoja. El `flex-end` alinea el
 * botón con la base de los dos campos y no con su rótulo. */
.total-cheques {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--paso);
}
.total-cheques .campo { flex: 0 0 auto; }
/* La salida del cotizador de vuelta a la operación. Separada del cuadro de
 * arriba y de la nota de abajo: es una acción y no un renglón de la tabla. */
.volver-a-la-carga { margin: var(--paso) 0; }

/* --- Dictar, y el estado de lo que está escuchando ------------------------ */

/* **Nace apagado y sólo lo enciende `gdv.js` cuando el navegador soporta la Web
 * Speech API**, poniéndole `data-dictado` al `<html>`. Sin JavaScript —o en un
 * navegador que no la tenga— el atributo no aparece nunca, este `display: none`
 * se queda puesto y el botón no existe para nadie: ni para el mouse, ni para el
 * tabulador, ni para un lector de pantalla. Un botón que no hace nada es peor
 * que ninguno, y la pantalla anda igual escribiendo, que es como se cargó
 * siempre. */
.dictar { display: none; }
:root[data-dictado] .dictar { display: inline-flex; }
.dictar .rotulo-dictar { display: inline; }

/* El icono es un **micrófono**, y cambia con el estado: en reposo el micrófono
 * solo, mientras toma el micrófono con dos ondas a los costados. Antes era un
 * punto de 10×10, que decía que algo pasaba y no qué: en un botón que abre el
 * micrófono del navegador, el dibujo tiene que ser el objeto.
 *
 * SVG en línea y no un emoji: un emoji se dibuja distinto en cada sistema y no
 * respeta el color del tema; un SVG hereda `currentColor` y se tiñe solo cuando
 * el botón pasa a rojo. Los dos vienen siempre en el HTML y acá se muestra el
 * que corresponde: intercambiar marcado desde JavaScript sería pedirle al script
 * que sepa dibujar, y este archivo no lo hace en ningún otro lado.
 *
 * El color **no está solo**, que es la regla 5 de esta hoja: el icono cambia de
 * forma, el rótulo pasa a «Detener» y el texto de al lado dice qué se está
 * escuchando. Tres señales, ninguna sólo de color. */
.dictar .micro-escuchando { display: none; }
.dictar.escuchando .micro-reposo { display: none; }
.dictar.escuchando .micro-escuchando { display: inline-block; }
.dictar.escuchando { border-color: hsl(var(--destructive-text)); }
.dictar.escuchando .icono { color: hsl(var(--destructive-text)); }

/* Lo que se está reconociendo, antes de que quede firme. Envuelve: una operación
 * dictada es larga.
 *
 * **El `flex-basis` de 12ch vive en la `@media` y no acá**, que es la misma
 * trampa de `.salidas` y de `.decidir` vista del otro lado. La fila de abajo del
 * cuadro es una **columna** en el celular —los dos controles a ancho completo—,
 * así que el eje principal es el vertical y ahí `12ch` no mide ancho sino
 * **alto**: este `<span>` está vacío mientras nadie dicta —la plantilla lo dice:
 * «vacío no ocupa lugar»— y con la base afuera medía 96px, que llevaban la fila
 * de 56 a 152 medido a 390: cien píxeles de nada justo debajo del cuadro que
 * tiene que estar a la vista. Desde 640 la fila es fila, y recién ahí «lo que
 * sobra entre los dos botones» quiere decir algo. */
.dictado-estado {
  min-width: 0;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

@media (min-width: 640px) {
  .dictado-estado { flex: 1 1 12ch; }
}

/* La procedencia de una valuación cruzada, en el renglón de su posición. En
 * bloque y antes del motivo: es un dato del número de al lado —con qué paridad y
 * de cuándo— y no una aclaración al pie. No es de esta pantalla; está acá porque
 * es donde se escribió y moverla no le agrega nada a nadie. */
.cruce { display: block; }

/* --- Adjuntos (§4.11) ----------------------------------------------------- */

.adjuntos { display: flex; flex-direction: column; gap: var(--paso); }

/* En el diálogo de carga el bloque va plegado adentro de un `<details class="alta
 * adjuntar">`: lo que se mira en esa pantalla es lo que se está cargando, y la
 * foto es algo que se agrega. La caja y el `<summary>` de 44px se los da `.alta`,
 * que es el mismo plegado de las ocho altas del sistema. */
.adjuntar { margin-bottom: var(--paso); }

/* Una tarjeta por comprobante. En el celular, una por renglón: dos miniaturas de
 * 56px con un nombre de archivo de WhatsApp al lado no entran en 350px. */
.lista-adjuntos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--paso);
}

/* La miniatura a la izquierda y los datos a la derecha: es una lista para
 * reconocer un comprobante de un vistazo, no una galería. */
.adjunto {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 6px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}

@media (min-width: 640px) {
  /* Desde acá entran de a dos. Dos y no «las que quepan»: un `auto-fill` con un
   * mínimo en píxeles es una pista que puede desbordar su contenedor —§12.2— y
   * acá la lista vive adentro de un panel plegado que a 1440 mide media
   * columna. Con dos pistas de `minmax(0, 1fr)` la tarjeta nunca es más ancha
   * que el lugar que hay, en ninguno de los cuatro anchos. */
  .lista-adjuntos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.ver-adjunto { display: block; flex: 0 0 auto; line-height: 0; }

/* Cuadrada y recortada: los comprobantes vienen en cualquier proporción y una
 * lista con miniaturas de alturas distintas no se recorre. */
.miniatura {
  inline-size: 56px;
  block-size: 56px;
  object-fit: cover;
  border-radius: var(--radio-chico);
  background: hsl(var(--muted));
}

/* Lo que no es imagen no se previsualiza: nginx manda `X-Frame-Options: DENY`
 * para todo el sitio —también para el mismo origen— así que un PDF en un
 * `<iframe>` quedaría en blanco. En su lugar, las tres letras de lo que es. */
.sin-vista {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

.datos-adjunto {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
/* El nombre puede ser larguísimo —`WhatsApp Image 2026-08-24 at 11.53.07.jpeg`—
 * y lo que importa es el principio: se corta con puntos suspensivos en vez de
 * empujar la tarjeta. */
.nombre-adjunto {
  font-size: var(--t-dato);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.secundario-adjunto {
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

/* §9 — si el intérprete ya leyó este comprobante o si lo va a leer.
 *
 * Los dos estados se dibujan y no sólo uno: «leído» explica por qué no vuelve a
 * mandarse en cada vuelta —ya está en el hilo, y reenviarlo sería pagar dos
 * veces la misma lectura— y «va con el próximo mensaje» explica por qué la
 * propuesta que está en pantalla no lo tuvo en cuenta. Dibujar sólo uno dejaría
 * al otro caso pareciendo un olvido.
 *
 * Sin fondo y sin versales, como el resto de las marcas chicas: es un estado del
 * archivo, no una alarma, y lo que lo dice es la palabra. */
.marca-leido, .marca-por-leer { font-size: var(--t-rotulo); }
.marca-leido { color: hsl(var(--success-text)); }
.marca-por-leer { color: hsl(var(--warning-text)); }

/* El formulario de subida: «Qué es» mide lo que mide su lista y «Archivo» se
 * estira. En el celular los dos ocupan el renglón, que es lo que hace `.campo`
 * solo; acá alcanza con la fila. */
.subir-adjunto {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--paso) 10px;
}

/* --- Pendientes de definición (§9) ---------------------------------------- */

/* Una tarjeta por pendiente, y arriba de todo lo que hace falta para decidir si
 * uno puede contestarla: qué falta y a quién se le preguntó. La conversación
 * entera va plegada abajo, porque se abre sólo cuando lo de arriba no alcanza. */
.definiciones {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* Una pista, y escrita (§12.2): una grilla sin `grid-template-columns` arma
   * una columna implícita de mínimo automático, y el prompt original de una
   * conversación larga —monoespaciado y con los saltos de línea intactos— le
   * daría a esa columna el ancho de su renglón más largo. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--paso);
}
.definicion {
  min-width: 0;
  padding: 10px 12px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-left: 4px solid hsl(var(--border));
  border-radius: var(--radio);
}
/* Pasadas las 24 horas, el mismo rojo del contador de la pantalla de inicio y
 * por la misma razón: es la señal de que algo se quedó atrás. Acompañada del
 * «hace N h» escrito al lado, porque el color solo no alcanza. */
.definicion.atrasada {
  border-color: hsl(var(--destructive-text) / 0.6);
  background: hsl(var(--destructive) / 0.14);
}
/* **El renglón de arriba de la tarjeta se llama `cabecera` y hay otra cosa en la
 * aplicación que se llama igual: la barra de arriba de la página.** Aquélla pesa
 * (0,1,0) y ésta (0,2,0), así que ésta gana en lo que declara —y hasta acá
 * declaraba cinco propiedades de diez—: las otras cinco pasaban enteras y cada
 * tarjeta de esta pantalla tenía un renglón `sticky`, con el fondo de la barra
 * lateral, un borde inferior, el relleno lateral que la desalineaba del resto de
 * la tarjeta, el alto mínimo de una cabecera de página —56px de aire para un
 * renglón de dos palabras— y un `z-index: 20` que apilaba las tarjetas contra la
 * cabecera real al scrollear. Se apagan las seis acá, por nombre, hasta que el
 * renglón se llame de otra manera en la plantilla. El `top: 0` no hace falta
 * apagarlo: sin `position` no lo lee nadie. */
.definicion .cabecera {
  position: static;
  z-index: auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: baseline;
  min-height: 0;
  margin-bottom: 6px;
  padding: 0;
  background: none;
  border-bottom: none;
}
.definicion .espera { font-size: var(--t-rotulo); color: hsl(var(--muted-foreground)); }
.definicion .falta, .definicion .a-quien { margin: 0 0 3px; font-size: var(--t-dato); }
/* Lo que falta puede ser más de una pregunta, una por renglón: el formulario lo
 * precompleta con todas las que el parser dejó sin responder. */
.definicion .falta { white-space: pre-line; }
/* El texto original, tal como se tipeó. Va en monoespaciada y con los saltos de
 * línea intactos porque es una cita: es lo que se le mandó al parser, y de eso
 * depende entender qué se le estuvo pidiendo. */
.definicion .prompt {
  margin: 6px 0;
  padding: 6px 9px;
  background: hsl(var(--muted) / 0.5);
  border-radius: var(--radio-chico);
  font-family: var(--mono);
  font-size: var(--t-dato);
  white-space: pre-wrap;
}
.definicion .dialogo-previo > summary {
  display: flex;
  align-items: center;
  min-height: var(--toque);
  cursor: pointer;
  font-size: var(--t-dato);
  color: hsl(var(--primary-text));
}
.definicion form { margin-top: var(--paso); }
/* --- Fichas: los pares, el asiento y el espejo --------------------------- */

/* Una ficha es una pantalla que contesta «qué es esto»: una operación, un
 * cliente, un cheque. Tres cosas la componen y las tres están acá.
 *
 * 1. **Los pares rótulo/dato.** Las cuatro tablas de dos columnas de una ficha
 *    —tres se llaman `table.datos.ficha` y la cuarta hace lo mismo sin la
 *    clase— ponían en un monitor «Tasa mensual» a la izquierda y «5,00 %» a
 *    1200px a la derecha. Pasan a `dl.datos-clave` (el componente vive en
 *    «Tablas»), y acá se les pone lo único que las distingue: **el tope de
 *    línea**. Es texto sobre una persona o sobre un papel, no una columna de
 *    números que se compara con la de al lado.
 * 2. **El asiento.** El formulario donde se corrige una operación, que es el
 *    lugar más denso de la aplicación: seis campos por movimiento y hasta ocho
 *    movimientos. A 390 esos seis controles se apretaban hasta «CA▾», «AR▾»,
 *    «$ 3.5» y el asiento dejaba de poder leerse y de poder corregirse.
 * 3. **El espejo.** La regla de `ESPECIFICACION.md` §3.2 —la que el código
 *    todavía cita como §3.8— dice que cada movimiento de caja y cada movimiento
 *    de resultado tiene su reflejo de signo opuesto en la cuenta de la
 *    contraparte. Hoy eso se lista en cuatro bloques apilados y hay que ir
 *    arriba y abajo para verlo. Desde 1440 se lee **en horizontal**, y ése es
 *    el único lugar de la interfaz donde el diseño muestra la contabilidad en
 *    vez de sólo listarla.
 *
 * Las dos decisiones del espejo que salen de medir y no de dibujar, porque
 * corrigen al plan (contrato §12.7):
 *
 * * **El par es `Caja | Cuentas corrientes` y `Resultado | Cuentas de
 *   capital`**, y no el del plan. La partición que el sistema ya usa —la misma
 *   que cuenta `_parece_neteada` en `paginas.py`— es `filas_caja +
 *   filas_resultado` de un lado y `grupos_cc + grupos_capital` del otro: lo que
 *   se refleja contra quien lo refleja. Con el orden del plan, el descuento de
 *   la operación #21 y su reflejo quedan **en diagonal**.
 * * **El movimiento pasa a dos renglones.** Dos tablas de seis columnas cómodas
 *   piden una ventana de 2557px medidos con estas fuentes; a 1536 hay 1280px de
 *   contenido. Con cuenta, moneda e importe arriba y el detalle abajo, el par
 *   entra a 1440 con la columna de Cuenta en 272px, que es un código de hasta
 *   veintisiete caracteres. O la fila cambia, o el espejo no existe.
 *
 * Y hay **dos** copias de esta tabla, no una. `/ejemplos/promover/{id}` dibuja
 * el mismo asiento editable escrito a mano —la misma cabecera y las mismas seis
 * celdas de control, sin la macro—, dentro del mismo `<form class="asiento">`
 * pero **sin ningún `.bloque-asiento` alrededor**: una sola tabla, sin título de
 * bloque y con su marco todavía haciendo de tarjeta. Es la diferencia que hoy
 * hace que las dos se vean distintas. Por eso lo que estructura el movimiento
 * cuelga de **`.datos-asiento`**, que es la clase de la tabla y la única cosa
 * que las dos copias comparten; `.bloque-asiento` sólo dice qué le pasa a la
 * tabla cuando además está adentro de un bloque. De `.asiento` cuelgan dos
 * reglas y nada más, las dos anotadas donde están: el marco que no scrollea y
 * el `<fieldset>` que apaga la edición. */

/* --- Los pares de una ficha --------------------------------------------- */

/* `.ficha` sobre la `dl.datos-clave`: los mismos pares del componente, con el
 * tope de `--linea`. Es la única variante que tiene, y existe por la regla 7
 * del encabezado: el texto tiene largo de línea y los datos no. Diez pares de
 * dos palabras estirados a 1200px se leen peor que en un teléfono, porque el
 * ojo tiene que volver desde el final del renglón hasta el rótulo siguiente.
 *
 * Y **una sola columna en el celular**, contra las dos del componente: a 390,
 * media pantalla son unos 170px y «Persona física, por el prefijo» vuelve a
 * partirse en tres renglones, que es exactamente lo que la tabla vieja hacía.
 * Desde 640 son dos y ahí se quedan: con el tope de 70ch, una tercera columna
 * mide 230px y no alcanza para una dirección.
 *
 * Las dos reglas pesan (0,2,0) y le ganan por especificidad a las del
 * componente, así que no importa en qué orden queden respecto de ellas. */
.datos-clave.ficha {
  grid-template-columns: minmax(0, 1fr);
  max-width: var(--linea);
}

@media (min-width: 640px) {
  .datos-clave.ficha { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Las migas: el camino de vuelta, arriba de todo. En un monitor es un renglón
 * de nada; en un teléfono es **el** botón de volver, y por eso su enlace mide
 * el objetivo táctil entero aunque el texto sea de una línea. El `inline-flex`
 * es lo que deja que el alto exista sin que el enlace ocupe el renglón: un
 * `min-height` sobre un elemento en línea no hace nada. */
.migas {
  margin: 0 0 var(--paso);
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}
.migas a {
  display: inline-flex;
  align-items: center;
  min-height: var(--toque);
}

/* En el monitor la ficha se parte en dos: los pares a la izquierda y las cifras
 * y las relaciones a la derecha. Eso lo reparten `main.familia-ficha
 * .zona-principal` y `.zona-secundario`, con el esqueleto, y no se repite acá:
 * una pantalla que declarara su propio reparto sería una pantalla que mañana
 * no sigue al sistema. La ficha de una operación es la excepción y también está
 * dicha allá: su `principal` es el asiento, que necesita el ancho entero. */

/* --- El asiento: un movimiento son dos renglones ------------------------- */

/* Cada bloque —Caja, Cuentas corrientes, Cuentas de capital, Resultado— es su
 * propia tarjeta. Antes eran tres encabezados chicos sobre tablas contiguas y
 * se leían como una sola tabla larga, que es justo lo contrario de lo que el
 * asiento quiere decir: son cuatro preguntas distintas y ninguna se deduce de
 * las otras. Mismo criterio que `.tarjeta-seguimiento`. */
.bloque-asiento {
  margin: 0 0 calc(var(--paso) * 1.5);
  min-width: 0;
  padding: 10px 12px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}

/* Adentro del bloque, el marco de la tabla pierde su caja: la caja **es** el
 * bloque, y dos bordes concéntricos a 10px uno del otro no dicen nada que el de
 * afuera no diga. El `background: none` corto se lleva también los cuatro
 * degradados de «hay más a la derecha», y está bien que se los lleve: acá no
 * hay nada que desplazar (ver la regla de abajo).
 *
 * **Sólo `.tabla-marco`, y no `.tabla-scroll`.** Las cuatro tablas de la
 * propuesta del diálogo viven dentro de un `.bloque-asiento` con
 * `.tabla-scroll`, tienen siete columnas de texto y **sí** desbordan en un
 * teléfono: apagarles el fondo sería apagarles la única señal de que la fila
 * sigue. Y el color de tapa que necesitan es `hsl(var(--card))`, que es
 * exactamente el fondo de este bloque (contrato §12.10): adentro de acá la
 * señal funciona sin tocarle nada. */
.bloque-asiento .tabla-marco {
  border: none;
  border-radius: 0;
  background: none;
}

/* La primera de las dos reglas de la sección que cuelgan del formulario, y va
 * con su motivo: el asiento **nunca** desborda —el movimiento son dos renglones
 * y todo control mide el 100% de su columna— así que su marco no tiene por qué
 * ser un contenedor de scroll. La barra horizontal siempre visible es la regla base de
 * los marcos, y sin nada que desplazar quedaría una barra vacía debajo de cada
 * uno de los marcos de la pantalla —uno por bloque, y uno más por cada cliente
 * y cada socio—. Cuelga de `.asiento` porque es lo único que comparten las dos
 * copias del asiento editable: en la ficha el marco está adentro de un bloque y
 * en el ejemplo manual del corpus no hay bloque y el marco sigue siendo la
 * tarjeta. */
.asiento .tabla-marco { overflow-x: visible; }

/* La segunda, y ésta sólo puede colgar de ahí: el `<fieldset>` que apaga el
 * asiento de una operación que no se puede editar existe únicamente en la ficha
 * —el ejemplo manual del corpus no tiene estados y su asiento es siempre
 * editable—, así que no hay una segunda copia a la que llegar.
 *
 * `min-width: 0` no es cosmético: un `fieldset` trae de fábrica un ancho mínimo
 * igual al de su contenido, y con una tabla adentro eso estira la página entera
 * por más `min-width` que lleven la columna y la grilla. */
.asiento fieldset {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}

/* El título del bloque es un `<h3>` y se dibuja como un encabezado: el cuerpo y
 * el peso se los da la base. Acá sólo se le saca el aire de arriba, porque es
 * lo primero que hay adentro de la tarjeta y el relleno del bloque ya lo
 * separa. Lo que se fue son las versales y el cuerpo de rótulo: «CAJA» a 12px y
 * en gris se leía como la etiqueta de un campo y no como el nombre de la mitad
 * del asiento que se está mirando.
 *
 * **Hijo directo de `.bloque-asiento` y no la clase suelta**, porque el motivo
 * de arriba es el relleno del bloque y hay dos títulos que no lo tienen:
 * `/padron/bancos` usa esta misma clase para «En cheques» y «En bancos de
 * firmante», que son dos secciones seguidas y **fuera** de todo bloque. Ahí lo
 * único que las separa de la lista de arriba es el margen del `h3`, y sacárselo
 * a las dos las pega contra ella. La hoja de hoy lo evitaba con un
 * `:first-of-type` que salvaba sólo a la primera; acotar al bloque las salva a
 * las dos y dice el motivo en el selector. */
.bloque-asiento > .titulo-bloque-asiento { margin-top: 0; }

/* De quién es la cuenta y con qué saldo queda. Es lo que convierte una lista de
 * movimientos en «esto es lo que le pasa a esta persona», y por eso va arriba
 * de su tabla y no adentro. Envuelve: con dos monedas y una columna angosta
 * pasa a dos renglones, y eso está previsto —es el caso que descalza el
 * espejo, y se resuelve en la grilla del par, no acá—. */
.grupo-cuenta-corriente {
  margin: 0 0 4px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  font-size: var(--t-dato);
}
.grupo-cuenta-corriente .nombre-cliente { font-weight: 500; }
/* La cifra usa las reglas globales `.num` y `.neg`, y acá no se le agrega
 * ningún color propio: el rojo del negativo ya lo pone `.neg` sobre el número,
 * y de qué lado está el saldo lo dice la palabra de al lado, que es la señal
 * que se lee sin color. Lo que sí va tenue es el resto del renglón —«saldo»,
 * la moneda—, porque es el envoltorio de la cifra y no la cifra. */
.grupo-cuenta-corriente .saldo-resultante { color: hsl(var(--muted-foreground)); }
/* La palabra que dice de qué lado está el saldo (§4.8): «nos debe» o «a favor
 * del cliente». El signo y el color siguen puestos —acompañan—, pero la que
 * informa es ésta, y es la que se lee en blanco y negro. */
.sentido-saldo {
  font-style: italic;
  color: hsl(var(--muted-foreground));
}
/* **Adentro de una celda la frase va debajo del número, no al lado.** Pegada al
 * importe y con el `nowrap` de la celda, la columna mide número **más** frase —«a
 * favor del cliente» son unos 145px sobre los 126 del importe—, y con eso el
 * saldo de la primera moneda de `/cuentas` quedaba cortado en el celular y la
 * tabla se iba 23px fuera del monitor a 1536. Debajo, la celda mide lo que mide
 * el más ancho de los dos y la frase sigue pegada a su número, que es lo único
 * que importa: un saldo sin la palabra se lee para el lado contrario (§4.8).
 *
 * Va como regla base y hasta 1440, que es donde el ancho de la columna falta.
 * Fuera de la tabla —el saldo resultante de la propuesta, las tarjetas de la
 * ficha— la frase se queda en el renglón, que es donde se escribió para leerse.
 *
 * **Decía «va en todos los anchos» y eso costó la densidad donde el ancho
 * sobraba** (regresión N8): a 1536 las filas de `mayor`, `socio` y `cuentas`
 * alternaban 44 y 36px contra los 28-29 parejos de antes del rediseño, `socio`
 * pasó de 949 a 1.239px de página y `cuentas` de 844 a 1.033. No se perdía
 * ningún dato; se perdía la regla 1 del encabezado de esta hoja. */
table.datos .sentido-saldo {
  display: block;
  font-size: var(--t-rotulo);
}
/* **Y desde 1440 vuelve al renglón del número, porque desde ahí el ancho alcanza
 * de verdad.** El corte no es intuición: está medido con el navegador sobre las
 * tres tablas que llevan la frase, con el panel lateral como nace a cada ancho.
 *
 *   · `mayor` y `socio` (`table.datos.ancha`): en renglón entran a 1440 y a 1536
 *     sin desplazar nada —la columna `Detalle` tiene de sobra— y las filas pasan
 *     de 44 a 29px. A 1024 **no**: la tabla entra igual, pero `Detalle` envuelve
 *     y la fila termina midiendo 48, o sea peor que los 44 del bloque.
 *   · `cuentas` (`table.datos.podable`, cuatro columnas de moneda y la frase en
 *     todas): en renglón pide 1.146px de mínimo. A 1536 el marco son 1.238 y
 *     sobran 92; a 1440 son 1.142 y faltan cuatro, que es lo que se paga y está
 *     dicho acá abajo; a 1024 son 918 y faltan 51, con la última columna cortada.
 *
 * O sea: 1024 no alcanza en ninguna de las tres y 1536 alcanza en las tres. El
 * corte va en 1440, que es el único breakpoint que hay entre esos dos, y el
 * precio exacto son esos cuatro píxeles de `cuentas` **a 1440 justo**: el marco
 * ya vive adentro de un `overflow-x`, la columna que se roza es la de fechas y
 * está alineada a la izquierda, así que lo que se corta es el borde de la tabla y
 * no un dato. Antes del rediseño la frase iba en renglón en **todos** los anchos
 * y esa misma tabla se iba 23px afuera a 1536, así que a 1440 esto no es peor que
 * lo que había.
 *
 * **Lo que se probó y no anduvo**, para que no se vuelva a intentar: dejar la
 * frase en renglón y que la celda la baje sola cuando no entra
 * (`white-space: normal` sobre `.sentido-saldo`, que envuelve aunque el `<td>`
 * lleve `nowrap`). Funciona —a 1440 no sobra ni un píxel— pero parte la frase por
 * el medio, y el saldo queda diciendo «nos / debe» y «a favor del / cliente» en
 * dos renglones: el corte cae en cualquier espacio, no en el que separa el número
 * de la frase, porque ese espacio vive **adentro** del `<span class="sentido-
 * saldo">` y las plantillas lo tienen ahí a propósito (ver la nota de
 * `mayor_tabla.html` sobre `tests.html`). Entre un borde de tabla rozado a un
 * ancho y una frase partida al medio, se eligió el borde. */
@media (min-width: 1440px) {
  table.datos .sentido-saldo { display: inline; }
}

/* El total del bloque de resultado (§7): mismo cuerpo y misma posición que el
 * rótulo del grupo, pero **sin su clase** —no es «a quién le queda qué», es el
 * total del bloque entero, y hay pantallas y tests que recorren
 * `.grupo-cuenta-corriente` buscando un cliente que acá no existe—. El color lo
 * ponen `.ganancia` y `.perdida` sobre `.num`. */
.total-resultado {
  margin: 0;
  padding-top: 6px;
  font-size: var(--t-dato);
}

/* --- El movimiento, en el celular: una tarjeta -------------------------- */

/* La regla base es la del teléfono, y en el teléfono el asiento **no es una
 * tabla**: seis controles en una fila de 344px daban columnas de 50px y un
 * desplazamiento horizontal sobre el formulario más importante de la
 * aplicación. Cada `<tbody class="mov">` —un movimiento, dos `<tr>`— se dibuja
 * como una tarjeta:
 *
 *   ┌───────────────────────────────┐
 *   │ CAJA.ARS.CHEQUES            ▾ │  el código entero, 330px
 *   │ ARS ▾        5.000.000,00     │  moneda e importe en el mismo renglón
 *   │ Cheques recibidos, nominal    │
 *   │ más                           │  tipo de cambio y clase, plegados
 *   └───────────────────────────────┘
 *
 * Medida: 208px por movimiento. Es cara —siete líneas son 1500px de scroll— y
 * es el precio que el plan ya aceptó: hoy esas mismas siete entran en 400px y
 * no se pueden ni leer ni corregir, que es peor que scrollear.
 *
 * **La moneda va abajo, con el importe, y no arriba con la cuenta.** Es una
 * desviación consciente de la letra del plan y está medida: subirla obliga a
 * recortar el `<select>` de cuenta a 236px —donde `CC.DISTRIBUIDORA.NORTE.SA`
 * ya no entra— y la tarjeta pasa de 208 a 262px, porque el importe se queda
 * solo en un renglón. Abajo, además, junta las dos cosas que se leen juntas:
 * `ARS  (5.000.000,00)`.
 *
 * Los seis campos siguen **siempre** en el DOM y en el mismo orden: el POST del
 * asiento son seis listas paralelas que se zipean por índice, sin ningún id de
 * fila. Un campo que no se renderiza no manda nada y corre todas las filas de
 * abajo; un campo duplicado descalza las seis listas. Por eso el «más»
 * **mueve** los dos controles, no los copia, y nada se esconde con `{% if %}`:
 * lo que se pliega se pliega con CSS. */
table.datos-asiento { display: block; }
/* Sin cabecera: en la tarjeta cada control dice qué es —el código de cuenta, el
 * código de moneda, el importe en monoespaciada a la derecha— y tres rótulos
 * repetidos ocho veces serían un tercio de la pantalla. */
.datos-asiento thead { display: none; }
.datos-asiento tbody,
.datos-asiento tr,
.datos-asiento td { display: block; }

/* La tarjeta. `--radio` y no `--radio-chico` porque es una caja y no un
 * control: la regla de los dos radios del encabezado. */
.datos-asiento tbody.mov {
  margin-bottom: var(--paso);
  padding: 6px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
}
/* La celda del asiento no lleva la línea de abajo, y no la lleva **en ningún
 * ancho**: en el celular porque el borde de la tarjeta ya separa un movimiento
 * del siguiente, y de 640 para arriba porque la línea caería también entre los
 * dos renglones de un mismo movimiento, partiendo en dos algo que es una sola
 * cosa. Lo que separa un movimiento del siguiente allá es el cebreado, que va
 * por `<tbody>` y está más abajo. La que sí se queda es la línea del `<thead>`,
 * que es de un `th` y esta regla no la toca.
 *
 * El `nowrap` de las celdas tampoco corresponde acá: en la tarjeta la celda es
 * del ancho de la pantalla. Va calificado con `table.` para empatarle los
 * (0,1,2) a la regla de celdas de una tabla de datos y ganarle por orden. */
table.datos-asiento td {
  padding: 2px 0;
  border-bottom: 0;
  white-space: normal;
}

/* El primer renglón: la cuenta ocupa el ancho entero y abajo, en la misma
 * línea, la moneda y el importe. */
.datos-asiento .mov-principal {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.datos-asiento .mov-principal .c-cuenta { flex: 1 1 100%; min-width: 0; }
.datos-asiento .mov-principal .c-moneda { flex: 0 0 9ch; }
.datos-asiento .mov-principal .c-importe { flex: 1 1 auto; min-width: 0; }

/* Todo control del asiento llena su columna. Es la regla que hoy vive como
 * `.asiento table.datos input { width: 100% }` y que era la causa raíz del 390:
 * pisaba al ancho por dato del importe y dejaba que las seis columnas se
 * comprimieran. Con tres columnas y el detalle abajo, llenar la columna es lo
 * correcto —la columna ya mide lo que tiene que medir—. El `max-inline-size:
 * none` apaga el tope de 26ch que llevan todos los `<select>` desde 640: acá el
 * desplegable lista **todas** las cuentas del plan y su ancho lo decide la
 * columna, no la opción más larga. */
.datos-asiento input,
.datos-asiento select {
  inline-size: 100%;
  max-inline-size: none;
  min-width: 0;
}

/* El segundo renglón: el detalle, y el «más» con lo que casi nunca se toca.
 *
 * Se pega al primero —sin aire arriba— porque los dos renglones **son un solo
 * movimiento**: el espacio entre ellos los separaría igual que el espacio entre
 * dos movimientos, y entonces un asiento de cuatro líneas se leería como uno de
 * ocho. Lo que separa un movimiento del siguiente es la tarjeta en el celular y
 * el cebreado de 640 para arriba. La regla pesa (0,2,1) contra el (0,1,2) del
 * relleno de la celda, así que vale en los dos anchos con una sola declaración. */
.datos-asiento .mov-detalle td { padding-top: 0; }
.datos-asiento .linea-detalle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
/* Hijo directo y no descendiente: adentro de la misma línea, plegados, están
 * los `<input>` del tipo de cambio y de la clase, y ésos miden lo que mide su
 * campo. El que se estira es el detalle, que es texto libre. */
.datos-asiento .linea-detalle > input { flex: 1 1 auto; }

/* Tipo de cambio y clase de resultado valen 1 y «—» en el 95% de las líneas, y
 * ocupaban dos de las seis columnas. Plegados en un `<details>` propio y no en
 * el `details.mas` de las tablas podables, que **deja de dibujarse desde 1440**:
 * éste tiene que seguir existiendo en todos los anchos, porque los dos controles
 * viven adentro y esconderlos sería sacarlos del formulario.
 *
 * El rótulo es una pista y va como una pista —tenue y a 12px—: es una salida a
 * lo excepcional, no la acción del renglón. Y mide los 44px enteros, que es lo
 * que lo hace tocable con el pulgar en movimiento. */
.mas-movimiento > summary {
  display: flex;
  align-items: center;
  min-height: var(--toque);
  cursor: pointer;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
  list-style: none;
}
/* El triángulo se apaga con las dos declaraciones y no con una: `list-style:
 * none` alcanza en un navegador de hoy, y en el Safari de un iPhone que no se
 * actualizó hace falta el pseudo-elemento. Es la misma pareja que llevan
 * `details.mas` y los `summary` de la navegación, y acá importa más que allá:
 * éste es el único plegado que se toca **adentro de un formulario**, y el
 * marcador nativo se pisa con el rótulo en una tarjeta de 344px. */
.mas-movimiento > summary::-webkit-details-marker { display: none; }
.campos-plegados {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: 6px;
}
/* Los dos campos arrancan en dieciséis caracteres y envuelven solos: a 390 caen
 * uno debajo del otro y desde 640 entran los dos en el renglón. */
.campos-plegados .campo { flex: 1 1 16ch; }

/* Las acciones al pie. En el celular ocupan el renglón entero y se tocan sin
 * apuntar; desde 640 vuelven a medir lo que mide su texto y quedan alineadas a
 * la izquierda, que es donde termina de leerse el asiento. */
.acciones-asiento {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  margin-top: calc(var(--paso) * 1.5);
}
.acciones-asiento button { flex: 1 1 100%; }

/* --- El movimiento, desde 640: vuelve a ser una tabla ------------------- */

/* Tres columnas arriba —Cuenta 260, Moneda 88, Importe 185— y el detalle abajo
 * a lo ancho de las tres. Los anchos van en píxeles y no en `ch` a propósito:
 * un `ch` sobre un `<th>` se resuelve contra los 12px del encabezado, así que
 * `26ch` da 208px y no los 260 que se querían para un `<select>` de 15px. Son
 * anchos preferidos, no fijos: la tabla reparte lo que sobra y a 1536 las tres
 * quedan en 295, 100 y 210. */
@media (min-width: 640px) {
  table.datos-asiento { display: table; }
  .datos-asiento thead { display: table-header-group; }
  .datos-asiento tbody.mov {
    display: table-row-group;
    margin: 0;
    padding: 0;
    border: 0;
  }
  .datos-asiento tr { display: table-row; }
  /* El selector largo va repetido y no alcanza con el `tr` de arriba: la regla
   * de celular pesa (0,2,0) contra (0,1,1) y le gana **aunque esté adentro de
   * esta `@media`**. Sin esto la fila medía 162px a 1440 y 106 a 1536, y el
   * espejo se descalzaba solo en algunos anchos. */
  .datos-asiento .mov-principal { display: table-row; }
  .datos-asiento td,
  .datos-asiento th { display: table-cell; }
  /* La celda de un asiento es más apretada que la de una tabla de datos porque
   * adentro hay un control de 44px que ya trae su propio alto: los 4+10 de una
   * celda normal le sumarían diez píxeles por renglón y veinte por movimiento. */
  table.datos-asiento td {
    padding: 3px 5px;
    white-space: nowrap;
  }
  .datos-asiento .c-cuenta { width: 260px; }
  .datos-asiento .c-moneda { width: 88px; }
  .datos-asiento .c-importe { width: 185px; }
  /* El `display: flex` de la línea del detalle va en el `<div>` de adentro y
   * **no** en el `<td>`: cambiarle el `display` a una celda con `colspan` la
   * saca del algoritmo de tabla y deja de abarcar las tres columnas. Está
   * declarado con la regla base, que acá sirve igual.
   *
   * Cerrado, el «más» es un rótulo al final del renglón del detalle; abierto,
   * se lleva el renglón entero, que es la única forma de que los dos campos
   * entren sin robarle ancho al detalle.
   *
   * **Y para que eso sea cierto hace falta la línea de abajo**, que faltaba: el
   * campo del detalle llevaba `inline-size: 100%` de la regla base de los
   * controles del asiento —tres columnas y el detalle a lo ancho, que es lo
   * correcto en la tarjeta del celular— y un ítem con `flex: 1 1 auto` mide su
   * `width`, así que se llevaba el renglón entero y empujaba al «más» abajo. En
   * `/ejemplos/promover/{id}` eso son ocho renglones de 44px que la hoja decía
   * que no estaban: 350px de una pantalla de 2.292 a 1024. Con `auto` el campo
   * mide su contenido y el `flex-grow` le devuelve todo lo que el rótulo no usa,
   * o sea que no pierde ni un píxel de escritura. Pesa (0,2,1) contra los (0,1,1)
   * de aquella regla y está adentro de esta `@media`: en el celular la tarjeta
   * sigue con el campo a lo ancho y el «más» debajo, que es donde se toca. */
  .mas-movimiento { flex: 0 0 auto; }
  .mas-movimiento[open] { flex: 1 1 100%; }
  .datos-asiento .linea-detalle > input { inline-size: auto; }

  /* El cebreado va por **movimiento** y no por renglón: el de las tablas de
   * datos pinta uno de cada dos `<tr>` y acá pintaría el renglón del detalle de
   * todos los movimientos, que es partir en dos lo que es uno. Se apaga el de
   * los renglones y se prende el de los `<tbody>`.
   *
   * Y es `odd` y no `even` porque **el `<thead>` es el primer hijo de la
   * tabla**: el segundo movimiento es el tercer hijo. Sin esa cuenta el rayado
   * arranca en la primera fila y el asiento se lee empezando pintado.
   *
   * Pesos: la regla que apaga pesa (0,2,3) y empata con la de las tablas de
   * datos, así que gana por venir después; la que prende pesa (0,3,2) y le gana
   * a las dos. */
  table.datos-asiento tbody tr:nth-child(even) { background: none; }
  table.datos-asiento tbody.mov:nth-child(odd) { background: hsl(var(--muted) / 0.35); }
  /* Y el resaltado al pasar por encima se apaga por lo mismo: alumbra medio
   * movimiento y dice que la mitad de abajo es otra cosa. En un formulario la
   * señal que importa es el foco del campo, que ya está. */
  table.datos-asiento tbody tr:hover { background: none; }

  .acciones-asiento button { flex: 0 0 auto; }
}

/* --- El espejo, desde 1440 ---------------------------------------------- */

/* Los dos bloques de un par, uno al lado del otro, con las tablas arrancando en
 * la misma `y`: `CAJA.ARS.CHEQUES +5.000.000` a la izquierda y
 * `CC.MELLADO.JULIAN −5.000.000` a la derecha, en el mismo renglón.
 *
 * **Lo que descalzaba las dos columnas no era la altura de fila.** Los dos
 * bloques ya miden lo mismo por movimiento —101px, dos renglones de 51 y 50—.
 * Lo que las corría eran los 26px del rótulo del cliente, que la columna
 * derecha tiene y la izquierda no; y con un saldo en dos monedas el rótulo
 * envuelve y pasa a 48. Cualquier `margin-top` escrito a mano acierta en un
 * caso y falla en el otro.
 *
 * La solución es estructural: los dos bloques se vuelven `display: contents` y
 * sus hijos caen en **tres filas de grilla compartidas** —título, rótulo,
 * tabla—. La fila 2 mide lo que mide el rótulo más alto de las dos columnas, así
 * que las dos tablas empiezan a la misma altura sin que nadie calcule nada, con
 * una moneda o con cinco. Medido: `y = 155` en las dos columnas a 1440 y a 1536,
 * y `y = 181` en las dos con el rótulo de dos monedas.
 *
 * Con `display: contents` el bloque pierde su tarjeta, y por eso **la tarjeta
 * pasa a ser el par**: un asiento y su espejo son una sola cosa, y un marco lo
 * dice mejor que dos.
 *
 * Los bloques se ubican por posición —`:first-child` y `:last-child`— y no con
 * una clase de lado: el envoltorio se emite sólo cuando hay con quién aparear y
 * entonces adentro hay exactamente dos, así que «el primero» ya quiere decir
 * «la izquierda». Una clase `izq`/`der` sería el mismo dato escrito otra vez, y
 * en la plantilla nadie tendría que decidir de qué lado va Caja.
 *
 * Un segundo cliente trae su propio rótulo y su propia tabla y caen en las
 * filas automáticas de la columna derecha, solos, sin nada enfrente. Es la
 * lectura correcta: su reflejo son líneas de caja que ya se leyeron arriba, y
 * el diseño no finge lo contrario.
 *
 * **Las dos filas en blanco se quedan en el bloque de Caja**, aunque alarguen la
 * columna izquierda dos movimientos sin reflejo. Darles un bloque propio al pie
 * era lo primero que se probó, y cuesta más de lo que arregla: rompe cuatro
 * casos de test que cuentan los bloques del asiento por su título, y —esto es
 * lo caro— cambia el orden en que aparece un movimiento nuevo en la carga
 * siguiente, porque las filas salen ordenadas por `id` y el `id` sale de la
 * posición en el POST. Hoy un movimiento nuevo aparece en el medio; con el
 * bloque al pie aparecería último. El desfasaje visual es el precio más barato
 * de los dos, y por eso la columna de Caja puede terminar más abajo que su
 * espejo sin que eso sea un defecto. */
.asiento-par {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}
/* §12.2: el ítem de una grilla lleva `min-width: 0`, y lo lleva **también en la
 * columna sola**. Sin esto el mínimo automático del bloque es el de su tabla con
 * `nowrap` en todas las celdas, y el par empujaría la página en vez de dejar que
 * el marco de adentro se desplace. */
.asiento-par > .bloque-asiento { min-width: 0; }

@media (min-width: 1440px) {
  .asiento-par {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* Título, rótulo del cliente y tabla. Las que hagan falta después —el
     * segundo cliente, el total del resultado— las agrega la grilla sola. */
    grid-template-rows: auto auto auto;
    column-gap: calc(var(--paso) * 2);
    row-gap: 0;
    align-items: start;
    margin-bottom: calc(var(--paso) * 1.5);
    padding: 10px 12px;
    background: hsl(var(--card));
    border: 1px solid hsl(var(--card-border));
    border-radius: var(--radio);
  }
  /* El bloque desaparece como caja y deja pasar a sus hijos, que son los que se
   * ubican en la grilla. Su borde, su fondo y su relleno se los quedó el par. */
  .asiento-par > .bloque-asiento { display: contents; }

  .asiento-par > .bloque-asiento:first-child > * {
    grid-column: 1;
    min-width: 0;
  }
  .asiento-par > .bloque-asiento:last-child > * {
    grid-column: 2;
    min-width: 0;
  }
  /* Las tres filas compartidas. Se nombran en las dos columnas aunque la
   * izquierda no tenga rótulo: es lo que hace que la fila exista y mida lo mismo
   * de los dos lados, que es todo el truco. */
  .asiento-par > .bloque-asiento > .titulo-bloque-asiento { grid-row: 1; }
  .asiento-par > .bloque-asiento > .grupo-cuenta-corriente:first-of-type { grid-row: 2; }
  .asiento-par > .bloque-asiento > .tabla-marco:first-of-type { grid-row: 3; }

  /* Y el título de la izquierda **se come también la fila del rótulo**. No es
   * cosmético y cuesta explicarlo, así que va explicado: el bloque de Resultado
   * lleva su `p.total-resultado` —uno por moneda— después de la tabla, sin fila
   * asignada, y el cursor de la ubicación automática de la grilla busca el
   * primer hueco libre de la columna **hacia abajo desde arriba**. Con la fila 2
   * vacía en la columna izquierda, el total caía ahí: arriba de su propia tabla
   * y a la altura del rótulo del socio de al lado. Ocupándola con el título
   * —que con `align-items: start` sigue dibujándose exactamente donde estaba— el
   * hueco no existe y el total cae abajo, que es donde va.
   *
   * Vale sólo para la izquierda porque la izquierda es siempre `Caja` o
   * `Resultado`, y ninguno de los dos tiene rótulo de titular: los grupos de
   * clientes y de socios están siempre del otro lado, que es la partición de la
   * regla espejo. */
  .asiento-par > .bloque-asiento:first-child > .titulo-bloque-asiento { grid-row: 1 / 3; }
  /* Del segundo grupo en adelante, el aire que en la columna sola daba el
   * margen del bloque. */
  .asiento-par > .bloque-asiento > .grupo-cuenta-corriente { margin-top: var(--paso); }
  .asiento-par > .bloque-asiento > .grupo-cuenta-corriente:first-of-type { margin-top: 0; }
}

/* --- La regla espejo: «parece neteada» ----------------------------------- */

/* El aviso de que la contraparte tiene menos líneas que la caja más el
 * resultado. Va **arriba de los dos bloques y a todo el ancho**, y ahí se
 * queda: habla de la relación entre las dos columnas, no de una de ellas.
 *
 * No lleva tope de ancho propio: es texto de corrido y lo acota la clase de
 * texto que le pone la plantilla, como cualquier otro párrafo de la aplicación.
 * El tope de 92ch que tenía era uno de los siete que estaban repartidos por la
 * hoja pantalla por pantalla.
 *
 * `--radio-chico` y no `--radio`: es un renglón con una barra al costado, de la
 * familia de las marcas, y no un panel. */
.aviso-neteada {
  margin: var(--paso) 0;
  padding: 7px 10px;
  border-left: 3px solid hsl(var(--warning));
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.1);
  font-size: var(--t-dato);
  line-height: 1.45;
}
.aviso-neteada strong { color: hsl(var(--warning-text)); }

/* El aviso de la comisión desmedida es de la misma familia —un renglón con la
 * barra al costado, arriba de la propuesta— y por eso lleva las dos clases: la
 * forma la pone `.aviso-neteada` y esto existe para que el HTML diga cuál de
 * los dos avisos es. No agrega nada visual a propósito: dos amarillos distintos
 * en la misma pantalla serían dos gravedades que nadie definió. */
.aviso-comision { margin-top: var(--paso); }

/* El del TC recalculado es de la misma familia y por el mismo motivo: puede
 * dibujarse debajo de cualquiera de los otros dos. */
.aviso-tc { margin-top: var(--paso); }

/* --- El saldo cambió entre la propuesta y la confirmación (§9) ---------- */

/* **No es de la familia de arriba, y por eso no es ámbar.** Aquellos avisan y
 * dejan confirmar; éste dice que no se confirmó nada y que no se puede, así que
 * lleva el rojo de `.error` —el mismo tinte, el mismo texto calculado para el
 * contraste— y no un tercer amarillo. Lo que lo separa de `.error` es que
 * adentro hay una lista con dos números por renglón y un botón: es un panel,
 * con `--radio`, y va pegado a la fila de decidir y no arriba del cuadro.
 *
 * Los números usan `.num` y `.neg` como cualquier importe, y la palabra que dice
 * de qué lado está cada saldo va en `.sentido-saldo`: son los mismos dos datos
 * que muestra la procedencia de la propuesta, y se leen igual. */
.saldo-cambiado {
  margin: var(--paso) 0;
  padding: var(--paso) 12px;
  border: 1px solid hsl(var(--destructive-text) / 0.8);
  border-left-width: 4px;
  border-radius: var(--radio);
  background: hsl(var(--destructive) / 0.18);
  font-size: var(--t-dato);
  line-height: 1.45;
}
.saldo-cambiado > p { margin: 0; }
.saldo-cambiado strong { color: hsl(var(--destructive-text)); }
.saldo-cambiado ul { margin: 6px 0 var(--paso); padding-left: 18px; }
.saldo-cambiado li { overflow-wrap: anywhere; }
/* La palabra va con el color del texto del panel y no con el tenue de la regla
 * global: el tenue sobre el tinte rojo no llega al contraste mínimo. */
.saldo-cambiado .sentido-saldo { color: inherit; }
.saldo-cambiado form { margin: 0; }
/* **A 390 el botón llena el panel**, como las tres salidas de la fila de abajo,
 * y el rótulo puede partirse en dos renglones. Con el `nowrap` de todo botón el
 * rótulo medía 380px en un panel de 300 y la página se iba 38px a la derecha
 * (medido con `scripts/capturas.py`). Desde 640 vuelve a medir lo que mide su
 * rótulo, que ahí entra en un renglón. */
.saldo-cambiado button {
  width: 100%;
  white-space: normal;
  text-align: center;
  padding-top: 6px;
  padding-bottom: 6px;
}
@media (min-width: 640px) {
  .saldo-cambiado button { width: auto; }
}

/* --- La ficha de un cheque ---------------------------------------------- */

/* El tope de 92ch se fue con los otros seis: esto no es un párrafo sino una
 * ficha con pares, una tabla de cambios y dos formularios, y a 92 caracteres la
 * tabla de cambios propuestos quedaba angosta al lado de media pantalla vacía.
 * Lo que acota el ancho ahora es la mitad de ficha que le da la familia, y
 * adentro cada cosa mide lo suyo. Queda el `min-width: 0`, que es lo que evita
 * que la tabla de adentro le ponga el ancho a la columna. */
.ficha-cheque { min-width: 0; }

/* El renglón de identificación: número, banco, tipo, estado y, si hay, la marca
 * de que alguien propuso cambiarlo. Envuelve, porque son cinco cosas cortas y
 * en un teléfono entran en dos renglones sin que ninguna se corte. */
.resumen-cheque {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--paso);
  font-size: var(--t-dato);
}

/* Los datos del papel: `<dl class="datos-clave ficha datos-cheque">`. Los pares
 * y el tope de línea son los de cualquier ficha —no hay una segunda forma de
 * dibujar un rótulo y su dato— y lo único que agrega esta clase es el panel.
 * Acá el marco sí paga: lo que rodea a estos diez pares son dos formularios y
 * una propuesta de edición, y sin él «lo que el cheque dice hoy» se mezcla con
 * «lo que alguien quiere que diga». */
.datos-cheque {
  margin: var(--paso) 0;
  padding: var(--paso) 10px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}
/* El importe no se alinea a la derecha acá: en una columna de números eso los
 * hace comparables, pero en un par rótulo/dato lo único que hace es alejar el
 * número de su rótulo. Pesa (0,2,0) contra el (0,1,0) de `.num`, que es lo que
 * le deja ganar sin depender del orden. La monoespaciada se queda: un nominal y
 * un precio de venta se siguen leyendo por su largo. */
.datos-cheque .num { text-align: left; }
/* Dónde está y a quién se le mandó son las dos que llevan una aclaración detrás
 * —«la cuenta en la que está: no toca ninguna cuenta corriente»—, y esa
 * aclaración es un renglón propio: pegada al dato se lee como parte del dato. */
.datos-cheque .ubicacion .secundario,
.datos-cheque .enviado-a .secundario {
  display: block;
  margin-left: 0;
}

/* Por qué operaciones pasó el papel. Cada renglón lleva el enlace a la
 * operación, que es el camino de un cheque a su asiento: por eso mide el
 * objetivo táctil entero y no los 22px que mide su texto. */
.operaciones-del-cheque {
  margin: 0;
  padding: 0;
  list-style: none;
}
.operaciones-del-cheque li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--paso);
  min-height: var(--toque);
  padding: 4px 0;
  border-bottom: 1px solid hsl(var(--border));
}
/* «Entró por», «Se vendió en»: el rótulo de la fila, al ancho de la palabra más
 * larga para que los números de operación queden en columna. */
.operaciones-del-cheque .rotulo-op {
  min-width: 10ch;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}

/* §4.9 — físico o e-cheq, distinguibles sin color. El e-cheq lleva el trazo
 * doble y la palabra; el físico, la palabra apagada y sin caja: es el caso
 * normal y no tiene que saltar. Sin versales: «E-CHEQ» al lado de un nombre del
 * padrón —que está en mayúsculas porque **es** un dato— competía con el nombre. */
.marca-tipo-cheque {
  font-size: var(--t-rotulo);
  white-space: nowrap;
}
.marca-tipo-cheque.fisico { color: hsl(var(--muted-foreground)); }
.marca-tipo-cheque.echeq {
  padding: 1px 6px;
  border: 2px double hsl(var(--primary-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--primary) / 0.12);
  color: hsl(var(--primary-text));
  font-weight: 700;
}
/* §4.20 — la persona de paso: dónde está el e-cheq. El trazo punteado dice
 * «esto es un lugar, no una cuenta», y se lee sin color. Era una píldora de
 * 999px y ahora es un rectángulo redondeado como el resto de las marcas: lo que
 * la distingue de un botón no es la forma sino que no se toca. */
.marca-via {
  padding: 1px 6px;
  border: 1px dotted hsl(var(--foreground) / 0.6);
  border-radius: var(--radio-chico);
  font-size: var(--t-rotulo);
  white-space: nowrap;
}
/* El enlace que identifica al papel en una lista de ediciones: es el dato por el
 * que se busca la fila, así que pesa más que lo que lo rodea. */
.ver-cheque { font-weight: 600; }

/* El tipo del papel en la cola de pendientes, donde se lee y no se edita. Es un
 * `.campo` cuyo control son dos marcas y un enlace, así que se dibuja como
 * cualquier campo —el rótulo arriba, en su propio renglón— y el contenido en
 * una fila que envuelve. Antes se pegaba abajo con un alto de 36px para
 * alinearse con los controles de al lado; con los campos alineados por arriba
 * eso ya no hace falta y además dejaba el rótulo a una altura distinta de todos
 * los demás. */
.tipo-del-papel {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
}
.tipo-del-papel .rotulo-campo { flex: 1 1 100%; }
/* **La jerarquía del grupo, al derecho.** Adentro de este campo el dato es el
 * tipo del papel —`.marca-tipo-cheque`, a 12px— y «corregir» es la salida a lo
 * excepcional; con el `--t-dato` de `.secundario` la salida se dibujaba un
 * treinta por ciento más grande que el dato que acompaña, que es la regla 6 al
 * revés. Va al cuerpo del rótulo, como la marca y como la vía de al lado. Pesa
 * (0,2,0) contra el (0,1,0) de `.secundario`. */
.tipo-del-papel .secundario { font-size: var(--t-rotulo); }

/* --- Ediciones de cheque con aprobación (§4.21) -------------------------- */

/* «Hay una edición esperando»: el trazo punteado de lo que no es lo normal y
 * tampoco es un error, en el ámbar de la advertencia. Es un enlace en la
 * cartera y un rótulo en la ficha, y **no lleva objetivo táctil propio**: 44px
 * acá le sumarían dieciséis píxeles a cada fila de cheque que tenga una edición
 * propuesta, y va pegada al número del cheque, que sí es el enlace de la fila.
 * Es la misma excepción declarada de `.pendiente`, y por el mismo motivo. */
.edicion-pendiente {
  display: inline-block;
  padding: 1px 6px;
  border: 1px dashed hsl(var(--warning-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.12);
  color: hsl(var(--warning-text));
  font-size: var(--t-rotulo);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

/* La propuesta, dibujada como propuesta: un recuadro aparte de los datos —que
 * siguen siendo los de antes y siguen valiendo— con el borde de la advertencia
 * y la barra gruesa a la izquierda. */
.propuesta-edicion {
  margin: var(--paso) 0;
  padding: 11px 14px;
  border: 1px solid hsl(var(--warning-text) / 0.8);
  border-left-width: 4px;
  border-radius: var(--radio);
  background: hsl(var(--warning) / 0.08);
}
/* El cuerpo del `<h2>` lo pone la base: acá sólo el color, que es lo que lo ata
 * al recuadro. Antes se lo bajaba a 16px para que no gritara, y era resolver
 * con el tamaño algo que resuelve el color. */
.propuesta-edicion h2 {
  margin: 0 0 6px;
  color: hsl(var(--warning-text));
}
.propuesta-edicion p { margin: 0 0 6px; font-size: var(--t-dato); }
/* El marco que le faltaba a la única tabla `datos` de la interfaz que no tenía
 * ninguno (contrato §12.13). El margen va acá y no en la tabla: la tabla ahora
 * vive adentro del marco. */
.propuesta-edicion .tabla-marco { margin: 6px 0; }
/* Qué dice hoy y qué pasaría a decir son texto libre —un firmante, un motivo—,
 * así que envuelven en vez de estirar la tabla. Pesa (0,2,1) contra el (0,1,2)
 * de la celda de una tabla de datos. */
.cambios-propuestos td { white-space: normal; }
/* La misma lista de cambios, en una fila de la pantalla de ediciones. */
.cambios-propuestos-lista {
  margin: 0;
  padding-left: 18px;
  font-size: var(--t-dato);
}
/* Aprobar y rechazar-con-motivo: dos formularios, alineados por arriba como
 * todos los demás. En el celular cada uno ocupa el renglón entero —el del
 * rechazo lleva un campo de texto, y medio renglón para escribir un motivo no
 * es un campo—; desde 640 vuelven a medir lo suyo y quedan uno al lado del
 * otro. */
.acciones-edicion {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--paso);
  margin-top: 6px;
}
.acciones-edicion form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 6px;
  margin: 0;
  flex: 1 1 100%;
}
/* **Y el botón llena su formulario, que es lo que hace que las dos salidas midan
 * lo mismo.** El del rechazo ya lo hacía sin que nadie lo escribiera: cuelga de
 * un `.campo.acciones`, que en el celular ocupa el renglón. El de aprobar cuelga
 * directo del `<form>` y medía lo que mide la palabra: ~110px contra ~330, o sea
 * que **el control con más área táctil de la pantalla era el destructivo**, tres
 * veces el otro. Antes del rediseño los dos median lo mismo.
 *
 * Es el criterio de la casa y está escrito tres veces más arriba, en las tres
 * salidas del diálogo (`.decidir`), en las dos de antes de la propuesta
 * (`.salidas`) y en las del cliente inexistente: ninguna se deduce de las otras,
 * así que ninguna se dibuja más chica, y lo único que distingue a la que escribe
 * en el libro es el color —`.principal`—, nunca el tamaño. Desde 640 las dos
 * vuelven a medir su texto, que es cuando entran una al lado de la otra. */
.acciones-edicion form > button { width: 100%; }

@media (min-width: 640px) {
  .acciones-edicion form { flex: 0 1 auto; }
  .acciones-edicion form > button { width: auto; }
}
.proponer-edicion { margin: var(--paso) 0; }
.cambiar-ubicacion { margin: var(--paso) 0; }
/* **El botón se apoya a la altura del `<select>` y no al final de la pista.** La
 * regla general apoya el casillero de acciones abajo (`.campo.acciones {
 * align-self: flex-end }` desde 640), y eso es lo correcto mientras el campo
 * termine en su control: entonces «abajo» **es** el renglón del control. Acá el
 * campo lleva una pista debajo del desplegable —«En el acto: la plata no se
 * mueve, sigue en la cartera de e-cheqs»— y «Mover» caía unos 85px más abajo,
 * pegado al final de una frase que se lee como su etiqueta.
 *
 * `center` y no `flex-start`: arriba está el rótulo del campo, no el control, y
 * el botón quedaría a la altura de la palabra «Corregir la ubicación». Centrado
 * contra un campo que es rótulo + control + pista, el botón cae sobre el
 * control, que es lo que se busca, y sigue cayendo sobre él si la pista envuelve
 * en dos renglones. No hay ningún número escrito: es la única forma de alinearse
 * con el control sin escribir el alto del rótulo a mano. Pesa (0,3,0) contra el
 * (0,2,0) de la regla de los 640. */
.cambiar-ubicacion .campo.acciones { align-self: center; }
/* Las ediciones que ya se contestaron, debajo de la que espera. */
.ediciones-del-cheque {
  margin: 0 0 var(--paso);
  padding-left: 18px;
  font-size: var(--t-dato);
}
.ediciones-del-cheque li { margin-bottom: 4px; }
.ediciones-del-cheque .secundario { display: block; }
/* **`table.datos.ediciones` ya no declara nada, y eso es a propósito.** Acá vivía
 * un `vertical-align: top` para sus cuatro columnas; la fila de una edición es un
 * formulario —dos salidas y el campo del motivo del rechazo— y ahora se dibuja
 * apilada en todos los anchos (`papel tarjeta-siempre`, más abajo), así que sus
 * celdas son bloques y no celdas de tabla: alinear por arriba no alineaba nada, y
 * una declaración que no hace nada es una mentira escrita.
 *
 * **La clase se queda igual en el HTML**: `tests/test_ubicacion_y_ediciones.py`
 * busca la tabla con `uno("table", clase="ediciones")` para afirmar que un junior
 * no ve ningún `<form>` en ella. Es el caso raro de un nombre que existe para la
 * suite y no para la hoja, y por eso está dicho acá y no sólo allá. */
/* §4.21 — el badge de una edición que espera. Punteado como el resto de lo que
 * espera a alguien, y con regla propia: hay un test que verifica estado por
 * estado que la señal de forma la ponga una regla **del estado**, y juntarlo
 * con otro grupo es como un estado termina distinguiéndose sólo por el tono. */
.estado.e-pendiente {
  border: 1px dashed hsl(var(--warning-text) / 0.8);
  background: hsl(var(--warning) / 0.12);
  color: hsl(var(--warning-text));
}

/* --- Cuatro cosas del papel que se leen en otras pantallas -------------- */

/* Viven acá porque son del cheque y no de la pantalla donde caen: si mañana
 * cambia cómo se dibuja un e-cheq, cambia en un solo lugar.
 *
 * §4.10 — en el arqueo, las filas que son una ubicación de la caja de e-cheqs
 * cuelgan de la fila de la cartera: la sangría es lo que dice que son parte de
 * ella y no siete carteras más. */
tr.por-ubicacion td:first-child { padding-left: 22px; }
/* §4.10 — «faltan tres e-cheqs en la aplicación del banco» es una frase y no un
 * pie de dos palabras: envuelve. */
.cifra.echeqs-faltantes .pie { white-space: normal; }
/* §4.6 — dónde está lo que se cuenta: sobre la mesa o en la aplicación del
 * banco. Debajo del nombre y en el tono de las notas. */
.donde-se-cuenta {
  display: block;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
/* §4.6 — la tarjeta de la cartera de e-cheqs lleva el mismo trazo doble que la
 * marca del papel, para que cuál es cuál se reconozca de un vistazo y sin
 * depender del color. */
.cifra.por-tipo.echeq { border-style: double; border-width: 3px; }

/* --- Aprobación por lote ------------------------------------------------ */

/* Un botón por día con algo esperando, y no un «aprobar todo»: lo que se aprueba
 * es una jornada, que es la unidad que alguien puede revisar antes de decir que
 * sí. Vive con el asiento porque es la otra forma de aprobar una operación.
 *
 * Los botones de día van en monoespaciada porque son una columna de fechas, y
 * eso vale también para el que aprueba el día entero. Lo demás —el alto de 44,
 * el relleno, el cuerpo— se lo da la regla de los botones: la lista de
 * excepciones que había acá era de cuando un `.lote button` posterior le ganaba
 * por orden a `button.principal` y dejaba a la acción más irreversible de la
 * pantalla siendo el botón más chico. */
.lote {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: var(--paso);
}
.lote .rotulo {
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
.lote form { display: inline-flex; }
.lote button { font-family: var(--mono); }
/* --- Los listados y los informes: lo propio de cada pantalla ------------- */

/* Todo lo de acá para abajo es de **una** pantalla y no de una familia: el
 * cotizador, la cola de papeles pendientes, el padrón, los firmantes, las dos
 * mitades de la unificación, el corpus de ejemplos, el badge de dónde salió un
 * cierre y los informes de resultados. La grilla del contenido, el marco de una
 * tabla, la prioridad de columna, el campo de un formulario y el chip los ponen
 * las secciones de arriba; lo que se escribe acá es lo que **sólo** pasa en esa
 * pantalla y en ninguna otra.
 *
 * Dos cosas que se arreglan de una vez y se explican donde aparecen:
 *
 * 1. **La colisión del cotizador** (contrato §9). `.fila-cheque` era a la vez la
 *    fila del cotizador y el `<fieldset>` de un cheque de `/cargar`, con la misma
 *    especificidad (0,1,0) y en dos lugares del archivo separados por mil
 *    líneas: ganaba la última, y por eso el cotizador mostraba un campo de
 *    importe de 1200px con la fecha en el renglón siguiente. Acá se llaman
 *    `.fila-cotizador` y `.titulo-cotizador`, y `.fila-cheque` queda **sólo**
 *    para el cheque de `/cargar`, con el formulario del diálogo.
 * 2. **La colisión de `.procedencia`** (contrato §12.8). Era la lista «de dónde
 *    salió cada dato» de la propuesta **y** el badge de origen de un cierre, con
 *    la misma forma: el badge ganaba y la lista se dibujaba en negrita, a 11px y
 *    con `nowrap`, así que «nominal 3.500.000 del comprobante 12» no envolvía y
 *    se salía por la derecha. El badge pasa a `.procedencia-cierre` —renombrar
 *    la lista tocaría cuatro tests— y la lista se queda con su nombre, calificada
 *    por `.propuesta`, allá con el diálogo.
 *
 * Y una que se resuelve sin renombrar nada: `.grupo` es la tarjeta de un grupo
 * de unificación, la tarjeta de un ejemplo del corpus **y** el `<th>` de un grupo
 * de columnas de la grilla de Nosis. Las dos primeras son el mismo componente y
 * comparten regla; para que el fondo de tarjeta no se cuele en la celda de la
 * grilla, las reglas van calificadas con su contenedor —`.grupos-unificacion` y
 * `.corpus`—, que es el mismo remedio que la propuesta usa para `.cheques` y
 * `.terminos`. */

/* --- El cotizador -------------------------------------------------------- */

/* La única pantalla que ya estaba pensada para usarse de pie, y se conserva:
 * cada cheque es una tarjeta con sus dos campos. Lo que cambia es que ahora eso
 * es **la regla base** y la grilla de dos columnas es lo que se agrega desde
 * 640, en vez de al revés. */
.cotizador {
  padding: 12px;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}

/* Los campos que se pactan una vez —modo, términos, fecha de la operación—. No
 * lleva `.terminos .campo { flex: 0 1 auto }`: ese ancho lo pone la sección de
 * formularios, y lo pone **desde 640**, que es lo que deja un campo por línea en
 * el celular. Escribirlo acá sin `@media` era apretar tres campos a 120px en la
 * pantalla que se usa parado. */
.terminos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso) 10px;
  align-items: end;
}

/* El renglón que explica la notación —`5+2.5`, `96+2.5`, `2.5`—. Es texto que se
 * lee, no un rótulo: va al cuerpo de un dato y no al de una etiqueta. La barra
 * ámbar de la izquierda dice «esto es una convención que hay que conocer», que
 * es distinto de un aviso: no pasó nada, hay algo que saber. */
.ayuda {
  margin: var(--paso) 0;
  padding: 8px 11px;
  border-left: 3px solid hsl(var(--warning) / 0.7);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.1);
  color: hsl(var(--foreground));
  font-size: var(--t-dato);
}

/* El contenedor de las filas, y el destino del `hx-swap="beforeend"` de «+ Otro
 * cheque». **Calificado con `.cotizador`**: `.cheques` es también la lista de
 * papeles que entran en la propuesta del diálogo, y sin el contenedor delante
 * esta regla le daba la forma a aquélla —una `<ul>` convertida en columna
 * flexible, con el `padding-left` puesto allá para recuperar la sangría que este
 * `flex` se llevaba puesta—. */
.cotizador .cheques {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: var(--paso) 0;
}

/* La fila de rótulos de la grilla. **En el celular no se dibuja**: cada campo
 * lleva su propio `aria-label` y la tarjeta de abajo tiene lugar para el rótulo
 * al lado del campo; un encabezado de columnas arriba de una sola columna rotula
 * lo que no está. Desde 640 vuelve, con exactamente la misma grilla que la fila
 * de datos —es la única razón por la que existe: que las columnas coincidan—. */
.titulo-cotizador { display: none; }

/* Cada cheque, en el celular: una tarjeta con el nominal arriba y la fecha
 * abajo, los dos del ancho de la tarjeta. El `minmax(0, …)` y no `1fr` a secas
 * es el §12.2 del contrato: una pista `1fr` es `minmax(auto, 1fr)`, y el mínimo
 * automático de un campo con `nowrap` adentro empuja el documento. */
.fila-cotizador {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 6px;
  padding: var(--paso);
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}

/* Los rótulos de las columnas: el mismo tratamiento que el encabezado de una
 * tabla —más chico y más tenue que el dato que encabezan, regla 6— y **sin
 * versales**, que es la regla 8. El `min-width: 0` es el §12.2 otra vez: son
 * ítems de grilla. */
.titulo-cotizador span {
  min-width: 0;
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}

/* Los dos controles llegan al objetivo grande, y en las dos pantallas: el
 * cotizador se usa parado, con el teléfono en una mano y el papel en la otra, y
 * son los únicos dos campos que hay. Un campo de 48px en un monitor no le quita
 * nada a nadie; uno de 44 en la vereda, sí. */
.cotizador input, .cotizador select { min-height: var(--toque-grande); }

@media (min-width: 640px) {
  /* Desde acá entran las dos columnas: lo que sobra para el nominal y los
   * dieciséis caracteres de una fecha —los mismos 16ch que la tabla de anchos
   * por dato le da a todo `input[type="date"]`: diez de dato más el calendario
   * que el navegador dibuja adentro de la caja—. Las dos reglas comparten
   * declaración porque las columnas **tienen** que coincidir: que se separaran
   * fue la mitad menos contada de la colisión de `.fila-cheque`, y dejó «Fecha
   * de pago» rotulando el final del campo de importe. */
  .titulo-cotizador,
  .fila-cotizador { grid-template-columns: minmax(0, 1fr) 16ch; gap: 10px; }
  .titulo-cotizador { display: grid; }
  /* Con los rótulos arriba, la tarjeta por cheque deja de hacer falta: lo que se
   * lee es una tabla de dos columnas y no una lista de fichas. */
  .fila-cotizador { padding: 0; border-width: 0; }

  /* Acá los dos campos llenan su celda de la grilla, así que el ancho por tipo
   * de dato lo pone la grilla y no la tabla de anchos de la sección de
   * formularios. **Los tres selectores y no uno, y el motivo hay que contarlo
   * bien**: allá al nominal lo alcanzan `input[data-importe]` y
   * `input[name="nominal"]` y a la fecha `input[type="date"]`, y los tres pesan
   * (0,1,1) —un atributo cuenta en la columna de las clases—, que es exactamente
   * lo que pesa `.fila-cotizador input` a secas. O sea que con un selector solo
   * esto es un empate, y un empate lo decide el orden en el archivo concatenado:
   * andaría hoy, porque los listados van después de los formularios, y dejaría
   * de andar el día que alguien mueva una sección. Calificados con el atributo
   * pesan (0,2,1) y ganan por especificidad, que no depende de dónde quedó cada
   * parte. */
  .fila-cotizador input,
  .fila-cotizador input[name="nominal"],
  .fila-cotizador input[type="date"] { inline-size: 100%; }
}

/* «+ Otro cheque» y «Calcular». En el celular las dos del ancho de la pantalla y
 * una debajo de la otra: son la acción que agrega y la que resuelve, y apretadas
 * en un renglón de 390 quedan a media palabra cada una. Desde 640 vuelven a la
 * misma línea. */
.acciones-cotizador {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  margin-top: var(--paso);
}
@media (min-width: 640px) {
  .acciones-cotizador { flex-direction: row; flex-wrap: wrap; align-items: center; }
}

/* Lo que se pactó, arriba del resultado: modo, notación, fecha, tasa y comisión.
 * Es la lectura de los términos con los que se calculó lo de abajo, así que va
 * al cuerpo de un dato y tenue: acompaña a la tabla, no compite con ella. */
.resumen-terminos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: center;
  margin: calc(var(--paso) * 1.5) 0 var(--paso);
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* --- Los datos pendientes del papel (§4.9) ------------------------------- */

/* Las dos secciones de `/pendientes` y las dos de `/pendientes-definicion`.
 * Separadas de verdad y no sólo por el título: son colas distintas —el papel y
 * la ficha del cliente— en la misma pantalla, y sin aire entre ellas la tabla de
 * abajo se lee como la continuación de la de arriba. La segunda es además el
 * destino de un ancla, así que el `scroll-margin-top` es lo que impide que el
 * título quede pegado al borde cuando el navegador salta.
 *
 * El `+` es un combinador de hermano y está permitido acá porque lo que declara
 * es un margen: lo que el resolvedor de la suite no puede leer son las reglas de
 * `display`, `border`, `white-space`, `min-height`, `font-size`, `text-align` y
 * `animation`, y ninguna de esas se decide con un hermano en toda esta parte. */
.cola-pendientes + .cola-pendientes { margin-top: calc(var(--paso) * 4); }
.cola-pendientes > h2 { margin-bottom: var(--paso); scroll-margin-top: 16px; }
.cola-pendientes .formulario-fila { margin: 0; }

/* --- La fila que **es** un formulario: en el celular, una tarjeta -------- */

/* El marco sin tabla adentro. Lo usa el estado vacío de `/ejemplos`, que quiere
 * el borde, el fondo y el radio del marco para que el mensaje no flote suelto
 * sobre el fondo, y no quiere su desplazamiento: la regla base es `overflow-x:
 * scroll` —a propósito, para que la barra avise que la tabla sigue a la derecha
 * antes de que nadie la arrastre—, y sobre un párrafo de cuatro palabras eso
 * dibuja una barra debajo de un texto que no se mueve. Es el mismo apagado que
 * hace `.tabla-marco.papel` cuando la tabla se vuelve tarjeta. */
.tabla-marco.sin-tabla { overflow-x: auto; }

/* `.papel` marca las **once** tablas cuya fila lleva controles y no datos: o el
 * formulario que edita la fila no está en una columna sino que **es** la celda,
 * o la fila entera termina en él. Son la cola de cheques y la de fichas de
 * cliente (§4.9 y §4.4), el conteo del arqueo (§4.10), el catálogo de bancos
 * (§4.19), las personas de paso (§4.20), las preferencias de avisos (§15), las
 * dos del detalle de un seguimiento y el historial de un CUIT (§14) —esas tres
 * terminan en el formulario de archivar—, la de referencias que podrían ser
 * alias (§14.D.5) —termina en el `<form>` que las carga— y las ediciones de
 * cheque (§4.21), que es la única que además lleva `tarjeta-siempre` porque no
 * entra en ningún ancho.
 *
 * El contrato §12.5 ya había sacado a las primeras de las podables por la regla
 * dura «lo que se edita no se esconde»: si todas las columnas son `p1` no hay
 * nada que podar, así que la poda no era una salida para el celular.
 * **Desplazarse tampoco lo era**, y está medido: en
 * `/pendientes` a 390 la tabla pide 1.127px en un marco de 366 y el formulario
 * entero —número, CUIT, firmante, banco, garante y `Guardar`— queda fuera de la
 * pantalla, con la fila alta como su celda invisible: 2.500px de blanco adentro
 * del marco. En `/arqueo` a 390 no se veía **un solo campo de conteo**, que es
 * lo único que esa pantalla hace, y la primera columna `sticky` —del ancho
 * entero del marco— viajaba tapando el lugar donde tenían que aparecer.
 *
 * Lo que queda es lo que pide el plan §2b: **en el celular la fila es el
 * formulario, a lo ancho, con los datos de referencia de cabecera**. Hasta 640
 * la tabla deja de ser tabla —`display: block`, el `thead` escondido y cada
 * `tr` convertido en una tarjeta que envuelve— y desde 640 vuelve a serlo, con
 * sus columnas y su encabezado. La única que no vuelve es la que lleva además
 * `tarjeta-siempre`, y el porqué está en la `@media` de abajo, con su medición.
 * Es el mismo molde que `.propuesta table.datos` usa para el asiento del
 * diálogo, y el marcado de las plantillas ya servía tal como estaba.
 *
 * **El reparto de la tarjeta es por posición y no por clase**: la primera celda
 * es el título —de qué fila se trata: el cheque, el cliente, la caja, el banco,
 * la persona, el aviso, la severidad de la novedad, el número de la edición—, la
 * última es el formulario y va a lo ancho, y las del medio son la tira de
 * referencia, que mide lo que miden sus datos y envuelve. Es el orden que las
 * once tablas ya tenían escrito.
 *
 * Y `.papel` va **también en el marco**: con `overflow-x: scroll` —que es la
 * regla base de todo marco, contrato §12.12— una tarjeta que no se desplaza
 * dibujaría igual la barra debajo. `auto` la deja aparecer sólo si hace falta, y
 * es a propósito que no es `visible`: si mañana una tarjeta lleva algo más ancho
 * que el marco, el que se desplaza sigue siendo el marco y no la página. */
.tabla-marco.papel { overflow-x: auto; }

.datos.papel { display: block; }
/* El encabezado no se dibuja: en una tarjeta el `<th>` no titula nada —la celda
 * está debajo del título de su fila y no debajo de una columna— y costaría un
 * renglón de rótulos por tabla. Desde 640 vuelve, que es donde hay columnas que
 * nombrar. */
.datos.papel thead { display: none; }
.datos.papel tbody { display: block; }
/* **La canaleta va acá, y sin ella dos campos comparten píxel.** El hueco era
 * `2px 0`: separación entre renglones y **ninguna** entre celdas del mismo
 * renglón. Mientras la tira de referencia fueron datos sueltos no se notó —cada
 * celda trae su propio relleno—, pero en las cuatro cajas del arqueo que llevan
 * tipo de cambio el renglón son dos `<input>`, y dos cajas con borde pegadas una
 * a la otra se leen como una sola partida al medio: a 390 el `sin contar` de
 * `Contado` quedaba tapado por la caja del vecino, que se dibuja encima por ser
 * posterior en el documento. Un hueco de `--paso` es lo que hace que los dos
 * bordes se vean como dos bordes. */
.datos.papel tbody tr {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--paso);
  padding: 6px 0;
  border-bottom: 1px solid hsl(var(--border));
}
/* La última tarjeta no dibuja su línea: abajo ya está el borde del marco. */
.datos.papel tbody tr:last-child { border-bottom: none; }
/* §12.2 aplicado a una fila flexible: sin `min-width: 0` una razón social o un
 * código de cuenta le ponen al renglón el mínimo de su contenido y estiran la
 * tarjeta entera. El borde se va porque ahora lo lleva la fila.
 *
 * **El `white-space` es el que importa.** `table.datos td` va con `nowrap` y
 * pesa (0,1,2); esta regla pesa (0,2,2) y le gana. En una tabla el `nowrap` es
 * lo que hace que las columnas se lean —lo que sobra se alcanza desplazando el
 * marco—; en una tarjeta no hay ninguna columna a la derecha que alcanzar, así
 * que lo que no envuelve se sale del marco y se pierde. El `overflow-wrap` es
 * para lo que no tiene un solo espacio donde cortar, que acá es un código de
 * cuenta —`CAJA.ARS.CHEQUES`— y es el mismo motivo por el que la propuesta del
 * diálogo lo usa.
 *
 * **El `<th scope="row">` entra en la misma regla que la celda**, y por eso la
 * lista nombra a los dos. Un encabezado de fila es la primera celda de la tabla
 * de preferencias de avisos: sin nombrarlo se queda con el `nowrap` de
 * `table.datos th` —«Fuente de cotizaciones caída» en una sola línea— y sin el
 * reparto de abajo, así que la casilla de al lado le arranca al costado en vez
 * de debajo. Ninguna de las otras `papel` tiene encabezados de fila, así que
 * agregarlo no le cambia el dibujo a ninguna. Pesa (0,2,2) contra el (0,1,2) de
 * `table.datos th`. */
.datos.papel tbody td,
.datos.papel tbody th {
  display: block;
  min-width: 0;
  border-bottom: none;
  white-space: normal;
  overflow-wrap: anywhere;
}
/* El título de la tarjeta y el formulario, cada uno con el renglón entero. Entre
 * los dos queda la tira de referencia, que es todo lo demás y envuelve sola.
 *
 * La celda de «no hay nada» —`<td colspan>` en bancos y en personas de paso— es
 * la primera **y** la última de su fila, así que cae acá y ocupa el ancho: es la
 * mitad que el `colspan` deja de hacer cuando la tabla es `display: block`, y
 * por eso el estado vacío del catálogo de bancos deja de cortarse a mitad del
 * comando que dice cómo llenarlo. Y el `th:first-child` es el título de la
 * tarjeta de un aviso: ahí la primera celda es el encabezado de la fila —el
 * nombre del aviso— y las dos casillas cuelgan debajo, cada una con su rótulo
 * escrito. */
.datos.papel tbody th:first-child,
.datos.papel tbody td:first-child,
.datos.papel tbody td:last-child { flex: 1 1 100%; }

/* La tarjeta de un cheque sin identificar. Es el que además **no se puede
 * vender**, así que se distingue de los que sólo esperan el firmante —con el
 * filo y con la palabra en la columna «Falta», no sólo con el color—. En la
 * tabla el filo lo lleva la primera celda; en la tarjeta lo lleva la tarjeta,
 * que es lo que la marca de punta a punta. */
.datos.papel tbody tr.sin-identificar {
  border-left: 3px solid hsl(var(--destructive-text));
}

.datos.papel td { vertical-align: top; }
.datos.papel .formulario-fila { margin: 0; }
/* **Las dos tablas de catálogo llevan el formulario en piezas sueltas, y sin
 * esto nadie les reparte el renglón.** En bancos y en personas de paso la celda
 * tiene un `<input>`, un `<select>` y un `<button>` colgando directo del `form`,
 * sin ningún `.campo` alrededor: todo control mide el 100% de su caja en el
 * celular, así que el campo se llevaba un renglón, el estado otro, y el botón
 * quedaba solo en un tercero midiendo lo que mide la palabra «Guardar» —chico y
 * a media izquierda, cuarenta y cinco píxeles de alto por fila para eso—. Las
 * otras cinco `papel` no las alcanza este selector porque ahí las piezas van
 * adentro de un `.campo` y no son hijas directas del formulario.
 *
 * El reparto: el que se tipea se lleva el renglón entero —es el nombre corto del
 * banco o los alias de la persona, y medio renglón para escribir no es un
 * campo—, y el estado y el botón comparten el de abajo. Dos renglones en vez de
 * tres, y un botón de medio marco en vez de uno del ancho de su palabra. El
 * `40%` es una base y no un ancho: los dos crecen con el `flex-grow` hasta
 * partir el renglón por la mitad. */
.datos.papel .formulario-fila > input { flex: 1 1 100%; min-width: 0; }
.datos.papel .formulario-fila > select,
.datos.papel .formulario-fila > button { flex: 1 1 40%; min-width: 0; }

/* **El arqueo es la excepción del reparto, y no por capricho**: su formulario no
 * vive en una celda sino en tres —papeles, contado y tipo de cambio, una columna
 * cada uno—, que es lo que su propia plantilla dice cuando anota que cuatro de
 * sus cinco columnas llevan un control. Con el reparto de arriba, dos de los
 * tres campos caerían en la tira de referencia, y un `<input>` en el celular
 * mide el 100% de su caja: en una celda que se encoge a su contenido eso no
 * quiere decir nada.
 *
 * Se las reconoce por `.ancha` y por `.num`: el arqueo es la única `papel` que
 * además es `ancha` —la primera columna se queda quieta mientras se llega a
 * «Contado»— y en ella las columnas numéricas **son** el formulario. Los tres
 * campos van juntos en un renglón que envuelve y no apilados: son una cantidad
 * de papeles, un importe y un tipo de cambio, y tres renglones de 366px para
 * tres números serían tres pantallas de conteo.
 *
 * **Cada celda mide lo que mide su campo, y eso es la corrección de un
 * `flex: 1 1 12ch` que repartía el renglón en tres partes iguales.** Los anchos
 * de los tres controles ya están escritos en `ch` unas líneas más arriba —17 el
 * conteo, 6 los papeles, 10 el tipo de cambio, y salen del dato que entra, no de
 * la caja que lo contiene—, así que una celda de doce caracteres le quedaba
 * **corta** al campo de diecisiete: el `<input>` se salía de su celda y se
 * dibujaba por debajo del de al lado, que es exactamente el defecto que se vio a
 * 390 —«sin c» y la caja del vecino encima—. Repartir en tres iguales tampoco
 * era la salida: 364px menos la moneda y los huecos dan noventa y pico por
 * campo, y ahí lo que se corta deja de ser el placeholder para ser **el importe
 * que alguien acaba de tipear**, que en esta pantalla es el dato.
 *
 * Con `0 1 auto` la celda mide su contenido, nada se superpone y el renglón
 * envuelve donde tiene que envolver: `moneda | papeles | contado` entran en los
 * 364 del marco (unos 311) y `Tipo de cambio` cae al renglón de abajo con su
 * rótulo. **En las once tarjetas igual**, que era la otra mitad del defecto: la
 * de `CAJA.USDT` envolvía y las otras diez no, así que la misma fila se armaba
 * de dos formas distintas en la misma pantalla —y la que no envolvía era la que
 * se superponía—.
 *
 * **El precio, medido y elegido: un renglón más por tarjeta**, unos 60px por
 * caja. La alternativa era forzar los tres `<input>` al ancho de su celda —tres
 * de noventa píxeles— y no cuesta alto, pero deja el campo del conteo mostrando
 * siete caracteres de un importe de trece en la única pantalla que existe para
 * tipear importes. Es exactamente la regla que la sección de arriba declara y que
 * `arqueo.html` repite: el ancho de un campo sale del dato que entra, y estos
 * tres «no se tocan». El alto es la moneda barata acá; el ancho del campo no. */
.datos.papel.ancha tbody td.num { flex: 0 1 auto; }
/* Y cada uno se lleva su rótulo. En la tarjeta no hay `<thead>` que diga qué se
 * está tipeando, y tres cuadros de números sin nombre no son un conteo. Va en la
 * sans y a la izquierda porque `.num` pone la mono y la derecha **para la
 * cifra**, no para su nombre: es la misma corrección que `table.datos th.num` ya
 * hace en el encabezado de una columna numérica. Desde 640 se esconde, que es
 * donde el `<thead>` lo dice una vez por tabla en vez de una por fila. */
.datos.papel.ancha td.num .rotulo-campo {
  display: block;
  text-align: left;
  font-family: var(--sans);
}
/* La primera columna quieta no tiene sentido en una tabla que dejó de ser tabla:
 * no hay eje horizontal que recorrer, y lo que hacía a 390 era viajar por encima
 * de los campos de conteo con el fondo opaco que un `sticky` necesita. Pesa
 * (0,4,3) contra el (0,3,2) de `table.datos.ancha td:first-child`, que es lo que
 * le deja ganarle; y por eso mismo hay que **devolverla** desde 640, donde la
 * tabla vuelve a desplazarse y la columna vuelve a ser el ancla de la fila. */
table.datos.papel.ancha thead th:first-child,
table.datos.papel.ancha tbody th:first-child,
table.datos.papel.ancha tbody td:first-child {
  position: static;
  background: none;
  box-shadow: none;
}

@media (min-width: 640px) {
  /* Y vuelve a ser una tabla, con su encabezado y sus columnas. */
  .datos.papel { display: table; }
  .datos.papel thead { display: table-header-group; }
  .datos.papel tbody { display: table-row-group; }
  .datos.papel tbody tr {
    display: table-row;
    gap: 0;
    padding: 0;
    border-bottom: none;
  }
  .datos.papel tbody td,
  .datos.papel tbody th {
    display: table-cell;
    border-bottom: 1px solid hsl(var(--border));
    white-space: nowrap;
    overflow-wrap: normal;
  }
  /* La columna de alias sigue envolviendo. `table.datos td.alias` pesa (0,2,2) y
   * la regla de acá arriba pesa lo mismo, así que a igualdad ganaría por venir
   * después en el archivo y la fila de un cliente con tres alias volvería a
   * estirarse sin techo —que es el defecto que la sección del padrón cuenta—. Se
   * le devuelve con la tabla nombrada, que pesa (0,3,3). */
  table.datos.papel tbody td.alias,
  /* Y las columnas de texto libre, por lo mismo y con más motivo: la regla que
   * las hace envolver —`table.datos .descripcion, .notas, .detalle`— pesa
   * (0,2,1) y la de acá arriba (0,2,2), así que al ponerle `papel` a las dos
   * tablas del seguimiento de Nosis la causal y el detalle de una novedad
   * pasaron a dibujarse en **una línea sin techo** de 640 para arriba. Es el bug
   * histórico de la casa otra vez —`table.datos td` ganándole a `.num`— y acá
   * hacía justo lo contrario de lo que se buscaba: una causal larga estira la
   * fila y empuja el formulario de archivar más lejos del borde. */
  table.datos.papel tbody td.descripcion,
  table.datos.papel tbody td.notas,
  table.datos.papel tbody td.detalle { white-space: normal; }
  /* La celda de referencia de la **cola de cheques**: número de operación,
   * estado y fecha de entrada, unos treinta y cinco caracteres en una línea.
   * Acotada a dieciocho envuelve en dos renglones y las cinco columnas de
   * referencia se achican, que es lo que deja que el formulario empiece antes en
   * el marco que sí se desplaza.
   *
   * Va atada al `id` del bloque que HTMX reemplaza porque es un ajuste de **esa**
   * tabla y no de la clase: los mismos dieciocho caracteres partirían en dos toda
   * razón social del catálogo de bancos, y en el arqueo no entraría ni el código
   * de la caja. Hasta 640 no hace falta ninguna de las dos cosas: ahí la celda es
   * el título de la tarjeta y se lleva el renglón entero. */
  #tabla-pendientes .datos.papel tbody td:first-child {
    max-width: 18ch;
    white-space: normal;
  }
  /* En la fila, el filo del cheque sin identificar vuelve a la primera celda. Se
   * apaga el de la tarjeta con la misma especificidad y no se lo deja puesto: en
   * el modelo de bordes colapsados el `border` de un `tr` **sí** se dibuja, y
   * quedarían dos filos, uno pegado al otro. */
  .datos.papel tbody tr.sin-identificar { border-left: none; }
  .datos.papel tr.sin-identificar > td:first-child {
    border-left: 3px solid hsl(var(--destructive-text));
  }
  /* El rótulo lo dice el `<thead>`, una vez por tabla. */
  .datos.papel.ancha td.num .rotulo-campo { display: none; }
  /* Y las tres piezas sueltas del formulario de catálogo vuelven a medir lo
   * suyo: acá la celda es una celda de una fila y los tres entran en un renglón
   * con el ancho por dato que la sección de formularios les da. Sin esto, el
   * `flex: 1 1 100%` del campo lo seguiría mandando solo a un renglón en los
   * tres anchos donde no hace falta. */
  .datos.papel .formulario-fila > input,
  .datos.papel .formulario-fila > select,
  .datos.papel .formulario-fila > button { flex: 0 1 auto; }
  /* Y la columna quieta vuelve, con el fondo y la línea que la separan de las
   * que se mueven (§12.10). `left` y `z-index` no hacen falta acá: la regla de
   * `table.datos.ancha` los declara y esta rama nunca los tocó. */
  table.datos.papel.ancha thead th:first-child,
  table.datos.papel.ancha tbody th:first-child,
  table.datos.papel.ancha tbody td:first-child {
    position: sticky;
    background: hsl(var(--card));
    box-shadow: inset -1px 0 0 hsl(var(--border));
  }

  /* **`tarjeta-siempre`: la tabla que no vuelve, porque no entra en ningún
   * ancho.** Las `papel` de arriba recuperan la forma de tabla acá porque a 640
   * su formulario ya entra en la columna que la tabla le da. La de
   * `/cartera/ediciones` no entra en ninguno de los cuatro cortes, y está
   * medido: la fila pide 1.001px en los 366px de marco del celular, 1.698 en
   * los 920 de la notebook y 1.930 en los 1.240 del monitor —`medidas.json`—,
   * así que `Aprobar`, `Rechazar` y el campo del motivo quedaban fuera del
   * marco **en los tres anchos** y de la fila sólo se veía una caja blanca
   * vacía de 180px. Era el defecto más grave de la interfaz y era anterior al
   * rediseño.
   *
   * **El número a batir el día que alguien le quiera devolver la forma de
   * tabla es 1.930 contra 1.240**: mientras el motivo de una edición sea texto
   * libre y la fila termine en un campo de texto con dos botones, ese ancho no
   * lo cierra ningún corte de los que el contrato §1 permite.
   *
   * Cada regla repite el selector de la que revierte y le suma la clase: pesa
   * un elemento más —(0,3,0) contra (0,2,0), (0,3,2) contra (0,2,2)— y gana sin
   * depender de dónde caiga en el archivo. Lo que no se repite —`flex-wrap`,
   * `align-items`, el reparto de la primera y la última celda— lo sigue
   * poniendo la regla base de `papel`, que esta `@media` nunca tocó. */
  .datos.papel.tarjeta-siempre { display: block; }
  .datos.papel.tarjeta-siempre thead { display: none; }
  .datos.papel.tarjeta-siempre tbody { display: block; }
  .datos.papel.tarjeta-siempre tbody tr {
    display: flex;
    gap: 2px var(--paso);
    padding: 6px 0;
    border-bottom: 1px solid hsl(var(--border));
  }
  .datos.papel.tarjeta-siempre tbody td {
    display: block;
    border-bottom: none;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* --- El padrón y los firmantes: la columna de alias ---------------------- */

/* **Acá estaba el defecto que hacía filas de 100 a 170 píxeles.** La columna de
 * alias no tenía ancho mínimo, así que en una tabla de ocho columnas el
 * repartidor automático le daba el ancho de **un** chip —unos 110px— y los
 * alias se apilaban en vertical, uno por renglón, a 44px cada uno. Tres alias
 * eran tres renglones más el campo de «+ alias»: 176px de fila para tres
 * palabras. Y en la tabla de firmantes pasa dos veces por fila, porque son dos
 * columnas de chips —alias y bancos—.
 *
 * El arreglo es el ancho mínimo: con veinticuatro caracteres entran dos o tres
 * chips por renglón y **envuelven en horizontal**, que es como se lee una lista
 * de etiquetas. El tope de arriba se queda: sin él, un cliente con quince alias
 * se lleva el ancho de las columnas de importes. Los dos van juntos porque son
 * la misma decisión —cuánto de la fila es de esta columna— y por eso viven acá y
 * no con las columnas de texto libre de la sección de tablas.
 *
 * El mínimo entra desde 640: en el celular la columna no se dibuja —es `p2`—, y
 * en las tablas de unificación —que no se podan— veinticuatro caracteres de
 * mínimo en una pantalla de 390 sólo alargarían el desplazamiento. **Y desde
 * 640 el mínimo tiene algo que medir en las tres**, que es lo que cambió al
 * pasar `Alias` de `p3` a `p2`: mientras fue `p3` la columna del padrón y la de
 * firmantes recién aparecían a 1440 —o sea que en la notebook no se podía
 * agregar ni quitar un alias, y una columna que contiene un control nunca es
 * `p3`—, y de 640 a 1439 el único que usaba este piso era el de unificación. */
table.datos td.alias { max-width: 34ch; }
@media (min-width: 640px) {
  /* **El piso vale para la celda que tiene chips que acomodar, y sólo para
   * ésa.** Escrito para todas, un `<td class="alias">` que lleva únicamente el
   * campo de «+ alias» —el firmante sin ningún alias cargado, que en el padrón
   * de firmantes es el caso normal— se llevaba 24ch cuando su contenido mide 14:
   * 240px de columna para un campo de 154. Y `min-width` es un piso que aprieta
   * **justo cuando no hay ancho**, porque es entonces cuando el navegador reparte
   * por mínimos: en `firmantes` a 1536 esos 66px de más eran los que empujaban la
   * columna de acciones fuera del marco (regresión N2). Donde el ancho sobra la
   * columna crece igual sin el piso, por reparto —medido: 174 de mínimo, 235
   * dibujados en `clientes` a 1536—, así que el piso no compra nada ahí y cuesta
   * todo acá.
   *
   * El `:has()` es de los pocos que sobreviven en esta hoja, y sobrevive por lo
   * mismo que el de `.alias .chip:has(button)`: lo que declara es un `min-width`,
   * y ninguna afirmación de la suite pregunta por esa propiedad, así que no deja
   * a ningún test sin poder concluir —`tests/estilos.py` no sabe leer `:has()` y
   * envenena a todo test que pregunte por una propiedad que aparezca adentro de
   * uno—. En un navegador sin `:has()` no hay piso en ninguna celda y los chips
   * de un alias largo vuelven a apilarse de a uno por renglón: la fila queda más
   * alta y nada más. */
  table.datos td.alias:has(.chip) { min-width: 24ch; }
}

/* La otra mitad del alto de la fila. Un chip de 44px alineado por su línea de
 * base deja debajo el hueco de los descendientes del renglón, así que dos filas
 * de chips medían más de 88px sin que nada lo pidiera; alineados al medio, la
 * caja del renglón mide lo que mide el chip. Y el relleno vertical de la celda
 * baja a uno, como en la columna de acciones y por el mismo motivo: el objetivo
 * táctil ya lo pone el chip. **Calificado con `table.datos`**: el relleno de una
 * celda lo pone `table.datos th, table.datos td`, que pesa (0,1,2), y un
 * `td.alias` a secas pesa (0,1,1) y no llegaba. Es la trampa de especificidad de
 * siempre, en otra propiedad. */
table.datos td.alias { padding-top: 1px; padding-bottom: 1px; }
.alias .chip { min-height: var(--toque); margin: 1px 3px 1px 0; vertical-align: middle; }

/* La cruz que saca un alias también mide 44, y ahí no hay excepción que valga:
 * hace un POST destructivo, con auditoría y sin confirmación, y medía doce
 * píxeles. El chip crece con ella.
 *
 * El `:has()` es porque no todos los chips de alias llevan la cruz: en la ficha
 * de un cliente son sólo etiquetas, y ahí el relleno de la derecha hace falta.
 * Es uno de los pocos que sobreviven, y sobrevive porque lo que declara es un
 * relleno: ninguna afirmación de la suite pregunta por el `padding` de un chip,
 * así que no deja a ningún test sin poder concluir. En un navegador sin `:has()`
 * el chip queda ocho píxeles más ancho y nada más. */
.alias .chip:has(button) { padding-right: 0; }
.alias .chip button {
  min-height: var(--toque);
  padding: 0 10px;
  border: none;
  background: none;
  color: hsl(var(--primary-text));
  font-size: var(--t-cuerpo);
  line-height: 1;
  cursor: pointer;
}
.alias .chip button:hover { background: none; color: hsl(var(--destructive-text)); }

/* «+ alias»: el campo que agrega uno, en la misma celda y en el mismo renglón
 * que los chips. Catorce caracteres, que es lo que mide un alias del padrón, y
 * **sin `font-size` propio**: todo campo de formulario va a `--t-cuerpo`, porque
 * por debajo de 16 iOS hace zoom al enfocar y el zoom adentro de una tabla de
 * ocho columnas deja la fila fuera de cuadro. */
.alias-nuevo { display: inline-flex; gap: 4px; vertical-align: middle; }
.alias-nuevo input { inline-size: 14ch; min-height: var(--toque); padding: 0 8px; }
.alias-nuevo button { min-height: var(--toque); padding: 0 12px; font-size: var(--t-dato); }

/* --- Firmantes: lo que contestó la escritura (§4.16, §4.17, §4.18) ------- */

/* El bloque de banco, firmante y CUIT dentro de la fila de un cheque pendiente.
 * `display: contents` y no una caja: los tres campos de adentro tienen que
 * repartirse en la misma fila flexible que el resto del formulario, y una caja
 * intermedia los encerraría en un renglón propio. Existe como elemento porque es
 * lo único de esa fila que se reemplaza solo, al soltar el campo del CUIT. */
.bloque-firmante { display: contents; }

/* El renglón que contesta debajo del campo. Es la traducción de las tres
 * gravedades de `gdv.web.avisos` al hueco de un formulario: acá el cartel es una
 * línea debajo de un control y no el aviso de pantalla, así que tiene su propio
 * vocabulario. La tabla que traduce una a otra es `CLASES_DE_LA_PISTA`, en
 * `paginas.py`. */
.estado-firmante { margin-top: 2px; }
.estado-firmante .pista {
  display: block;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
.estado-firmante button { min-height: var(--toque); padding: 0 12px; font-size: var(--t-dato); }

/* Verde: la escritura entró e hizo lo que se pidió. **Sin calificar con
 * `.estado-firmante`**, que es como estaba escrita: la misma pista verde
 * aparece también debajo del campo del CUIT de un cheque y en la respuesta de
 * los candidatos parecidos, y en esos dos lugares se dibujaba gris. Pesa (0,2,0) igual que
 * `.estado-firmante .pista` y va después, así que le gana donde las dos
 * alcanzan. */
.pista.ok { color: hsl(var(--success-text)); }

/* Ámbar: **no falló y tampoco pasó nada**. Es «ya tenía todo esto cargado, y este
 * cheque ya estaba vinculado a él», que es la pantalla volviendo exactamente
 * igual que antes. Faltaba, y esto salía de verde: la señal que hace que alguien
 * dé por cargado un padrón que no cargó. En rojo diría que algo falló, y no falló
 * nada.
 *
 * **Punteada**, como `.marca-provisorio`, `.marca-falta` y `.marca-sin-datos`: en
 * esta interfaz el trazo punteado es «esto no es lo normal y no es un error», y
 * es lo que hace que el renglón se distinga del verde de arriba **sin el color**
 * —GDV_DESIGN §4 y §11—. Las otras dos gravedades no lo necesitan: son las que
 * el ojo ya separa por el lugar donde aparecen, y ésta es la que se confunde con
 * la de al lado.
 *
 * El `white-space: normal` y el tope de ancho, por lo mismo que el rojo: la frase
 * nombra al firmante, que es texto de largo variable, y con el `nowrap` de la
 * celda ensancharía la fila del cheque sin techo. */
.estado-firmante .pista.aviso-firmante {
  max-width: 46ch;
  margin-top: 3px;
  padding: 2px 7px;
  border: 1px dotted hsl(var(--warning-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.14);
  color: hsl(var(--warning-text));
  white-space: normal;
}

/* Rojo: la escritura fue rechazada y no entró —«el CUIT no verifica»—. Se llamaba
 * `.aviso-firmante`, que es el nombre del ámbar en toda la hoja: dejarlo así al
 * lado de un ámbar nuevo era dejar la trampa puesta para el próximo que eligiera
 * la clase por el nombre. */
.estado-firmante .pista.error-firmante {
  max-width: 46ch;
  color: hsl(var(--destructive-text));
  white-space: normal;
}

/* «¿No es alguno de éstos?»: los firmantes parecidos al que se acaba de
 * escribir. Va arriba de la tabla porque el cheque que la disparó suele haber
 * salido ya de la cola en el mismo movimiento. */
.sugerencia-firmante {
  margin: 0 0 var(--paso);
  padding: 10px 12px;
  border: 1px solid hsl(var(--primary-text) / 0.7);
  border-left-width: 4px;
  border-radius: var(--radio);
  background: hsl(var(--primary) / 0.14);
  font-size: var(--t-dato);
}
.sugerencia-firmante p { margin: 0 0 6px; }
.sugerencia-firmante .pista {
  margin: 6px 0 0;
  font-size: var(--t-rotulo);
  color: hsl(var(--muted-foreground));
}
.candidatos { display: flex; flex-wrap: wrap; gap: 6px; }

/* «Ese nombre ya está, ¿es el mismo?»: los parecidos que aparecen **antes** de
 * crear un firmante nuevo, cada uno con su peso —cuántos cheques, qué bancos—.
 * El peso va en la misma línea y no escondido: un nombre parecido sólo dice que
 * se parece, y 230 cheques con cuatro bancos es lo que permite reconocerlo.
 *
 * `flex-wrap` y un `flex-basis` en caracteres para el nombre: en un celular el
 * nombre se lleva el renglón y el botón cae abajo, del ancho que necesite, en
 * vez de aplastarse contra el borde. */
.candidatos-peso { list-style: none; margin: 0; padding: 0; }
.candidatos-peso li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--paso);
  padding: 4px 0;
  border-top: 1px solid hsl(var(--border));
}
.candidatos-peso li:first-child { border-top: 0; }
.candidatos-peso .quien { flex: 1 1 24ch; min-width: 0; }
/* El peso baja de renglón: al lado del nombre lo empujaba fuera de la fila. El
 * cuerpo lo pone `.secundario`, que ya es `--t-dato`; acá sólo cambia que sea un
 * bloque. */
.candidatos-peso .secundario { display: block; }
.candidatos-peso form { margin: 0; }

/* Dentro de la fila de un cheque el mismo recuadro tiene que ocupar menos: ahí
 * compite con los campos que se están tipeando, y no con una tabla. */
.sugerencia-firmante.en-fila {
  max-width: 52ch;
  margin: 6px 0 0;
  padding: 6px var(--paso);
  font-size: var(--t-dato);
  white-space: normal;
}

/* --- La pantalla de unificación ------------------------------------------ */

/* Los firmantes que faltan clasificar. Es una sección con su propio título
 * porque son dos trabajos distintos sobre el mismo padrón —decir quién es quién,
 * y decir qué es cada uno— y se hacen en la misma sentada. */
.por-clasificar { margin-bottom: calc(var(--paso) * 2); }
.por-clasificar h2 { margin-top: 0; }
/* Las acciones de esta tabla son tres o cuatro y no caben en un renglón de 390:
 * envuelven en vez de desbordar la celda. */
.por-clasificar .fila-acciones { display: flex; flex-wrap: wrap; gap: 4px; }
/* El filtro por forma del nombre. Va arriba de la tabla y no adentro del lote:
 * recorta a quién se mira, y lo que se decide sobre lo mirado es otra cosa. */
.por-clasificar .filtros-padron { align-items: center; margin-bottom: var(--paso); }
.por-clasificar .filtros-padron .nota { margin: 0; }

.grupos-unificacion { display: flex; flex-direction: column; gap: var(--paso); }

/* Cada grupo es una tarjeta con sus salidas. Ninguna es «después lo veo» —eso es
 * lo que dejó el padrón como está—, y por eso las tres están al mismo nivel: las
 * dos que contestan el grupo entero y la que lo contesta por partes.
 *
 * **Calificada con `.grupos-unificacion` y `.corpus`**, que son sus dos
 * contenedores: `.grupo` es además el `<th>` de un grupo de columnas de la
 * grilla de Nosis, y sin el contenedor delante ese encabezado se llevaba el
 * fondo de superficie de una tarjeta. Es la misma cuenta que la propuesta hace
 * con `.cheques` y `.terminos`, y evita un renombre que tocaría una plantilla y
 * un test para arreglar una celda.
 *
 * Sin sombra: la tarjeta se separa del fondo con el borde y el color de
 * superficie, que alcanza en los dos temas. La única sombra que queda en la hoja
 * es la del menú de usuario desplegado y la de la hoja de «Más», que son las dos
 * cosas que de verdad flotan. */
.grupos-unificacion .grupo,
.corpus .grupo {
  padding: 10px 12px;
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
  background: hsl(var(--card));
}
/* Por qué el sistema juntó estos: «mismo CUIT», «mismo nombre normalizado». Es
 * la explicación de la propuesta y se lee antes que la lista. */
.criterio {
  margin: 0 0 var(--paso);
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}
.grupos-unificacion .grupo table.datos,
.corpus .grupo table.datos { margin: 0; }
/* Las salidas del grupo, al pie y envolviendo: son dos o tres botones y en un
 * celular no entran en un renglón. */
.grupos-unificacion .grupo .acciones,
.corpus .grupo .acciones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  margin-top: 10px;
}
.grupos-unificacion .grupo .nota,
.corpus .grupo .nota { margin: var(--paso) 0 0; }

/* --- Unificar por búsqueda ----------------------------------------------- */

/* El bloque del buscador va **arriba** de los grupos y separado por una línea:
 * son dos trabajos sobre el mismo padrón —lo que uno ya sabe y lo que el sistema
 * sospecha— y mezclarlos haría dudar de cuál de los dos botones contesta qué. */
#unificar-busqueda {
  padding-bottom: var(--paso);
  margin-bottom: calc(var(--paso) * 2);
  border-bottom: 1px solid hsl(var(--border));
}
#unificar-busqueda h2 { margin-top: 0; }
#unificar-busqueda .lote .nota { margin: 0; }

/* El formulario del firmante que queda. Es una tarjeta como la de un grupo: lo
 * que se está por hacer tiene que verse separado de la lista sobre la que se
 * marcó, o el botón parece pertenecer a la fila que se está mirando. El borde
 * primario es lo que dice que esto es la consecuencia de lo de arriba. */
.unificar-resultante {
  padding: 10px 12px;
  margin-bottom: var(--paso);
  border: 1px solid hsl(var(--primary-text) / 0.6);
  border-radius: var(--radio);
  background: hsl(var(--card));
}
/* Adentro del formulario el criterio es un ítem más de la fila flexible, así que
 * se lleva el renglón entero para no quedar apretado entre dos campos. */
.unificar-resultante .criterio { flex: 1 1 100%; margin: 0 0 4px; }

/* Las razones sociales candidatas, una por línea. Van como radios y no como un
 * desplegable porque son la lista de lo que se marcó: hay que poder leerlas
 * todas juntas para elegir la que está bien escrita. Monoespaciadas porque lo
 * que se hace con ellas es compararlas carácter por carácter —«MOTO SPORT SA» y
 * «MOTO SPORT S.A.»—, que es exactamente para lo que sirve la mono. */
.opciones-razon .opcion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: var(--t-dato);
}
.opciones-razon .opcion input[type="radio"] { margin: 0; }
/* La que se escribe a mano se lleva lo que sobre del renglón: es texto libre y
 * no tiene largo previsible. */
.opciones-razon .opcion input[type="text"] { flex: 1 1 24ch; min-width: 0; }

/* Las fusiones que se pueden deshacer. Que la operación sea reversible no sirve
 * de nada si el botón no está en ningún lado. */
.lista-fusiones { list-style: none; margin: 0; padding: 0; font-size: var(--t-dato); }
.lista-fusiones li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 5px 0;
  border-bottom: 1px solid hsl(var(--border));
}
.lista-fusiones li:last-child { border-bottom: none; }
.lista-fusiones button { min-height: var(--toque); padding: 0 12px; font-size: var(--t-dato); }

/* --- El corpus de ejemplos verificados (§9) ------------------------------ */

/* Una lista de tarjetas y no una tabla, y la razón no es estética: para juzgar
 * si un ejemplo enseña bien hay que leer el mensaje y el asiento **juntos**, y
 * una fila de doce columnas hace exactamente lo contrario —parte las dos mitades
 * y obliga a desplazar—. Reusa la tarjeta de los grupos de unificación, que es
 * el mismo problema: una decisión por bloque, con sus salidas al pie. */
.corpus { display: flex; flex-direction: column; gap: var(--paso); }

/* El mensaje tal como lo escribió el operador. Monoespaciada porque es texto que
 * se compara con otro texto —lo que la oficina escribe todos los días—, y con el
 * salto de línea respetado porque un mensaje de dos renglones es de dos
 * renglones. `overflow-wrap: anywhere` es lo que impide que un adjunto pegado sin
 * espacios estire la tarjeta a lo ancho.
 *
 * Radio grande y no chico: tiene borde propio, relleno y fondo, o sea que es un
 * panel y no un control —contrato §2, la lista de trece cajas mal archivadas—. */
.mensaje-corpus {
  margin: 0 0 var(--paso);
  padding: var(--paso) 10px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
  background: hsl(var(--background));
  font-family: var(--mono);
  font-size: var(--t-dato);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Un ejemplo dado de baja se sigue viendo entero: es la respuesta a «¿por qué el
 * prompt de marzo tenía este caso y el de hoy no?». Lo que cambia es que se lee
 * como lo que es, algo que ya no está en el corpus. El trazo punteado es la
 * señal que no depende del color, como en las marcas. */
.corpus .grupo.de-baja { border-style: dashed; opacity: 0.72; }

/* El motivo de la baja y su botón, en la misma línea: son una sola respuesta. El
 * campo se estira para que quepa una frase y no tres palabras. */
.corpus .acciones .formulario-fila { display: flex; gap: 6px; flex: 1 1 32ch; }
.corpus .acciones .formulario-fila input[type="text"] { flex: 1 1 auto; min-width: 0; }

/* --- De dónde salió el cierre de un día (§13) ---------------------------- */

/* Tres procedencias y tres formas distintas, no tres colores: relleno para el
 * capturado, trazo punteado para el arrastrado —que es el que hay que poder
 * distinguir de un vistazo, porque su precio es de otro día— y trazo lleno para
 * el que escribió una persona.
 *
 * Se llamaba `.procedencia`, y así se llama todavía la lista «de dónde salió cada
 * dato» de la propuesta del diálogo: dos reglas desnudas con la misma
 * especificidad, en dos secciones separadas por novecientas líneas, y ganaba
 * ésta. La lista se dibujaba entonces como un badge —en versales, en negrita, a
 * 11px y con `nowrap`—, así que «nominal 3.500.000 del comprobante 12» no
 * envolvía y se salía por la derecha de un celular. El badge es el que se
 * renombra (contrato §12.8) porque renombrar la lista tocaría cuatro tests, y
 * este badge vive en dos parciales y en dos archivos de test, que se tocan en
 * el mismo commit que el renombre.
 *
 * Sin versales: lo que separa un badge del texto de al lado son el cuerpo, el
 * peso y la caja, y ninguno de los tres necesita mayúsculas. */
.procedencia-cierre {
  display: inline-block;
  padding: 1px 7px;
  border: 1px solid transparent;
  border-radius: var(--radio-chico);
  font-size: var(--t-rotulo);
  font-weight: 600;
  white-space: nowrap;
}
/* El precio que salió de una captura automática: es el caso normal y el que
 * menos tiene que llamar la atención. */
.procedencia-cierre.capturado {
  background: hsl(var(--muted));
  color: hsl(var(--muted-foreground));
}
/* El que se arrastró de otro día: el único de los tres que puede estar viejo, y
 * el badge lleva la fecha de origen escrita al lado. */
.procedencia-cierre.arrastrado {
  border-style: dashed;
  border-color: hsl(var(--warning));
  color: hsl(var(--warning-text));
}
/* El que escribió una persona: queda en la auditoría con su motivo, y por eso es
 * el único que se dibuja con el color de lo que se decide a mano. */
.procedencia-cierre.a-mano {
  background: hsl(var(--primary) / 0.18);
  border-color: hsl(var(--primary-text));
  color: hsl(var(--primary-text));
}

/* --- Los informes: resultados y el reparto entre socios (§13) ------------- */

/* **Ninguna de las seis tablas de `/resultados` se poda, y ninguna se acorta.**
 * No están en las nueve podables del contrato §12.5 y no podrían estarlo: en
 * «Por moneda», «De dónde vino» y «Mes a mes» las cuatro columnas son la
 * pantalla entera —el concepto, lo aprobado, lo que falta aprobar y el total—, y
 * esconder una en el celular sería esconder la mitad de la respuesta. Se
 * desplazan adentro de su marco, con la barra de scroll a la vista y la sombra
 * de «hay más a la derecha» que pone la sección de tablas.
 *
 * El reparto entre socios y la valuación de posiciones van además con `ancha`, y
 * ahí la primera columna queda fija: son las dos tablas por las que se abre esta
 * pantalla, y a 390 hoy **no se ve un solo importe de ninguna de las dos**
 * —el reparto muestra «Socio» y «Participación», la valuación muestra
 * «Cuenta»—. Con la columna del socio quieta, desplazarse a los importes deja a
 * la vista de quién son. */

/* El pie de la valuación arranca con un `<th colspan="3">Valuado</th>`, y una
 * celda fija que abarca tres columnas taparía justamente las que se están
 * desplazando por debajo. Una celda de pie que no dice de qué fila se trata no
 * es el ancla de nada: se queda con el resto y se desplaza con él.
 *
 * El `:first-child` es por precisión y no por especificidad, que es al revés de
 * lo que parece: `[colspan]` ya cuenta en la columna de las clases, así que
 * `table.datos.ancha tfoot th[colspan]` pesa (0,3,3) y le gana solo al (0,3,2)
 * de `table.datos.ancha th:first-child`, que es la regla que fija la columna.
 * Lo que agrega el `:first-child` es decir de qué celda se habla: la primera del
 * pie y ninguna otra, porque un `colspan` que no arranque la fila no es la
 * columna quieta y no hay nada que apagarle.
 *
 * Se apagan las dos declaraciones que hacen el anclaje y ninguna más. El `left`
 * y el `z-index` que quedan de aquella regla son inertes sobre una celda
 * estática, y el fondo `--card` que también queda es el mismo que
 * `table.datos tfoot th` le da a cualquier pie: apagarlo dejaría esta celda de
 * otro color que las de al lado. */
table.datos.ancha tfoot th[colspan]:first-child { position: static; box-shadow: none; }

/* La valuación de posiciones abiertas va adentro de esto y no suelta al final de
 * la pantalla. La caja y la advertencia arriba **son** la sección: un dólar que
 * subió no es una ganancia hasta que se vende, y lo que hay que impedir es que
 * alguien lea ese número como parte del resultado del mes. Separarla con un
 * título y nada más no alcanza —tres títulos más arriba hay otros dos que sí son
 * resultado—. El trazo punteado dice lo mismo que el texto sin gastar una
 * palabra: esto no cuenta. */
.no-es-resultado {
  margin-top: calc(var(--paso) * 4);
  padding: var(--paso) 14px 14px;
  border: 1px dashed hsl(var(--border));
  border-radius: var(--radio);
  background: hsl(var(--card));
}
.no-es-resultado > h2 { margin-top: var(--paso); }

/* La advertencia de arriba de esa sección, y la de las novedades. No es el cartel
 * ámbar de pantalla —ése es `.aviso`— sino una nota de gravedad dentro del
 * contenido: barra a la izquierda, sin borde alrededor y sin ocupar un bloque
 * entero. Va al cuerpo de un dato porque es texto que se lee. */
.advertencia {
  margin: 0 0 var(--paso);
  padding: 7px 10px;
  border-left: 3px solid hsl(var(--warning));
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.1);
  font-size: var(--t-dato);
  line-height: 1.45;
}
.advertencia strong { color: hsl(var(--warning-text)); }
/* --- Novedades de Nosis (§14) y avisos (§15) ----------------------------- */

/* Es el área con más clases del sistema —noventa y cuatro— y toda ella dibuja
 * lo mismo: **antecedentes de una persona con la que estamos por operar**. Por
 * eso lo que la ordena no es la pantalla sino la gravedad, y la gravedad se
 * escribe cuatro veces —la palabra adentro, el color, el filo de la izquierda y
 * el grosor de ese filo— para que se lea aunque falte cualquiera de las cuatro.
 *
 * Dos cosas de acá no salen de esta hoja y no se tocan:
 *
 * 1. **Los colores oficiales de Nosis** —los cinco de la situación del BCRA y el
 *    azul de la columna `SC`— son fijos en los dos temas a propósito: es lo que
 *    la oficina ya tiene aprendido de mirar el correo, y un verde que cambiara
 *    con el tema dejaría de ser reconocible. Sus tokens están arriba del todo.
 * 2. **La grilla de quince columnas va entera**, siempre. Es la única tabla del
 *    sistema donde los guiones vacíos importan: son lo que deja saltar con la
 *    vista a la celda que tiene número, y podarla sería mentir sobre qué
 *    columnas hay. En el celular no se poda: se pliega y se desplaza. */

/* Las cuatro severidades, con los mismos tokens que el resto de la interfaz: el
 * rojo de `--destructive` para lo crítico, el ámbar de `--warning` para la
 * advertencia y el verde de `--success` para lo informativo —que acá son buenas
 * noticias: un rechazo que pasó a pagado—.
 *
 * **Y no sólo color.** La palabra va escrita adentro de la celda («Crítica»,
 * «Advertencia», «Informativa») y el peso de la tipografía la acompaña: quien no
 * distingue el rojo del ámbar lee lo mismo. Es la regla 5 del encabezado. */
.severidad { font-weight: 700; }
.severidad.critica { color: hsl(var(--destructive-text)); }
/* El cuarto nivel se separa del tercero **por forma y no por otro rojo**: arriba
 * de `--destructive` no hay nada, y GDV_DESIGN §4 reserva ese rojo justamente
 * para esto. Lo que lo distingue es el trazo del doble de grueso y el tinte
 * cargado detrás —quien no distingue los colores igual ve que es otra cosa— y,
 * sobre todo, que el texto dice «Crítica urgente».
 *
 * Las versales que traía se fueron con las otras cuarenta: en la misma columna
 * convivían «CRÍTICA URGENTE» y «Crítica», y la diferencia de forma se leía como
 * una diferencia de énfasis. Ahora las cuatro se escriben igual y lo que las
 * separa es el marco.
 *
 * **El marco es de la palabra y no de la celda, y por eso `.severidad` es
 * siempre un `<span>`.** Las seis tablas que tienen columna de severidad lo
 * llevaban en la clase del `<td>`, y el fondo y el borde de una celda se dibujan
 * sobre el **alto entero de la fila**: escrito para una etiqueta de un renglón,
 * en el archivo de novedades a 390 —donde las filas son altas y las cuatro
 * primeras son urgentes— daba una columna roja maciza de 520px, que es la
 * pantalla gritando cuatro veces lo que dice una vez. Con el `<span>` el marco
 * mide lo que mide la palabra en cualquier alto de fila, y la celda vuelve a ser
 * una celda. Las tarjetas del índice y las de mora ya lo escribían así: ahora es
 * la única forma que hay. */
.severidad.critica_urgente {
  padding: 0 5px;
  border: 2px solid hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.16);
  color: hsl(var(--destructive-text));
  white-space: nowrap;
}
.severidad.advertencia { color: hsl(var(--warning-text)); }
.severidad.informativa { color: hsl(var(--success-text)); }
/* En la tarjeta del índice y en la de una variación de situación, la severidad es
 * un badge y va al cuerpo de rótulo; adentro de una celda de tabla es la columna
 * «Severidad» y hereda el cuerpo de la celda, que ahí es el correcto. Se escribe
 * calificado con el contenedor y no sobre `.severidad` a secas porque
 * `table.datos td` pesa (0,1,2) y le ganaría igual (§11.2): la regla que se lee y
 * la que se aplica tienen que ser la misma. */
.salida-tarjeta .severidad,
.cabecera-mora .severidad { font-size: var(--t-rotulo); }

/* La fila que nadie miró todavía, en `/notificaciones`. Una barra a la izquierda
 * y no un fondo: el fondo compite con el rayado par/impar de la tabla y termina
 * haciendo que las filas vistas parezcan de otra tabla.
 *
 * El `inset` **no es una sombra decorativa** y por eso sobrevive a la limpieza
 * del §2e: es una línea de 3px dibujada adentro de la celda, que es la única
 * forma de ponerle un filo a un `td` sin pelearse con el colapso de bordes de la
 * tabla. */
table.datos tbody tr.sin-ver > td:first-child {
  box-shadow: inset 3px 0 0 hsl(var(--primary));
}

/* La marca comercial de Nosis. **No es un antecedente del BCRA** y por eso no se
 * pinta como una severidad: es una decisión que tomó la oficina, y se lee como
 * una etiqueta y no como un estado del firmante.
 *
 * Sin versales: el texto ya está escrito `NO TOMAR` en la plantilla, tal como lo
 * escribe Nosis. La declaración no cambiaba nada de lo que se ve y sí escondía
 * que el grito es del dato y no de esta hoja. */
.marca-no-tomar {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px solid hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.16);
  color: hsl(var(--destructive-text));
  font-size: var(--t-rotulo);
  font-weight: 700;
  white-space: nowrap;
}
/* El mismo aviso cuando ocupa un párrafo entero —«NO TOMAR — así está marcado en
 * Nosis. Es una decisión comercial, no un antecedente, y no bloquea nada»—: ahí
 * deja de ser una etiqueta y pasa a ser una oración, así que va al cuerpo del
 * texto, con peso normal y envolviendo. El tope de línea se lo pone `.nota` o
 * `.prosa` en la plantilla —`.prosa` y no `.texto`, que ya es el rótulo del
 * botón de `.con-carga` (contrato §12.8)—: **ningún selector de esta parte
 * declara `max-width` para acotar texto**, que es la mitad de la regla 7. */
p.marca-no-tomar {
  display: block;
  margin: var(--paso) 0 0;
  padding: 7px 10px;
  font-size: var(--t-dato);
  font-weight: 400;
  white-space: normal;
}

/* El rechazo que sigue sin regularizar. En el BCRA el registro se levanta cuando
 * se paga el cheque **y** la multa: mientras la multa figure impaga, la persona
 * no regularizó, y ésa es la señal que interesa. */
.marca-impaga {
  padding: 1px 6px;
  border: 1px solid hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.16);
  color: hsl(var(--destructive-text));
  font-size: var(--t-rotulo);
  font-weight: 700;
}

/* La marca de novedades al lado de un nombre, en el padrón, la ficha y el mayor.
 * Es un enlace y no un `<span>`: la pregunta que sigue a verla es siempre «¿qué
 * pasó?», y esa respuesta está a un clic. Se pinta como las otras marcas de
 * estado —cuerpo de rótulo, radio chico, sin fondo fuerte— porque es lo mismo
 * que ellas: el estado de la fila, no un dato de la entidad. */
.marca-novedades {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px solid hsl(var(--warning-text) / 0.8);
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.18);
  color: hsl(var(--warning-text));
  font-size: var(--t-rotulo);
  white-space: nowrap;
  text-decoration: none;
}
.marca-novedades.critica {
  border-color: hsl(var(--destructive-text) / 0.8);
  background: hsl(var(--destructive) / 0.16);
  color: hsl(var(--destructive-text));
  font-weight: 700;
}
/* La misma marca con el borde doble: es la forma, otra vez, la que dice que hay
 * un escalón más arriba de crítica. */
.marca-novedades.critica_urgente {
  border: 2px solid hsl(var(--destructive-text));
  background: hsl(var(--destructive) / 0.2);
  color: hsl(var(--destructive-text));
  font-weight: 700;
}
.marca-novedades.informativa {
  border-color: hsl(var(--success-text) / 0.8);
  background: hsl(var(--success) / 0.14);
  color: hsl(var(--success-text));
}

/* --- NIVEL 0 — lo que ya tocó papel nuestro (§14.C-bis) ------------------ */

/* Arriba de la exposición, y la diferencia entre los dos bloques es la que
 * justifica que sean dos: aquél dice **a qué estamos expuestos** y éste dice
 * **qué ya pasó**. Lo segundo va primero porque no se puede prevenir.
 *
 * **No se distingue con un rojo más rojo**, que es lo que pediría la intuición y
 * lo que GDV_DESIGN §4 no permite: el rojo ya es de lo destructivo y no hay un
 * escalón arriba. Se distingue por **forma** —el borde de la izquierda del doble
 * de grueso y el tinte más cargado—, que es el mismo recurso con el que la
 * grilla separa sus severidades sin depender del color.
 *
 * Es un panel y por eso lleva el radio grande (contrato §2): las trece cajas que
 * pasan de `--radio-chico` a `--radio` son las que tienen borde y fondo propios
 * y contienen otras cosas, y ésta contiene una lista entera. */
.urgentes {
  margin: 0 0 calc(var(--paso) * 2);
  padding: var(--paso) var(--paso) var(--paso) 12px;
  border: 1px solid hsl(var(--destructive) / 0.5);
  border-left: 6px solid hsl(var(--destructive));
  border-radius: var(--radio);
  background: hsl(var(--destructive) / 0.12);
}
/* Sin versales: «Novedades que tocan papel nuestro» son cinco palabras, y en
 * mayúsculas un título de cinco palabras se lee letra por letra. Lo que lo
 * distingue del `h2` de cualquier otra sección es el panel rojo que lo rodea. */
.urgentes h2 { margin-top: 0; }
.lineas-urgentes { margin: var(--paso) 0 0; padding: 0; list-style: none; }
.lineas-urgentes li {
  padding: 3px 0;
  font-size: var(--t-dato);
  line-height: 1.4;
}
/* El símbolo, que no dice nada solo: el renglón entero está escrito al lado.
 * Está para que el ojo encuentre el bloque, no para reemplazar palabras. */
.lineas-urgentes .senal {
  margin-right: 6px;
  color: hsl(var(--destructive-text));
  font-weight: 700;
}
.lineas-urgentes a { font-weight: 700; }
/* **Un renglón y no una lista de pares**, y es una decisión contra el plan §2e
 * que el contrato §5 cierra: la línea es un titular denso a propósito, y en
 * `dl.datos-clave` cada urgente costaría cuatro renglones en la pantalla donde
 * más importa que entren muchas. El punto medio se queda, y lo pone el CSS: el
 * segmento que no se dibuja —los tres primeros son condicionales— no deja un
 * punto huérfano en el medio del renglón.
 *
 * Y **sin `color`**: un `::before` no lo puede resolver el evaluador de estilos
 * de la suite, así que una regla de pseudoelemento que declarara color dejaría
 * sin poder concluir a todo test que pregunte de dónde sale el color de un
 * texto. El separador hereda el del renglón, que es lo que tiene que hacer. */
.lineas-urgentes .dato::before { content: " · "; }
/* El motivo es la mitad del renglón que se lee: por qué esto está acá. */
.lineas-urgentes .motivo { font-weight: 700; }
/* Firme y probable **no se distinguen sólo por color**: la probable va con borde
 * punteado, que es la forma con la que esta interfaz dice «esto todavía lo tiene
 * que confirmar alguien» —la misma de `.marca-falta`—.
 *
 * Sin versales, y acá es donde más se gana de las cuarenta que se van: la
 * probable es una oración de veinte palabras —«coincidencia probable — el número
 * coincide y el monto no (rechazado por $ 4.180.000); la confirma una persona»—
 * que hasta hoy se dibujaba entera en mayúsculas. */
.lineas-urgentes .coincidencia {
  padding: 0 5px;
  border-radius: var(--radio-chico);
  font-size: var(--t-rotulo);
}
.lineas-urgentes .coincidencia.firme {
  border: 1px solid hsl(var(--destructive-text) / 0.8);
  color: hsl(var(--destructive-text));
  font-weight: 700;
}
.lineas-urgentes .coincidencia.probable {
  border: 1px dotted hsl(var(--warning-text) / 0.9);
  color: hsl(var(--warning-text));
}
/* La regla del bloque —«éstas no se archivan solas»— **no es una nota al pie**:
 * es lo que hay que saber para entender por qué una novedad de hace un mes está
 * arriba de todo. Va con el color del texto y no con el tenue, que además sobre
 * este tinte no llega al contraste mínimo en el tema claro. */
.urgentes .nota { margin-bottom: 0; color: hsl(var(--foreground)); }

/* La misma explicación, dentro de una tarjeta del índice, de una de situación y
 * del detalle de un seguimiento: por qué **ésta** está arriba de todo. Es otra
 * clase de frase que el resumen de al lado —aquél habla de lo que dice Nosis y
 * ésta de lo que tenemos nosotros— y por eso se dibuja distinto y no como un
 * segmento más. No es un panel: es un renglón resaltado, y se queda con el radio
 * chico. */
.por-que-urgente {
  margin: 0 0 4px;
  padding: 4px 8px;
  border-left: 3px solid hsl(var(--destructive));
  border-radius: var(--radio-chico);
  background: hsl(var(--destructive) / 0.12);
  font-size: var(--t-dato);
  line-height: 1.45;
}
.por-que-urgente .senal {
  margin-right: 6px;
  color: hsl(var(--destructive-text));
  font-weight: 700;
}

/* --- NIVEL 1 — la exposición en cartera (§14.D.2) ------------------------ */

/* Lo único de la pantalla que puede costar plata hoy, y por eso es lo primero
 * que se dibuja. **Un renglón por firmante y no una tabla**: una tabla obliga a
 * leer encabezados para saber qué dice cada celda, y esto se tiene que leer como
 * se lee un titular.
 *
 * Cuando no hay exposición, este bloque no se dibuja: eso lo decide la plantilla,
 * y es deliberado. Un panel vacío que dijera «sin exposición» ocuparía lugar y
 * enseñaría a saltearlo. */
.exposicion {
  margin: 0 0 calc(var(--paso) * 2);
  padding: var(--paso) var(--paso) var(--paso) 12px;
  border-left: 3px solid hsl(var(--destructive));
  border-radius: var(--radio);
  background: hsl(var(--destructive) / 0.08);
}
.exposicion h2 { margin-top: 0; }
.lineas-exposicion { margin: var(--paso) 0 0; padding: 0; list-style: none; }
.lineas-exposicion li {
  padding: 3px 0;
  font-size: var(--t-dato);
  line-height: 1.4;
}
/* El símbolo, que no dice nada solo: lo que dice el renglón está escrito al
 * lado. Está para que el ojo encuentre el bloque, no para reemplazar palabras. */
.lineas-exposicion .senal {
  margin-right: 6px;
  color: hsl(var(--destructive-text));
  font-weight: 700;
}
.lineas-exposicion a { font-weight: 700; }
/* Cada dato con su separador delante. El separador va en el CSS y no en el HTML
 * porque un segmento que no se dibuja —«trajo: …», cuando el papel no tiene
 * cliente cargado— dejaría un punto huérfano en el medio del renglón.
 *
 * **Sin apagar**: lo que va acá son las cifras que deciden, no rótulos, y sobre
 * un tinte del 8% el gris tenue queda al filo del contraste mínimo en el tema
 * claro. Lo que separa el nombre del resto es la negrita del enlace. */
.lineas-exposicion .dato::before { content: " · "; }

/* Lo que no cerró en un envío: el texto crudo, monoespaciado, con scroll propio.
 * Es para leer y copiar en un mail a Nosis, no para maquetar. Es una caja con
 * borde y fondo y por eso pasa al radio grande.
 *
 * El alto acotado va en `em` y no en píxeles a propósito: lo que se quiere son
 * quince o dieciséis renglones de volcado, y eso sigue al cuerpo de la letra. La
 * medida es de alto y no de tipografía, así que no le toca la regla de los cinco
 * tamaños. */
.discrepancias {
  max-height: 18em;
  margin: var(--paso) 0 0;
  padding: 10px 12px;
  overflow: auto;
  border: 1px solid hsl(var(--warning) / 0.45);
  border-radius: var(--radio);
  background: hsl(var(--warning) / 0.1);
  color: hsl(var(--foreground));
  font-family: var(--mono);
  font-size: var(--t-rotulo);
  line-height: 1.5;
  white-space: pre-wrap;
}

/* Que hace días que no llega el correo. Mismo tratamiento que `.advertencia`: es
 * la misma clase de cartel —algo que hay que leer antes de mirar los números— y
 * dos estilos distintos para lo mismo sería una diferencia sin diferencia. */
.aviso-atraso {
  margin: var(--paso) 0;
  padding: 7px 10px;
  border-left: 3px solid hsl(var(--warning));
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.1);
  font-size: var(--t-dato);
  line-height: 1.45;
}

/* --- NIVEL 2 — el índice (§14.E) ----------------------------------------- */

/* Los filtros. **Son enlaces y no un formulario**: en esta pantalla todo
 * formulario escribe —archivar, subir un envío— y filtrar es navegar. Un `<a>`
 * anda sin JavaScript por construcción; el `hx-get` de al lado sólo evita
 * repintar la pantalla entera. El chip en sí lo dibuja la familia de chips, con
 * el del padrón y el del filtro rápido: acá va sólo cómo se agrupan. */
.filtros-indice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--paso);
  margin: var(--paso) 0;
}
.grupo-filtro { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
/* «Severidad», «Tipo», «Padrón»: el rótulo de cada grupo. Tenue y a doce, que es
 * lo que lo separa de los chips que le siguen; sin versales, porque el peso 500
 * contra el 400 de un chip ya dice cuál de los dos es el nombre del grupo. */
.rotulo-filtro {
  margin-right: 2px;
  color: hsl(var(--muted-foreground));
  font-size: var(--t-rotulo);
  font-weight: 500;
}

/* La tarjeta de un seguimiento: la grilla de Nosis arriba, su ficha debajo y la
 * salida al detalle al costado. **Compacta**, con el mismo criterio que Caja y
 * el Libro: lo que se hace con esta pantalla es barrerla, y en un envío normal
 * tienen que entrar unas cuatro por pantalla.
 *
 * Sin aire entre la grilla y la ficha: en el correo son una sola cosa y acá
 * también. El borde de la izquierda lleva la severidad, que además está escrita
 * al costado. Es una tarjeta —lo dice su nombre— y por eso el radio grande. */
.tarjeta-seguimiento {
  margin: 0 0 var(--paso);
  padding: 6px 10px 6px 9px;
  border: 1px solid hsl(var(--border));
  border-left: 3px solid hsl(var(--border));
  border-radius: var(--radio);
  background: hsl(var(--card));
}
.tarjeta-seguimiento.critica { border-left-color: hsl(var(--destructive)); }
/* La urgente, con el borde del doble de grueso y un tinte propio: en un índice
 * de cincuenta y nueve tarjetas el color del filo no alcanza para que salte. */
.tarjeta-seguimiento.critica_urgente {
  border-left: 6px solid hsl(var(--destructive));
  background: hsl(var(--destructive) / 0.07);
}
.tarjeta-seguimiento.advertencia { border-left-color: hsl(var(--warning)); }
.tarjeta-seguimiento.informativa { border-left-color: hsl(var(--success)); }

/* **En el celular la tarjeta empieza por la noticia y no por un control.** A 390
 * la grilla se pliega, y lo que quedaba arriba de todo —lo primero que se lee de
 * cada una de las cincuenta y nueve tarjetas— era el «Ver grilla» del plegado:
 * un botón, no de quién es la novedad. Lo que la tarjeta tiene que decir primero
 * es el resumen en castellano y, si la hay, la línea de por qué es urgente; la
 * grilla queda debajo, que es donde se la busca cuando se la busca.
 *
 * Con `order` y no moviendo el HTML, y acá el motivo es doble: el orden de la
 * tarjeta —grilla, resumen, ficha— es el del correo de Nosis y hay un test que
 * lo fija leyendo los hijos directos del `<article>`; y desde 640 la grilla
 * vuelve a estar a la vista, arriba, donde entra entera. La tarjeta pasa a ser
 * una columna de flex sólo para que el `order` exista: los cuatro bloques ya
 * llevaban su margen abajo y ninguno de arriba, así que no hay margen que
 * colapse ni espaciado que cambie.
 *
 * El foco no se descalza: el único control que se adelanta es el `<summary>` de
 * la grilla, que baja junto con lo que abre; los enlaces de la tarjeta están
 * todos en `.ficha-y-salida`, que queda última en los dos órdenes. */
.tarjeta-seguimiento {
  display: flex;
  flex-direction: column;
}
.tarjeta-seguimiento > details.ver-grilla,
.tarjeta-seguimiento > .sin-grilla { order: 1; }
.tarjeta-seguimiento > .ficha-y-salida { order: 2; }

/* Desde 640 la grilla entra y vuelve arriba, que es la forma del correo: la
 * tarjeta vuelve a ser un bloque y el `order` deja de tener efecto. */
@media (min-width: 640px) {
  .tarjeta-seguimiento { display: block; }
}
/* El marco de la grilla, adentro de la tarjeta, se queda **sólo con el scroll**:
 * sin borde, sin fondo propio y sin la sombra de «hay más a la derecha». En el
 * correo la grilla y la ficha son una sola cosa y acá también, y una caja adentro
 * de otra caja las separa en dos.
 *
 * El `background: none` es también lo que apaga los cuatro fondos de la señal de
 * desplazamiento, y está previsto donde se declaran: adentro de la tarjeta la
 * señal es la barra de scroll, que en el celular está siempre a la vista.
 *
 * **El `box-shadow: none` se escribe aunque ya no haya ninguna sombra que
 * anular.** La sombra decorativa se fue de toda la hoja, así que esta línea hoy
 * no apaga nada; sin ella, `estilos.valor(marco, "box-shadow")` devuelve `None`
 * —«nadie lo declara»— y el test que verifica que la grilla y la ficha no estén
 * separadas en dos cajas no puede concluir y falla. Una afirmación que se quiere
 * poder hacer necesita una declaración que la conteste. */
.tarjeta-seguimiento .tabla-marco {
  margin: 0 0 4px;
  border: none;
  /* Y sin el radio del marco, que sin borde ni fondo no se ve pero **recorta**:
   * `overflow-x` hace del marco un contenedor de scroll, y un contenedor de
   * scroll clipea contra sus esquinas redondeadas. Con los 8px del marco suelto,
   * la grilla —que arranca pegada al borde y tiene celdas de doce píxeles—
   * perdería la esquina de la primera y la última celda de cada punta. Es la
   * misma línea que `.bloque-asiento .tabla-marco` escribe por la misma razón. */
  border-radius: 0;
  background: none;
  box-shadow: none;
}
/* Cuando de un CUIT no hay grilla guardada, la explicación ocupa su lugar. */
.tarjeta-seguimiento .sin-grilla { margin: 0 0 4px; }

/* **La grilla plegada, y sólo en el celular** (plan §2d). A 390 las quince
 * columnas se cortan en «Juicios» dentro de cada tarjeta, sin resumen visible
 * arriba ni forma de desplegarlas. Lo que se ve de entrada pasa a ser el resumen
 * en palabras que ya existe —«3 rechazos nuevos sobre 90 históricos · $ 4.180.000
 * impagos»—, y la grilla queda detrás de un `<details>` que la despliega
 * **entera**: la única tabla del sistema donde los guiones vacíos importan no se
 * poda nunca, ni siquiera acá.
 *
 * El `<details>` envuelve al mismo `.tabla-marco` que ya estaba: no hay una
 * segunda copia de la grilla en el HTML, que es lo que haría que
 * `Nodo.uno(clase="grilla-nosis")` encontrara dos y reventara.
 *
 * El `<summary>` es un objetivo táctil de 44px enteros, como el de la fila que
 * se expande y el de los filtros plegados: es el mismo control —se abre algo que
 * estaba plegado— y se toca con el pulgar en movimiento. */
details.ver-grilla > summary {
  display: flex;
  align-items: center;
  min-height: var(--toque);
  cursor: pointer;
  font-size: var(--t-dato);
  color: hsl(var(--primary-text));
  /* Sin el triángulo: el `display: flex` ya se lo lleva puesto en varios
   * navegadores, así que lo que dice que esto se abre es el texto —«Ver grilla»—
   * y no un adorno que existe en la mitad de los casos. */
  list-style: none;
}
/* Que el marco **esté escondido mientras el `<details>` está cerrado** se
 * escribe acá y no se deja en manos del navegador: es la misma razón que en los
 * filtros plegados —una regla de autor le gana siempre a la hoja del navegador,
 * que es la que esconde el contenido de un `<details>` cerrado—, y sin esta
 * línea la grilla se ve plegada y desplegada al mismo tiempo. */
details.ver-grilla:not([open]) > .tabla-marco { display: none; }

/* Desde 640 la grilla entra y el plegado deja de existir: el `<summary>` no se
 * dibuja y el marco está a la vista **aunque el `<details>` siga cerrado**, que
 * es lo que hace que abrir la misma pantalla en la notebook no dependa de lo que
 * se tocó en el celular.
 *
 * Son tres declaraciones: el `<summary>` que se va, y **las dos formas** en que
 * los navegadores esconden el contenido de un `<details>` cerrado —los viejos
 * con `display: none` sobre los hijos y los nuevos con `content-visibility`
 * sobre `::details-content`, que es un pseudoelemento y no se alcanza de otra
 * manera—. Esa última es la única regla de esta parte que el resolvedor de la
 * suite no sabe leer, y no declara ninguna propiedad que un test mire. */
@media (min-width: 640px) {
  details.ver-grilla > summary { display: none; }
  details.ver-grilla:not([open]) > .tabla-marco { display: block; }
  details.ver-grilla::details-content { content-visibility: visible; }
}

/* --- El resumen de la tarjeta: la grilla dicha en castellano (§14.E) ----- */

/* Un renglón entre la grilla y la ficha, que es donde cae la vista al terminar
 * de leer los números. La grilla es densa a propósito y se lee de un vistazo,
 * pero un «2» no distingue dos rechazos nuevos sobre noventa y seis de los dos
 * primeros de alguien que no tenía ninguno, ni un rebote de una regularización.
 *
 * **Un renglón y no una lista**, y es la otra decisión que el contrato §5 cierra
 * contra el plan §2e: son tres o cuatro segmentos cortos y en `dl.datos-clave`
 * costarían cuatro renglones a una tarjeta que tiene que entrar cuatro veces en
 * una pantalla. Envuelve cuando no entra, que es lo correcto: lo que no puede
 * pasar es que se corte.
 *
 * En el celular es, además, **lo único que se ve de la grilla** hasta que
 * alguien despliega el `<details>` de arriba: por eso va al cuerpo de dato y no
 * al de rótulo. Es contenido, no un pie. */
.resumen-tarjeta {
  margin: 0 0 4px;
  font-size: var(--t-dato);
  line-height: 1.4;
}
/* El separador entre segmentos lo pone el CSS y no el HTML: el segmento que no
 * se dibuja —no hubo regularizaciones, no hubo secciones ilegibles— dejaría un
 * punto huérfano. `:first-child` y no `+`, por lo mismo de siempre: el resolvedor
 * de `tests/estilos.py` no lee los combinadores de hermano, y una regla que cae
 * en esa bolsa deja sin poder concluir a todo test que mire esa propiedad. */
.resumen-tarjeta .segmento::before { content: " · "; }
.resumen-tarjeta .segmento:first-child::before { content: ""; }
/* La marca va pegada a su texto y **nunca sola**: el texto dice lo mismo. */
.resumen-tarjeta .senal { margin-right: 4px; font-weight: 700; }
.resumen-tarjeta .codigo-nosis { margin-right: 4px; }
/* Cada tipo con el color de su severidad, que es la misma escala de toda la
 * pantalla. `buena` no es ninguna de las tres: una regularización es una noticia
 * **buena**, y prestarle el verde de lo informativo las confundiría —lo
 * informativo es lo que no importa, y esto importa y es a favor—.
 *
 * No hay regla para `critica_urgente` acá, y es a propósito: el segmento no
 * puede salir con esa clase —`novedades._clase_del_segmento` topea en `critica`—
 * y la que había existía sólo para ponerle versales a algo que nunca se dibuja. */
.resumen-tarjeta .critica { color: hsl(var(--destructive-text)); font-weight: 700; }
.resumen-tarjeta .advertencia { color: hsl(var(--warning-text)); }
.resumen-tarjeta .informativa { color: hsl(var(--muted-foreground)); }
.resumen-tarjeta .buena { color: hsl(var(--success-text)); font-weight: 700; }

/* La ficha y la salida, en la misma banda desde 640: el espacio que la ficha
 * deja libre a la derecha alcanza para la severidad y el botón, así que no
 * cuestan un renglón. **En el celular no hay ese espacio**: con 390 de ancho, un
 * botón fijo a la derecha le deja a la razón social poco más de la mitad de la
 * tarjeta y parte los nombres. Ahí la banda se apila y la salida pasa a ser un
 * renglón horizontal —la severidad a la izquierda, «Ver detalle» a la derecha—,
 * que es el renglón que la grilla plegada acaba de devolver. */
.ficha-y-salida {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--paso);
}
/* La severidad arriba y la salida abajo, contra el borde derecho de la tarjeta;
 * en el celular, las dos en la misma línea y separadas. */
.salida-tarjeta {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  flex: 0 0 auto;
  min-width: 0;
}
@media (min-width: 640px) {
  .ficha-y-salida { flex-direction: row; justify-content: space-between; }
  .salida-tarjeta {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: flex-end;
    justify-content: space-between;
    text-align: right;
  }
}

/* Los seis renglones de la ficha del correo. Una lista de definiciones y no una
 * tabla: son pares de rótulo y dato de **un** seguimiento, y una tabla de una
 * fila obligaría a leer un encabezado para saber qué dice cada celda.
 *
 * Dos columnas —el rótulo lo más angosto que entre, el dato el resto— con el
 * renglón bien corto: es lo que hace que seis pares midan lo que mide la grilla
 * de al lado. La pista del rótulo es `max-content` a propósito y no una fracción:
 * son seis palabras fijas del correo de Nosis y no crecen. La del dato sí lleva
 * el `minmax(0, 1fr)` del §12.2, que es la que puede recibir una razón social de
 * sesenta caracteres y sin el cero mínimo empujaría la tarjeta entera. */
.ficha-seguimiento {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  column-gap: var(--paso);
  margin: 0;
  min-width: 0;
  font-size: var(--t-dato);
  line-height: 1.35;
}
/* Los rótulos son rótulos: tenues, como el encabezado de cualquier tabla. El
 * `min-width: 0` va también acá, y no sólo en el dato: §12.2 dice **todo** ítem
 * de grilla, y una excepción escrita «porque la pista es `max-content` y no
 * encoge igual» es la clase de razonamiento que deja de valer el día que la
 * pista cambia. */
.ficha-seguimiento dt { color: hsl(var(--muted-foreground)); min-width: 0; }
.ficha-seguimiento dd { margin: 0; min-width: 0; }
/* El nombre es lo que se busca con la vista dentro de la tarjeta. */
.ficha-seguimiento .quien { font-weight: 600; }
/* El documento, monoespaciado como todo lo que se compara dígito a dígito, y a
 * la izquierda: acá no es una columna de cifras sino un dato de una ficha.
 * **Sin `font-size`**: se dibuja al cuerpo de la ficha que lo contiene. El 0,9em
 * que traía era la misma decisión al revés que los `0.88em` de `.num` —achicar
 * el dato para que entre— y se fue con ellos. */
.ficha-seguimiento .documento {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
/* El renglón del nombre es el único que puede pasar de una línea: lleva la razón
 * social de Nosis más el vínculo con el padrón. Que corte por donde haga falta,
 * para que una razón social larga no empuje la ficha fuera de la tarjeta. */
.ficha-seguimiento .nombre { overflow-wrap: anywhere; }
/* §14.D — lo único que se le agrega a la ficha de Nosis: de quién tenemos papel.
 * Cada segmento trae su separador delante, y el separador va en el CSS y no en
 * el HTML porque un segmento que no se dibuja —«trajo: …» cuando el papel no
 * tiene cliente— dejaría un punto huérfano en el medio del renglón.
 *
 * **Sin apagar**: son datos y no rótulos, que es la regla 6. Lo que los separa
 * del nombre es que el nombre va en negrita. */
.dato-vinculo::before { content: " · "; }
/* Cuánto papel suyo hay hoy en el cajón: es la cifra que decide si esta tarjeta
 * importa, y va en negrita por eso. */
.dato-vinculo.en-cartera { font-weight: 700; }
.dato-vinculo.trajo { font-style: italic; }

/* El paso al detalle. Es un `<a href>` de verdad —anda sin JavaScript— dibujado
 * como un control: en la tarjeta es la acción, no una referencia dentro de un
 * texto. Lleva debajo cuántas novedades hay del otro lado, que es lo que decide
 * si vale el clic.
 *
 * Los 44px son los de la regla 2 del encabezado y acá no se negocian: es la
 * única salida de la tarjeta y se toca parado. */
.ver-detalle {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: var(--toque);
  padding: 4px 12px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  background: hsl(var(--background));
  color: hsl(var(--foreground));
  font-size: var(--t-dato);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.ver-detalle:hover { border-color: hsl(var(--primary-text) / 0.7); }
.ver-detalle .secundario { font-weight: 400; }
/* Una crítica que no se archivó sola porque toca papel vivo. Necesita decir por
 * qué está ahí: una novedad de hace un mes arriba de todo, sin explicación, se
 * lee como un error de la pantalla. Punteada, que es como esta interfaz dice
 * «esto es provisorio»: se va a ir solo cuando el papel salga. */
.marca-retenida {
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px dashed hsl(var(--destructive-text) / 0.8);
  border-radius: var(--radio-chico);
  color: hsl(var(--destructive-text));
  font-size: var(--t-rotulo);
  font-weight: 700;
  white-space: nowrap;
}
/* Y la urgente, que no se archiva nunca: sólida y del doble de grueso en lugar
 * de punteada. Punteado es «esto se va a ir solo»; sólido es «esto no se va».
 * Va después de la regla de arriba porque pesa lo mismo más una clase y tiene
 * que ganarle al `border` corto de allá, que declara los tres valores juntos. */
.marca-retenida.urgente {
  border-style: solid;
  border-width: 2px;
}

/* --- NIVEL 3 — el detalle de un seguimiento ------------------------------ */

/* Una sección del adjunto de Nosis, con su nombre y su forma. El borde de la
 * izquierda lleva la severidad de lo más grave que tiene adentro, que es lo que
 * permite bajar por el detalle sin leer ninguna tabla. Es un panel: radio
 * grande, como las otras doce cajas del contrato §2. */
.seccion-nosis {
  margin: var(--paso) 0 calc(var(--paso) * 2);
  padding: var(--paso) 0 var(--paso) 10px;
  border-left: 3px solid hsl(var(--border));
  border-radius: var(--radio);
  min-width: 0;
}
.seccion-nosis.critica { border-left-color: hsl(var(--destructive)); }
.seccion-nosis.critica_urgente { border-left: 6px solid hsl(var(--destructive)); }
.seccion-nosis.advertencia { border-left-color: hsl(var(--warning)); }
.seccion-nosis.informativa { border-left-color: hsl(var(--success)); }
.seccion-nosis h3 { margin-top: 0; }
/* Una sección puede traer dos tablas —las novedades de cheque y las de texto— y
 * necesitan aire entre ellas. Se escribe sobre **todas** y no con un `+` sobre
 * la segunda: el resolvedor de la suite no lee los combinadores de hermano, y el
 * margen de arriba de la primera se colapsa contra el de abajo del `h3`, así que
 * dibuja exactamente lo mismo con una regla que sí se puede verificar. */
.seccion-nosis .tabla-marco { margin-top: var(--paso); }

/* Las salidas del detalle, en una línea arriba de todo: volver al índice, el
 * historial, el archivo y el informe completo en Nosis. Van pegadas al `h1`, sin
 * el aire de arriba que `.nota` le pone a un pie de pantalla: acá no es un pie,
 * es la barra de salidas.
 *
 * **`p.migas-novedades` y no `.migas-novedades`** (§11.2), por lo mismo que
 * `p.retencion` acá abajo: `.nota` declara el atajo `margin` con el mismo peso
 * y en una sección posterior, así que a igualdad gana por orden y el margen de
 * arriba volvería sin que nada lo diga. */
p.migas-novedades { margin-top: 0; }

/* Por qué hay novedades de este seguimiento que no se archivaron solas. Es un
 * `<p class="nota retencion" role="status">`, o sea que el tope de línea y el
 * cuerpo se los pone `.nota`: lo único suyo es **no ser tenue**. Es la misma
 * razón que en el pie de las urgentes —lo que explica por qué algo viejo está a
 * la vista no es una nota al pie, es la mitad de la pantalla— y la única forma
 * de que esta clase siga significando algo después de que los topes de ancho se
 * fueran a un solo lugar.
 *
 * **Se escribe `p.retencion` y no `.retencion` a secas** (§11.2): `.nota`
 * —que declara `color: hsl(var(--muted-foreground))`— pesa lo mismo y se
 * declara en la última sección de la hoja, así que a igualdad de peso gana por
 * orden y este color no se vería nunca. El tipo, que el elemento siempre tiene,
 * es lo que inclina el empate sin inventar un contenedor. */
p.retencion { color: hsl(var(--foreground)); }

/* La novedad que **no** se archiva sola: es crítica y toca papel que todavía
 * está en cartera. Misma barra que la fila sin ver, y por lo mismo: es lo único
 * de la pantalla que puede costar plata hoy. El `inset` dibuja una línea, no una
 * sombra, y por eso sobrevive. */
table.datos tbody tr.retenida > td:first-child {
  box-shadow: inset 3px 0 0 hsl(var(--destructive));
}
/* El formulario de archivar a mano: el motivo y el botón en la misma celda. El
 * motivo es obligatorio, así que el campo no se puede achicar hasta desaparecer.
 *
 * **Y en el celular está a la vista porque su tabla se apila, no porque su
 * columna sea `p1`.** Acá decía lo segundo y era falso: las tres tablas que lo
 * dibujan —las dos del detalle de un seguimiento y la del historial de un
 * CUIT— no son podables, así que no tienen `p1` ninguna, y lo que pasaba a 390
 * era que la celda de acciones arrancaba a 600 o 900px del borde de un marco de
 * 366. Las tres llevan ahora `papel` además de `ancha` (contrato §6, «la fila
 * que es un formulario»): hasta 640 la fila se dibuja apilada y el formulario se
 * lleva el renglón entero al pie de la tarjeta; de 640 para arriba vuelven a ser
 * tablas que se desplazan con la primera columna quieta.
 *
 * **La base del `flex` son doce caracteres y no veintidós, y eso vale por cuatro
 * pantallas en los tres anchos.** Veintidós más el botón no entran en la columna
 * que ninguna de las cuatro tablas de Nosis le da, así que el campo envolvía
 * **siempre**: la fila del seguimiento pasaba de 53 a 103px a 1536 —con espacio
 * de sobra al lado— y la del historial por CUIT de 60 a 103, con el campo del
 * motivo cortado igual. A 390 eran cien píxeles de fila de los cuales el ochenta
 * por ciento era blanco. Con doce, el campo y el botón entran en un renglón en
 * la columna que hay y el campo **sigue creciendo** hasta donde la columna dé,
 * porque el `flex-grow` se queda en 1: doce es el piso, no el ancho. El
 * `min-width` acompaña al `flex-basis` por lo mismo de siempre —un campo de
 * motivo obligatorio no se achica hasta desaparecer—. */
.archivar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.archivar input { flex: 1 1 12ch; min-width: 12ch; }
.archivar button { padding: 0 12px; }

/* --- La grilla de Nosis (§14.B) ------------------------------------------ */

/* La tabla de quince columnas, replicada del correo. Angosta a propósito: son
 * quince celdas de dos caracteres y tiene que entrar de un vistazo. **No lleva
 * `datos`** y por eso nada de la cascada de tablas la alcanza: la fila de 28px,
 * el rayado par/impar y el encabezado tenue son de un listado, y esto es una
 * matriz de conteos donde las dos filas son la noticia y el fondo de la noticia.
 *
 * Tampoco lleva `podable`, y eso es lo que garantiza que no haya **ninguna**
 * regla en la hoja que le esconda una celda en ningún ancho. Lo que pasa en el
 * celular es que se pliega entera y se desplaza, no que se recorte. */
.grilla-nosis {
  border-collapse: collapse;
  font-size: var(--t-rotulo);
}
.grilla-nosis th,
.grilla-nosis td {
  padding: 3px 6px;
  border: 1px solid hsl(var(--border));
  text-align: center;
  white-space: nowrap;
}
.grilla-nosis thead th {
  color: hsl(var(--muted-foreground));
  font-weight: 600;
}
/* El código de dos letras. `abbr` con `title` y sin el subrayado punteado del
 * navegador: el nombre completo está en la leyenda plegada al pie, que es donde
 * se lee, y quince subrayados punteados en fila son ruido. */
.grilla-nosis .codigo abbr,
.leyenda-nosis abbr {
  text-decoration: none;
  border-bottom: none;
  cursor: help;
}
.grilla-nosis .grupo { font-weight: 700; }
.grilla-nosis .rotulo-grilla { border: none; }
.grilla-nosis tbody th {
  padding-right: 10px;
  color: hsl(var(--muted-foreground));
  font-weight: 400;
  text-align: right;
  white-space: nowrap;
}

/* **La columna que dice de qué fila se trata queda quieta mientras el resto se
 * desplaza**, en la pantalla de detalle. Es la mitad que le faltaba a esta
 * tabla: quince columnas no entran en 390, y tres columnas a la derecha uno ya
 * no sabe si está leyendo lo de hoy o los antecedentes.
 *
 * Lo que se fija es la **columna de rótulos** —«Novedades del día» /
 * «Antecedentes históricos», con su esquina en el encabezado—, que en el detalle
 * es la primera columna de la tabla: ahí el `<th>` del encabezado ocupa una sola
 * columna y los dos `<th scope="row">` caen debajo de él. Es el único armado en
 * el que la columna quieta del encabezado y la del cuerpo son la misma, y por
 * eso es el único en el que esto se puede escribir (ver la regla de abajo).
 *
 * El fondo propio es obligatorio y no decorativo: una celda `sticky` sin fondo
 * deja pasar por debajo las que se están desplazando. Y el `inset` del borde
 * derecho **no es una sombra**: es la línea que separa la columna quieta de las
 * que se mueven, y va como `box-shadow` porque un `border` en una celda `sticky`
 * se corre con el colapso de bordes de la tabla. */
.grilla-nosis th.rotulo-grilla,
.grilla-nosis tbody th {
  position: sticky;
  left: 0;
  z-index: 1;
  background: hsl(var(--card));
  box-shadow: inset -1px 0 0 hsl(var(--border));
}
/* **Y en la tarjeta del índice no se fija ninguna columna.** No es un olvido: es
 * que ahí la cuenta no cierra. Con la columna «Búsqueda por», el encabezado es
 * **una** celda de `colspan="2"` —tapa el CUIT y el rótulo juntos— y el CUIT del
 * cuerpo va aparte, con `rowspan="2"`, así que el rótulo de la fila queda en la
 * segunda columna. Fijar el rótulo con `left: 0` deja arriba un bloque quieto de
 * dos columnas de ancho y abajo uno de una sola: al desplazar, la franja que
 * sobra —el ancho de un CUIT, unas tres columnas de la grilla— muestra números
 * con su código tapado por el «Búsqueda por» del encabezado. Números sin el
 * código encima es lo único que esta tabla no puede permitirse.
 *
 * Fijar el CUIT en su lugar no arregla nada —el desfasaje cambia de signo— y
 * fijar los dos pide saber cuánto mide el primero, que es lo único que el CSS
 * no puede saber acá. Así que en la tarjeta la grilla se desplaza entera: son
 * dos filas, la de arriba es siempre la del día, y arriba de la grilla está el
 * resumen en castellano, que dice lo mismo sin ninguna columna. */
.tarjeta-seguimiento .grilla-nosis th.rotulo-grilla,
.tarjeta-seguimiento .grilla-nosis tbody th { position: static; }

/* Los números de la grilla, monoespaciados como todo lo que se compara de a
 * columna. El color de la letra es el del texto normal y **no** el de la
 * severidad: la severidad la pone el fondo y la forma del borde, y así el número
 * —que es el dato— contrasta igual en los dos temas. */
.grilla-nosis td.celda-nosis,
.grilla-nosis td.cuit {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: hsl(var(--foreground));
}
/* La celda sin dato es un guion y no un cero: «no hubo ninguna» y «hubo cero»
 * son la misma cosa dicha de dos maneras, y una grilla llena de ceros deja de
 * leerse de un vistazo.
 *
 * El guion va en el color del texto normal y **no** en el tenue: es el dato de
 * esa celda, no un rótulo, y un dato tenue es un dato que en el tema claro no
 * llega al contraste mínimo. Lo que lo separa del número es el peso y la
 * ausencia de tinte, que alcanza y sobra.
 *
 * Va **después** de la regla de arriba y pesa lo mismo: la celda vacía lleva las
 * dos clases, y lo que decide es el orden en el archivo. Moverla arriba deja
 * todos los guiones en negrita. */
.grilla-nosis td.vacia { font-weight: 400; }
/* Las tres severidades. Además del tinte, cada una trae una **forma**: trazo
 * grueso lo crítico, punteado la advertencia, nada lo informativo. Con el número
 * adentro y el borde distinto, la grilla se lee en blanco y negro. */
.grilla-nosis td.critica {
  background: hsl(var(--destructive) / 0.22);
  border: 2px solid hsl(var(--destructive-text));
}
.grilla-nosis td.advertencia {
  background: hsl(var(--warning) / 0.18);
  border: 1px dashed hsl(var(--warning-text));
}
.grilla-nosis td.informativa {
  background: hsl(var(--success) / 0.16);
  border: 1px solid hsl(var(--success-text) / 0.6);
}
/* Una columna cuya severidad este sistema no conoce. No se pinta de ningún
 * color: pintarla de alguno sería inventar una clasificación. */
.grilla-nosis td.sin-severidad { background: hsl(var(--muted)); }
/* §14.F — los cinco colores oficiales de la situación del BCRA, fijos en los
 * dos temas (ver los tokens `--situacion-N-…` al principio del archivo). Sólo
 * en la celda de `CI` de **hoy**, y sólo cuando el texto la trae: el resto
 * sigue por severidad, arriba. Sin borde propio —a diferencia de
 * `.critica`/`.advertencia`/`.informativa`—: son los colores que la oficina
 * ya reconoce del correo tal cual, y agregarles una forma sería una
 * clasificación de más que Nosis no puso. */
.grilla-nosis td.situacion-1 { background: hsl(var(--situacion-1-fondo)); color: hsl(var(--situacion-1-texto)); }
.grilla-nosis td.situacion-2 { background: hsl(var(--situacion-2-fondo)); color: hsl(var(--situacion-2-texto)); }
.grilla-nosis td.situacion-3 { background: hsl(var(--situacion-3-fondo)); color: hsl(var(--situacion-3-texto)); }
.grilla-nosis td.situacion-4 { background: hsl(var(--situacion-4-fondo)); color: hsl(var(--situacion-4-texto)); }
.grilla-nosis td.situacion-5 { background: hsl(var(--situacion-5-fondo)); color: hsl(var(--situacion-5-texto)); }
/* Los mismos cinco colores, para cuando la situación no viene en una celda de
 * la grilla sino en una fila de lista —el historial de un CUIT, el detalle de
 * un seguimiento, la tarjeta de una variación— como la que trae el correo
 * mensual de CI. Un `<span>` y no un `<td>`: es la misma escala oficial, en otro
 * lugar de la pantalla.
 *
 * **Sin `font-size`**: se dibujan al cuerpo del renglón que las lleva. El 0,9em
 * que traían achicaba justo el número que hay que leer. Y el radio pasa a ser el
 * chico de la hoja: es una marca, y las marcas tienen un solo radio. */
.insignia-situacion-1 { background: hsl(var(--situacion-1-fondo)); color: hsl(var(--situacion-1-texto)); }
.insignia-situacion-2 { background: hsl(var(--situacion-2-fondo)); color: hsl(var(--situacion-2-texto)); }
.insignia-situacion-3 { background: hsl(var(--situacion-3-fondo)); color: hsl(var(--situacion-3-texto)); }
.insignia-situacion-4 { background: hsl(var(--situacion-4-fondo)); color: hsl(var(--situacion-4-texto)); }
.insignia-situacion-5 { background: hsl(var(--situacion-5-fondo)); color: hsl(var(--situacion-5-texto)); }
.insignia-situacion-1, .insignia-situacion-2, .insignia-situacion-3,
.insignia-situacion-4, .insignia-situacion-5 {
  display: inline-block;
  padding: 0 6px;
  border-radius: var(--radio-chico);
  font-weight: 600;
}
/* La columna `SC` —Boletines Oficiales, cambios societarios—, en el azul fijo
 * de Nosis (`--sc-…`) y no en el ámbar genérico de `.advertencia`: es la
 * misma razón que `.situacion-N`, un color de columna que la oficina ya
 * reconoce del correo. */
.grilla-nosis td.columna-sc { background: hsl(var(--sc-fondo)); color: hsl(var(--sc-texto)); }
/* Lo del día es la noticia y los antecedentes son el fondo sobre el que pasó.
 * La primera fila va entera; la segunda, un punto más tenue. El rótulo de cada
 * una las distingue igual, para quien no ve la diferencia de tono. */
.grilla-nosis tr.del-dia th { font-weight: 600; }
/* El `:not` es por la celda del CUIT, que abarca las dos filas y vive en la
 * primera: sin él, la fila de antecedentes apagaría el documento del
 * seguimiento, que es un dato de la tarjeta y no un antecedente. */
.grilla-nosis tr.historicos td:not(.cuit) { opacity: 0.8; }

/* La primera columna del correo —«Búsqueda por»— con el CUIT abarcando las dos
 * filas. Va en la tarjeta del índice, donde hay una grilla debajo de otra y cada
 * una tiene que decir de quién es; en el detalle no hace falta, que es de a uno
 * y el CUIT está en el encabezado de la pantalla. */
.grilla-nosis td.cuit {
  padding-right: 10px;
  font-weight: 700;
  opacity: 1;
}
.grilla-nosis th.busqueda {
  padding-right: 10px;
  text-align: left;
}

/* De cuál de las dos fuentes de cheques vino la novedad. `CH` y `HC` son dos
 * registros distintos con el mismo tipo, así que sin esta marca la lista los
 * mostraría idénticos. */
.codigo-nosis {
  margin-left: 6px;
  padding: 0 5px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio-chico);
  color: hsl(var(--muted-foreground));
  font-family: var(--mono);
  font-size: var(--t-rotulo);
  text-decoration: none;
  cursor: help;
}

/* La leyenda de los códigos, plegada. Sin ella la grilla es ilegible para quien
 * no la conoce de memoria; abierta siempre, ocuparía media pantalla con algo que
 * se consulta una vez por mes. A diferencia de la grilla, ésta se queda plegada
 * en los cuatro anchos: no es que no entre, es que no se lee todos los días. */
.leyenda-nosis { margin: calc(var(--paso) * 2) 0; }
.leyenda-nosis > summary {
  min-height: var(--toque);
  display: flex;
  align-items: center;
  font-weight: 600;
  cursor: pointer;
}

/* La lista de envíos, plegada como la leyenda: es «¿esto viene llegando?», que
 * se pregunta una vez por semana. Lo que sí interrumpe —que hace días que no
 * llega— es un cartel arriba de todo y no vive acá adentro. */
.envios-nosis { margin: calc(var(--paso) * 2) 0; }
.envios-nosis > summary {
  min-height: var(--toque);
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  cursor: pointer;
}

/* El botón de «marcar todo» de la pantalla de avisos (§15). En §14 ya no existe
 * —las novedades se archivan solas— y acá sí: un aviso se marca visto. */
.marcar-lote { margin: var(--paso) 0; }
.marcar-lote button { padding: 0 14px; }

.preferencias-avisos button { padding: 0 14px; margin-top: var(--paso); }
/* La casilla y su rótulo, en la misma celda: el rótulo existe para el lector de
 * pantalla y para que el objetivo táctil sea la fila y no diez píxeles. */
.preferencias-avisos td { white-space: nowrap; }
.preferencias-avisos td label { margin-left: 6px; font-size: var(--t-dato); }

/* El enlace al archivo, al lado del título de la pantalla. Va en cuerpo normal y
 * no en el tamaño del `h2`: es una salida, no un título. Y **con objetivo táctil
 * propio**: es la única forma de llegar al archivo desde acá y se toca parado, así
 * que estira el renglón del `h2` veinte píxeles una vez por pantalla. Es el
 * precio de la regla 2 y se paga. */
h2 .ir-al-archivo {
  display: inline-flex;
  align-items: center;
  min-height: var(--toque);
  margin-left: 10px;
  font-size: var(--t-dato);
  font-weight: 400;
}

/* --- El aviso del firmante, al recibir un cheque (§14.D.1) --------------- */

/* Va pegado al campo del CUIT, en la cola de pendientes y en el diálogo de carga.
 * El borde de la izquierda lleva el color de la severidad y el texto dice las
 * cifras: es lo que se lee parado frente a alguien que está entregando el papel.
 *
 * **No bloquea nada** y por eso no se pinta como un error de formulario: es un
 * antecedente, no un campo mal cargado. */
.novedades-firmante {
  margin: var(--paso) 0 0;
  padding: 8px 10px;
  border-left: 3px solid hsl(var(--warning));
  border-radius: var(--radio-chico);
  background: hsl(var(--warning) / 0.1);
  font-size: var(--t-dato);
  line-height: 1.45;
  white-space: normal;
}
.novedades-firmante.critica {
  border-left-color: hsl(var(--destructive));
  background: hsl(var(--destructive) / 0.12);
}
/* Un cheque nuestro de este firmante rebotó, o tenemos papel suyo venciendo
 * ahora. Es lo más fuerte que este bloque puede decir estando parado frente a
 * quien está entregando el papel, y se distingue por el filo grueso. */
.novedades-firmante.critica_urgente {
  border-left: 6px solid hsl(var(--destructive));
  background: hsl(var(--destructive) / 0.12);
}
.novedades-firmante.informativa {
  border-left-color: hsl(var(--success));
  background: hsl(var(--success) / 0.1);
}
/* Los párrafos, separados de a cuatro píxeles y sin margen arriba del primero.
 * Se escribe con `:first-child` y no con `p + p`, que era lo que había: el
 * resolvedor de la suite no lee los combinadores de hermano y una regla así
 * queda fuera de lo que se puede verificar, aunque dibuje bien. */
.novedades-firmante p { margin: 4px 0 0; }
.novedades-firmante p:first-child { margin-top: 0; }
.novedades-firmante .cifras strong { color: hsl(var(--foreground)); }
.novedades-firmante .secundario { display: block; margin-left: 0; }
/* **El peor caso de versales que tenía la hoja.** Acá el `NO TOMAR` no es una
 * etiqueta al lado de un nombre sino el principio de una oración —«NO TOMAR —
 * así está marcado en Nosis»—, y esta regla, que le ganaba por especificidad a
 * la del párrafo, la dibujaba entera en mayúsculas: en el diálogo de carga y en
 * la cola de pendientes, parado frente al cliente. Ahora dice lo único que tiene
 * que decir, que es que adentro del cartel el aviso no lleva el aire de arriba. */
.novedades-firmante .marca-no-tomar {
  display: block;
  margin: 0 0 4px;
  padding: 1px 6px;
  font-size: var(--t-dato);
  font-weight: 400;
  white-space: normal;
}
/* El hueco que recibe el intercambio de HTMX. Vacío no ocupa nada, y tiene que
 * seguir existiendo: un destino que desaparece no puede recibir el intercambio
 * siguiente. */
.hueco-novedades:empty { display: none; }
.novedades-del-dialogo { margin: var(--paso) 0; }

/* --- El apartado de situación del BCRA (§14.F-bis) ----------------------- */

/* Las variaciones de situación del correo mensual de CI, en su propio apartado
 * y no mezcladas con el índice del día: son de otra fuente y de otro período, y
 * una tarjeta de mora arriba de una de novedades se leería como si algo hubiera
 * pasado hoy. Es un panel, con el radio de las trece cajas del contrato §2. */
.situacion-bcra {
  margin: 0 0 calc(var(--paso) * 2);
  padding: var(--paso) var(--paso) 4px;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radio);
  background: hsl(var(--muted) / 0.25);
}
.situacion-bcra h2 { margin-top: 0; }
/* El truncado se declara y no se calla: Nosis no manda un total contra el que
 * comparar, así que lo único que se puede decir es lo que el correo dijo. */
.truncado-mora { margin-top: 0; }
/* Una tarjeta por variación, más chica que la del índice: no tiene grilla ni
 * ficha, tiene un nombre, un salto y qué papel suyo tenemos. */
.tarjeta-mora {
  margin: 0 0 6px;
  padding: 5px 10px 5px 9px;
  border: 1px solid hsl(var(--border));
  border-left: 3px solid hsl(var(--border));
  border-radius: var(--radio);
  background: hsl(var(--card));
}
.tarjeta-mora.critica { border-left-color: hsl(var(--destructive)); }
.tarjeta-mora.critica_urgente {
  border-left: 6px solid hsl(var(--destructive));
  background: hsl(var(--destructive) / 0.07);
}
.tarjeta-mora.advertencia { border-left-color: hsl(var(--warning)); }
.tarjeta-mora.informativa { border-left-color: hsl(var(--success)); }
/* La flecha del salto se pinta de rojo **sólo cuando la situación empeoró**: es
 * la única señal de dirección que hay, y una flecha roja en una mejora diría lo
 * contrario de lo que pasó. Los dos números al lado la dicen igual. */
.tarjeta-mora.empeoro .flecha-salto { color: hsl(var(--destructive-text)); }
/* Envuelve: en el celular el nombre y el documento no entran en un renglón con
 * la severidad al final, y partir un nombre es peor que bajarlo. */
.cabecera-mora {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}
.cabecera-mora .quien { font-weight: 600; }
/* Monoespaciado y tenue, sin achicar: es el dato que se compara dígito a dígito
 * con lo que hay en el padrón. */
.cabecera-mora .documento {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  color: hsl(var(--muted-foreground));
}
/* El `margin-left: auto` la manda contra el borde derecho mientras entre en el
 * renglón, y la deja caer al siguiente cuando no. */
.cabecera-mora .severidad { margin-left: auto; }
.salto-situacion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 4px 0;
  font-size: var(--t-dato);
}
.flecha-salto { font-weight: 700; }
.periodo-bcra { margin-left: 4px; }
.vinculo-mora {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 4px;
  margin: 0;
  font-size: var(--t-dato);
}
.vinculo-mora .ver-detalle { margin-left: auto; }
/* --- Avisos: el mismo vocabulario en los tres huecos --------------------- */

/* Rojo, ámbar y verde, y nada más. `.error` es «no se hizo», `.aviso` es «pasó
 * algo que conviene mirar» y `.hecho` es «se guardó lo que pediste»: las tres
 * comparten forma —el mismo relleno, el mismo radio, la misma barra de 4px al
 * costado— porque las tres aparecen en el mismo lugar de la pantalla, y lo
 * único que las distingue tiene que ser el color y la palabra que traen dentro.
 *
 * Radio chico y no radio de panel: no son cajas de contenido, son marcas sobre
 * lo que se acaba de hacer. La barra de 4px a la izquierda es lo que las hace
 * reconocibles de reojo, incluso en blanco y negro. */
.error, .error-al-pie, .aviso, .hecho {
  margin: 0 0 var(--paso);
  padding: 9px 12px;
  border-width: 1px;
  border-style: solid;
  border-left-width: 4px;
  border-radius: var(--radio-chico);
  font-size: var(--t-dato);
}
.error, .error-al-pie {
  background: hsl(var(--destructive) / 0.18);
  color: hsl(var(--destructive-text));
  border-color: hsl(var(--destructive-text) / 0.8);
}
.aviso {
  background: hsl(var(--warning) / 0.12);
  color: hsl(var(--foreground));
  border-color: hsl(var(--warning) / 0.7);
}
/* La confirmación de un guardado que salió bien (`gdv.web.avisos`). Verde, y
 * distinta del ámbar de `.aviso`: el ámbar es «pasó algo que conviene mirar» y
 * esto es «se guardó lo que pediste». Comparte el hueco con `.error` porque es
 * donde el que apretó el botón ya está mirando, y por eso tienen que verse
 * distintas de un vistazo y no sólo leerse distintas.
 *
 * El verde sale de `--success`, que es el token que el kit no trae y que se
 * define arriba en la misma familia que el azul primario. Antes era un verde
 * suelto que no salía de ninguna paleta. */
.hecho {
  background: hsl(var(--success) / 0.28);
  color: hsl(var(--success-text));
  border-color: hsl(var(--success-text) / 0.7);
}

/* El cartel dibujado adentro de una fila de tabla, en cualquiera de las tres
 * gravedades: la fila del padrón lo usa para el rechazo de una fusión y para el
 * «ya estaba completo», que no es un error. Sólo `.error` tenía el tamaño
 * compacto, así que las otras dos entraban con el padding del cartel grande y
 * estiraban el renglón. */
.error.en-fila, .aviso.en-fila, .hecho.en-fila {
  margin: 3px 0 0;
  padding: 3px 7px;
  font-size: var(--t-rotulo);
  white-space: normal;
}

/* La segunda línea de un error: «No se guardó nada (código 500)». Va más chica
 * —eso es lo que la separa de la primera— y **en el color del cartel**, no en
 * el gris de `.secundario`: ese gris está calibrado contra el fondo de la
 * página y sobre el tinte rojo no llega a 4,5:1. Por lo mismo se le sacó el
 * `opacity: .85` que traía: una opacidad apaga la letra igual que un alfa y el
 * test de contraste la compone, así que era medio punto de contraste regalado
 * en la línea que dice si se guardó o no. */
.error .secundario {
  display: block;
  margin-top: 3px;
  font-size: var(--t-rotulo);
  color: hsl(var(--destructive-text));
}

/* El renglón del panel de avisos lleva **la misma clase** que el cartel de
 * pantalla y no es un cartel (contrato §12.8: las dos se quedan). Adentro de la
 * lista es un renglón con su línea de separación arriba, y la caja la dibuja el
 * panel una sola vez; sin esto, cuatro avisos sin ver son cuatro cajitas ámbar
 * apiladas dentro de otra caja.
 *
 * Se distinguen por el elemento —el cartel es un `<p>` o una `<section>`, el
 * renglón es un `<li>`— y pesa (0,1,1): lo justo para pisar al cartel y no lo
 * suficiente para tocar lo que el panel declara sobre el renglón —su relleno y
 * su línea, que pesan (0,2,0)—. Por eso acá no se escribe ni el `padding` ni el
 * `border-top`: son de allá. */
li.aviso {
  margin: 0;
  background: none;
  border-width: 0;
}

/* El hueco donde aterrizan los errores de las escrituras hechas por HTMX. Vacío
 * no ocupa nada: está en todas las pantallas y la mayoría de las veces no tiene
 * nada que decir. */
#avisos:empty { display: none; }

/* --- Texto de corrido, pies y estados vacíos ---------------------------- */

/* El tope de línea del texto que se lee de corrido, como clase que se pone en
 * la plantilla. **Se llama `.prosa` y no `.texto`** (contrato §12.8): `.texto`
 * ya está ocupada —es el rótulo del botón que gira, trece usos— y una clase no
 * puede querer decir dos cosas sin que un día una de las dos se despinte. */
.prosa { max-width: var(--linea); }

/* El párrafo de explicación al pie de una pantalla. Es texto, así que lleva el
 * tope de línea; antes eran 92ch, que en un monitor son ciento veinte
 * caracteres por renglón y el ojo se pierde al volver. Al cuerpo del dato y no
 * más chico: una nota que aclara cómo se calcula un interés se lee tanto como
 * la tabla que aclara. */
.nota {
  margin: calc(var(--paso) * 1.5) 0 0;
  max-width: var(--linea);
  font-size: var(--t-dato);
  line-height: 1.5;
  color: hsl(var(--muted-foreground));
}
.nota strong { color: hsl(var(--foreground)); }

/* «Todavía no entró ningún envío», «No hay socios cargados». Es una pantalla
 * que no tiene nada que mostrar y lo dice en el medio, con aire: si la frase
 * fuera un renglón más arriba a la izquierda se leería como un error de carga.
 * El aire **es** el mensaje, y por eso no se achica en el celular. */
.vacio-grande {
  padding: calc(var(--paso) * 4);
  /* **El tope de línea, y el bloque centrado sobre él.** Cinco de estos mensajes
   * son un párrafo entero —el de las paridades explica cuándo se asienta la
   * primera y qué pasa con los días anteriores— y sin tope se dibujaban en dos
   * renglones de 1.170px, centrados, al lado de prosa a 70ch alineada a la
   * izquierda: dos anchos de línea en la misma pantalla, y el más largo para el
   * texto que hay que leer entero porque dice qué hacer.
   *
   * Es el tercer selector que acota texto, y el contrato §5 nombra dos
   * (`.prosa` y `.nota`). Va acá y no como una clase más en las once plantillas
   * que lo usan por lo mismo que `.nota` tiene el suyo escrito: es texto, el
   * tope es el mismo `--linea` de siempre, y el centrado —que es lo que hace
   * que el aire **sea** el mensaje— sólo tiene sentido junto con el tope. Sin el
   * `margin-inline`, acotar lo dejaría pegado a la izquierda y el centrado del
   * texto adentro de una caja angosta se leería como un error de alineación. */
  max-width: var(--linea);
  margin-inline: auto;
  text-align: center;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* El paginado del padrón, la cartera, el libro y el archivo de novedades.
 * Envuelve —a 390 son tres piezas y el hueco de escritorio no entra— y cada
 * enlace mide el objetivo táctil entero: es el control que más se toca de un
 * listado largo y el que peor se acierta, porque «‹» es un carácter de nada.
 * Acá está nada más la fila que los contiene. El «página 1 de 3 · 120 clientes»
 * de adentro **hoy sigue siendo un `<span>` suelto**: el contrato §5 lo manda a
 * `dl.datos-clave`, que es un componente de la sección de fichas y un cambio de
 * plantilla, no de esta regla. */
.paginado {
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
  align-items: center;
  justify-content: center;
  margin-top: var(--paso);
  padding: 6px var(--paso);
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}
.paginado a {
  display: inline-flex;
  align-items: center;
  min-height: var(--toque);
  padding: 0 14px;
}
/* Apagado pero legible: dice «no hay página anterior», que es información. Lo
 * que lo distingue del enlace de al lado es el gris contra el azul, no un
 * alfa: con alfa no llegaba a 4,5:1 en el tema claro. */
.paginado .inactivo { color: hsl(var(--muted-foreground)); }

@media (min-width: 640px) {
  /* Con ancho, las tres piezas se separan: el hueco chico existía sólo para
   * que entraran en un renglón de 390. */
  .paginado { gap: calc(var(--paso) * 2); }
}

/* --- Login y página de error -------------------------------------------- */

/* Las dos pantallas que **no** extienden `app.html`: no tienen barra lateral,
 * ni cabecera, ni hueco de avisos, y su `<main>` no lleva clase de familia, así
 * que no las alcanza ninguna regla de zona (contrato §12.13). Todo su layout
 * está acá, y son las únicas dos de la interfaz de las que se puede decir eso.
 *
 * `100dvh` y no `100vh`: en un celular la barra del navegador entra y sale, y
 * `100vh` cuenta la ventana como si no estuviera; la tarjeta quedaba medio
 * renglón corrida hacia abajo. Es el mismo motivo por el que el marco del libro
 * pasó a `dvh` (§12.1).
 *
 * El relleno propio pisa al de `<main>` —que reserva abajo el alto de la barra
 * inferior— porque acá esa barra no existe: pesa (0,1,0) contra (0,0,1). */
.centrado {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--paso) * 2);
}

/* La tarjeta de acceso: 400px en escritorio (GDV_DESIGN §7) y casi todo el
 * ancho en un celular. **Es el único `max-width` en píxeles que el diagnóstico
 * bendice** —«la única pantalla con un `max-width` que corresponde»—: no acota
 * un texto ni una tabla, acota un formulario de dos campos, y un formulario de
 * dos campos de 1400px de ancho se lee peor, no mejor.
 *
 * Sin sombra: la separa del fondo el borde y el color de superficie, que
 * alcanzan en los dos temas. */
.tarjeta {
  width: 100%;
  max-width: 400px;
  padding: calc(var(--paso) * 3) calc(var(--paso) * 2);
  background: hsl(var(--card));
  border: 1px solid hsl(var(--card-border));
  border-radius: var(--radio);
}

/* Los huecos del login: 6px entre un control y su etiqueta, y 6px más de aire
 * arriba de cada etiqueta. Son doce contra seis, que es lo que agrupa cada
 * rótulo con **su** campo y no con el de arriba; con un hueco parejo la
 * etiqueta «Contraseña» queda a igual distancia de los dos campos y hay que
 * leer para saber cuál nombra. */
.login { display: flex; flex-direction: column; gap: 6px; }

/* La marca arriba de todo, y el título de acceso abajo, más chico: lo que
 * identifica la pantalla es GDV, no la palabra «acceso». El `letter-spacing`
 * se queda: `GDV` son tres letras que son un nombre propio —está escrito así en
 * la plantilla— y no un `text-transform` de esta hoja. */
.marca-login {
  margin: 0 0 2px;
  text-align: center;
  font-size: var(--t-titulo);
  font-weight: 700;
  letter-spacing: 0.14em;
  color: hsl(var(--foreground));
}
.login h1 {
  margin-bottom: 0;
  text-align: center;
  font-size: var(--t-seccion);
  letter-spacing: 0;
}
.login .bajada {
  margin: 0 0 var(--paso);
  text-align: center;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}
/* Sin versales, como todo rótulo desde el rediseño (regla 8 del encabezado):
 * «Usuario» y «Contraseña» se leen igual y ocupan un tercio menos. */
.login label {
  margin-top: 6px;
  font-size: var(--t-rotulo);
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
/* Los dos campos ocupan el ancho de la tarjeta **en los cuatro anchos**: la
 * tabla de anchos por dato de la sección de formularios los devolvería a `auto`
 * desde 640, y un campo de usuario de nueve caracteres en el medio de una
 * tarjeta de 400px se lee como un campo roto. Pesa (0,1,1), lo mismo que
 * aquélla, y gana **por orden**: esta sección es la última de la hoja, y éste
 * es exactamente el trabajo de ir última.
 *
 * `--toque-grande` y no `--toque`: son los dos únicos controles de la pantalla
 * y no hay ninguna densidad que defender. */
.login input {
  inline-size: 100%;
  min-height: var(--toque-grande);
  font-size: var(--t-cuerpo);
}
.login button { margin-top: calc(var(--paso) * 2); width: 100%; }
/* La nota del pie va al cuerpo del resto: la letra chica de verdad no tiene
 * lugar en la única pantalla que se mira sin haber entrado todavía. */
.login .nota { margin-top: calc(var(--paso) * 2); }

/* La página de error es **texto**: el tope se lo pone `--linea` y no un ancho
 * de tarjeta. Pesa lo mismo que `.tarjeta` (0,1,0) y le gana por venir después,
 * que es lo que deja escribir la excepción en un solo renglón. */
.error-pagina {
  max-width: var(--linea);
  text-align: center;
}
/* El «404». En la escala de cinco no hay un paso de 42px, y tampoco hacía
 * falta: lo que hace grande al número es que está solo y en la fuente de las
 * cifras, no que mida catorce píxeles más que un `h1`. */
.error-pagina .codigo {
  margin: 0;
  font-size: var(--t-titulo);
  font-weight: 700;
  color: hsl(var(--muted-foreground));
}
/* El detalle sale de la excepción del dominio y explica el problema en lugar de
 * nombrarlo: es lo único útil de esta página, así que va alineado a la
 * izquierda —aunque el resto de la tarjeta esté centrado— porque son varios
 * renglones y un párrafo centrado se lee peor. `pre-wrap` conserva los saltos
 * que trae el mensaje. */
.error-pagina .detalle {
  text-align: left;
  white-space: pre-wrap;
  font-size: var(--t-dato);
  color: hsl(var(--muted-foreground));
}

/* --- Indicador de carga: el círculo adentro del botón ------------------- */

/* «Interpretar», «Confirmar», el alta de cliente y el resto de los botones que
 * tardan —el modelo, sobre todo—: el círculo va **adentro** del botón que se
 * tocó, y nada más de la pantalla cambia. No hay texto al lado —se probó y
 * era ruido: el único botón que puede estar corriendo es el que se tocó—, ni
 * cartel arriba, ni cambio de cursor: todo eso se probó antes y no era esto.
 *
 * La clase `cargando` la pone `gdv.js` al hacer clic —cubre tanto los envíos
 * por htmx como los que recargan la página entera (`operacion.html`, sin
 * `hx-post`)— y la saca `htmx:afterRequest` cuando el botón sobrevive al
 * pedido (el swap no lo reemplazó). `pointer-events: none` evita el doble
 * envío sin usar el atributo `disabled`, que en un submit corriente puede
 * cancelar el propio envío que dispara el clic.
 *
 * Es la única animación de todo este documento (ver el encabezado, «No hay
 * animaciones»): la excepción está anotada ahí y en el README, «Densidad y
 * formato». `prefers-reduced-motion` de abajo la alarga en vez de sacarla: el
 * botón gris y quieto ya es señal, pero un aro que dejó de girar del todo se
 * confunde con uno roto. */
.con-carga {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.con-carga .texto { flex: 1 1 auto; }

.con-carga .circulo-carga { display: none; }

.con-carga.cargando { pointer-events: none; opacity: 0.6; }

.con-carga.cargando .circulo-carga {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: girar 0.7s linear infinite;
  flex: none;
}

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

/* --- La última red ------------------------------------------------------ */

/* Lo que sigue está en el HTML, tenía regla en la hoja vieja y **ninguna de las
 * nueve secciones anteriores lo reclamó**. Va acá porque una clase del HTML sin
 * ninguna regla es una pantalla sin estilo que no rompe ningún test de
 * contenido —es la forma más silenciosa de romper esto— y porque este archivo
 * es el último. Está escrito con los tokens nuevos y sin versales, pero es el
 * dibujo de siempre: el día que alguien toque el arqueo o el formulario de
 * cheques, estas reglas se mudan a su sección. */

/* El arqueo frenado por los pendientes (§4.10). No es un `.aviso` ámbar: es un
 * freno, no una advertencia. Lo que sigue abajo cuando aparece esto es la lista
 * de lo que hay que resolver, no el formulario —salvo para un admin, que puede
 * declarar y contar igual—. Radio de panel: es una caja con contenido adentro,
 * no una marca. */
.bloqueo {
  margin: 0 0 var(--paso);
  padding: 11px 14px;
  background: hsl(var(--destructive) / 0.18);
  border: 1px solid hsl(var(--destructive-text) / 0.8);
  border-left-width: 4px;
  border-radius: var(--radio);
}
/* Más chico que el `h2` general de 18px, y por eso está escrito: no es el
 * título de una sección de la pantalla sino la frase que dice por qué no se
 * arranca —«El arqueo no arranca: hay 3 ediciones de cheque sin aprobar»—, y a
 * 18px esa frase son tres renglones en un celular y pesa más que la lista de
 * abajo, que es lo que hay que ir a resolver. */
.bloqueo h2 { margin: 0 0 6px; font-size: var(--t-cuerpo); color: hsl(var(--destructive-text)); }
.bloqueo p { margin: 0 0 6px; font-size: var(--t-dato); }
.bloqueo ul { margin: 6px 0; padding-left: 18px; font-size: var(--t-dato); }
.bloqueo li { margin-bottom: 3px; }

/* La declaración del admin, adentro del formulario de conteo. Es una frase de
 * dos renglones —«Declaro que ninguna de las tres pendientes afecta las cajas
 * que voy a contar, y por qué»—, no un rótulo de una palabra: va al cuerpo del
 * dato y en el color del texto, no en el gris de una etiqueta. Antes esta regla
 * además tenía que desactivar las versales de `.campo label`; ese problema ya
 * no existe y las dos líneas que lo arreglaban se fueron con él. */
.conteo .declaracion { margin-top: var(--paso); }
.conteo .declaracion label {
  display: block;
  margin-bottom: 4px;
  font-size: var(--t-dato);
  color: hsl(var(--foreground));
}
.conteo .declaracion textarea { inline-size: 100%; }

/* La marca del historial: este arqueo se hizo con pendientes abiertas. Ámbar y
 * no roja: no es un error, es un dato que cambia cómo se lee la fila de al
 * lado. */
.marca-declarado {
  display: inline-block;
  margin-left: 6px;
  padding: 0 6px;
  background: hsl(var(--warning) / 0.14);
  border: 1px solid hsl(var(--warning) / 0.6);
  border-radius: var(--radio-chico);
  color: hsl(var(--warning-text));
  font-size: var(--t-rotulo);
}

/* Y en la pantalla del resultado: la constancia de que se contó igual. */
.declaracion-arqueo ul { margin: 6px 0 0; padding-left: 18px; font-size: var(--t-dato); }
.declaracion-arqueo li { margin-bottom: 3px; }
.declaracion-arqueo p { margin: 0; }

/* §4.9 y §4.20 — el bloque de e-cheq de una fila de cheques. La casilla y su
 * rótulo van en una línea y alineados abajo con los otros campos: es el único
 * `.campo` de la fila que no tiene un control de alto completo, y sin el
 * `align-self` quedaba flotando a media altura. `--toque` y no los 36px de
 * antes: se toca, y un objetivo de 36 escrito en píxeles es un objetivo táctil
 * escondido. */
.casilla-echeq {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  align-self: end;
  min-height: var(--toque);
}
.casilla-echeq label { margin: 0; }

/* El rótulo que separa el bloque de destino del resto de la fila: importe,
 * fecha, banco, número, firmante y CUIT son datos del papel; endosado a y vía
 * son qué se hace con él, y por eso se leen como un bloque aparte, debajo de
 * una línea. Sin versales: la línea punteada ya dice que empieza otra cosa. */
.subtitulo-destino {
  flex: 1 1 100%;
  margin: 0;
  padding-top: 6px;
  border-top: 1px dashed hsl(var(--border));
  font-size: var(--t-rotulo);
  font-weight: 600;
  color: hsl(var(--muted-foreground));
}
/* La ubicación va con los datos del papel —en qué cuenta está el e-cheq— y no
 * con la salida. Es un `.campo` como los demás y no declara su propio ancho: lo
 * reparte la fila, que es la que sabe cuántos campos hay. */
.ubicacion-echeq select { inline-size: 100%; }
/* El destino que la casilla «E-cheq» habilita: a quién se endosa, si sale en el
 * acto. Un bloque propio dentro de la fila, a lo ancho, para que se lea como lo
 * que es: la salida del papel, no un dato más del papel. */
.endoso-echeq {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--paso);
}
.endoso-echeq select { inline-size: 100%; }
/* **Sin JavaScript están siempre a la vista**: la regla que esconde la
 * ubicación y el destino cuelga de `sin-echeq`, una clase que sólo pone
 * `gdv.js` sobre la fila de un cheque físico. Sin el script el HTML no la trae,
 * los campos se ven y el servidor los ignora en un físico. Con el script,
 * tildar la casilla los muestra. */
.fila-cheque.sin-echeq .subtitulo-destino,
.fila-cheque.sin-echeq .ubicacion-echeq,
.fila-cheque.sin-echeq .endoso-echeq { display: none; }
/* §4.20 — y adentro del e-cheq, un segundo estado: el papel que se endosa en el
 * acto no vive en ninguna cuenta de GDV, así que la ubicación no aplica y el
 * campo ni se muestra. La clase la pone el servidor cuando la fila vuelve con el
 * destino cargado y la mantiene `gdv.js` mientras se tipea. */
.fila-cheque.sale-en-el-acto .ubicacion-echeq { display: none; }
/* §4.20 — el e-cheq de la propuesta al que todavía no se le eligió cuenta: se
 * lee antes de confirmar, con el peso de una advertencia. */
.sin-ubicacion { font-weight: 600; color: hsl(var(--warning-text)); }
/* El cheque de la propuesta que sale endosado en el acto (§4.20): se lee antes
 * de confirmar, con el mismo peso que el resto de la línea. */
.sale-en-el-acto { font-weight: 600; }

/* --- Menos movimiento --------------------------------------------------- */

/* Quien pide menos movimiento no tiene por qué recibir transiciones.
 *
 * El círculo de carga queda afuera a propósito. Esta regla es `!important`
 * sobre `*`, así que le gana a cualquier selector, y durante un tiempo se llevó
 * puesto el `animation: girar` de `.circulo-carga` en toda máquina con «reducir
 * movimiento» activo: el aro se dibujaba adentro del botón y se quedaba quieto,
 * que es exactamente lo que se confunde con un botón roto. Para el círculo la
 * preferencia se respeta **alargando la vuelta**, no parándola, y esa es la
 * tercera regla de este bloque: misma especificidad que la de arriba y más
 * abajo en el archivo, que es todo lo que hace falta para que gane.
 *
 * Es la única `@media` de esta sección y una de las dos de toda la hoja que no
 * hablan de ancho. */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  *:not(.circulo-carga) { animation: none !important; }
  .con-carga.cargando .circulo-carga { animation-duration: 2s; }
}
