/* ==========================================================================
   UPrex — hoja de estilos única.

   Mobile-first de verdad: esto se usa parado en la calle, con una mano, con sol
   encima de la pantalla. De ahí salen tres decisiones que no son de gusto:
   contraste alto, objetivos táctiles de 44px, y nada de íconos donde una palabra
   dice lo mismo sin ambigüedad.
   ========================================================================== */

/* --------------------------------------------------------------------------
   LOS COLORES SON TOKENS Y NADA LOS ESCRIBE A MANO.

   El tema lo elige la persona (Mi cuenta → Apariencia) y se guarda en el
   navegador: es del APARATO, no del negocio. El cobrador quiere la pantalla
   oscura a la noche en su teléfono y el administrador la quiere clara en la PC
   de la oficina, y los dos entran con la misma cuenta.

   Son TRES estados y no dos. Elegir "Claro" u "Oscuro" estampa data-tema en el
   <html>; el default —"Automático"— no estampa nada y ahí manda el sistema
   operativo. Por eso el bloque de abajo define el tema claro COMPLETO sobre
   :root pelado, la media query redefine sólo los tokens (guardada con
   :not([data-tema=claro]) para que la elección explícita le gane al sistema), y
   [data-tema=oscuro] los redefine otra vez para que gane en el otro sentido.

   La regla que no se puede romper: NINGÚN color se declara adentro de la media
   query ni del [data-tema]. Un color cuya única definición viva ahí no existe en
   el estado sin estampar, y la pantalla sale con el texto de un tema sobre el
   fondo del otro.
   -------------------------------------------------------------------------- */

:root {
    --fondo:          #f3f4f6;
    --superficie:     #ffffff;
    --superficie-2:   #f8f9fb;
    --borde:          #dcdfe4;
    --borde-fuerte:   #c3c8d0;

    --texto:          #171b23;
    --texto-suave:    #58616f;
    --texto-tenue:    #838b98;

    /* --primario es el ACENTO (enlaces, foco, botón, pestaña activa) y --barra
       es el FONDO del header. En claro dan el mismo azul y parece que sobra uno;
       en oscuro no pueden serlo: un acento legible sobre fondo negro tiene que
       ser claro, y un header claro con letra blanca no se lee. */
    --primario:       #1e3a5f;
    --primario-hover: #16304f;
    --primario-suave: #eaeff5;
    --sobre-primario: #ffffff;

    --barra:          #1e3a5f;
    --sobre-barra:    #ffffff;

    --exito:          #08694a;
    --exito-suave:    #e6f4ef;
    --peligro:        #a4231b;
    --peligro-hover:  #8c1d16;
    --peligro-suave:  #fdecea;
    --aviso:          #9a5b06;
    --aviso-suave:    #fdf3e3;

    /* Los dos velos. El de "cargando" es del color del FONDO y por eso es un
       token: escrito a mano en claro, en tema oscuro tapaba la pantalla con una
       cortina blanca — que es exactamente el fogonazo que el modo oscuro viene a
       evitar. */
    --velo:           rgba(23, 27, 35, .45);
    --velo-carga:     rgba(243, 244, 246, .72);

    --panel:          #262a33;
    --panel-activo:   #eef0f3;

    /* EL ACENTO DE CADA SECCIÓN. Cinco listados que se veían idénticos —mismo azul,
       mismo blanco, mismo gris— y no había forma de saber, al abrir, en cuál se
       está parado. Cada uno tiene su color y lo usa en TRES lugares y nada más: la
       barra del título, el chip de filtro elegido y la línea de arriba de la lista.
       Las filas no se tocan, así que la pantalla sigue siendo blanca y gris.

       LOS CINCO TONOS ESTÁN REPARTIDOS EN EL CÍRCULO —azul, ciruela, violeta, cobre
       y oliva— y ninguno cae cerca del verde de "cobrado", del rojo de "atrasado" ni
       del ámbar de "por vencer": un acento de sección que se confunda con un estado
       hace que el estado deje de significar algo. Los cinco pasan 5:1 sobre la
       tarjeta —para el título— y con blanco encima —para el chip—, y están a más de
       22 de distancia entre sí. Los tres números los mide `dev/test_secciones.php`
       en vez de darlos por buenos. */
    --sec-inicio:      #1e3a5f;
    --sec-clientes:    #8a3d6b;
    --sec-prestamos:   #63389c;
    --sec-cobros:      #8f4a34;
    --sec-movimientos: #5c6330;
    --radio:      8px;
    --radio-chico: 5px;
    --e1: .25rem;
    --e2: .5rem;
    --e3: .75rem;
    --e4: 1rem;
    --e5: 1.5rem;
    --e6: 2rem;

    --alto-header:   3.25rem;
    --alto-navpie:   3.5rem;
    --sombra:        0 1px 2px rgba(23, 27, 35, .06), 0 1px 3px rgba(23, 27, 35, .04);
    --sombra-flotante: 0 4px 16px rgba(23, 27, 35, .14);

    color-scheme: light;
}

/* Automático: manda el sistema operativo. Guardada con :not([data-tema=claro])
   para que quien eligió claro a mano no vea oscuro por tener el celular en
   modo noche. */
@media (prefers-color-scheme: dark) {
    :root:not([data-tema="claro"]) {
        --fondo:          #0f1319;
        --superficie:     #171c24;
        --superficie-2:   #1e242e;
        --borde:          #2b3340;
        --borde-fuerte:   #3d4756;

        --texto:          #e9ecf1;
        --texto-suave:    #a3adbd;
        --texto-tenue:    #788291;

        --primario:       #86b0e8;
        --primario-hover: #a3c4f0;
        --primario-suave: #1b2738;
        --sobre-primario: #0d1218;

        --barra:          #10151d;
        --sobre-barra:    #e9ecf1;

        --exito:          #4cc79a;
        --exito-suave:    #10261e;
        --peligro:        #f08a7d;
        --peligro-hover:  #f5a99e;
        --peligro-suave:  #2c1613;
        --aviso:          #e0b055;
        --aviso-suave:    #2a2113;

        --velo:           rgba(0, 0, 0, .62);
        --velo-carga:     rgba(15, 19, 25, .78);

        --panel:          #0c0f14;
        --panel-activo:   #1e242e;

        /* En oscuro una sombra clara no existe: lo que separa una tarjeta del
           fondo es una sombra MÁS negra, no más suave. */
        --sombra:        0 1px 2px rgba(0, 0, 0, .5), 0 1px 3px rgba(0, 0, 0, .35);
        --sombra-flotante: 0 4px 20px rgba(0, 0, 0, .6);

        /* Los mismos cinco tonos, subidos: sobre fondo negro un acento oscuro no se
           lee. El cobre se desatura además de aclararse —queda nuez y no salmón—
           porque en claro el rojo de peligro es apagado y en oscuro es un salmón
           brillante, y ahí sí se le pondría al lado. */
        --sec-inicio:      #86b0e8;
        --sec-clientes:    #e79ac6;
        --sec-prestamos:   #b99ceb;
        --sec-cobros:      #cba98f;
        --sec-movimientos: #b6c46a;

        color-scheme: dark;
    }
}

/* Elegido a mano. Repite los mismos tokens para ganarle al sistema en el otro
   sentido: celular en claro y app en oscuro. */
:root[data-tema="oscuro"] {
    --fondo:          #0f1319;
    --superficie:     #171c24;
    --superficie-2:   #1e242e;
    --borde:          #2b3340;
    --borde-fuerte:   #3d4756;

    --texto:          #e9ecf1;
    --texto-suave:    #a3adbd;
    --texto-tenue:    #788291;

    --primario:       #86b0e8;
    --primario-hover: #a3c4f0;
    --primario-suave: #1b2738;
    --sobre-primario: #0d1218;

    --barra:          #10151d;
    --sobre-barra:    #e9ecf1;

    --exito:          #4cc79a;
    --exito-suave:    #10261e;
    --peligro:        #f08a7d;
    --peligro-hover:  #f5a99e;
    --peligro-suave:  #2c1613;
    --aviso:          #e0b055;
    --aviso-suave:    #2a2113;

    --velo:           rgba(0, 0, 0, .62);
    --velo-carga:     rgba(15, 19, 25, .78);

    --panel:          #0c0f14;
    --panel-activo:   #1e242e;

    --sombra:        0 1px 2px rgba(0, 0, 0, .5), 0 1px 3px rgba(0, 0, 0, .35);
    --sombra-flotante: 0 4px 20px rgba(0, 0, 0, .6);

    --sec-inicio:      #86b0e8;
    --sec-clientes:    #e79ac6;
    --sec-prestamos:   #b99ceb;
    --sec-cobros:      #cba98f;
    --sec-movimientos: #b6c46a;

    color-scheme: dark;
}

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

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

body {
    margin: 0;
    background: var(--fondo);
    color: var(--texto);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    font-size: 15px;
    line-height: 1.5;
    /* El rebote elástico al final de un listado se lee como que la pantalla se
       movió sola cuando se está tocando con el pulgar. */
    overscroll-behavior-y: none;
}

/* El texto de la app no se selecciona (es una app, no un documento), pero los
   datos SÍ: el teléfono de un cliente se copia todo el tiempo. */
body { -webkit-user-select: none; user-select: none; }
input, textarea, select, .seleccionable, .dato, td, .lista-dato { -webkit-user-select: text; user-select: text; }

h1, h2, h3 { margin: 0 0 var(--e3); line-height: 1.25; font-weight: 600; }
h1 { font-size: 1.25rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .95rem; }
p  { margin: 0 0 var(--e3); }

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

/* [hidden] tiene que ganar SIEMPRE: el navegador lo aplica desde su hoja de
   usuario, que pierde contra cualquier clase del proyecto, y este sistema pliega
   cosas con hidden (los paneles de pestañas, los bloques condicionales). */
[hidden] { display: none !important; }

/* ==========================================================================
   Estructura
   ========================================================================== */

.app-header {
    position: sticky;
    top: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: var(--e3);
    height: var(--alto-header);
    padding: 0 var(--e4);
    background: var(--barra);
    color: var(--sobre-barra);
}
.app-header a { color: var(--sobre-barra); }
.app-header .marca { font-weight: 600; letter-spacing: .01em; }
.app-header .empresa { font-size: .78rem; opacity: .8; display: block; line-height: 1.2; }
.app-header .derecha { margin-left: auto; display: flex; align-items: center; gap: var(--e3); }
.app-header .usuario { font-size: .82rem; opacity: .9; }

.contenido {
    padding: var(--e4);
    padding-bottom: calc(var(--alto-navpie) + var(--e6) + env(safe-area-inset-bottom, 0px));
    max-width: 60rem;
    margin: 0 auto;
}

/* La navegación de abajo: es donde llega el pulgar. Sin íconos, con palabras
   cortas — un ícono ambiguo en una app de plata se aprende mal una vez y se
   equivoca siempre. */
.nav-pie {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 50;
    display: flex;
    background: var(--superficie);
    border-top: 1px solid var(--borde);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}
.nav-pie a {
    flex: 1;
    min-height: var(--alto-navpie);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: .8rem;
    font-weight: 500;
    color: var(--texto-suave);
    text-decoration: none;
    border-top: 2px solid transparent;
}
.nav-pie a.activo { color: var(--primario); border-top-color: var(--primario); background: var(--primario-suave); }

/*
   EL BOTÓN DE PRÉSTAMO NUEVO, en el medio de la barra.

   `flex: 0 0 auto` y no `flex: 1` como los otros cuatro: el círculo mide lo que
   mide, y estirado ocuparía un quinto de la barra con el dibujo perdido en el
   medio. Los otros cuatro se reparten lo que queda.

   No lleva `.activo`: es una acción y no una sección donde uno esté parado.
*/
.nav-pie a.destacado {
    flex: 0 0 auto;
    padding: 0 var(--e2);
    border-top-color: transparent;
}
.nav-pie a.destacado .mas {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.9rem;
    height: 2.9rem;
    border-radius: 50%;
    background: var(--primario);
    color: var(--sobre-primario);
    /* El "+" se dibuja con la tipografía y no con un SVG: es un carácter que
       existe en todas, y un ícono suelto sería un archivo más que cachear. El
       line-height en 1 es lo que lo deja centrado de verdad — con el de la página
       queda unos píxeles arriba. */
    font-size: 1.75rem;
    font-weight: 400;
    line-height: 1;
    /* El signo tiene el alto de un dígito, así que ópticamente cae bajo. */
    padding-bottom: .12em;
}
.nav-pie a.destacado:hover .mas { background: var(--primario-hover); }

/* El rótulo que sólo lee un lector de pantalla: el "+" solo no dice qué hace, y
   un title no se muestra en un teléfono. */
.visualmente-oculto {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

@media (min-width: 48rem) {
    .contenido { padding-bottom: var(--e6); }
    .nav-pie {
        position: sticky;
        top: var(--alto-header);
        border-top: 0;
        border-bottom: 1px solid var(--borde);
        z-index: 40;
    }
    .nav-pie a { min-height: 2.75rem; border-top: 0; border-bottom: 2px solid transparent; }
    .nav-pie a.activo { border-bottom-color: var(--primario); }
    /* En pantalla grande la barra es una tira de solapas arriba y un círculo de
       2,9rem la haría más alta que las demás. */
    .nav-pie a.destacado .mas { width: 2.1rem; height: 2.1rem; font-size: 1.35rem; }
}

/* ==========================================================================
   Tarjetas y bloques
   ========================================================================== */

.tarjeta {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: var(--e4);
    margin-bottom: var(--e4);
    box-shadow: var(--sombra);
}
.tarjeta > h2:first-child, .tarjeta > h1:first-child { margin-top: 0; }
.tarjeta-titulo {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--e3); margin-bottom: var(--e3);
}

/* Las cifras se acomodan solas: con auto-fit entran dos en un teléfono, tres en
   uno grande y cuatro en una tablet, sin un breakpoint por cada caso. El piso de
   7.5rem es lo que mide "$120.000" en el cuerpo del valor — abajo de eso el
   número se corta, y esta es la pantalla que se le muestra AL CLIENTE: el importe
   se tiene que leer de lejos y del otro lado del mostrador. Antes de condensar
   más, el número manda. */
.panel-cifras {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
    gap: var(--e2);
    margin-bottom: var(--e4);
}

.cifra {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    padding: var(--e3);
}
.cifra .rotulo {
    font-size: .68rem; text-transform: uppercase; letter-spacing: .05em;
    font-weight: 600; color: var(--texto-tenue);
}
.cifra .valor  { font-size: 1.2rem; font-weight: 600; font-variant-numeric: tabular-nums; margin-top: 2px; }
.cifra.peligro .valor { color: var(--peligro); }

/* LO QUE SE ESTÁ RECALCULANDO. Cambiar el porcentaje ya no recarga la pantalla, así
   que hay una fracción de segundo en la que el bloque de cifras Y el desglose son
   los del porcentaje VIEJO — y son los números que se le leen al cliente en la
   puerta. El atenuado dice que todavía no son los definitivos; sin él, en una
   conexión mala se muestran como buenos y nadie tiene manera de saberlo.
   No se ocultan ni se deshabilitan: quedan legibles, sólo que dichos a medias.
   Y va SIN id adelante para que la próxima zona que haga falta la use como está. */
.actualizando { opacity: .45; transition: opacity .12s; }
.cifra.exito   { background: var(--exito-suave); border-color: transparent; }
.cifra.exito .valor   { color: var(--exito); }
.cifra.peligro { background: var(--peligro-suave); border-color: transparent; }
/* El ámbar de "se está acercando al límite": ya existía como etiqueta y faltaba
   como cifra. Los colores salen de los mismos tokens, así que sigue el tema. */
.cifra.aviso   { background: var(--aviso-suave);   border-color: transparent; }
.cifra.aviso .valor   { color: var(--aviso); }

/* ==========================================================================
   LA IDENTIDAD DE CADA LISTADO

   Cinco pantallas de lista —Inicio, Clientes, Préstamos, Cobros y Movimientos—
   dibujadas con el mismo blanco, el mismo gris y el mismo azul. Al abrir
   cualquiera de ellas no había cómo saber en cuál se había caído, y volver de una
   ficha se sentía igual que no haber ido a ningún lado.

   CADA SECCIÓN TRAE SU ACENTO Y LO USA EN TRES LUGARES:

       1. la barra del título        ▌Clientes
       2. el chip de filtro elegido  [Con deuda]
       3. la línea de arriba de la lista

   Y EN NINGUNO MÁS. Las filas, los montos, las etiquetas de estado y los botones
   se quedan como están: lo que distingue una pantalla de otra es el marco, no el
   contenido. Pintar las filas haría que dos listas de la misma app se leyeran como
   dos aplicaciones, y encima le pelearía el color a los estados, que es lo único
   que en estas pantallas TIENE que llamar la atención.

   `--sec` es el único nombre que usan las reglas de abajo; el mapa de sección a
   color vive en un solo lugar. Con fallback a `--primario`, toda pantalla que no
   declare sección —las fichas, los formularios, «Más»— se dibuja como siempre.
   ========================================================================== */

body[data-seccion="inicio"]      { --sec: var(--sec-inicio); }
body[data-seccion="clientes"]    { --sec: var(--sec-clientes); }
body[data-seccion="prestamos"]   { --sec: var(--sec-prestamos); }
body[data-seccion="cobros"]      { --sec: var(--sec-cobros); }
body[data-seccion="movimientos"] { --sec: var(--sec-movimientos); }

/*
   1 · EL TÍTULO CON SU BARRA.

   La barra va a la IZQUIERDA y no debajo: subrayado se lee como una pestaña —algo
   que se toca— y esto no se toca, dice dónde estás. Son 3px porque a 2 se pierde
   contra el título en negrita y a 4 empieza a ser una franja.

   El título toma el color del acento. Es una palabra sola en una pantalla que por
   lo demás es gris, así que alcanza para reconocer la sección de un vistazo, y no
   hay ningún otro texto de color con el que se pueda confundir.
*/
.cabecera-seccion {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--e3);
    margin: 0 0 var(--e3);
}
.cabecera-seccion h1 {
    margin: 0;
    display: flex; align-items: center; gap: var(--e3);
    color: var(--sec, var(--primario));
    min-width: 0;
}
/* La barra es un ::before y no un border-left del <h1>: con el borde, el alto lo
   fija el texto y en un título de dos renglones —un teléfono angosto— la barra
   crecería con él. Acá mide lo que mide una línea y siempre se ve igual. */
.cabecera-seccion h1::before {
    content: "";
    flex: none;
    width: 3px; height: 1.15em;
    border-radius: 2px;
    background: var(--sec, var(--primario));
}
.cabecera-seccion .acciones { flex: none; }

/*
   2 · EL CHIP ELEGIDO toma el acento también, y su regla NO está acá: sigue en el
   bloque de botones, que es donde se la busca. Lo único que cambió ahí es de dónde
   sale el color.

   3 · LA LÍNEA DE ARRIBA DE LA LISTA.

   Es la que más se ve: la lista ocupa la pantalla entera y esto la firma sin tocar
   una sola fila. Va como `border-top` del envoltorio —que ya recorta con
   `overflow: hidden`— y no como una barra aparte, para que no agregue un elemento
   que después haya que acordarse de poner.
*/
/* La regla NO está acá: iría antes de la definición de `.lista-envoltorio`, que
   declara `border` completo y la pisaría. Está allá abajo, en el borde mismo. */

@media print {
    /* En papel el acento no aporta nada y se lleva tinta. */
    .cabecera-seccion h1 { color: var(--texto); }
    .cabecera-seccion h1::before { display: none; }
    .lista-envoltorio { border-top-color: var(--borde); }
}


/* ==========================================================================
   Listados
   ========================================================================== */

.lista { list-style: none; margin: 0; padding: 0; }
.lista-item {
    display: flex; align-items: center; gap: var(--e3);
    padding: var(--e3) var(--e4);
    border-bottom: 1px solid var(--borde);
    background: var(--superficie);
    min-height: 3.5rem;
    color: inherit;
    text-decoration: none;
}
.lista-item:last-child { border-bottom: 0; }
.lista-item:hover { background: var(--superficie-2); text-decoration: none; }
.lista-item .cuerpo { flex: 1; min-width: 0; }
.lista-item .titulo { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/*
   LA BARRA DE PROGRESO DEL LISTADO DE PRÉSTAMOS.

   Va en la misma línea que el nombre, a la derecha. El nombre se lleva lo que
   sobra y la barra tiene ancho fijo: al revés —la barra elástica— cada fila
   tendría una barra de largo distinto según lo largo que sea el apellido, y
   comparar dos filas de un vistazo dejaría de funcionar, que es todo el punto.
*/
.fila-progreso {
    display: flex;
    align-items: center;
    gap: var(--e2);
}
.fila-progreso .nombre {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
.barra-progreso {
    flex: 0 0 auto;
    width: 4.5rem;
    height: .5rem;
    border-radius: 999px;
    /* El fondo es el tramo que FALTA. Gris y no blanco: sobre la tarjeta blanca no
       se vería dónde termina la barra, y una barra sin final no se puede leer. */
    background: var(--superficie-2);
    border: 1px solid var(--borde);
    overflow: hidden;
}
.barra-progreso > span {
    display: block;
    height: 100%;
    border-radius: 999px;
    /* Sin transición: la barra es un dato fijo, no algo que esté avanzando. Una
       animación al cargar la pantalla la haría parecer un progreso en curso. */
}
.barra-progreso.ok     > span { background: var(--exito); }
.barra-progreso.atento > span { background: var(--aviso); }
.barra-progreso.mal    > span { background: var(--peligro); }

.progreso-texto {
    flex: 0 0 auto;
    font-size: .75rem;
    font-weight: 500;
    color: var(--texto-suave);
    font-variant-numeric: tabular-nums;
}

.texto-peligro { color: var(--peligro); }
.lista-item .sub    { font-size: .82rem; color: var(--texto-suave); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lista-item .monto  { font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; white-space: nowrap; }
.lista-item.inactivo .titulo { color: var(--texto-tenue); font-weight: 500; }

/* El renglón de arriba de un movimiento: NOMBRE y, si es un cobro, qué cuota pagó.

   EL QUE SE RECORTA ES EL NOMBRE Y NO LA CUOTA. `.titulo` recorta con puntos
   suspensivos lo que no entra, así que con los dos textos sueltos adentro «JUAN
   CARLOS PEREZ» se comería la cuota en un teléfono angosto — y la cuota es corta y
   es justamente lo que distingue una fila de otra del mismo cliente. Con el flex, la
   cuota declara `flex: none` y el que cede es el nombre. */
.lista-item .titulo.mov-titulo { display: flex; align-items: baseline; gap: var(--e2); }
.mov-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mov-cuota  { flex: none; font-size: .78rem; font-weight: 500; color: var(--texto-suave); }

.lista-envoltorio {
    background: var(--superficie);
    border: 1px solid var(--borde);
    /* LA LÍNEA DE LA SECCIÓN. Va en el borde de arriba y DESPUÉS del `border`
       completo, que si no la pisa: escrita más arriba en la hoja se ve gris y no
       hay ninguna regla rota que mirar.
       En el Inicio son dos listas —«Atrasados» y el día— y las dos la llevan: son
       la misma sección, y lo que las distingue entre sí es su rótulo. */
    border-top: 3px solid var(--sec, var(--borde));
    border-radius: var(--radio);
    overflow: hidden;
    box-shadow: var(--sombra);
}


/* El rótulo de cada bloque del inicio: UN RENGLÓN, no una franja.
   Antes era un <h1> con el total al lado y se comía casi dos filas de lista antes
   de mostrar la primera. Acá lo que se mira es la lista. */
.encabezado-lista {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--e2);
    margin: 0 0 var(--e2);
    padding: 0 var(--e2);
}
.encabezado-lista h2 {
    margin: 0;
    font-size: .82rem; font-weight: 700;
    letter-spacing: .04em; text-transform: uppercase;
    color: var(--texto-suave);
}
.encabezado-lista .total {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}
.nota-lista { margin: calc(var(--e2) * -1) 0 var(--e2); padding: 0 var(--e2); }

/* El segundo bloque necesita aire respecto del primero. */
.lista-envoltorio + .encabezado-lista { margin-top: var(--e4); }

/* --------------------------------------------------------------------------
   La fila de cobro del inicio: DOS RENGLONES en 60px, tocable de punta a punta.

       NOMBRE                                    3751-445566
       1 de 10                3 días              $ 36.000

   ES UNA GRILLA DE 3 COLUMNAS Y NO DOS FLEX APILADOS, y la diferencia está en el
   renglón de abajo: con `justify-content: space-between` y tres elementos, el del
   medio NO queda centrado en la fila — queda en el hueco que le dejan los otros
   dos, así que se corre a un lado según cuánto midan la cuota y el importe. Con
   `1fr auto 1fr` los dos laterales ocupan lo mismo pase lo que pase y el atraso
   queda centrado de verdad, que es lo que se pidió.

   Y la columna del medio ARRIBA no se usa: el nombre la atraviesa. Eso es lo que
   le da el renglón entero para él.

   EL ALTO ES FIJO Y NO MÍNIMO. Con `min-height`, un nombre que envuelve estira la
   fila y la lista deja de tener un ritmo parejo — y el que baja la vista buscando
   un cliente cuenta filas, no píxeles. Lo que no entra se recorta.
   -------------------------------------------------------------------------- */
.fila-cobro {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-content: center;
    row-gap: 2px; column-gap: var(--e2);
    height: 60px;
    padding: 0 var(--e4);
    border-bottom: 1px solid var(--borde);
    background: var(--superficie);
    color: inherit;
    text-decoration: none;
    overflow: hidden;
}
.fila-cobro:last-child { border-bottom: 0; }
.fila-cobro:hover  { background: var(--superficie-2); text-decoration: none; }
.fila-cobro:active { background: var(--superficie-2); }

/* --- Renglón de arriba: nombre a la izquierda, celular a la derecha --------- */

/* El nombre se lleva las dos primeras columnas: es el dato que más largo puede ser
   y el único que vale la pena recortar. Lo recorta el `overflow: hidden`; el
   `min-width: 0` va por costumbre y, medido, acá no cambia nada. */
.fila-cobro .fc-nombre {
    grid-column: 1 / 3;
    min-width: 0;
    font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.fila-cobro .fc-tel {
    grid-column: 3;
    text-align: right;
    white-space: nowrap;
}

/* --- Renglón de abajo: cuota | atraso centrado | importe -------------------- */

.fila-cobro .fc-cuota  { grid-column: 1; }
.fila-cobro .fc-atraso { grid-column: 2; text-align: center; }
.fila-cobro .fc-monto  { grid-column: 3; text-align: right; }

.fila-cobro .fc-tel,
.fila-cobro .fc-cuota,
.fila-cobro .fc-atraso {
    font-size: .82rem;
    color: var(--texto-suave);
    white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
}

.fila-cobro .fc-atraso { color: var(--aviso); font-weight: 600; }
.fila-cobro .fc-atraso.grave { color: var(--peligro); }

.fila-cobro .fc-monto {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
}

/* En pantallas angostas se achican los costados. El cuerpo de los datos NO se toca:
   con dos renglones ya no hay que pelear por el ancho, y letra más chica en una
   pantalla más chica es lo contrario de lo que hace falta. */
@media (max-width: 420px) {
    .fila-cobro { padding: 0 var(--e3); }
}

.vacio {
    padding: var(--e6) var(--e4);
    text-align: center;
    color: var(--texto-suave);
}
.vacio strong { display: block; color: var(--texto); margin-bottom: var(--e1); }

/* ==========================================================================
   Tablas (pantalla grande / reportes)
   ========================================================================== */


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

table.datos { width: 100%; border-collapse: collapse; font-size: .9rem; }
table.datos th, table.datos td { padding: var(--e2) var(--e3); text-align: left; white-space: nowrap; }
table.datos thead th {
    position: sticky;
    /* -1px y no 0: con 0 se cuela una franja de un píxel entre el borde del
       scrollport y la celda mientras se scrollea, y se lee como una línea de la
       fila de datos asomando por encima del encabezado. */
    top: -1px;
    z-index: 10;
    background: var(--superficie-2);
    font-size: .75rem; text-transform: uppercase; letter-spacing: .03em;
    color: var(--texto-suave);
    /* box-shadow y no border: con bordes colapsados el borde lo pinta la tabla,
       no la celda, y al scrollear se va con las filas. */
    box-shadow: inset 0 -1px 0 var(--borde);
}
table.datos tbody tr { border-top: 1px solid var(--borde); }
table.datos td.numero, table.datos th.numero { text-align: right; font-variant-numeric: tabular-nums; }

@media print {
    /* Impresa, la grilla va entera: un informe de trescientas filas saldría
       cortado en una pantalla. */
    .tabla-contenedor { max-height: none; overflow: visible; }
    .app-header, .nav-pie, .no-imprimir { display: none !important; }
}

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

.campo { margin-bottom: var(--e3); }
.campo > label { display: block; font-size: .8rem; font-weight: 600; color: var(--texto-suave); margin-bottom: var(--e1); }
.campo .ayuda { font-size: .76rem; color: var(--texto-tenue); margin-top: var(--e1); line-height: 1.35; }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=tel], input[type=date], input[type=search], select, textarea {
    width: 100%;
    /* 16px o más: abajo de eso iOS hace zoom al enfocar y descoloca la pantalla. */
    font-size: 16px;
    font-family: inherit;
    color: var(--texto);
    background: var(--superficie);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio);
    padding: var(--e2) var(--e3);
    /* 2.75rem = 44px. Es el objetivo táctil y NO se baja para condensar: lo que
       se gana de alto se paga errándole al campo con el pulgar en la calle. Lo
       que condensa el formulario es poner dos por fila, no achicar. */
    min-height: 2.75rem;
}
textarea { min-height: 5rem; resize: vertical; }
input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--primario);
    outline-offset: -1px;
    border-color: var(--primario);
}
input[readonly], input:disabled, select:disabled, textarea[readonly], textarea:disabled {
    background: var(--superficie-2);
    color: var(--texto-suave);
}
input.monto, input.numero { font-variant-numeric: tabular-nums; text-align: right; }

/* --------------------------------------------------------------------------
   VARIOS CAMPOS POR FILA, TAMBIÉN EN EL CELULAR.

   El patrón ya existía y no se veía: el corte estaba en 34rem (544px), o sea que
   en el teléfono —que es donde se usa esto— TODOS los pares colapsaban a una
   columna y el formulario del cliente salía de once renglones. El corte real es
   22rem (352px): entra en cualquier teléfono de 360px para arriba, y el iPhone SE
   de 320px se queda en una columna, que ahí es lo correcto.

   `min-width: 0` en los hijos no es decorativo: por defecto un item de grid mide
   como mínimo su contenido, y un input[type=date] tiene ancho intrínseco propio.
   Sin esto la fila se pasa del ancho de la pantalla en vez de repartirse, y el
   síntoma es la página entera scrolleando de costado.
   -------------------------------------------------------------------------- */

.fila-campos { display: grid; gap: var(--e3); }
.fila-campos > * { min-width: 0; }
@media (min-width: 22rem) { .fila-campos.dos { grid-template-columns: 1fr 1fr; } }
/* Y LOS TRES DE «se cobra por / cuotas / interés» TAMBIÉN, que es la fila donde
   se define el préstamo. Estaba en 34rem (544px), o sea apilada en todo teléfono:
   79px de alto contra 262 — tres renglones para tres datos que se leen juntos.

   LAS COLUMNAS SON DESIGUALES Y ESO ESTÁ MEDIDO. El select tiene que mostrar
   «Quincenal» más la flecha que le dibuja el navegador: pide 117px y no se achica
   sin comerse el texto. Los dos números piden 51 y 54. Con tres columnas iguales,
   a 360px cada una queda en 90 y el select sale recortado; con 2fr el select se
   lleva 135 y a los números les sobra. De paso su columna coincide con la primera
   de las filas `dos`, así que el formulario alinea a lo largo.

   El corte es el mismo 22rem: a 320px el select tendría 107 y no entra, así que
   ahí se apila — que es lo correcto, es preferible el renglón de más a un campo
   que no se puede leer. `dev/_medir_fila_campos.php` mide los dos lados. */
@media (min-width: 22rem) { .fila-campos.tres { grid-template-columns: 2fr 1fr 1fr; } }

/* Cuando uno de los dos necesita más lugar que el otro: nombre + apodo,
   descripción + importe. Debajo del corte van uno abajo del otro igual. */
@media (min-width: 22rem) { .fila-campos.dos-desigual { grid-template-columns: 2fr 1fr; } }

.check { display: flex; align-items: flex-start; gap: var(--e2); margin-bottom: var(--e2); }
.check input { width: 1.15rem; height: 1.15rem; min-height: 0; margin-top: .18rem; flex: none; }
.check label { font-weight: 500; }

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

.btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--e2);
    min-height: 2.75rem;
    padding: var(--e2) var(--e4);
    font-size: .92rem; font-weight: 600; font-family: inherit;
    border: 1px solid transparent;
    border-radius: var(--radio-chico);
    background: var(--primario); color: var(--sobre-primario);
    cursor: pointer;
    text-decoration: none;
}
.btn:hover { background: var(--primario-hover); text-decoration: none; }
.btn:disabled, .btn[aria-disabled=true] { opacity: .5; cursor: not-allowed; }
.btn.secundario { background: var(--superficie); color: var(--texto); border-color: var(--borde-fuerte); }
.btn.secundario:hover { background: var(--superficie-2); }
/*
   EL CHIP DE FILTRO ELEGIDO. Sin esto los chips se ven todos iguales y no hay forma
   de saber qué se está mirando: se filtra por Vigentes, la lista se acorta, y eso se
   lee como que faltan préstamos.

   Va con fondo lleno y no sólo con el borde: en un teléfono, a la luz del día, un
   borde de un píxel de otro color no se distingue.
*/
.btn.secundario.activo {
    /* EL COLOR ES EL DE LA SECCIÓN. Con el azul fijo, los chips de las cuatro
       pantallas que los tienen se veían iguales y el filtro elegido no decía en
       cuál estabas parado. El respaldo deja igual a cualquier pantalla sin
       sección declarada. */
    background: var(--sec, var(--primario));
    color: var(--sobre-primario);
    border-color: var(--sec, var(--primario));
}
/* Aclarar en vez de nombrar un `--sec-hover` por sección: serían cinco tokens más
   para un estado que en un teléfono no existe. */
.btn.secundario.activo:hover { filter: brightness(1.12); }
.btn.peligro { background: var(--peligro); color: var(--sobre-primario); }
.btn.peligro:hover { background: var(--peligro-hover); }
.btn.bloque { width: 100%; }
.btn.chico { min-height: 2.15rem; padding: var(--e1) var(--e3); font-size: .82rem; }

/*
   UN GRUPO DE OPCIONES DONDE LA ELECCIÓN VIAJA SOLA. Son radios de verdad y no
   botones con JavaScript: el POST se la lleva sin una línea de script, el teclado
   las recorre y un lector de pantalla las anuncia. Lo que se ve es el <label>, que
   reusa el chip de `.btn.secundario` —el radio se esconde SIN sacarlo del foco: con
   `display:none` deja de existir para el teclado—.

   Envuelve en vez de recortarse: son hasta cuatro y en un teléfono a 390px no
   entran en un renglón. Un `.segmentos` las apretaría hasta que "30 días" no se lea.
*/
.opciones { display: flex; flex-wrap: wrap; gap: var(--e2); }
.opciones input[type=radio] { position: absolute; width: 1px; height: 1px; opacity: 0; }
.opciones input[type=radio]:checked + label {
    background: var(--sec, var(--primario));
    color: var(--sobre-primario);
    border-color: var(--sec, var(--primario));
}
.opciones input[type=radio]:focus-visible + label { outline: 2px solid var(--sec, var(--primario)); outline-offset: 2px; }

.acciones { display: flex; flex-wrap: wrap; gap: var(--e2); }
.acciones.fin { justify-content: flex-end; }

/* Control segmentado: elegir UNA de pocas opciones que se ven todas a la vez.
   Se usa para el tema. Un <select> escondería las otras dos y acá justamente lo
   que se quiere es poder tocar la de al lado y ver el cambio. */
.segmentos { display: flex; gap: 0; border: 1px solid var(--borde-fuerte); border-radius: var(--radio); overflow: hidden; }
.segmentos button {
    flex: 1;
    min-height: 2.75rem;
    padding: var(--e2) var(--e3);
    font-size: .88rem; font-weight: 600; font-family: inherit;
    background: var(--superficie); color: var(--texto-suave);
    border: 0;
    border-left: 1px solid var(--borde);
    cursor: pointer;
}
.segmentos button:first-child { border-left: 0; }
.segmentos button[aria-pressed="true"] { background: var(--primario); color: var(--sobre-primario); }

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

.etiqueta {
    display: inline-block;
    padding: 1px var(--e2);
    border-radius: 999px;
    font-size: .72rem; font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}
.etiqueta.exito   { background: var(--exito-suave);   color: var(--exito); }
.etiqueta.peligro { background: var(--peligro-suave); color: var(--peligro); }
.etiqueta.aviso   { background: var(--aviso-suave);   color: var(--aviso); }
.etiqueta.neutra  { background: var(--superficie-2);  color: var(--texto-suave); border: 1px solid var(--borde); }

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

.aviso {
    display: flex; gap: var(--e3);
    padding: var(--e3) var(--e4);
    border: 1px solid var(--borde);
    border-left-width: 3px;
    border-radius: var(--radio-chico);
    background: var(--superficie);
    margin-bottom: var(--e4);
    font-size: .9rem;
}
.aviso.exito   { border-left-color: var(--exito);   background: var(--exito-suave); }
.aviso.error   { border-left-color: var(--peligro); background: var(--peligro-suave); }
.aviso.aviso-  { border-left-color: var(--aviso);   background: var(--aviso-suave); }
.aviso.info    { border-left-color: var(--primario); background: var(--primario-suave); }

/* ==========================================================================
   Buscador
   ========================================================================== */

.buscador { position: relative; margin-bottom: var(--e3); }
.buscador input { padding-right: 2.5rem; }
.buscador .limpiar {
    position: absolute; right: var(--e2); top: 50%; transform: translateY(-50%);
    background: none; border: 0; color: var(--texto-tenue);
    font-size: 1.1rem; cursor: pointer; padding: var(--e1) var(--e2);
}

/* ==========================================================================
   Diálogos propios (nunca alert() ni confirm())
   ========================================================================== */

.dialogo-fondo {
    position: fixed; inset: 0; z-index: 200;
    background: var(--velo);
    display: flex; align-items: center; justify-content: center;
    padding: var(--e4);
}
.dialogo-fondo[hidden] { display: none !important; }
.dialogo {
    background: var(--superficie);
    border-radius: var(--radio);
    box-shadow: var(--sombra-flotante);
    width: 100%; max-width: 24rem;
    padding: var(--e5);
}
/* El diálogo que trae un FORMULARIO adentro y no una pregunta: el alta rápida de
   cliente. Más ancho porque los campos van de a dos por fila, y con scroll propio
   porque en un teléfono no entra —sin el max-height, el botón de guardar queda
   abajo del pliegue y no hay forma de llegar—. */
.dialogo.ancho {
    max-width: 34rem;
    max-height: calc(100vh - var(--e6));
    overflow-y: auto;
}
.dialogo h2 { margin-top: 0; }
.dialogo p { color: var(--texto-suave); }
.dialogo .acciones { margin-top: var(--e4); justify-content: flex-end; }

/* ==========================================================================
   Velo de "estoy cargando"
   ========================================================================== */

.cargando {
    position: fixed; inset: 0; z-index: 300;
    display: flex; align-items: center; justify-content: center;
    background: var(--velo-carga);
    backdrop-filter: blur(1.5px);
    visibility: hidden;
    pointer-events: none;
}
.cargando.visible { visibility: visible; pointer-events: auto; }
.cargando .rueda {
    width: 2.25rem; height: 2.25rem;
    border: 3px solid var(--borde-fuerte);
    border-top-color: var(--primario);
    border-radius: 50%;
    animation: girar .7s linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }
@media print { .cargando { display: none !important; } }

/* ==========================================================================
   Login
   ========================================================================== */

.pantalla-centrada {
    min-height: 100vh;
    display: flex; align-items: center; justify-content: center;
    padding: var(--e4);
}
.caja-login { width: 100%; max-width: 22rem; }
.caja-login .marca-grande {
    text-align: center; margin-bottom: var(--e5);
    font-size: 1.6rem; font-weight: 700; letter-spacing: .02em; color: var(--primario);
}
.caja-login .marca-grande span { display: block; font-size: .8rem; font-weight: 400; color: var(--texto-suave); letter-spacing: 0; }

/* Teclado numérico del PIN */
.teclado-pin { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e3); margin-top: var(--e4); }
.teclado-pin button {
    min-height: 3.5rem; font-size: 1.3rem; font-weight: 600; font-family: inherit;
    background: var(--superficie); color: var(--texto);
    border: 1px solid var(--borde-fuerte); border-radius: var(--radio);
    cursor: pointer;
}
.teclado-pin button:active { background: var(--primario-suave); }
.puntos-pin { display: flex; gap: var(--e3); justify-content: center; margin: var(--e4) 0; }
.puntos-pin i {
    width: .9rem; height: .9rem; border-radius: 50%;
    border: 2px solid var(--borde-fuerte); background: transparent;
}
.puntos-pin i.lleno { background: var(--primario); border-color: var(--primario); }

/* ==========================================================================
   Utilidades
   ========================================================================== */

.texto-suave  { color: var(--texto-suave); }
.texto-tenue  { color: var(--texto-tenue); }
.texto-chico  { font-size: .82rem; }
.texto-peligro { color: var(--peligro); }
.texto-exito  { color: var(--exito); }
.numeros      { font-variant-numeric: tabular-nums; }
.sin-margen   { margin: 0; }
.mt-3 { margin-top: var(--e3); }
.mt-4 { margin-top: var(--e4); }
.mb-0 { margin-bottom: 0; }
.mb-3 { margin-bottom: var(--e3); }
.mb-4 { margin-bottom: var(--e4); }
.flex-entre { display: flex; align-items: center; justify-content: space-between; gap: var(--e3); }
.flex-gap   { display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap; }
.text-upper { text-transform: uppercase; }

/* ==========================================================================
   El panel del operador.

   Barra oscura a proposito: tiene que ser obvio de un vistazo que NO es la
   aplicacion del cliente. Confundir las dos pantallas es como se suspende a la
   empresa equivocada.
   ========================================================================== */

.app-header.panel { background: var(--panel); }
.nav-pie.panel a.activo { color: var(--texto); border-color: var(--texto); background: var(--panel-activo); }

.marca-panel {
    text-align: center; margin-bottom: var(--e5);
    font-size: 1.5rem; font-weight: 700; color: var(--texto);
}
.marca-panel span {
    display: block; font-size: .78rem; font-weight: 400;
    color: var(--texto-suave); letter-spacing: .04em; text-transform: uppercase;
}

/* El codigo de 6 digitos: grande y espaciado, que es como se tipea sin errarle. */
.campo-codigo {
    font-size: 1.6rem !important;
    letter-spacing: .5em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* El secreto del segundo factor, para copiarlo a mano. */
.secreto {
    font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
    font-size: 1.05rem;
    letter-spacing: .08em;
    background: var(--superficie-2);
    border: 1px solid var(--borde);
    border-radius: var(--radio-chico);
    padding: var(--e3);
    word-break: break-all;
    -webkit-user-select: all; user-select: all;
}

/* Una grilla que NO scrollea sola: la pantalla la muestra entera y scrollea la
   pagina. Se usa donde el cuadro es el contenido principal —el cuadro de cuotas
   del simulador— y no una tabla de datos dentro de una pantalla mas grande.
   Conserva el overflow horizontal, que en un celular sigue haciendo falta. */
.tabla-contenedor.tabla-completa { max-height: none; }

/* Al reves: el cuadro de cuotas cuando NO es el contenido de la pantalla sino
   una tabla adentro de otra cosa —el dialogo que confirma el prestamo—. Ahi
   scrollea solo, porque con las 24 filas enteras los botones de confirmar y
   volver quedan abajo de todo y hay que scrollear el dialogo para llegar a
   ellos. Es la unica diferencia entre el cuadro del simulador y el de la
   confirmacion, y por eso el partial es el mismo. */
.tabla-contenedor.tabla-scroll { max-height: 40vh; overflow-y: auto; }
