/*
 * Sistema de diseno de Finanzas (ADR 0021).
 *
 * Ni un estilo en linea y todo color sale de un token: la CSP no lleva
 * 'unsafe-inline', asi que un `style=""` en una plantilla no se aplicaria, y un
 * color literal no sabria cambiar con el tema.
 *
 * Se carga DESPUES de bootstrap.min.css y no lo reemplaza: redefine sus
 * variables donde existen y agrega variables propias con prefijo `--fz-` donde
 * Bootstrap no tiene equivalente.
 *
 * Tres hechos de Bootstrap 5.3.3 que condicionan todo lo de abajo, verificados
 * leyendo el CSS compilado:
 *
 *   1. `.btn-primary` NO lee `--bs-primary`: trae `#0d6efd` compilado en
 *      `--bs-btn-bg`. Redefinir la variable global no repinta un solo boton. Se
 *      arregla re-fijando las variables `--bs-btn-*` de cada clase.
 *   2. `.form-control:focus` trae `#86b7fe` y `rgba(13,110,253,.25)` LITERALES,
 *      sin variable de por medio. Es el unico sitio donde no queda mas remedio
 *      que escribir una regla propia; sin ella el foco sigue siendo azul
 *      Bootstrap por muy propia que sea la paleta.
 *   3. `--bs-card-bg` vale `var(--bs-body-bg)`: de fabrica una tarjeta es del
 *      MISMO color que la pagina, y de ahi viene que hoy todo se vea plano y
 *      haga falta `shadow-sm` cuarenta veces. Separar las dos superficies es lo
 *      que hace que una tarjeta se lea como tarjeta sin sombra.
 */

/*
 * El atributo `hidden` pierde contra CUALQUIER utilidad de Bootstrap que fije
 * `display` -`.d-flex`, `.d-grid`, `.d-block`...-, porque esas llevan
 * `!important` y la regla nativa del navegador (`[hidden] { display: none }`)
 * no. El elemento queda con `hidden="true"` en el DOM y sigue viendose en
 * pantalla: un JavaScript que hace `el.hidden = true` sobre una fila
 * `.list-group-item.d-flex` -el filtro de busqueda de /recurring, por
 * ejemplo- no rompe con ningun error, simplemente no hace nada. Esta regla
 * devuelve a `hidden` la ultima palabra, sea cual sea la utilidad de layout
 * que lleve el elemento al lado.
 */
[hidden] {
    display: none !important;
}

/* ===========================================================================
   1. TOKENS
   ===========================================================================

   Se declaran en `[data-bs-theme=...]` y no en `:root` + media query a
   proposito: asi el atributo manda siempre y se pueden pintar los dos temas en
   la misma pagina, que es como se revisa que el oscuro no sea una inversion
   apresurada. La preferencia del sistema se aplica mas abajo, solo cuando el
   usuario todavia no ha elegido.
   =========================================================================== */

[data-bs-theme='light'] {
    /* El chip «Plataforma» sobre la pagina clara: ambar oscuro sobre crema,
       7.4:1 (ADR 0145). En el armazon grafito va siempre el oscuro. */
    --fz-platform-chip-text: #7A4A00;
    --fz-platform-chip-bg: #FDF0D5;
    --fz-platform-chip-border: #EBC77A;

    /* --- Superficies. Tres niveles y no dos: pagina, tarjeta y hundido. El
       fondo de pagina no es blanco puro para que la tarjeta blanca flote sin
       sombra; el blanco puro se reserva para la superficie que lleva el dato. */
    --fz-surface-sunken: #ECEEF2;
    --fz-surface: #FFFFFF;
    --fz-surface-raised: #FFFFFF;

    --bs-body-bg: #F6F7F9;
    --bs-body-bg-rgb: 246, 247, 249;
    --bs-secondary-bg: #ECEEF2;
    --bs-tertiary-bg: #F1F3F6;

    /* --- Texto. El principal es un casi-negro con una gota de azul: el negro
       puro sobre blanco vibra y cansa en pantallas con mucho texto numerico. */
    --bs-body-color: #151922;
    --bs-body-color-rgb: 21, 25, 34;
    --bs-emphasis-color: #0B0E14;
    --bs-secondary-color: #565E6D;
    --bs-tertiary-color: #6B7382;
    --bs-heading-color: #151922;

    /* --- Bordes. Casi invisibles a proposito (1.36:1): delimitan sin dibujar
       una rejilla, que es lo que hace que un panel financiero parezca una hoja
       de calculo. */
    --bs-border-color: #D9DDE4;
    --bs-border-color-translucent: rgba(21, 25, 34, 0.11);

    /* --- Marca. Indigo y no el azul de Bootstrap por dos razones: el azul
       #0d6efd es la firma visual de "plantilla sin tocar", y el verde y el rojo
       estan ocupados por el signo del dinero, asi que la marca no puede ser
       ninguno de los dos sin volverse ambigua. */
    --fz-brand: #2B3FB8;
    --fz-brand-rgb: 43, 63, 184;
    --fz-brand-hover: #22339A;
    --fz-brand-active: #1C2B84;
    --fz-brand-fill: #2B3FB8;
    /* El otro extremo del degradado del boton de guardar de la captura (ADR
       0068). Blanco encima: 6.41:1, y 8.38:1 en el extremo de partida. */
    --fz-brand-fill-end: #3A50D4;
    --fz-brand-on-fill: #FFFFFF;
    /* Pasar el raton y pulsar el boton principal (ADR 0080). Son RELLENOS con
       texto blanco encima: 10.46:1 y 12.13:1. El boton tomaba antes
       `--fz-brand-hover`, que es el color de un ENLACE al pasar el raton: en
       claro coincide, en oscuro no (ver alli). */
    --fz-brand-fill-hover: #22339A;
    --fz-brand-fill-active: #1C2B84;

    --bs-primary: #2B3FB8;
    --bs-primary-rgb: 43, 63, 184;
    --bs-primary-text-emphasis: #1C2B84;
    --bs-primary-bg-subtle: #E8EAF9;
    --bs-primary-border-subtle: #B9C0EC;
    --bs-link-color: #2B3FB8;
    --bs-link-color-rgb: 43, 63, 184;
    --bs-link-hover-color: #1C2B84;

    /* --- Dinero. Entrada y salida son los unicos colores con objetivo AAA:
       son el dato con mas peso de la pantalla y el que mas se lee de reojo.

       La salida es TERRACOTA y no roja (ADR 0021 §4). Antes este token y
       `--fz-state-over-text` valian los dos #9F211A: gastar y excederse se
       veian exactamente igual, y son cosas distintas. Un gasto es lo normal;
       el rojo queda reservado para lo que hay que corregir -"Excedido",
       "Atrasada"-, que es donde el rojo significa algo.

       Medido, no estimado: 7.11:1 sobre el fondo de pagina y 7.62:1 sobre la
       tarjeta. AAA en los dos, que es el requisito de los importes. */
    --fz-money-in: #0B6138;
    --fz-money-out: #8A3D12;

    /* --- Estados. El texto y el relleno de un mismo estado son colores
       DISTINTOS: el relleno cubre superficie grande y como texto no llegaria a
       4.5:1; el texto es oscuro y como relleno de barra se veria como un
       borron. */
    --fz-state-ok-text: #0B6138;
    --fz-state-warn-text: #7A4A00;
    --fz-state-over-text: #9F211A;
    --fz-state-ok-fill: #12805A;
    --fz-state-warn-fill: #B87A08;
    --fz-state-over-fill: #C93B32;
    /* La punta del degradado de las barras (ADR 0080). En claro OSCURECE y en
       oscuro aclara: en los dos temas la punta gana contraste, asi que el peor
       caso de la barra sigue siendo el de partida, que ya estaba medido. */
    --fz-state-ok-fill-end: #0D6A4A;
    --fz-state-warn-fill-end: #9A6206;
    --fz-state-over-fill-end: #A93028;
    --fz-track: #E4E7EC;

    --bs-success: #12805A;
    --bs-success-rgb: 18, 128, 90;
    --bs-success-text-emphasis: #0B6138;
    --bs-success-bg-subtle: #E3F3EC;
    --bs-success-border-subtle: #A9D9C4;
    --bs-danger: #C93B32;
    --bs-danger-rgb: 201, 59, 50;
    --bs-danger-text-emphasis: #9F211A;
    --bs-danger-bg-subtle: #FBE9E7;
    --bs-danger-border-subtle: #EFB4AF;
    --bs-warning: #B87A08;
    --bs-warning-rgb: 184, 122, 8;
    --bs-warning-text-emphasis: #7A4A00;
    --bs-warning-bg-subtle: #FBF0DC;
    --bs-warning-border-subtle: #E7C98B;

    /* --- Elevacion. En claro la profundidad es sombra, porque hay luz que
       proyectar. Deliberadamente corta: dos niveles, no cinco. */
    --fz-elev-1: 0 1px 2px rgba(21, 25, 34, 0.06), 0 1px 3px rgba(21, 25, 34, 0.04);
    --fz-elev-2: 0 2px 4px rgba(21, 25, 34, 0.07), 0 8px 24px rgba(21, 25, 34, 0.07);
    /* El brillo en la esquina de la pagina (ADR 0080). Solo en oscuro, donde le
       quita al fondo su aspecto de plano negro; en claro no hay nada que
       iluminar y vale transparente. */
    --fz-page-glow: rgba(43, 63, 184, 0);
    /* El velo detras de una hoja inferior en movil (ADR 0044): oscurece lo de
       atras lo justo para que la hoja se lea como lo que esta delante. */
    --fz-scrim: rgba(11, 14, 20, 0.5);
    --fz-skeleton-base: #ECEEF2;
    --fz-skeleton-sheen: #F7F8FA;

    /* --- Categorias. Doce tonos, todos >= 4.5:1 sobre la superficie del tema,
       asi que valen como relleno de grafica Y como texto de leyenda. */
    --fz-cat-1: #1F6B36;
    --fz-cat-2: #0F6B62;
    --fz-cat-3: #0A6C86;
    --fz-cat-4: #1F5BAF;
    --fz-cat-5: #4B3FB5;
    --fz-cat-6: #7A2F9E;
    --fz-cat-7: #A62463;
    --fz-cat-8: #AF2A2A;
    --fz-cat-9: #8F4B10;
    --fz-cat-10: #7A5B00;
    --fz-cat-11: #4A5B68;
    --fz-cat-12: #5C4238;

    /* --- Superficies de categoria. Son el MISMO color que `--fz-cat-N`, pero
       para el trabajo contrario: ahi el color se pinta SOBRE la superficie del
       tema; aqui el color ES la superficie y encima va texto.
       `--fz-cat-N` no sirve para esto y no es cuestion de gusto: en oscuro es un
       tono claro -tiene que serlo para verse sobre un fondo oscuro-, y de fondo
       dejaria texto blanco sobre verde menta.
       Por eso son iguales en los dos temas: una tarjeta con color de fondo es
       oscura siempre, y quien la separa de la pagina es su propio color, no la
       superficie de debajo. Los doce pasan de 7:1 con blanco -lo que este
       proyecto le pide a un importe- y lo comprueba una prueba sobre este mismo
       archivo, no un comentario. */
    --fz-cat-surface-1: #1D6533;
    --fz-cat-surface-2: #0E625A;
    --fz-cat-surface-3: #096077;
    --fz-cat-surface-4: #1D56A6;
    --fz-cat-surface-5: #4B3FB5;
    --fz-cat-surface-6: #7A2F9E;
    --fz-cat-surface-7: #A32361;
    --fz-cat-surface-8: #A62828;
    --fz-cat-surface-9: #88470F;
    --fz-cat-surface-10: #705400;
    --fz-cat-surface-11: #495A67;
    --fz-cat-surface-12: #5C4238;

    /* La tarjeta del patrimonio (ADR 0079): pizarra azulada de `from` a `to` con
       un brillo verde (`glow`) en la esquina de abajo. Los tres son oscuros: el
       blanco pasa de 7:1 sobre cada uno, y lo mide una prueba sobre este
       archivo. Encima, la linea de los ultimos dias, el verde de lo que sube
       -flecha, insignia y barra de activos- y el ambar de lo que baja. */
    --fz-networth-from: #3A4B68;
    --fz-networth-to: #222D3B;
    --fz-networth-glow: #2B4A43;
    --fz-networth-line: #8CB8FF;
    --fz-networth-accent: #7BE495;
    --fz-networth-down: #FFC97A;

    /* Lo que va ENCIMA de una superficie de esas. Blanco puro para el dato, y
       una version rebajada para el rotulo: 4.88:1 en el peor de los doce, que
       sigue por encima del minimo de texto normal. */
    --fz-on-accent: #FFFFFF;
    --fz-on-accent-muted: rgba(255, 255, 255, 0.78);

    /* La barra del limite sobre una tarjeta de color (ADR 0080): de un tono
       claro a otro mas intenso, segun el estado. Iguales en los dos temas por
       la misma razon que las superficies -la tarjeta es oscura siempre- y por
       encima de 3:1 contra la pista hundida de las doce; lo mide una prueba. */
    --fz-on-color-bar-on: #C7D2FE;
    --fz-on-color-bar-on-end: #FFFFFF;
    --fz-on-color-bar-warn: #FDE68A;
    --fz-on-color-bar-warn-end: #FBBF24;
    --fz-on-color-bar-over: #FECACA;
    --fz-on-color-bar-over-end: #F87171;
    /* La meta alcanzada dentro de una cuenta de color (ADR 0110): el verde
       que en el resto de la app dice «logrado», en claro. */
    --fz-on-color-bar-ok: #BBF7D0;
    --fz-on-color-bar-ok-end: #4ADE80;

    /* --- El riel (ADR 0030). Iguales en los dos temas por la misma razon que
       `--fz-cat-surface-*`: aqui el color ES la superficie y encima va texto,
       asi que no puede cambiar con el tema. El riel es oscuro siempre. El
       porque de cada tono, y sus contrastes medidos, en la seccion 19. */
    --fz-rail-bg: #141B34;
    --fz-rail-border: rgba(255, 255, 255, 0.09);
    --fz-rail-text: #C7CEE0;
    --fz-rail-text-strong: #FFFFFF;
    --fz-rail-group: #8792AD;
    --fz-rail-hover-bg: rgba(255, 255, 255, 0.07);
    --fz-rail-icon: #7488EE;
    --fz-rail-icon-glow: rgba(64, 92, 255, 0.75);
    --fz-rail-current-bg: #262E55;
    --fz-rail-current-glow: #4055C2;
    --fz-rail-current-text: #FFFFFF;
    --fz-rail-current-mark: #6178DC;
    --fz-rail-mark: #9DABFF;

    /* --- La cabecera de un alta en tarjetas (ADR 0096). Iguales en los dos temas
       por lo mismo que el riel: es una superficie azul marino con texto encima.
       `CabeceraDelAltaTest` mide el blanco del titulo, el gris azulado de la
       entrada y la palabra resaltada sobre los tres tonos del fondo. */
    --fz-form-hero-from: #0D1940;
    --fz-form-hero-mid: #12245A;
    --fz-form-hero-to: #1A3478;
    --fz-form-hero-text: #FFFFFF;
    --fz-form-hero-muted: #C9D6F7;
    --fz-form-hero-accent: #8FB4FF;
    --fz-form-hero-accent-end: #B7CBFF;
    --fz-form-hero-icon: #2F4FE0;
    --fz-form-hero-icon-end: #5B86FF;
    --fz-form-hero-glow: rgba(84, 124, 255, 0.38);
    --fz-form-hero-border: rgba(125, 155, 255, 0.3);

    /* El final violeta del boton que guarda un alta en tarjetas (ADR 0096): el
       degradado va de `--fz-brand-fill` a este. Blanco encima: 6.2:1. */
    --fz-cta-end: #6E3FD8;

    /* --- Los mosaicos del resumen del reporte (ADR 0047): fondo tintado y borde
       del mismo tono. La cifra va en el texto de su familia -dinero que entra,
       que sale, progreso neutral, frontera cruzada-. Medido sobre su tinte: la
       cifra da de 6.6:1 a 9.8:1 y la nota #3F4654 no baja de 6.5:1. */
    --fz-kpi-in-bg: #E8F4EC;
    --fz-kpi-in-border: #5BA57E;
    --fz-kpi-in-text: #0B6138;
    --fz-kpi-out-bg: #FBEEE6;
    --fz-kpi-out-border: #C27A4E;
    --fz-kpi-out-text: #8A3D12;
    --fz-kpi-rate-bg: #ECEEFB;
    --fz-kpi-rate-border: #6E7BDB;
    --fz-kpi-rate-text: #1C2B84;
    --fz-kpi-over-bg: #FCEBEA;
    --fz-kpi-over-border: #D9736C;
    --fz-kpi-over-text: #9F211A;
    --fz-kpi-note: #3F4654;

    /* El mas y el menos de «Total activos» y «Total deudas» (ADR 0079). Son
       muestras, no texto: piden 3:1 contra la tarjeta, y dan 3.3:1 el verde y
       3.1:1 el gris sobre blanco. */
    --fz-worth-plus-bg: #2E9E6F;
    --fz-worth-plus-fg: #FFFFFF;
    --fz-worth-minus-bg: #8A93A3;
    --fz-worth-minus-fg: #FFFFFF;
}

[data-bs-theme='dark'] {
    /* El chip «Plataforma» sobre la pagina oscura: ambar sobre su velo. */
    --fz-platform-chip-text: #F2B84B;
    --fz-platform-chip-bg: rgba(242, 184, 75, 0.12);
    --fz-platform-chip-border: rgba(242, 184, 75, 0.38);

    /* El fondo no es negro puro: en OLED el negro absoluto arrastra al hacer
       scroll y, sobre todo, deja sin sitio a la superficie hundida -no hay nada
       mas oscuro que el negro-, que es justo lo que ordena la jerarquia. */
    --fz-surface-sunken: #0A0D11;
    --fz-surface: #161A21;
    --fz-surface-raised: #1F242D;

    --bs-body-bg: #0E1116;
    --bs-body-bg-rgb: 14, 17, 22;
    --bs-secondary-bg: #1F242D;
    --bs-tertiary-bg: #232935;

    /* Ni el texto es blanco puro: a 15.8:1 ya sobra contraste, y el blanco puro
       sobre fondo oscuro produce el halo que hace ilegible una tabla de cifras. */
    --bs-body-color: #E8EBF0;
    --bs-body-color-rgb: 232, 235, 240;
    --bs-emphasis-color: #F7F9FC;
    --bs-secondary-color: #9BA4B4;
    --bs-tertiary-color: #8A93A3;
    --bs-heading-color: #E8EBF0;

    --bs-border-color: #2C323C;
    --bs-border-color-translucent: rgba(232, 235, 240, 0.12);

    /* La marca sube de luminosidad en vez de invertirse: es el MISMO indigo
       aclarado, para que la identidad no cambie de tema a tema. El relleno del
       boton es un tono medio porque el indigo claro con texto negro encima se
       leeria como un aviso, no como la accion principal. */
    --fz-brand: #9DABFF;
    --fz-brand-rgb: 157, 171, 255;
    --fz-brand-hover: #B4BEFF;
    --fz-brand-active: #C6CDFF;
    --fz-brand-fill: #4E5FD6;
    /* Blanco encima: 4.72:1, y 5.34:1 en el extremo de partida (ADR 0068). */
    --fz-brand-fill-end: #5566E8;
    --fz-brand-on-fill: #FFFFFF;
    /* Aqui SI difieren del enlace: `--fz-brand-hover` es un lavanda para texto
       sobre fondo oscuro, y como fondo del boton dejaba el rotulo blanco a
       1.79:1 al pasar el raton. El relleno baja de tono en vez de subir:
       6.53:1 y 7.69:1 con blanco (ADR 0080). */
    --fz-brand-fill-hover: #4352C2;
    --fz-brand-fill-active: #3A48B0;

    --bs-primary: #9DABFF;
    --bs-primary-rgb: 157, 171, 255;
    --bs-primary-text-emphasis: #C6CDFF;
    --bs-primary-bg-subtle: #1B2140;
    --bs-primary-border-subtle: #303C73;
    --bs-link-color: #9DABFF;
    --bs-link-color-rgb: 157, 171, 255;
    --bs-link-hover-color: #B4BEFF;

    /* El par oscuro del terracota: 9.40:1 sobre la pagina, 8.67:1 sobre la
       tarjeta. Sigue siendo AAA y sigue sin confundirse con el rojo de
       "excedido", que en este tema es #FF9E96. */
    --fz-money-in: #5FD69C;
    --fz-money-out: #EDA870;

    --fz-state-ok-text: #5FD69C;
    --fz-state-warn-text: #F3C169;
    --fz-state-over-text: #FF9E96;
    --fz-state-ok-fill: #2E9E6F;
    --fz-state-warn-fill: #D99A2B;
    --fz-state-over-fill: #E05A50;
    --fz-state-ok-fill-end: #47BC8A;
    --fz-state-warn-fill-end: #F2B84B;
    --fz-state-over-fill-end: #F07B72;
    --fz-track: #242A33;

    --bs-success: #2E9E6F;
    --bs-success-rgb: 46, 158, 111;
    --bs-success-text-emphasis: #5FD69C;
    --bs-success-bg-subtle: #10241B;
    --bs-success-border-subtle: #1E5740;
    --bs-danger: #E05A50;
    --bs-danger-rgb: 224, 90, 80;
    --bs-danger-text-emphasis: #FF9E96;
    --bs-danger-bg-subtle: #2A1413;
    --bs-danger-border-subtle: #6B2C27;
    --bs-warning: #D99A2B;
    --bs-warning-rgb: 217, 154, 43;
    --bs-warning-text-emphasis: #F3C169;
    --bs-warning-bg-subtle: #26190A;
    --bs-warning-border-subtle: #5E441A;

    /* En oscuro la sombra no se ve: la profundidad la da que la superficie sea
       MAS CLARA que el fondo. Se conserva una sombra minima solo para separar
       lo que flota de verdad.

       Medido en pantalla, ese hairline aporta 1.081:1 sobre el fondo de pagina
       (ΔL* ≈ 1): en la practica es invisible. Quien dibuja el limite de una
       tarjeta en oscuro es su BORDE -1.467:1, ΔL* 15.6- con el relleno de la
       superficie ayudando (ΔL* 4.2). Conviene saberlo antes de tocar nada:
       quitarle el borde a `.card` en oscuro no la dejaria "con menos marco", la
       dejaria sin ninguno, porque aqui no hay sombra que la respalde. Hay una
       prueba que lo sujeta. */
    --fz-elev-1: 0 0 0 1px rgba(232, 235, 240, 0.04);
    --fz-elev-2: 0 8px 24px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(232, 235, 240, 0.06);
    /* Indigo de la marca a poca opacidad, arriba a la derecha. Detras de texto
       solo aclara el fondo un par de puntos: el gris secundario sigue por
       encima de 7:1 donde el brillo es mas fuerte. */
    --fz-page-glow: rgba(78, 95, 214, 0.16);
    /* Mas denso que en claro: sobre un fondo ya oscuro, medio velo no separa. */
    --fz-scrim: rgba(0, 0, 0, 0.65);
    --fz-skeleton-base: #1F242D;
    --fz-skeleton-sheen: #2A313C;

    /* No son los mismos doce colores aclarados a ojo: son los pares claros de
       cada familia. La paleta actual (Material 800) da 1.70:1 en el violeta
       sobre tarjeta oscura, muy por debajo del 3:1 minimo de un relleno. */
    --fz-cat-1: #69CE8C;
    --fz-cat-2: #4FCFC0;
    --fz-cat-3: #5CC6E8;
    --fz-cat-4: #84B2FF;
    --fz-cat-5: #A8A2FF;
    --fz-cat-6: #D49AF0;
    --fz-cat-7: #F894BE;
    --fz-cat-8: #FF9B95;
    --fz-cat-9: #EBA96A;
    --fz-cat-10: #D3BC55;
    --fz-cat-11: #A9BAC8;
    --fz-cat-12: #C0A294;

    /* --- Superficies de categoria. Son el MISMO color que `--fz-cat-N`, pero
       para el trabajo contrario: ahi el color se pinta SOBRE la superficie del
       tema; aqui el color ES la superficie y encima va texto.
       `--fz-cat-N` no sirve para esto y no es cuestion de gusto: en oscuro es un
       tono claro -tiene que serlo para verse sobre un fondo oscuro-, y de fondo
       dejaria texto blanco sobre verde menta.
       Por eso son iguales en los dos temas: una tarjeta con color de fondo es
       oscura siempre, y quien la separa de la pagina es su propio color, no la
       superficie de debajo. Los doce pasan de 7:1 con blanco -lo que este
       proyecto le pide a un importe- y lo comprueba una prueba sobre este mismo
       archivo, no un comentario. */
    --fz-cat-surface-1: #1D6533;
    --fz-cat-surface-2: #0E625A;
    --fz-cat-surface-3: #096077;
    --fz-cat-surface-4: #1D56A6;
    --fz-cat-surface-5: #4B3FB5;
    --fz-cat-surface-6: #7A2F9E;
    --fz-cat-surface-7: #A32361;
    --fz-cat-surface-8: #A62828;
    --fz-cat-surface-9: #88470F;
    --fz-cat-surface-10: #705400;
    --fz-cat-surface-11: #495A67;
    --fz-cat-surface-12: #5C4238;

    /* La tarjeta del patrimonio (ADR 0079): pizarra azulada de `from` a `to` con
       un brillo verde (`glow`) en la esquina de abajo. Los tres son oscuros: el
       blanco pasa de 7:1 sobre cada uno, y lo mide una prueba sobre este
       archivo. Encima, la linea de los ultimos dias, el verde de lo que sube
       -flecha, insignia y barra de activos- y el ambar de lo que baja. */
    --fz-networth-from: #3A4B68;
    --fz-networth-to: #222D3B;
    --fz-networth-glow: #2B4A43;
    --fz-networth-line: #8CB8FF;
    --fz-networth-accent: #7BE495;
    --fz-networth-down: #FFC97A;

    /* Lo que va ENCIMA de una superficie de esas. Blanco puro para el dato, y
       una version rebajada para el rotulo: 4.88:1 en el peor de los doce, que
       sigue por encima del minimo de texto normal. */
    --fz-on-accent: #FFFFFF;
    --fz-on-accent-muted: rgba(255, 255, 255, 0.78);

    /* La barra del limite sobre una tarjeta de color: los mismos que en claro. */
    --fz-on-color-bar-on: #C7D2FE;
    --fz-on-color-bar-on-end: #FFFFFF;
    --fz-on-color-bar-warn: #FDE68A;
    --fz-on-color-bar-warn-end: #FBBF24;
    --fz-on-color-bar-over: #FECACA;
    --fz-on-color-bar-over-end: #F87171;
    /* La meta alcanzada dentro de una cuenta de color (ADR 0110): el verde
       que en el resto de la app dice «logrado», en claro. */
    --fz-on-color-bar-ok: #BBF7D0;
    --fz-on-color-bar-ok-end: #4ADE80;

    /* --- El riel (ADR 0030). Iguales en los dos temas por la misma razon que
       `--fz-cat-surface-*`: aqui el color ES la superficie y encima va texto,
       asi que no puede cambiar con el tema. El riel es oscuro siempre. El
       porque de cada tono, y sus contrastes medidos, en la seccion 19. */
    --fz-rail-bg: #141B34;
    --fz-rail-border: rgba(255, 255, 255, 0.09);
    --fz-rail-text: #C7CEE0;
    --fz-rail-text-strong: #FFFFFF;
    --fz-rail-group: #8792AD;
    --fz-rail-hover-bg: rgba(255, 255, 255, 0.07);
    --fz-rail-icon: #7488EE;
    --fz-rail-icon-glow: rgba(64, 92, 255, 0.75);
    --fz-rail-current-bg: #262E55;
    --fz-rail-current-glow: #4055C2;
    --fz-rail-current-text: #FFFFFF;
    --fz-rail-current-mark: #6178DC;
    --fz-rail-mark: #9DABFF;

    /* --- La cabecera de un alta en tarjetas (ADR 0096). Iguales en los dos temas
       por lo mismo que el riel: es una superficie azul marino con texto encima.
       `CabeceraDelAltaTest` mide el blanco del titulo, el gris azulado de la
       entrada y la palabra resaltada sobre los tres tonos del fondo. */
    --fz-form-hero-from: #0D1940;
    --fz-form-hero-mid: #12245A;
    --fz-form-hero-to: #1A3478;
    --fz-form-hero-text: #FFFFFF;
    --fz-form-hero-muted: #C9D6F7;
    --fz-form-hero-accent: #8FB4FF;
    --fz-form-hero-accent-end: #B7CBFF;
    --fz-form-hero-icon: #2F4FE0;
    --fz-form-hero-icon-end: #5B86FF;
    --fz-form-hero-glow: rgba(84, 124, 255, 0.38);
    --fz-form-hero-border: rgba(125, 155, 255, 0.3);

    /* El final violeta del boton de alta (ADR 0096). Blanco encima: 5.1:1. */
    --fz-cta-end: #7B4FE6;

    /* --- Los mosaicos del reporte en oscuro: el tinte baja a un fondo casi
       negro de su familia y la cifra sube al texto claro de esa familia, el mismo
       que ya usan `--fz-money-*` y `--fz-state-*-text` en este tema. */
    --fz-kpi-in-bg: #10261B;
    --fz-kpi-in-border: #2E9E6F;
    --fz-kpi-in-text: #5FD69C;
    --fz-kpi-out-bg: #2A1A10;
    --fz-kpi-out-border: #B87342;
    --fz-kpi-out-text: #EDA870;
    --fz-kpi-rate-bg: #171C3A;
    --fz-kpi-rate-border: #6E7BDB;
    --fz-kpi-rate-text: #B4BEFF;
    --fz-kpi-over-bg: #2E1413;
    --fz-kpi-over-border: #E05A50;
    --fz-kpi-over-text: #FF9E96;
    --fz-kpi-note: #C4CAD6;

    /* En oscuro la muestra se aclara y su signo se oscurece, como en la referencia. */
    --fz-worth-plus-bg: #6CC07A;
    --fz-worth-plus-fg: #0E1116;
    --fz-worth-minus-bg: #C4C9D2;
    --fz-worth-minus-fg: #0E1116;
}

/*
 * La preferencia del sistema, solo mientras el usuario no haya elegido.
 *
 * `:root:not([data-bs-theme])` no se cumple nunca en produccion porque el
 * servidor siempre estampa el atributo; existe para que esta hoja sea correcta
 * por si sola y para el primer render antes de que haya preferencia guardada.
 * Ojo: esto tinta los tokens propios, pero las variables que Bootstrap declara
 * bajo `[data-bs-theme=dark]` NO se activan solas. Por eso el atributo en
 * `<html>` es obligatorio y no un adorno.
 */
@media (prefers-color-scheme: dark) {
    :root:not([data-bs-theme]) {
        color-scheme: dark;
    }
}

/* ===========================================================================
   2. TIPOGRAFIA
   ===========================================================================

   El problema que describe el diagnostico no es la pila: es que hoy conviven
   DOS familias -`font-monospace` para importes y `system-ui` para texto- que no
   comparten ni eje vertical ni ancho de trazo. Eso se arregla con una sola
   familia y `font-variant-numeric: tabular-nums`, que da la unica propiedad por
   la que se usaba la monoespaciada: que la columna de cifras cuadre. Esa parte
   ya esta hecha aqui abajo, y es la que resuelve el problema real.

   PENDIENTE: IBM Plex Sans (ADR 0021 §3, aprobada). Todavia se usa la pila del
   sistema porque los WOFF2 no estan en el repositorio: la fuente hay que
   descargarla, subsetarla a latino y MEDIR el archivo generado -no citar un
   tamano de memoria-. Cuando esten en `public/assets/vendor/fonts/`, esto es lo
   que falta y no hay mas:

     1. Un bloque `@font-face` por peso (400, 600, 700) con `font-display: swap`.
     2. Cambiar la primera entrada de `--bs-body-font-family` por 'IBM Plex Sans'.

   La pila del sistema se queda de reserva en la lista, que es donde tiene que
   estar de todos modos: si la WOFF2 no carga, el texto sigue apareciendo.

   Segoe UI, SF Pro y Roboto -las tres que resuelve `system-ui` en los sistemas
   del mercado inicial- soportan `tnum`. Verificar en el navegador de destino
   antes de dar por buena la alineacion.
   =========================================================================== */

[data-bs-theme] {
    --bs-body-font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --bs-body-font-size: 1rem;
    --bs-body-line-height: 1.5;

    /* Escala de importes: cuatro tallas y ni una mas. Cada una tiene un sitio
       donde vive, para que "grande" deje de ser una decision por pantalla. */
    --fz-amount-hero: 2rem;      /* el importe que se teclea al capturar */
    --fz-amount-lg: 1.5rem;      /* saldo de una cuenta, total del mes */
    --fz-amount-md: 1.0625rem;   /* cifra de fila de lista o de tabla */
    --fz-amount-sm: 0.8125rem;   /* cifra dentro de una grafica */

    --fz-weight-amount: 600;
    --fz-weight-heading: 600;

    /* Espaciado en pasos de 4px. Un solo ritmo para margenes y rellenos. */
    --fz-space-1: 0.25rem;
    --fz-space-2: 0.5rem;
    --fz-space-3: 0.75rem;
    --fz-space-4: 1rem;
    --fz-space-5: 1.5rem;
    --fz-space-6: 2rem;
    --fz-space-7: 3rem;

    /* Radios. 0.5rem lee como software actual sin caer en la burbuja de
       juguete que dan los 16px de moda; el grande se reserva a la tarjeta de
       captura, que es la superficie protagonista. */
    --bs-border-radius: 0.5rem;
    --bs-border-radius-sm: 0.375rem;
    --bs-border-radius-lg: 0.875rem;
    --bs-border-radius-xl: 1.25rem;

    /* Densidad: UNA altura de control. 2.75rem son los 44px de objetivo tactil,
       asi que `form-control-sm` queda descartado en cualquier pantalla, no solo
       en movil. La unica excepcion es el importe de captura, que es mas grande
       porque es el protagonista. */
    --fz-control-height: 2.75rem;

    /*
     * El alto de la barra inferior de movil. DECLARADO: la barra se construye
     * desde aqui (`.fz-tabbar`, grid-template-rows), no al reves.
     *
     * Lo usan tres sitios que tienen que decir lo mismo: la propia barra, el
     * hueco que el body le reserva y el `bottom` de la barra de pago de /loans.
     *
     * Historia, porque explica por que es asi. Primero cada sitio llevaba su
     * estimacion -3.5rem "porque la barra mide ~53px"- y la barra media 62.89:
     * medido el 2026-09-15, la barra de pago quedaba 5.89 px por debajo de la de
     * pestañas. Luego fue un numero MEDIDO copiado aqui, que seguia dependiendo
     * del contenido: el alto lo fijaba la pestaña mas alta, "Capturar", con su
     * disco de 40 px, y cualquier cambio de rotulo lo podia mover sin avisar.
     *
     * Ahora la dependencia va al reves: la fila de la barra mide este valor
     * menos su borde, y lo que haya dentro se alinea abajo en ella. El valor
     * sigue siendo el que cabe lo que hay -el disco de Capturar con su rotulo,
     * 61.9 px, en una fila de 62-, pero ya no se deduce del contenido: se
     * decide aqui. Se descarto sacar el disco del flujo: no cabe en una pestaña
     * normal con su rotulo, y habria obligado a que sobresaliera de la barra o
     * a encogerlo, un cambio visible en todas las pantallas.
     *
     *   2.5rem + 0.15rem + 0.71875rem + 0.5rem   disco, hueco, rotulo, relleno
     * + 1px                                     borde superior de la barra
     * = 3.9375rem (63 px), redondeado hacia arriba.
     */
    --fz-tabbar-h: 3.9375rem;

    --fz-focus-width: 0.1875rem;

    /* Calendario de /recurring: el numero de un dia pintado con el color
       solido de su leyenda va en blanco en los dos temas, por decision del
       usuario. Por eso el dia que vence pronto es un amarillo oscuro y no el
       primary del tema: 4.92:1 con el blanco, y 3.54:1 como relleno sobre la
       tarjeta oscura. Los otros dos siguen en danger y success del tema: en
       claro 5.05:1 y 4.93:1 con el blanco; en oscuro, 3.65:1 y 3.37:1. */
    --fz-cal-on-fill: #FFFFFF;
    --fz-cal-upcoming: #A16207;

    /* La consola del operador (ADR 0145): grafito y ambar en los DOS temas,
       para que se reconozca el lado sin leer. Texto sobre el grafito medido:
       #C7CEDB 12:1, #8F99AB 6.3:1, el ambar 10:1. */
    --fz-platform-bg: #10141B;
    --fz-platform-border: rgba(255, 255, 255, 0.09);
    --fz-platform-text: #C7CEDB;
    --fz-platform-text-strong: #FFFFFF;
    --fz-platform-muted: #8F99AB;
    --fz-platform-hover: rgba(255, 255, 255, 0.07);
    --fz-platform-accent: #F2B84B;
    --fz-platform-accent-strong: #FFE2A6;
    --fz-platform-accent-soft: rgba(242, 184, 75, 0.13);
    --fz-platform-accent-line: rgba(242, 184, 75, 0.4);
}

/*
 * Toda cifra lleva `tabular-nums`, y ademas `slashed-zero` donde hay riesgo de
 * confundir 0 con O en un identificador de cuenta.
 *
 * `.text-nums` es la clase base; las de importe le suman talla y peso. Un
 * importe SIEMPRE va con su signo, asi que la clase no pinta color: el color lo
 * pone `.movement-in` / `.movement-out`, y el signo lo pone el servidor.
 */
.text-nums,
.capture-input,
.fz-amount-hero,
.fz-amount-lg,
.fz-amount-md,
.fz-amount-sm,
.fz-table-financial td,
.fz-table-financial th {
    font-variant-numeric: tabular-nums;
}

.fz-amount-hero {
    font-size: var(--fz-amount-hero);
    font-weight: var(--fz-weight-amount);
    line-height: 1.1;
    letter-spacing: -0.01em;
}

.fz-amount-lg {
    font-size: var(--fz-amount-lg);
    font-weight: var(--fz-weight-amount);
    line-height: 1.2;
}

.fz-amount-md {
    font-size: var(--fz-amount-md);
    font-weight: var(--fz-weight-amount);
    line-height: 1.35;
}

.fz-amount-sm {
    font-size: var(--fz-amount-sm);
    font-weight: var(--fz-weight-amount);
}

/*
 * En un telefono, la talla grande cede.
 *
 * `--fz-amount-lg` vive sobre todo en tarjetas de resumen que van de dos en dos
 * (`col-6`): a 390 px eso son unos 170 px de ancho util, y "S/ 130.624,85" a
 * 24 px no cabe. Lo que se hace NO es partir el importe -un numero cortado a la
 * mitad se lee mal y se lee mal en el peor momento- sino bajar un escalon la
 * talla. La jerarquia se mantiene: sigue siendo la cifra mas grande de su
 * tarjeta, solo que en una pantalla donde todo es mas pequeño.
 */
@media (max-width: 575.98px) {
    [data-bs-theme] {
        --fz-amount-lg: 1.25rem;
    }
}

/* ===========================================================================
   3. SUPERFICIES Y ELEVACION
   =========================================================================== */

/*
 * El brillo de la esquina (ADR 0080): una elipse del indigo de la marca arriba
 * a la derecha, de tamaño fijo para que en una pagina larga se quede arriba y
 * no se estire con ella. El color es un token del tema y en claro vale
 * transparente, asi que la regla es la misma en los dos.
 */
body {
    background-color: var(--bs-body-bg);
    background-image: radial-gradient(70rem 35rem at 90% -10%, var(--fz-page-glow), transparent 62%);
    background-repeat: no-repeat;
    color: var(--bs-body-color);
}

/*
 * La tarjeta deja de ser del color de la pagina.
 *
 * Con esto `shadow-sm` sobra en las 40 tarjetas que hoy lo repiten: la
 * separacion la da la superficie, no la sombra. Se mantiene el borde porque en
 * tema oscuro es lo unico que dibuja el limite.
 */
.card {
    --bs-card-bg: var(--fz-surface);
    --bs-card-border-color: var(--bs-border-color);
    --bs-card-spacer-y: var(--fz-space-4);
    --bs-card-spacer-x: var(--fz-space-4);
    --bs-card-border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--fz-elev-1);
}

/*
 * La marca, en un solo sitio.
 *
 * La usan el riel de escritorio, las pantallas de acceso, la barra del
 * operador y la landing. Vivia dentro del `@media (min-width: 1024px)` del
 * riel, asi que fuera de ahi no existia: el acceso -que se ve en todos los
 * anchos y es la primera pantalla del producto- habria tenido que redibujarla
 * por su cuenta.
 *
 * Es el `<img>` del logo que pinta `View::brandMark()`. Proporcion 7:5, la del
 * archivo (ADR 0095; hasta ahi era 3:4): el ancho sale de la altura, y
 * `object-fit` lo protege si alguien cambia una sola de las dos. Sin fondo ni
 * esquinas: el logo trae su forma y se lee igual sobre el claro, el oscuro y
 * el navy del riel.
 */
.fz-mark {
    display: inline-block;
    width: 2.1875rem;
    height: 1.5625rem;
    flex: 0 0 auto;
    object-fit: contain;
}

.fz-mark-lg {
    width: 3.5rem;
    height: 2.5rem;
}

/* La superficie hundida marca lo que esta "dentro" de una tarjeta: un resumen
   dentro de un panel, la fila de totales de una tabla. */
.fz-sunken {
    background-color: var(--fz-surface-sunken);
    border-radius: var(--bs-border-radius);
    padding: var(--fz-space-3);
}

/* ===========================================================================
   4. FOCO
   ===========================================================================

   Una sola regla de foco para todo, y visible en los dos temas. Se declara
   sobre `:focus-visible` para que el raton no lo dispare, pero NUNCA se
   suprime: sin foco visible el teclado navega a ciegas.
   =========================================================================== */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
    box-shadow: none;
}

/*
 * Los componentes de Bootstrap que QUITAN el outline al enfocar.
 *
 * La regla de arriba va en `:where()` -especificidad cero- para que cualquier
 * zona pueda afinarla (el riel le cambia el color). Pero `.btn:focus-visible`,
 * `.nav-link:focus-visible` y `.btn-close:focus-visible` de Bootstrap traen
 * `outline: 0` y un anillo de sombra translucido, y con su especificidad de
 * clase le ganaban: medido en /mortgages, el anillo quedaba a ~3:1 contra el
 * fondo, y a 2.90:1 en el boton del aviso verde. El foco de la casa se repone
 * aqui, con la especificidad justa para ganarles y ninguna mas.
 */
.btn:focus-visible,
.nav-link:focus-visible,
.btn-close:focus-visible {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
    box-shadow: none;
}

/*
 * El unico sitio donde Bootstrap obliga a escribir una regla propia.
 *
 * `.form-control:focus` trae `border-color:#86b7fe` y
 * `box-shadow:...rgba(13,110,253,.25)` literales, sin variable. Sin esta regla
 * el campo enfocado sigue siendo azul Bootstrap aunque la marca sea otra.
 */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--fz-brand);
    box-shadow: 0 0 0 var(--fz-focus-width) rgba(var(--fz-brand-rgb), 0.3);
}

.form-check-input:checked {
    background-color: var(--fz-brand-fill);
    border-color: var(--fz-brand-fill);
}

/* ===========================================================================
   5. BOTONES
   ===========================================================================

   Se re-fijan las variables `--bs-btn-*` porque las clases de Bootstrap traen
   el hex compilado. Es la forma soportada de retematizar sin recompilar Sass.
   =========================================================================== */

.btn {
    /*
     * El anillo de foco, en TODOS los botones y no solo en los de marca.
     *
     * Bootstrap trae `rgba(49,132,253,.5)` compilado en cada variante. Fijarlo
     * solo en `.btn-primary` y `.btn-outline-primary` dejaba el azul de fabrica
     * asomando al tabular por los `.btn-link` -los "Eliminar" de la lista de
     * movimientos- y por los `.btn-outline-secondary`. Aqui cubre a todos, y
     * cada variante puede seguir pisandolo si alguna vez hace falta.
     */
    --bs-btn-focus-shadow-rgb: var(--fz-brand-rgb);
    --bs-btn-padding-y: 0.5rem;
    --bs-btn-padding-x: 1rem;
    --bs-btn-border-radius: var(--bs-border-radius);
    --bs-btn-font-weight: 500;
    /* Altura minima y no padding suelto: garantiza el objetivo tactil de 44px
       aunque la etiqueta sea de una sola linea corta. */
    min-height: var(--fz-control-height);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-2);
}

/*
 * El boton principal (ADR 0080): degradado entre los dos tonos de la marca,
 * medidos los dos con el rotulo blanco, y un brillo de su color debajo.
 *
 * El borde es transparente para que el degradado llegue al canto: con el borde
 * del primer tono, el lado claro del boton quedaba enmarcado en el oscuro.
 *
 * Al pasar el raton o pulsar manda un color SOLIDO, que tambien esta medido. Y
 * no es `--fz-brand-hover`: ese es el color de un enlace, y en oscuro es un
 * lavanda que dejaba el rotulo blanco a 1.79:1.
 */
.btn-primary {
    --bs-btn-bg: var(--fz-brand-fill);
    --bs-btn-border-color: transparent;
    --bs-btn-color: var(--fz-brand-on-fill);
    --bs-btn-hover-bg: var(--fz-brand-fill-hover);
    --bs-btn-hover-border-color: transparent;
    --bs-btn-hover-color: var(--fz-brand-on-fill);
    --bs-btn-active-bg: var(--fz-brand-fill-active);
    --bs-btn-active-border-color: transparent;
    --bs-btn-active-color: var(--fz-brand-on-fill);
    --bs-btn-disabled-bg: var(--fz-brand-fill);
    --bs-btn-disabled-border-color: transparent;
    --bs-btn-disabled-color: var(--fz-brand-on-fill);
    --bs-btn-focus-shadow-rgb: var(--fz-brand-rgb);
    background-image: linear-gradient(135deg, var(--fz-brand-fill), var(--fz-brand-fill-end));
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 8px 20px -10px rgba(var(--fz-brand-rgb), 0.75);
}

.btn-primary:hover,
.btn-primary:active,
.btn-primary.active {
    background-image: none;
}

.btn-outline-primary {
    --bs-btn-color: var(--fz-brand);
    --bs-btn-border-color: var(--bs-border-color);
    --bs-btn-hover-bg: var(--bs-primary-bg-subtle);
    --bs-btn-hover-border-color: var(--fz-brand);
    --bs-btn-hover-color: var(--fz-brand);
    --bs-btn-active-bg: var(--bs-primary-bg-subtle);
    --bs-btn-active-border-color: var(--fz-brand);
    --bs-btn-active-color: var(--fz-brand);
    --bs-btn-focus-shadow-rgb: var(--fz-brand-rgb);
    /* Apagado, en los tonos de la marca y no en el azul de fabrica de Bootstrap,
       que en oscuro hacia que un boton apagado se viera mas vivo que uno activo. */
    --bs-btn-disabled-color: var(--fz-brand);
    --bs-btn-disabled-border-color: var(--bs-border-color);
}

/*
 * El secundario, remapeado a los tokens del tema.
 *
 * Se habia quedado con el gris de fabrica de Bootstrap -#6C757D, el mismo en los
 * dos temas- y no llegaba al minimo de texto: 4.37:1 sobre la pagina en claro y
 * 3.72:1 sobre una tarjeta en oscuro, contra los 4.5 que exige un cuerpo de
 * 16 px. Y no era un boton suelto: son "Mes anterior", "Volver", "Editar",
 * "Saltar" y los segmentos de tipo de la captura, o sea la mitad de los
 * controles secundarios de la aplicacion.
 *
 * `--bs-secondary-color` es el color de texto secundario del sistema y da
 * 6.53:1 en claro y 6.95:1 en oscuro sobre tarjeta.
 *
 * El hover se define entero a proposito. De fabrica pinta el fondo de ese mismo
 * gris con el texto en blanco, que en tema oscuro habria quedado PEOR que el
 * estado normal -texto blanco sobre gris claro, 2.2:1-. Invirtiendo contra
 * `--bs-body-bg` el contraste sube en los dos temas.
 */
.btn-outline-secondary {
    --bs-btn-color: var(--bs-secondary-color);
    --bs-btn-border-color: var(--bs-border-color);
    --bs-btn-hover-bg: var(--bs-secondary-color);
    --bs-btn-hover-border-color: var(--bs-secondary-color);
    --bs-btn-hover-color: var(--bs-body-bg);
    --bs-btn-active-bg: var(--bs-secondary-color);
    --bs-btn-active-border-color: var(--bs-secondary-color);
    --bs-btn-active-color: var(--bs-body-bg);
}

/* El boton destructivo va contorneado y no relleno: el rojo relleno grita, y en
   una lista de cuentas el que grita deberia ser el saldo, no "Archivar". */
.btn-outline-danger {
    --bs-btn-color: var(--fz-state-over-text);
    --bs-btn-border-color: var(--bs-danger-border-subtle);
    --bs-btn-hover-bg: var(--bs-danger-bg-subtle);
    --bs-btn-hover-border-color: var(--fz-state-over-fill);
    --bs-btn-hover-color: var(--fz-state-over-text);
    --bs-btn-active-bg: var(--bs-danger-bg-subtle);
    --bs-btn-active-border-color: var(--fz-state-over-fill);
    --bs-btn-active-color: var(--fz-state-over-text);
}

/* `btn-lg` sobrevive SOLO para la accion principal de captura en movil, donde el
   pulgar apunta sin mirar. `btn-sm` se retira del vocabulario. */
.btn-lg {
    --bs-btn-padding-y: 0.75rem;
    --bs-btn-padding-x: 1.25rem;
    --bs-btn-font-size: 1.0625rem;
    min-height: 3.25rem;
}

/*
 * Pestañas de catalogo, en pildora y con contador (ADR 0081): /accounts,
 * /loans, /categories y /recurring, todas por `layouts/_tabs.php`.
 *
 * Sustituyen al subrayado de Bootstrap (`nav-underline`). Cada pildora es un
 * objetivo de 44 px con su borde, y la abierta se distingue por fondo, borde y
 * color, no solo por una raya de dos pixeles. Las no abiertas van en el gris
 * secundario, que pasa de 4.5:1 sobre la tarjeta en los dos temas
 * (`DensidadTest`).
 *
 * Si no caben, parten en filas y todas se siguen viendo. Se descarto la tira de
 * una sola linea con desplazamiento horizontal: la pestaña abierta puede quedar
 * fuera de la vista al cargar -"Otro credito" es la cuarta de /loans- y traerla
 * a la vista necesita JavaScript.
 */
.fz-pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
    margin: 0 0 var(--fz-space-4);
    padding: 0;
    list-style: none;
}

.fz-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: var(--fz-control-height);
    padding: 0.375rem 0.875rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.625rem;
    background-color: var(--fz-surface);
    color: var(--bs-secondary-color);
    font-weight: 500;
    text-decoration: none;
}

.fz-pill:hover {
    color: var(--bs-emphasis-color);
    border-color: var(--bs-secondary-color);
}

.fz-pill[aria-current='page'] {
    color: var(--bs-emphasis-color);
    border-color: color-mix(in srgb, var(--fz-brand) 65%, transparent);
    background-color: color-mix(in srgb, var(--fz-brand) 14%, var(--fz-surface));
}

/* El contador: un globo neutro, no un dato que compita con la etiqueta. */
.fz-pill-count {
    min-inline-size: 1.5rem;
    padding: 0.0625rem 0.375rem;
    border-radius: 999px;
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    font-size: 0.75rem;
    font-weight: 600;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* En un telefono, mas juntas: las seis de /accounts caben en dos filas a 390 px
   en vez de tres. */
@media (max-width: 575.98px) {
    .fz-pills {
        gap: 0.375rem;
    }

    .fz-pill {
        gap: 0.375rem;
        padding-inline: 0.625rem;
        font-size: 0.9375rem;
    }
}

/* Pestañas y buscador en la misma fila (/accounts, /recurring); el buscador se
   va a la derecha y, en un telefono, a su propia linea. */
.fz-pills-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

.fz-pills-row .fz-pills {
    margin: 0;
}

/* ===========================================================================
   6. CAMPOS
   ===========================================================================

   Una sola talla, la de 44px. Todo `form-control-sm` del codigo actual
   -prestamos, hipotecas- pasa a la talla normal.
   =========================================================================== */

.form-control,
.form-select {
    min-height: var(--fz-control-height);
    background-color: var(--fz-surface);
    border-color: var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.form-label {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    font-weight: 500;
    margin-bottom: var(--fz-space-1);
}

.form-text {
    color: var(--bs-secondary-color);
}

/* Un campo de importe se escribe y se lee en cifras: hereda la alineacion
   tabular para que el punto decimal no baile mientras se teclea. */
.form-control.text-nums {
    text-align: right;
}

/*
 * Opcion de radio o casilla: el objetivo es la FILA, no el circulito.
 *
 * De fabrica el control mide 16 px y la fila 24. La altura unica de esta casa
 * son 44 (§6), y la regla de un objetivo tactil es que se cuenta el area
 * pulsable entera: como el `<label for>` selecciona el radio, basta con que el
 * rotulo ocupe la fila para que el objetivo real sean 44 px de alto por todo el
 * ancho disponible.
 *
 * Bootstrap coloca el control con `float: left` y un `margin-left` negativo
 * contra el `padding-left` del contenedor. En flex no hay float, asi que los
 * tres valores se anulan a la vez o la fila queda descuadrada.
 */
.form-check {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
    padding-left: 0;
    margin-bottom: 0;
}

/* Con `.form-check` delante: Bootstrap declara el margen negativo como
   `.form-check .form-check-input`, dos clases, y una sola aqui no lo vencia. El
   control quedaba 1.5em a la izquierda del contenido, fuera del relleno de la
   tarjeta (medido en /goals/new, ADR 0044). */
.form-check-input,
.form-check .form-check-input {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
    margin-top: 0;
    margin-left: 0;
}

.form-check-label {
    display: flex;
    align-items: center;
    flex: 1 1 auto;
    min-height: var(--fz-control-height);
    cursor: pointer;
}

/* ===========================================================================
   7. CAPTURA RAPIDA  (contrato de clases: no renombrar)
   =========================================================================== */

.sprite {
    display: none;
}

.capture-hidden {
    display: none !important;
}

/* El codigo de la moneda y el importe forman UNA pieza (ADR 0068): el
   recuadro de la moneda va pegado al campo y comparte su borde. No es un
   desplegable -la moneda la decide la cuenta-, y por eso no lleva flecha. */
.capture-amount {
    display: flex;
    align-items: stretch;
}

/* La bandera de la moneda (ADR 0096) y su codigo, en el recuadro de la izquierda. */
.capture-currency-box {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-2);
    min-width: 4.5rem;
    padding-inline: var(--fz-space-3);
    border: 1px solid var(--bs-border-color);
    border-inline-end: 0;
    border-start-start-radius: var(--bs-border-radius);
    border-end-start-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
}

/* El filo separa del fondo el blanco de la bandera de Peru. */
.capture-flag {
    display: inline-flex;
    flex: 0 0 auto;
    border-radius: 3px;
    box-shadow: 0 0 0 1px var(--bs-border-color);
}

.capture-currency {
    color: var(--bs-body-color);
    font-size: 1.125rem;
    font-weight: 600;
}

/* El campo y su simbolo («S/ 0.00», como la referencia): el borde y el foco son
   del recuadro (`:focus-within`) y no del `<input>`, para que el simbolo quede
   DENTRO del campo mida lo que mida el de cada moneda. */
.capture-field {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    min-width: 0;
    border: 1px solid var(--bs-border-color);
    border-start-end-radius: var(--bs-border-radius);
    border-end-end-radius: var(--bs-border-radius);
    background-color: var(--bs-body-bg);
    transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.capture-field:focus-within {
    border-color: var(--fz-brand);
    box-shadow: 0 0 0 var(--fz-focus-width) rgba(var(--fz-brand-rgb), 0.3);
}

.capture-field:has(.is-invalid) {
    border-color: var(--bs-form-invalid-border-color);
}

.capture-symbol {
    flex: 0 0 auto;
    padding-inline-start: var(--fz-space-3);
    color: var(--bs-secondary-color);
    font-size: 1.5rem;
    font-weight: 500;
    line-height: 1;
}

.capture-input {
    font-size: var(--fz-amount-hero);
    font-weight: var(--fz-weight-amount);
    /* Sin el 1.5 heredado, la cifra de 32 px hacia el campo de 61 px y la
       cuenta de al lado se quedaba en 56: que mande `min-height`, que descuenta
       el borde del recuadro que lo envuelve. */
    line-height: 1.2;
    padding-block: 0.35rem;
    padding-inline-start: var(--fz-space-2);
    min-height: calc(3.5rem - 2px);
    text-align: start;
}

/* El borde, la sombra de foco y el icono de error son del recuadro. */
.capture-field .capture-input,
.capture-field .capture-input:focus,
.capture-field .capture-input.is-invalid {
    border: 0;
    background-color: transparent;
    background-image: none;
    box-shadow: none;
}

.capture-feedback {
    margin-bottom: var(--fz-space-4);
}

.capture-feedback:empty {
    display: none;
}

/* --- Rejilla de categorias -------------------------------------------------
   `auto-fill` con minimo en rem y no un numero fijo de columnas: tres en un
   telefono y seis en un portatil, sin media queries que mantener. */

.cat-grid {
    display: grid;
    gap: var(--fz-space-2);
    grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
}

/* El radio real sigue ahi, invisible: el teclado y los lectores de pantalla
   necesitan un grupo de radios de verdad. `display:none` lo sacaria del orden
   de tabulacion. */
.cat-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.cat-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-1);
    /* 44px de alto minimo: es un objetivo tactil, no una etiqueta. */
    min-height: 4.5rem;
    padding: var(--fz-space-2) var(--fz-space-1);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    /*
     * Hundida, no del color de la tarjeta que la contiene.
     *
     * Con `--fz-surface` la baldosa valia exactamente lo mismo que la tarjeta y
     * lo unico que la separaba era el borde de 1px: doce recuadros dibujados
     * encima de una tarjeta en vez de doce piezas. Es el control principal de
     * este formulario y tiene que pesar como tal. `sunken` es el mismo token
     * que usa el fondo de pagina, que es el gesto de siempre para un control
     * que se mete hacia dentro.
     */
    background-color: var(--fz-surface-sunken);
    cursor: pointer;
    text-align: center;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}

/* El hover ACLARA, o sea sube hacia la tarjeta, en los dos temas. */
.cat-tile:hover {
    background-color: var(--bs-tertiary-bg);
}

/*
 * La seleccion NO se dice solo con el borde de color.
 *
 * Ademas del borde, el mosaico elegido cambia de fondo y sube el peso del
 * nombre. El radio real esta marcado, asi que el lector de pantalla lo anuncia;
 * esto es para quien mira.
 */
.cat-input:checked + .cat-tile {
    border-color: var(--fz-brand);
    border-width: 2px;
    background-color: var(--bs-primary-bg-subtle);
    /* Compensa el borde de 2px para que el mosaico no salte al elegirlo. */
    padding: calc(var(--fz-space-2) - 1px) calc(var(--fz-space-1) - 1px);
}

.cat-input:checked + .cat-tile .cat-name {
    font-weight: 600;
}

.cat-input:focus-visible + .cat-tile {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.cat-name {
    font-size: 0.75rem;
    line-height: 1.15;
    color: var(--bs-body-color);
}

.cat-icon {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
}

/* --- La tarjeta de captura (ADR 0068) ---------------------------------------
   Cabecera con el tipo a la derecha, monto y cuenta en una fila, categorias
   por grupo, fecha y nota a la vista y guardar a lo ancho. Todo sale de los
   tokens del tema: en oscuro se ve como el diseno de referencia y en claro es
   la misma estructura sobre las superficies claras. */

.fz-capture-form {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-5);
}

/* Vacia no ocupa hueco: con el `gap` del formulario sumaria 1.5rem de aire
   entre la nota y el boton. */
.fz-capture-form > [data-capture-error]:empty {
    display: none;
}

.fz-capture-head {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: var(--fz-space-4);
    padding-bottom: var(--fz-space-4);
    border-bottom: 1px solid var(--bs-border-color);
}

/* La insignia de la referencia: trazo de la marca sobre un tinte, con halo en
   oscuro, en vez del cuadro relleno. */
.fz-capture-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border: 1px solid rgba(var(--fz-brand-rgb), 0.5);
    border-radius: var(--bs-border-radius-lg);
    background-color: rgba(var(--fz-brand-rgb), 0.14);
    color: var(--fz-brand);
}

[data-bs-theme='dark'] .fz-capture-badge {
    box-shadow: 0 0 22px -4px rgba(var(--fz-brand-rgb), 0.6);
}

.fz-capture-badge-icon {
    width: 1.5rem;
    height: 1.5rem;
}

.fz-capture-title {
    margin-bottom: var(--fz-space-1);
    font-size: 1.25rem;
    font-weight: var(--fz-weight-heading);
}

.fz-capture-subtitle {
    margin-bottom: 0;
    color: var(--bs-secondary-color);
    font-size: 0.9375rem;
}

/* El selector de tipo: segmentos dentro de una pista hundida. En un telefono
   baja debajo de la pregunta y ocupa el ancho; el icono se pone ENCIMA del
   rotulo para que "Transferencia" quepa en un tercio de 358 px. */
.fz-capture-types {
    grid-column: 1 / -1;
    display: grid;
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    gap: var(--fz-space-1);
    padding: var(--fz-space-1);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--fz-surface-sunken);
}

.fz-capture-type {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.125rem;
    min-height: var(--fz-control-height);
    padding: var(--fz-space-1) var(--fz-space-2);
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.2;
    text-align: center;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}

.fz-capture-type:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

/* Elegido: relleno de la marca y peso mayor. El color no es lo unico que
   cambia, y el radio real sigue marcado para el lector de pantalla. */
/* El segmento elegido es translucido, como la referencia: tinte y filo de la
   marca. El peso y el filo dicen cual es ademas del color. */
.btn-check:checked + .fz-capture-type {
    background-color: rgba(var(--fz-brand-rgb), 0.2);
    box-shadow: inset 0 0 0 1px rgba(var(--fz-brand-rgb), 0.6);
    color: var(--bs-body-color);
    font-weight: 600;
}

.btn-check:focus-visible + .fz-capture-type {
    outline: var(--fz-focus-width) solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-capture-type-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
}

/* Rotulo de seccion de la tarjeta: con el color y la talla del texto, no los
   de `.form-label`, que es gris y de 14 px -en una tarjeta con tres secciones
   hacia falta ver donde empieza cada una-. */
.fz-capture-label {
    margin-bottom: var(--fz-space-2);
    color: var(--bs-body-color);
    font-size: 1rem;
    font-weight: 600;
}

/* Monto y cuenta. Cada celda tiene su sitio fijo y no un `grid-template-areas`:
   con areas, la segunda fila existiria aunque sus dos celdas estuvieran
   escondidas, y su hueco quedaria debajo del monto en todo gasto. Colocadas a
   mano, la fila solo nace cuando la transferencia enseña alguna. */
.fz-capture-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3) var(--fz-space-4);
}

.fz-capture-select {
    position: relative;
}

.fz-capture-select-icon {
    position: absolute;
    top: 50%;
    inset-inline-start: var(--fz-space-3);
    width: 1.5rem;
    height: 1.5rem;
    color: var(--bs-secondary-color);
    pointer-events: none;
    transform: translateY(-50%);
}

/* El chevron de la referencia en vez de la flecha de Bootstrap: la cuenta se
   lee como una fila que se toca. Sigue siendo el `<select>` nativo, que en un
   telefono abre el selector del sistema. */
.fz-capture-select .form-select {
    padding-inline: calc(var(--fz-space-3) * 2 + 1.5rem) calc(var(--fz-space-3) * 2 + 1.25rem);
    background-image: none;
}

.fz-capture-select-chevron {
    position: absolute;
    top: 50%;
    inset-inline-end: var(--fz-space-3);
    width: 1.25rem;
    height: 1.25rem;
    color: var(--bs-secondary-color);
    pointer-events: none;
    transform: translateY(-50%);
}

/* La cuenta mide lo mismo que el monto que tiene al lado. */
.fz-capture-cell-account .form-select {
    min-height: 3.5rem;
}

/* --- Categorias por grupo ---------------------------------------------------
   Un recuadro por grupo con su cabecera, y dentro la rejilla de siempre.
   `auto-fit` con 20rem da tres grupos por fila a 1440 px, dos en una tableta y
   uno en un telefono, sin media queries. Un bloque sin cabecera -los ingresos,
   o los gastos de un espacio sin grupos- no lleva recuadro y ocupa la fila
   entera: es la rejilla de antes. */

.fz-capture-categories {
    margin: 0;
}

.fz-cat-groups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
    gap: var(--fz-space-3);
}

.fz-cat-group {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-3);
    padding: var(--fz-space-3);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
}

.fz-cat-group-plain {
    grid-column: 1 / -1;
    padding: 0;
    border: 0;
}

/* Cada grupo con su color, como la referencia: borde y degradado del tono de
   su cabecera (`fz-kpi-tone-N`, el de `CategoryGroup::color()`), y en oscuro
   un halo. La baldosa elegida brilla en ese mismo color; ademas del color
   cambian el borde de 2 px, el fondo y el peso del nombre. */
.fz-cat-group-toned,
.fz-capture-box-toned {
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 45%, var(--bs-border-color));
    background-image: linear-gradient(160deg, color-mix(in srgb, var(--fz-kpi-tone) 9%, transparent) 0%, transparent 75%);
}

[data-bs-theme='dark'] .fz-cat-group-toned,
[data-bs-theme='dark'] .fz-capture-box-toned {
    background-image: linear-gradient(160deg, color-mix(in srgb, var(--fz-kpi-tone) 16%, transparent) 0%, transparent 75%);
    box-shadow: 0 0 26px -14px color-mix(in srgb, var(--fz-kpi-tone) 75%, transparent);
}

/* Los ingresos no llevan cabecera, pero si el recuadro de su color. */
.fz-cat-group-plain.fz-cat-group-toned {
    padding: var(--fz-space-3);
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 45%, var(--bs-border-color));
}

/* El icono del rotulo de cada recuadro, en su color. */
.fz-capture-box-toned .fz-capture-box-icon {
    color: var(--fz-kpi-tone);
}

.fz-cat-group-toned .cat-input:checked + .cat-tile {
    border-color: var(--fz-kpi-tone);
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 14%, var(--fz-surface-sunken));
}

[data-bs-theme='dark'] .fz-cat-group-toned .cat-input:checked + .cat-tile {
    box-shadow: 0 0 16px -4px color-mix(in srgb, var(--fz-kpi-tone) 70%, transparent);
}

.fz-cat-group-head {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    margin: 0;
    font-size: 1rem;
    font-weight: var(--fz-weight-heading);
}

.fz-cat-group-icon {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
}

/* En la captura la baldosa crece: es el control principal del formulario y
   aqui hay sitio. Las demas rejillas -iconos y colores de /categories- no.
   6.25rem de minimo es lo que pide "Entretenimiento" a 13 px, la etiqueta
   de una sola palabra mas larga de las semillas; con 5.5 se salia del recuadro. */
.fz-cat-group .cat-grid {
    grid-template-columns: repeat(auto-fill, minmax(6.25rem, 1fr));
}

.fz-cat-group .cat-tile {
    min-height: 5.25rem;
}

.fz-cat-group .cat-icon {
    width: 1.75rem;
    height: 1.75rem;
}

.fz-cat-group .cat-name {
    font-size: 0.8125rem;
    /* Ultimo recurso para el nombre que escriba el usuario: partido dentro de
       la baldosa antes que salido de ella. */
    overflow-wrap: anywhere;
}

/* Tres baldosas por fila en el telefono desde 390 px, y no dos (captura del
   panel, edicion de un movimiento y alta de una recurrente, ADR 0113 y 0117).
   Con 16 px de relleno en la tarjeta y 12 en el grupo, a 390 px quedaban 306 px
   para tres baldosas de 6.25rem (316). Con 12 y 8 quedan 322, y cada baldosa mide 102 px. El
   relleno lateral de la baldosa baja a 2 px para que «Entretenimiento», la
   palabra mas larga de las semillas (92 px a 13 px), tenga 96 y no se parta
   con otra letra del sistema. Por debajo de unos 384 px siguen siendo dos:
   tres no caben sin partirla. El bloque sin cabecera (los ingresos) no tiene
   recuadro y no lleva relleno. */
@media (max-width: 575.98px) {
    .fz-capture-body,
    .fz-mov-edit-category .fz-fcard-body,
    .fz-rec-form-category .fz-fcard-body {
        padding-inline: 0.75rem;
    }

    .fz-cat-group:not(.fz-cat-group-plain),
    .fz-cat-group-plain.fz-cat-group-toned {
        padding: 0.5rem;
    }

    .fz-cat-group .cat-tile {
        padding-inline: 0.125rem;
    }

    /* El borde de la elegida es de 2 px: el relleno cede el que gana. */
    .fz-cat-group .cat-input:checked + .cat-tile {
        padding-inline: calc(0.125rem - 1px);
    }
}

/* --- Recurrentes como atajos (ADR 0069) --------------------------------------
   Al pie del bloque de la categoria tocada: Netflix y Spotify bajo
   "Suscripciones". Pastillas de 44 px de alto -son objetivos tactiles- con el
   nombre y el monto; el vencido lleva ademas su estado en el color de aviso. */

.fz-quick {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-2);
    padding-top: var(--fz-space-3);
    border-top: 1px dashed var(--bs-border-color);
}

.fz-quick-title {
    margin: 0;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
}

.fz-quick-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
}

.fz-quick-chip {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 var(--fz-space-2);
    min-height: var(--fz-control-height);
    padding: var(--fz-space-1) var(--fz-space-3);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-surface-sunken);
    color: var(--bs-body-color);
    font-size: 0.875rem;
    text-align: start;
    cursor: pointer;
    transition: border-color 0.12s ease, background-color 0.12s ease;
}

.fz-quick-chip:hover {
    background-color: var(--bs-tertiary-bg);
}

.fz-quick-chip:focus-visible {
    outline: var(--fz-focus-width) solid var(--fz-brand);
    outline-offset: 2px;
}

/* Aplicado: el monto puede estar fuera de la pantalla, asi que el atajo dice
   que hizo algo. Borde y fondo de la marca, como la baldosa elegida. */
.fz-quick-chip[aria-pressed='true'] {
    border-color: var(--fz-brand);
    background-color: var(--bs-primary-bg-subtle);
}

.fz-quick-name {
    font-weight: 600;
}

.fz-quick-amount {
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.fz-quick-chip-due {
    border-color: var(--bs-warning-border-subtle);
}

.fz-quick-due {
    color: var(--fz-state-warn-text);
    font-size: 0.75rem;
    font-weight: 600;
}

/* --- Fecha y nota ----------------------------------------------------------- */

.fz-capture-extras {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3) var(--fz-space-4);
}

.fz-capture-box {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-2);
    padding: var(--fz-space-3);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
}

.fz-capture-box .date-echo {
    margin-top: 0;
}

.fz-capture-box-label {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    font-weight: 600;
}

.fz-capture-box-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
    color: var(--fz-brand);
}

.fz-capture-note {
    position: relative;
}

/* Hueco para el contador: el texto largo no se mete debajo de "500/500". */
.fz-capture-note .form-control {
    padding-inline-end: 4.75rem;
}

.fz-capture-count {
    position: absolute;
    top: 50%;
    inset-inline-end: var(--fz-space-3);
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
    transform: translateY(-50%);
}

/* --- Guardar ----------------------------------------------------------------
   El degradado de la marca ya no es suyo: desde el ADR 0080 lo lleva todo
   `.btn-primary`, con sus estados. Aqui solo queda la talla. */
.fz-capture-save {
    min-height: 3.5rem;
    font-weight: 600;
}

[data-bs-theme='dark'] .fz-capture-save {
    box-shadow: 0 0 28px -8px rgba(var(--fz-brand-rgb), 0.75);
}

/* Al tocar «+» la tarjeta se ve desde la cabecera, con el tipo a la vista. */
.fz-capture {
    scroll-margin-top: var(--fz-space-3);
}

/*
 * Movil: Guardar, siempre a mano.
 *
 * Del monto al boton hay mas de una pantalla de categorias, y el teclado
 * decimal del iPhone no tiene Intro. Pegado encima de la barra de pestañas
 * mientras la tarjeta esta en pantalla, como el pago de /loans: `sticky` y no
 * `fixed`, asi al final de la tarjeta vuelve a su sitio. El anillo del color
 * de la tarjeta tapa lo que pasa por detras al desplazar; en reposo no se ve.
 */
@media (max-width: 1023.98px) {
    .fz-capture-save {
        position: sticky;
        bottom: calc(var(--fz-tabbar-h) + env(safe-area-inset-bottom, 0px) + var(--fz-space-2));
        z-index: 2;
        box-shadow: 0 0 0 var(--fz-space-2) var(--bs-card-bg);
    }

    [data-bs-theme='dark'] .fz-capture-save {
        box-shadow: 0 0 0 var(--fz-space-2) var(--bs-card-bg), 0 0 28px -8px rgba(var(--fz-brand-rgb), 0.75);
    }
}

/* En el telefono el subtitulo ocupaba dos lineas para repetir lo que ya dice
   la pregunta. */
@media (max-width: 575.98px) {
    .fz-capture-subtitle {
        display: none;
    }
}

/*
 * En el telefono -una sola columna, por debajo de 768 px- los titulos de la
 * tarjeta van centrados, a pedido del usuario: la cabecera, con la insignia y
 * la pregunta como una sola pieza, el rotulo de cada recuadro, «Categoría»,
 * la cabecera de cada grupo y la de los atajos. Lo que se escribe o se elige
 * sigue alineado a la izquierda. La cabecera pasa de rejilla a flex para
 * poder centrar la pieza sin que el selector de tipo pierda el ancho entero.
 */
@media (max-width: 767.98px) {
    .fz-capture-head {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
    }

    .fz-capture-heading {
        min-width: 0;
        text-align: center;
    }

    .fz-capture-types {
        flex: 1 1 100%;
    }

    .fz-capture-box-label,
    .fz-capture .fz-cat-group-head {
        justify-content: center;
    }

    .fz-capture-categories > legend,
    .fz-capture .fz-quick-title {
        text-align: center;
    }

    /* Y solo el texto, también a pedido: sin la insignia de la cabecera ni el
       icono de cada rotulo o grupo. Los iconos que eligen algo -tipo, cuenta,
       categorias- y la bandera se quedan. La insignia sigue en el DOM: capture.js
       le cambia el icono aunque no se vea. */
    .fz-capture-badge,
    .fz-capture-box-icon,
    .fz-capture .fz-cat-group-icon {
        display: none;
    }
}

.fz-capture-save-icon {
    width: 1.375rem;
    height: 1.375rem;
    flex: 0 0 auto;
}

@media (min-width: 576px) {
    .fz-capture-type {
        flex-direction: row;
        gap: var(--fz-space-2);
        padding: var(--fz-space-2) var(--fz-space-3);
        font-size: 0.9375rem;
    }

    .fz-capture-badge {
        width: 3.5rem;
        height: 3.5rem;
    }

    .fz-capture-badge-icon {
        width: 1.75rem;
        height: 1.75rem;
    }
}

@media (min-width: 768px) {
    .fz-capture-title {
        font-size: 1.5rem;
    }

    .fz-capture-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .fz-capture-cell-amount {
        grid-row: 1;
        grid-column: 1;
    }

    .fz-capture-cell-account {
        grid-row: 1;
        grid-column: 2;
    }

    .fz-capture-cell-received {
        grid-row: 2;
        grid-column: 1;
    }

    .fz-capture-cell-target {
        grid-row: 2;
        grid-column: 2;
    }

    .fz-capture-extras {
        grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    }
}

/* Desde 992 px el tipo sube a la derecha de la pregunta. */
@media (min-width: 992px) {
    .fz-capture-head {
        grid-template-columns: auto minmax(0, 1fr) auto;
    }

    .fz-capture-types {
        grid-column: auto;
        min-width: 26rem;
    }
}

/*
 * La talla por defecto de un icono, y la razon por la que esta regla existe.
 *
 * `View::icon()` emite `class="icon"` cuando no le dan otra, y `.icon` no estaba
 * declarada en ningun sitio -ni aqui ni en Bootstrap-. Un `<svg>` sin `width` ni
 * `height` y sin CSS que lo dimensione mide CERO dentro de un contenedor flex:
 * la llamada no falla, no avisa, y lo que sale es un hueco vacio. Paso de
 * verdad -el menu "..." de una tarjeta de prestamo se veia como un recuadro en
 * blanco- y no lo caza ninguna prueba de PHP, porque el HTML es correcto.
 *
 * Los sitios que quieren otra talla siguen mandando: `.fz-account-type svg`,
 * `.fz-nav-icon` y compañia son mas especificos o llegan despues.
 */
.icon {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
}

/*
 * La baldosa de un icono: fondo solido de su color y el glifo en blanco encima
 * (ADR 0053).
 *
 * Generica y de nadie en particular, como `ColorToken`. Nacio en la tabla de
 * movimientos (ADR 0051) y acabo declarada tres veces -alli, en /budgets y en
 * el panel- con las mismas siete lineas cada vez. Ahora es una y vive aqui, con
 * los iconos, que es de lo que habla. La pintan la lista de movimientos, el
 * panel, el catalogo de categorias, los recurrentes y los topes.
 *
 * Las dos medidas van juntas por el mismo motivo: 36 px de caja y 18 px de
 * glifo son UNA proporcion, y separarlas en dos sitios es como se acaba con
 * baldosas de distinto tamano en dos pantallas seguidas.
 *
 * El HTML no se escribe a mano: lo emite `View::tile()`, que ademas comprueba
 * que la clase de superficie sea una de las de la lista. La unica excepcion es
 * la plantilla que rellena `movement-list.js`, y esta dicho alli.
 *
 * El color no esta aqui: lo pone `cat-surface-N` -o `fz-tile-brand`- en el
 * mismo atributo `class`, y el blanco de encima lo hereda el SVG por
 * `currentColor`.
 */
.fz-tile {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.5625rem;
}

.fz-tile-icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* No todo lo que lleva baldosa es una categoria: "Todo el gasto" de /budgets es
   un tope sin categoria y no tiene color propio, asi que va con el de la marca,
   igual que en el riel. Es una superficie mas -fondo y texto en el mismo sitio,
   como `cat-surface-N`- y por eso se declara junto a la baldosa y no dentro de
   la seccion de topes. */
.fz-tile-brand {
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

/* ===========================================================================
   8. LISTA DE MOVIMIENTOS
   ===========================================================================

   El color no es la unica senal: el importe llega con su signo puesto por el
   servidor. Quien no distingue rojo de verde sigue leyendo el signo.
   =========================================================================== */

.movement-out {
    color: var(--fz-money-out);
}

.movement-in {
    color: var(--fz-money-in);
}

/*
 * Filas de catalogo: icono + nombre + cifra + acciones, en una sola linea.
 *
 * A 390 px dejan de caber y hasta ahora se desbordaban: /accounts sacaba 29 px
 * fuera del viewport y la pagina entera cogia scroll horizontal. La causa:
 * `flex-grow-1` hace crecer, no encoger. Un hijo flex no baja del ancho de su
 * contenido mientras `min-width` valga `auto`, asi que un nombre largo empuja
 * al resto fuera. `min-width: 0` es lo que le da permiso para encoger, y
 * `overflow-wrap: anywhere` lo que deja partir una palabra suelta sin espacios
 * -si no, esa palabra sola vuelve a empujar-.
 *
 * Con eso YA no hace falta `flex-wrap` en el contenedor: el nombre se encoge y
 * envuelve DENTRO de su propia celda -mas alto, no mas ancho- y la fila entera
 * sigue en una sola linea de flex. `flex-wrap: wrap` se probo primero y parecia
 * la misma solucion, pero no lo es: en cuanto el nombre crecia a tres lineas,
 * mandaba la CIFRA a su propia linea, suelta y pegada a la izquierda (se vio
 * auditando /accounts con Claude in Chrome). El importe tampoco encoge ni
 * envuelve -`flex: 0 0 auto` + `white-space: nowrap`-: es lo ultimo que se
 * sacrifica al faltar ancho.
 */
.list-group-item.d-flex > .flex-grow-1 {
    min-width: 0;
    overflow-wrap: anywhere;
}

.list-group-item.d-flex > .text-nums {
    flex: 0 0 auto;
    white-space: nowrap;
}

/* Un nombre de cuenta largo se corta con puntos suspensivos y no empuja la
   pagina: el desplazamiento horizontal esta prohibido. */
.fz-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Fila archivada: se ve, pero apagada.
 *
 * La opacidad NO es la unica senal -al lado dice "Archivada" y el boton ofrece
 * "Restaurar"-, porque atenuar es justo lo que peor distingue quien tiene poca
 * vision o mira la pantalla al sol.
 */
.archived-row {
    opacity: 0.65;
}

/* El buscador de una lista (/recurring, /accounts; ADR 0081): con su lupa y sin
   estirarse a lo ancho de la fila, salvo en un telefono, donde va solo en su
   linea. */
.fz-list-search {
    position: relative;
    flex: 1 1 14rem;
    max-inline-size: 20rem;
    margin-inline-start: auto;
}

.fz-list-search-icon {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 0.875rem;
    inline-size: 1.125rem;
    block-size: 1.125rem;
    transform: translateY(-50%);
    color: var(--bs-secondary-color);
    pointer-events: none;
}

.fz-list-search .form-control {
    padding-inline-start: 2.5rem;
}

/* Por debajo de 992 px las pestañas ya parten en dos filas y el buscador caia
   solo, pegado a la derecha y con un hueco al lado: ahi va a lo ancho. */
@media (max-width: 991.98px) {
    .fz-list-search {
        flex-basis: 100%;
        max-inline-size: none;
        margin-inline-start: 0;
    }
}

/* Region viva del buscador: vacia no ocupa sitio, pero sigue en el arbol para
   que el lector de pantalla anuncie el "ninguna coincide" al escribirse. */
.fz-list-search-empty {
    margin: 0;
    color: var(--bs-secondary-color);
}

.fz-list-search-empty:not(:empty) {
    margin-bottom: var(--fz-space-4);
}

/*
 * El catalogo de categorias: en el telefono los botones bajan a su propia linea
 * (ADR 0053).
 *
 * El `overflow-wrap: anywhere` de "Filas de catalogo" evita el desbordamiento
 * partiendo el nombre por donde sea, y eso basta cuando al nombre le queda ancho. Aqui no le quedaba: a 390 px la
 * fila mide 332 y "Editar" + "Archivar" + los huecos se llevan casi 240, asi
 * que al nombre le sobraban unos 90 px y salia "Intere/ses hipote/carios". Que
 * no desborde no lo hace legible.
 *
 * El corte es 576 y no 992 -el de "toca pagar" (ADR 0049)- porque esta fila no
 * tiene tres columnas a la derecha, solo dos botones: medido, a 768 px los
 * nombres mas largos caben en una sola linea con holgura.
 *
 * El salto lo fuerza el ancho de los botones, no el `wrap` a secas. Con `wrap`
 * solo, un nombre corto -"Ropa"- dejaria sitio para los botones en la misma
 * linea y otro largo no: la mitad de las filas de una lista con los botones
 * arriba y la otra mitad con ellos abajo, que se lee como si fueran dos listas.
 * Con `calc(100% - 3.25rem)` no caben nunca al lado y todas las filas se ven
 * igual. La sangria es la baldosa (2.25rem) mas el hueco de la fila (1rem):
 * los botones empiezan bajo el NOMBRE, no bajo el icono.
 */
.list-group-item.fz-cat-row {
    /* 1rem, lo que daba `gap-3`, pero sin su `!important`: asi el telefono
       puede acortar el hueco vertical sin tocar el horizontal. */
    gap: var(--fz-space-4);
}

@media (max-width: 575.98px) {
    .list-group-item.fz-cat-row {
        flex-wrap: wrap;
        row-gap: var(--fz-space-2);
    }

    .fz-cat-actions {
        width: calc(100% - 3.25rem);
        margin-inline-start: 3.25rem;
    }
}

/* Los gastos del catalogo, por grupo (ADR 0069): la cabecera repite el rotulo
   y el icono del bloque de la captura, para reconocer aqui lo que se ve alli.
   El icono va gris: en esta pantalla el color es de las baldosas de las filas,
   que es donde se elige (hay una prueba que no deja pasar un trazo de color). */
.fz-cat-section + .fz-cat-section {
    margin-top: var(--fz-space-4);
}

.fz-cat-section-head {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    margin: 0;
    padding-bottom: var(--fz-space-2);
    border-bottom: 1px solid var(--bs-border-color);
    font-size: 1rem;
    font-weight: var(--fz-weight-heading);
}

.fz-cat-section-icon {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
}

.fz-cat-section-count {
    color: var(--bs-secondary-color);
    font-weight: 400;
}

/*
 * Los recurrentes: en el telefono, el nombre se queda con la primera linea (ADR 0053).
 *
 * Es la misma fila de catalogo -icono, nombre, cifra, accion- pero con dos
 * datos mas a la derecha: la fecha bajo el importe en "Proximas", y el chip de
 * frecuencia en "Activas". A 390 px la fila mide 332 y esos dos bloques mas el
 * boton se llevaban casi 300: al nombre le quedaban unos 30 px y, con el
 * `overflow-wrap: anywhere` de "Filas de catalogo", salia UNA LETRA POR RENGLON y la
 * fila medida 353 px de alto. No es un apreton, es ilegible.
 *
 * `flex-basis: calc(100% - 3.25rem)` en `.fz-rec-name` es lo que parte la fila en
 * dos: con esa base, el nombre y la baldosa llenan la primera linea exacta
 * -2.25rem de baldosa + 1rem de hueco + el resto- y todo lo demas se va a la
 * segunda. No hace falta un `::after` que fuerce el salto ni tocar el orden
 * del documento.
 *
 * En la segunda linea el importe arranca bajo el NOMBRE -no bajo el icono- y
 * la accion se pega a la derecha con `margin-inline-start: auto`, que es donde
 * el pulgar la espera. El chip de frecuencia, cuando lo hay, queda entre los
 * dos.
 *
 * El corte es 768 y lo manda la pestaña "Activas", que es la fila mas cargada
 * del modulo: lleva un chip de frecuencia que "Proximas" no tiene. Medido a
 * 576 px, esa fila deja 77 px para el nombre y vuelve a salir una letra por
 * renglon; "Proximas" a esa misma anchura si entra. Se corta a la vez en las
 * dos porque son la misma lista vista de dos formas: con dos cortes distintos,
 * cambiar de pestaña reordenaria la fila a mitad de camino, sin que nada en
 * pantalla explique por que.
 */
.list-group-item.fz-rec-row {
    /* 1rem, lo que daba `gap-3`, pero sin su `!important`. */
    gap: var(--fz-space-4);
}

@media (max-width: 767.98px) {
    .list-group-item.fz-rec-row {
        flex-wrap: wrap;
        row-gap: var(--fz-space-2);
    }

    .fz-rec-name {
        flex-basis: calc(100% - 3.25rem);
    }

    .fz-rec-amount {
        margin-inline-start: 3.25rem;
    }

    .fz-rec-actions {
        margin-inline-start: auto;
    }
}

/*
 * Fila de "toca pagar": icono, nombre, acciones, fecha, cifra y chip (ADR 0034).
 *
 * La fecha vivia dentro de una frase del renglon pequeno -"Toca el 22 ago"- y
 * el chip no existia. Ahora son tres columnas propias a la derecha del nombre:
 * CUANDO, CUANTO y A CUANTO. Una frase no se compara de un vistazo con la frase
 * de la fila de arriba; una columna si.
 *
 * El orden VISUAL no es el del documento y se decide aqui a proposito. En el
 * HTML la fila se lee "nombre, fecha, importe, chip, botones", que es lo que
 * oye un lector de pantalla y lo que recorre el teclado: cuanto te van a cobrar
 * antes de que te ofrezcan registrarlo. En pantalla ancha (desde 992; por
 * debajo bajan a su propia linea, ADR 0049) los botones se meten EN
 * MEDIO, justo detras del nombre, y es lo unico que mantiene alineadas las tres
 * columnas de la derecha entre los dos grupos de la tarjeta: solo las vencidas
 * traen botones, asi que si fueran al final arrastrarian consigo la fecha, la
 * cifra y el chip de ese grupo y ninguno cuadraria con el de abajo.
 *
 * Los `min-width` son lo que impide que las columnas bailen de fila en fila.
 * Sin ellos cada celda mide lo que mida su texto -"S/ 44.90" es mas corta que
 * "USD 15.00", "Hoy" mas corto que "Hace 12 dias"- y nada alinea con nada. Si
 * un contenido supera la medida, SOLO su fila se descuadra: cada fila es un flex
 * aparte y no sabe nada de sus vecinas. Por eso las medidas cubren el caso
 * largo y no el tipico.
 */
/* 1rem, lo que daba `gap-3`. Aqui y no en el HTML: la utilidad lleva
   `!important` y el telefono tiene que poder acortar el hueco vertical.

   El relleno lateral separa la baldosa y el chip del borde de la banda: la
   lista pinta su fondo propio sobre el degradado de la tarjeta, y con `px-0`
   la baldosa y el chip quedaban pegados a ese borde. */
.list-group-item.fz-due-row {
    gap: var(--fz-space-4);
    padding-inline: var(--fz-space-4);
}

.fz-due-name {
    flex: 1 1 auto;
    /* El unico que cede cuando falta ancho, y por eso el unico que puede
       truncar: un hijo flex no baja del ancho de su contenido sin esto. */
    min-width: 0;
}

.fz-due-actions {
    order: 1;
}

.fz-due-date {
    order: 2;
    flex: 0 0 auto;
    min-width: 4.5rem;
    font-size: 0.8125rem;
    text-align: right;
    white-space: nowrap;
}

/* 8rem cubre "S/ 4,800.00" con holgura. */
.fz-due-amount {
    order: 3;
    flex: 0 0 auto;
    min-width: 8rem;
    text-align: right;
    white-space: nowrap;
}

/* El chip se alinea por su borde IZQUIERDO -no se estira ni se centra- porque
   lo que se compara de fila en fila es donde empieza, y su ancho depende del
   texto: "Hoy" y "Hace 12 dias" no miden lo mismo y no deben.

   6rem y no 5.5: "Hace 16 dias" mide 91 px, pasaba de los 88 y empujaba 3 px
   a la izquierda la fecha y la cifra de SU fila, que dejaban de cuadrar con
   las demas. Una fila flex no hace crecer a sus vecinas. 96 px cubren
   cualquier "Hace NN dias" / "NN days ago". */
.fz-due-when {
    order: 4;
    flex: 0 0 auto;
    justify-content: flex-start;
    min-width: 6rem;
}

/*
 * Con sitio de sobra, la fila NO envuelve.
 *
 * Envolver reparte ANTES de encoger: mientras el nombre quepa a su ancho
 * natural nadie se aprieta, y lo que se va a la linea de abajo es el ultimo
 * elemento en orden visual, que es justo el chip. Con `nowrap` el unico que
 * puede ceder es el nombre -es el unico con `flex-shrink` y con `min-width: 0`-,
 * que era lo que se queria: un nombre largo se parte en dos renglones y la fila
 * sigue siendo una fila.
 *
 * `nowrap` es ya el valor por defecto de `.d-flex`; se escribe para que nadie
 * lo cambie aqui creyendo que da igual.
 *
 * Desde 992 y no desde 768 (ADR 0049): de 768 a 991 la fila mide 662 px, y
 * con los botones en medio al nombre de una fila vencida le quedaban 88 px,
 * truncado con elipsis a la tercera palabra ("Aporte a Vi...").
 */
@media (min-width: 992px) {
    .list-group-item.fz-due-row {
        flex-wrap: nowrap;
    }
}

/*
 * Por debajo, los botones bajan a su propia linea.
 *
 * Se gasta alto porque es lo que sobra: meter nombre, dos controles de 44 px
 * y las tres columnas en una linea deja el nombre en una columna de dos dedos.
 * `width` fuerza el salto y el `order` coloca los botones DEBAJO del resto, no
 * encima.
 *
 * El corte empezo en 575.98 y ya se movio una vez: de 576 a 767 el
 * `.container` se topa en 540 px -el `li` mide 482- y el diseno de escritorio
 * pedia 498. Ahora sube a 991.98 por lo mismo, medido: de 768 a 991 cabia, pero
 * solo truncando el nombre (ADR 0049).
 *
 * El salto SOLO ocurre si la fila envuelve, y por eso el `wrap`. Sin el -`.d-flex`
 * es `nowrap`- los botones, que no encogen (`flex-shrink-0`), median el ancho
 * entero de la fila y se salian por la derecha; el nombre, el unico que cede,
 * quedaba en 0 px y la pagina cogia scroll horizontal (666 px de documento a
 * 390 de pantalla).
 *
 * `flex-basis: 0` en el nombre para que envolver no reparta antes de encoger
 * (ver el bloque de arriba): con base 0 el nombre nunca empuja una columna a la
 * linea de abajo, solo se queda con lo que las demas dejan.
 *
 * Con los botones abajo, fecha, cifra y chip quedan al final de la linea en
 * las DOS listas, vencidas o no, y con sus medidas fijas vuelven a cuadrar
 * entre grupos: que es lo que el ADR 0034 conseguia poniendo los botones en
 * medio.
 */
@media (max-width: 991.98px) {
    .list-group-item.fz-due-row {
        flex-wrap: wrap;
        row-gap: var(--fz-space-2);
    }

    .fz-due-name {
        flex-basis: 0;
    }

    /* Bajo el nombre y no bajo el icono: la sangria es la baldosa (2.25rem) +
       el hueco de la fila (1rem). Los botones empiezan su linea, asi que ningun
       hueco se la da. */
    .fz-due-actions {
        order: 7;
        width: calc(100% - 3.25rem);
        margin-inline-start: 3.25rem;
    }
}

/*
 * Las tres columnas de la derecha sueltan su medida fija.
 *
 * Por debajo de 768 esos 128 + 72 + 96 px le hacen falta al nombre, que aqui es
 * el que menos sitio tiene. Lo que se pierde es la rejilla entre grupos; lo que
 * se gana es que "Seguro del auto" no salga partido en cuatro renglones. De 768
 * a 991 hay ancho para las dos cosas y la medida se queda.
 */
@media (max-width: 767.98px) {
    .fz-due-date,
    .fz-due-amount,
    .fz-due-when {
        min-width: 0;
    }
}

/*
 * En el telefono, dos renglones: nombre y cifra arriba, cuando y a cuanto abajo.
 *
 * A 390 px la fila mide unos 326; icono, fecha, cifra, chip y sus cuatro
 * huecos se comen casi 300 y al nombre le quedaban menos de 30 px, o sea una
 * letra por renglon. Arriba se queda lo que se pregunta primero -que y
 * cuanto-, y la fecha y el chip bajan juntos, que es como se leen ("20/09,
 * hace 1 dia").
 *
 * El salto lo pone el `::after`: un hijo flex vacio con base 100 % colocado
 * con `order` entre la cifra (1) y la fecha (3). No toca el HTML, asi que el
 * orden de lectura -nombre, fecha, cifra, chip, botones- sigue siendo el mismo
 * para el lector de pantalla y el teclado.
 *
 * La fecha lleva la misma sangria que los botones: empieza bajo el nombre.
 */
@media (max-width: 575.98px) {
    /* 12 px y no 16: aqui cada pixel lateral sale del ancho del nombre. */
    .list-group-item.fz-due-row {
        row-gap: var(--fz-space-1);
        padding-inline: var(--fz-space-3);
    }

    .list-group-item.fz-due-row::after {
        content: "";
        order: 2;
        flex-basis: 100%;
    }

    .fz-due-amount {
        order: 1;
    }

    .fz-due-date {
        order: 3;
        margin-inline-start: 3.25rem;
    }

    /* El hueco vertical aqui es de 4 px; con esto los botones siguen a 8. */
    .fz-due-actions {
        margin-top: var(--fz-space-1);
    }
}

/* ===========================================================================
   9. BARRAS DE PROGRESO Y ESTADOS  (contrato de clases: no renombrar)
   ===========================================================================

   El ancho lo pone el atributo `width` del `<rect>` que emite el servidor: la
   CSP no lleva 'unsafe-inline', asi que un `style="width:65%"` no se aplicaria.
   Aqui solo va el color, que depende del estado y no del dato.
   =========================================================================== */

.budget-bar {
    width: 100%;
    height: 0.5rem;
    display: block;
    margin: var(--fz-space-1) 0;
    /*
     * El redondeo va aqui y no en el `rx` de los rectangulos.
     *
     * El SVG se estira a lo ancho (`preserveAspectRatio="none"`), asi que
     * cualquier radio expresado en unidades del `viewBox` se escala solo en
     * horizontal: un `rx="4"` acababa midiendo 25 px de ancho por 4 de alto y
     * las barras cortas se veian como lentejas. `clip-path` recorta en pixeles
     * reales, donde 4 son 4 en las dos direcciones.
     *
     * Recorta el SVG entero, asi que la pista y el relleno comparten el mismo
     * contorno: el extremo del relleno queda recto -que es lo correcto, marca
     * hasta donde se ha llegado- y solo se redondean los extremos de la barra.
     */
    clip-path: inset(0 round 0.25rem);
}

.budget-track {
    fill: var(--fz-track);
}

/*
 * Los rellenos van en degradado (ADR 0080): de su tono de siempre a la punta
 * del mismo estado, que en los dos temas gana contraste.
 *
 * Un `<rect>` no admite `linear-gradient()`. En SVG el degradado es un
 * elemento, `<linearGradient>`, y vive UNA vez por pagina en el layout
 * (`layouts/_bar-gradients.php`); varias barras lo comparten por su id. Los
 * colores no estan alli sino aqui, en los `<stop>`, y por eso siguen al tema.
 *
 * El color que va despues de `url()` es la reserva: si una pagina no trajera
 * el layout, la barra sale solida, no vacia.
 *
 * `position: absolute` y tamaño cero, no `display: none`: un degradado dentro
 * de un SVG que no se pinta deja de pintar tambien en las barras que lo usan.
 */
.fz-defs {
    position: absolute;
    inline-size: 0;
    block-size: 0;
    overflow: hidden;
}

.fz-grad-from {
    stop-color: var(--fz-grad-from);
}

.fz-grad-to {
    stop-color: var(--fz-grad-to);
}

.fz-grad-on-track {
    --fz-grad-from: var(--fz-brand-fill);
    --fz-grad-to: var(--fz-brand-fill-end);
}

.fz-grad-warning {
    --fz-grad-from: var(--fz-state-warn-fill);
    --fz-grad-to: var(--fz-state-warn-fill-end);
}

.fz-grad-over {
    --fz-grad-from: var(--fz-state-over-fill);
    --fz-grad-to: var(--fz-state-over-fill-end);
}

.fz-grad-ok {
    --fz-grad-from: var(--fz-state-ok-fill);
    --fz-grad-to: var(--fz-state-ok-fill-end);
}

/* Sobre una tarjeta de color (la barra del limite de una tarjeta de credito). */
.fz-grad-color-on-track {
    --fz-grad-from: var(--fz-on-color-bar-on);
    --fz-grad-to: var(--fz-on-color-bar-on-end);
}

.fz-grad-color-warning {
    --fz-grad-from: var(--fz-on-color-bar-warn);
    --fz-grad-to: var(--fz-on-color-bar-warn-end);
}

.fz-grad-color-over {
    --fz-grad-from: var(--fz-on-color-bar-over);
    --fz-grad-to: var(--fz-on-color-bar-over-end);
}

.fz-grad-color-ok {
    --fz-grad-from: var(--fz-on-color-bar-ok);
    --fz-grad-to: var(--fz-on-color-bar-ok-end);
}

/*
 * "En curso" va en INDIGO, no en verde (ADR 0021 §4).
 *
 * Compartia el verde con "alcanzada", y entonces una meta al 40 % y una meta
 * cumplida se pintaban igual: el verde dejaba de significar logro por salir
 * siempre. El indigo es progreso neutral -no has hecho nada bien ni mal, vas
 * avanzando- y deja el verde para lo que de verdad se celebra.
 */
.budget-on-track {
    fill: url(#fz-grad-on-track) var(--fz-brand-fill);
}

.budget-warning {
    fill: url(#fz-grad-warning) var(--fz-state-warn-fill);
}

.budget-exceeded {
    fill: url(#fz-grad-over) var(--fz-state-over-fill);
}

/* Metas: comparten la barra con los presupuestos pero su vocabulario es otro.

   "Atrasada" era ambar -ibas por detras del ritmo, no habias hecho nada mal-.
   Desde el ADR 0044 una meta con plan esta atrasada cuando CON LO QUE TE
   COMPROMETISTE A APORTAR no llegas a la fecha: es una promesa que no se va a
   cumplir, la misma clase de frontera cruzada que un tope excedido. Por eso
   pasa al rojo, que es como la dibujo el diseño aprobado, en /goals y en el
   panel a la vez. */
.budget-behind {
    fill: url(#fz-grad-over) var(--fz-state-over-fill);
}

.budget-achieved {
    fill: url(#fz-grad-ok) var(--fz-state-ok-fill);
}

/*
 * Meta cuya cuenta esta en descubierto.
 *
 * Rojo y no ambar, aun cuando el ADR §4 reserva el rojo para "excedido": es el
 * mismo hecho visto del otro lado. Excederse es cruzar el limite por arriba;
 * quedarse en negativo es cruzar el cero por abajo. En los dos casos hay una
 * frontera pasada, no un ritmo flojo.
 *
 * El relleno casi nunca se ve -con saldo negativo el porcentaje es cero y la
 * barra queda vacia-, pero se declara igual: lo que decide el color no puede
 * depender de que el ancho sea o no cero.
 */
.budget-overdrawn {
    fill: url(#fz-grad-over) var(--fz-state-over-fill);
}

/* El estado tambien se dice con texto y con el porcentaje, nunca solo color. */
.budget-text-on_track,
.goal-text-on_track {
    color: var(--bs-secondary-color);
}

.budget-text-warning {
    color: var(--fz-state-warn-text);
}

.budget-text-exceeded,
.goal-text-behind,
.goal-text-overdrawn {
    color: var(--fz-state-over-text);
}

.goal-text-achieved {
    color: var(--fz-state-ok-text);
}

.budget-row + .budget-row {
    border-top: 1px solid var(--bs-border-color-translucent);
    padding-top: var(--fz-space-3);
}

.progress {
    --bs-progress-bg: var(--fz-track);
    --bs-progress-bar-bg: var(--fz-state-ok-fill);
    --bs-progress-height: 0.5rem;
    --bs-progress-border-radius: var(--bs-border-radius-sm);
}

/* ===========================================================================
   10. CHIP DE ESTADO
   ===========================================================================

   Lleva SIEMPRE texto. Un chip que solo es un punto de color no dice nada a
   quien no distingue ese color, y no se puede leer en voz alta.
   =========================================================================== */

.fz-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-1);
    padding: 0.125rem var(--fz-space-2);
    border: 1px solid transparent;
    border-radius: var(--bs-border-radius-sm);
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
}

.fz-chip-neutral {
    background-color: var(--bs-tertiary-bg);
    border-color: var(--bs-border-color);
    color: var(--bs-secondary-color);
}

.fz-chip-ok {
    background-color: var(--bs-success-bg-subtle);
    border-color: var(--bs-success-border-subtle);
    color: var(--fz-state-ok-text);
}

.fz-chip-warn {
    background-color: var(--bs-warning-bg-subtle);
    border-color: var(--bs-warning-border-subtle);
    color: var(--fz-state-warn-text);
}

.fz-chip-over {
    background-color: var(--bs-danger-bg-subtle);
    border-color: var(--bs-danger-border-subtle);
    color: var(--fz-state-over-text);
}

/* Ni bien ni mal, en camino: una suscripcion «En prueba» (ADR 0145). El
   indigo de la marca. */
.fz-chip-info {
    background-color: var(--bs-primary-bg-subtle);
    border-color: var(--bs-primary-border-subtle);
    color: var(--fz-brand);
}

/* El punto es redundante a proposito: refuerza para quien lo ve y no aporta
   nada que el texto no diga ya. */
.fz-chip-dot {
    width: 0.4375rem;
    height: 0.4375rem;
    border-radius: 50%;
    flex: 0 0 auto;
    background-color: currentcolor;
}

/*
 * Calendario de /recurring: una tabla clasica -no una rejilla `display:grid`
 * nueva-, porque una tabla es la forma que ya sabe leer un lector de
 * pantalla para "esta columna es lunes".
 *
 * `border-collapse: separate` con espacio entre celdas, y no `collapse`: cada
 * dia con algo que vence pinta SU fondo redondeado (`.fz-cal-day-*`), y con
 * los bordes fundidos dos dias seguidos del mismo color se verian como un
 * bloque, no como dos celdas.
 */
.fz-calendar {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0.125rem;
    text-align: center;
}

/* Los dias de la semana en el color del texto y en negrita, no en un color
   propio: en el calendario el color dice que le pasa a un dia (atrasado,
   proximo, ingreso), y en esta app el indigo marca enlaces. */
.fz-calendar th {
    font-weight: 600;
    font-size: 0.75rem;
    color: var(--bs-body-color);
    padding-bottom: var(--fz-space-2);
}

/* El dia SIN nada que decir: sin fondo propio, solo el numero. */
.fz-calendar td {
    padding: var(--fz-space-1) 0;
    font-size: 0.8125rem;
    border-radius: var(--bs-border-radius-sm);
}

/* Hoy: un aro, nunca un relleno -tiene que poder combinarse con el color de
   un dia que ademas trae algo que vence, sin que uno tape al otro-. Encima
   de un fondo solido el aro va separado por una linea del color de la
   tarjeta, para que no se confunda con el borde del propio relleno. */
.fz-calendar-today {
    box-shadow: inset 0 0 0 1.5px var(--bs-body-color);
}

.fz-calendar-today:is(.fz-cal-day-over, .fz-cal-day-upcoming, .fz-cal-day-income) {
    box-shadow:
        inset 0 0 0 1.5px var(--bs-body-color),
        inset 0 0 0 3px var(--bs-card-bg, var(--bs-body-bg));
}

/* El fondo de la celda ES la senal: el MISMO color solido que el punto de
   la leyenda, no un tinte suave -asi el dia y la muestra que lo explica se
   leen como lo mismo-, y no un punto aparte debajo del numero. */
.fz-cal-day-over {
    background-color: var(--bs-danger);
    color: var(--fz-cal-on-fill);
}

.fz-cal-day-upcoming {
    background-color: var(--fz-cal-upcoming);
    color: var(--fz-cal-on-fill);
}

.fz-cal-day-income {
    background-color: var(--bs-success);
    color: var(--fz-cal-on-fill);
}

/* La leyenda SI necesita el punto: es la unica muestra de color que explica
   que significa cada fondo, y ahi no compite con ningun numero. */
.fz-calendar-dot {
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background-color: currentcolor;
    flex: 0 0 auto;
}

/* Mismo color que el fondo de su `.fz-cal-day-*`, pero como TEXTO -es lo que
   `background-color: currentcolor` del punto necesita-, no como fondo. */
.fz-cal-dot-over {
    color: var(--bs-danger);
}

.fz-cal-dot-upcoming {
    color: var(--fz-cal-upcoming);
}

.fz-cal-dot-income {
    color: var(--bs-success);
}

/* ===========================================================================
   10 bis. TARJETAS DE CIFRA RESUMEN  (ADR 0081, 0082)
   ===========================================================================

   Las cifras de arriba de una pantalla: /accounts (disponible, deuda en
   tarjetas y ahorros) y /recurring (gasto mensual, vence esta semana y
   atrasado). Superficie del tema con un velo, un borde y un brillo de su
   tono, y la baldosa con el icono: no compiten con lo que va debajo.

   Una cifra por moneda: la del espacio en grande y las demas un escalon abajo
   (`.fz-kpi-second`), como el patrimonio del panel (ADR 0079). Nada suma
   monedas (ADR 0036).

   El parcial `layouts/_kpi.php` pinta la tarjeta comun: rotulo y una linea
   por moneda con su importe y su nota. Las de /accounts llevan ademas el
   desglose, la variacion y la barra de uso, y viven en su seccion.
   =========================================================================== */

/* Una, dos o tres en fila segun el ancho. Entre 576 y 991 px van dos y, si son
   impares, la ultima a lo ancho: tres en fila median 224 px a 768 y el importe
   se partia (ADR 0081 §5). */
.fz-kpis {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

@media (min-width: 576px) {
    .fz-kpis {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .fz-kpis > :last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

@media (min-width: 992px) {
    .fz-kpis {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .fz-kpis > :last-child:nth-child(odd) {
        grid-column: auto;
    }
}

.fz-kpi {
    display: flex;
    align-items: flex-start;
    gap: var(--fz-space-3);
    min-width: 0;
    padding: var(--fz-space-4);
}

/* La superficie sola, sin la disposicion de baldosa y cuerpo: para una tarjeta
   que ya tiene la suya, como la grande de /budgets en el telefono (ADR 0083). */
.fz-kpi,
.fz-kpi-surface {
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 38%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: var(--fz-surface);
    background-image: linear-gradient(145deg, color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent) 0%, transparent 70%);
    box-shadow: 0 8px 20px -14px color-mix(in srgb, var(--fz-kpi-tone) 60%, transparent);
}

[data-bs-theme='dark'] .fz-kpi,
[data-bs-theme='dark'] .fz-kpi-surface {
    background-image: linear-gradient(145deg, color-mix(in srgb, var(--fz-kpi-tone) 14%, transparent) 0%, transparent 70%);
    box-shadow: 0 0 26px -12px color-mix(in srgb, var(--fz-kpi-tone) 55%, transparent);
}

/* El tono es el de su baldosa: `fz-kpi-tone-N` va con `cat-surface-N`. */
.fz-kpi-tone-1 {
    --fz-kpi-tone: var(--fz-cat-1);
}

.fz-kpi-tone-2 {
    --fz-kpi-tone: var(--fz-cat-2);
}

.fz-kpi-tone-3 {
    --fz-kpi-tone: var(--fz-cat-3);
}

.fz-kpi-tone-4 {
    --fz-kpi-tone: var(--fz-cat-4);
}

.fz-kpi-tone-5 {
    --fz-kpi-tone: var(--fz-cat-5);
}

.fz-kpi-tone-6 {
    --fz-kpi-tone: var(--fz-cat-6);
}

.fz-kpi-tone-7 {
    --fz-kpi-tone: var(--fz-cat-7);
}

.fz-kpi-tone-8 {
    --fz-kpi-tone: var(--fz-cat-8);
}

.fz-kpi-tone-9 {
    --fz-kpi-tone: var(--fz-cat-9);
}

.fz-kpi-tone-10 {
    --fz-kpi-tone: var(--fz-cat-10);
}

.fz-kpi-tone-11 {
    --fz-kpi-tone: var(--fz-cat-11);
}

.fz-kpi-tone-12 {
    --fz-kpi-tone: var(--fz-cat-12);
}

.fz-kpi .fz-tile {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 0.75rem;
}

.fz-kpi .fz-tile-icon {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-kpi-body {
    flex: 1 1 auto;
    min-width: 0;
    display: grid;
    gap: 0.25rem;
}

.fz-kpi-label {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--bs-secondary-color);
}

.fz-kpi-body p {
    margin: 0;
}

/* Un importe no se parte nunca: cortado en dos lineas se lee mal justo cuando
   importa (ADR 0021). En la banda de dos columnas estrechas baja un escalon. */
.fz-kpi-amount {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--bs-emphasis-color);
}

@media (min-width: 576px) and (max-width: 767.98px) {
    .fz-kpi-amount {
        font-size: 1.25rem;
    }
}

.fz-kpi-second.fz-kpi-amount,
.fz-kpi-second .fz-kpi-amount {
    font-size: 1.125rem;
    font-weight: 600;
}

.fz-kpi-note {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* La variacion: flecha en CSS y el texto; sube en verde, baja en ambar y nunca
   en rojo (ADR 0079), sin cambios en gris. */
.fz-kpi-change {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-kpi-change::before {
    content: '';
    flex: none;
    inline-size: 0.625rem;
    block-size: 2px;
    background-color: currentColor;
}

.fz-kpi-change-up {
    color: var(--fz-state-ok-text);
}

.fz-kpi-change-down {
    color: var(--fz-state-warn-text);
}

.fz-kpi-change-up::before,
.fz-kpi-change-down::before {
    block-size: 0.5rem;
    background-color: currentColor;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.fz-kpi-change-down::before {
    clip-path: polygon(0 0, 100% 0, 50% 100%);
}

/* Una moneda por linea: el importe a la izquierda y su nota a la derecha. Si
   no caben juntos la nota baja, y sigue a la derecha (`margin-inline-start:
   auto`): con la primera linea partida y la segunda no, una a cada lado se
   leia como desalineado. */
.fz-kpi-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0 var(--fz-space-3);
}

.fz-kpi-row .fz-kpi-note {
    margin-inline-start: auto;
}

.fz-kpi-row + .fz-kpi-row {
    margin-top: var(--fz-space-1);
    padding-top: var(--fz-space-2);
    border-top: 1px solid var(--bs-border-color-translucent);
}

/* Lo atrasado: los importes en el color de aviso, el mismo ambar del tono. */
.fz-kpi-alert .fz-kpi-amount {
    color: var(--fz-state-warn-text);
}

/* Un bloque por moneda con la nota DEBAJO de la cifra: para tarjetas
   estrechas, como las cuatro de /budgets (ADR 0083), donde cifra y nota no
   caben en una linea. Misma raya entre monedas que `.fz-kpi-row`. */
.fz-kpi-group {
    display: grid;
    gap: 0.125rem;
}

.fz-kpi-group + .fz-kpi-group {
    margin-top: var(--fz-space-1);
    padding-top: var(--fz-space-2);
    border-top: 1px solid var(--bs-border-color-translucent);
}

/* Compacta: la baldosa va junto al rotulo y lo demas debajo, a todo el ancho
   de la tarjeta. Para cuatro en fila (/budgets, ADR 0083, en la rejilla con
   `.fz-kpis-compact`) y para una tarjeta en una columna estrecha (/goals,
   ADR 0084, con `.fz-kpi-compact`). Con la baldosa a la izquierda, a 992 px
   el cuerpo de /budgets medía 135 px y «S/ 11,000.00» (140) se salia.
   `display: contents` sube el rotulo y los bloques a la rejilla de la
   tarjeta; el `div` no tiene papel que perder. */
.fz-kpis-compact .fz-kpi,
.fz-kpi.fz-kpi-compact {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    align-content: start;
    gap: var(--fz-space-2) var(--fz-space-2);
}

.fz-kpis-compact .fz-kpi-body,
.fz-kpi-compact .fz-kpi-body {
    display: contents;
}

.fz-kpis-compact .fz-kpi-body > :not(.fz-kpi-label),
.fz-kpi-compact .fz-kpi-body > :not(.fz-kpi-label) {
    grid-column: 1 / -1;
}

.fz-kpis-compact .fz-kpi .fz-tile,
.fz-kpi-compact .fz-tile {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.625rem;
}

.fz-kpis-compact .fz-kpi .fz-tile-icon,
.fz-kpi-compact .fz-tile-icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* Dos en fila en un telefono (las cuatro cifras de un prestamo o de una
   hipoteca, ADR 0085): la cifra baja un escalon, como `.fz-amount-lg`, en vez
   de partirse. */
@media (max-width: 575.98px) {
    .fz-kpi-compact .fz-kpi-amount {
        font-size: var(--fz-amount-lg);
    }
}

/* Una cifra con color de sentido -el equity de una hipoteca entra en verde-.
   `.fz-kpi-amount` va despues que `.movement-in` en la hoja y le ganaria con
   su color de enfasis. */
.fz-kpi .movement-in {
    color: var(--fz-money-in);
}

.fz-kpi .movement-out {
    color: var(--fz-money-out);
}

/* Donde no hay cifra que dar ("Sin tope · USD"): texto apagado en vez de un
   importe inventado. */
.fz-kpi-none {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

/* ===========================================================================
   11. ALERTAS
   ===========================================================================
   Bootstrap ya las resuelve con `--bs-*-bg-subtle` y `--bs-*-text-emphasis`,
   que arriba estan redefinidos: no hace falta ni una regla de color aqui.
   =========================================================================== */

.alert {
    --bs-alert-border-radius: var(--bs-border-radius);
    display: flex;
    gap: var(--fz-space-3);
    align-items: flex-start;
}

.alert-icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.125rem;
}

/* ===========================================================================
   12. TABLA FINANCIERA
   ===========================================================================

   El caso limite es la amortizacion de una hipoteca a 30 anos: 360 filas por
   cinco columnas numericas. Tres decisiones:
   =========================================================================== */

/*
 * 1. El scroll horizontal vive DENTRO de la tabla, nunca en la pagina.
 *    `max-height` + encabezado pegajoso: la fila de rotulos no se pierde a la
 *    fila 200, que es cuando de verdad hace falta.
 */
.fz-table-wrap {
    overflow-x: auto;
    overflow-y: auto;
    max-height: 26rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    /* Que se vea que hay mas a los lados en un movil. */
    overscroll-behavior-x: contain;
}

.fz-table-financial {
    --bs-table-bg: var(--fz-surface);
    --bs-table-border-color: var(--bs-border-color-translucent);
    margin-bottom: 0;
    width: 100%;
}

/* 2. Toda cifra a la derecha y tabular; todo rotulo a la izquierda. Es lo que
      permite comparar dos filas de un vistazo. */
.fz-table-financial th,
.fz-table-financial td {
    padding: var(--fz-space-2) var(--fz-space-3);
    white-space: nowrap;
}

/* `thead th` y no `th` a secas: la tabla comparativa del simulador
   (loans/simulate.php) usa `<th scope="row">` para el rotulo de cada fila del
   cuerpo, y con el selector abierto ese rotulo quedaba pegado arriba,
   apilandose sobre el encabezado al desplazar. */
.fz-table-financial thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--fz-surface-raised);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
    text-align: right;
    /* `sticky` no arrastra los bordes de celda: se dibuja con sombra. */
    box-shadow: inset 0 -1px 0 var(--bs-border-color);
}

.fz-table-financial th:first-child,
.fz-table-financial td:first-child {
    text-align: left;
}

/* Una columna de texto que no es la primera -la fecha de una cuota-. La regla
   de la casa es cifra a la derecha, rotulo a la izquierda, y `:first-child` solo
   cubre la primera. */
.fz-table-financial .fz-col-text {
    text-align: left;
}

.fz-table-financial td {
    text-align: right;
    font-size: 0.9375rem;
}

.fz-table-financial tbody tr:hover td {
    background-color: var(--bs-tertiary-bg);
}

/*
 * En movil la tabla de cinco columnas no cabe, y no se resuelve con scroll de
 * pagina. Cada fila pasa a ser una ficha de pares rotulo/valor, y el rotulo lo
 * pone el CSS desde `data-label` -que ya es un gancho existente-, no texto
 * duplicado en el HTML.
 */
@media (max-width: 575.98px) {
    .fz-table-stack thead {
        /* `clip` y no `display:none`: sigue en el arbol de accesibilidad. */
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
    }

    /* Con las filas hechas fichas, la tabla deja de comportarse como tabla. Si
       no se dice, el navegador envuelve cada bloque en cajas anonimas de tabla
       y la separacion entre fichas queda a merced de esa reconstruccion. */
    .fz-table-stack,
    .fz-table-stack tbody {
        display: block;
    }

    .fz-table-stack tbody tr {
        display: block;
        padding: var(--fz-space-3);
        border-bottom: 1px solid var(--bs-border-color);
    }

    /*
     * Y cada ficha, una tarjeta de verdad.
     *
     * Apiladas y separadas solo por una linea de 1px, doce cuotas seguidas se
     * leen como un unico bloque de dieciocho pares rotulo/valor: el ojo no
     * tiene donde cortar entre una cuota y la siguiente. Con borde, radio y
     * aire entre ellas, cada cuota vuelve a ser una unidad.
     *
     * El fondo sale de `--bs-table-bg`, que es la variable que ya fija el
     * estado de la fila (`.fz-schedule-paid` / `.fz-schedule-next`): la pagada
     * queda gris y la proxima en el indigo palido de la marca, igual que en
     * escritorio y sin una sola regla de color aqui.
     *
     * La banda del ano se queda fuera: no es una cuota, es el titulo del grupo.
     */
    .fz-table-stack tbody tr:not(.fz-schedule-year) {
        margin-bottom: var(--fz-space-2);
        background-color: var(--bs-table-bg);
        border: 1px solid var(--bs-border-color);
        border-radius: var(--bs-border-radius);
    }

    .fz-table-stack tbody td {
        display: flex;
        justify-content: space-between;
        gap: var(--fz-space-3);
        padding: var(--fz-space-1) 0;
        white-space: normal;
        text-align: right;
        border: 0;
    }

    .fz-table-stack tbody td::before {
        content: attr(data-label);
        color: var(--bs-secondary-color);
        font-size: 0.8125rem;
        font-weight: 500;
        text-align: left;
    }

    /* Con la fila convertida en bloque, una celda que sigue siendo `table-cell`
       -la banda de ano del calendario- no llena el ancho y se queda encogida a
       la izquierda. */
    .fz-table-stack tbody .fz-schedule-year > th {
        display: block;
    }

    .fz-table-wrap {
        max-height: none;
        overflow: visible;
    }
}

/*
 * La tabla de comparacion del simulador, en un telefono.
 *
 * No se apila como el calendario -comparar "como vas" con "con los abonos" es
 * leer dos cifras EN LA MISMA FILA, y apiladas habria que recordar la primera-,
 * pero tampoco cabia: medido a 390 px, la tabla media 453 contra 332 de sitio, y
 * la columna que se sacaba de la vista era justo "Con los abonos", la que importa.
 *
 * Quien fijaba el ancho era la etiqueta mas larga ("Intereses de todo el
 * prestamo") con el `nowrap` de toda tabla financiera. Aqui la ETIQUETA puede
 * partir en lineas y las cifras no -una cifra cortada a la mitad se lee mal-, y
 * el relleno lateral baja de 12 a 8 px.
 */
@media (max-width: 575.98px) {
    .fz-table-compare th,
    .fz-table-compare td {
        padding-inline: var(--fz-space-2);
    }

    .fz-table-compare tbody th {
        white-space: normal;
    }
}

/* ===========================================================================
   13. ESTADO VACIO
   ===========================================================================
   Hoy es una frase gris. Un vacio util dice que falta, por que, y ofrece la
   accion que lo resuelve.
   =========================================================================== */

.fz-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--fz-space-3);
    /* El paso mas grande de la escala: un vacio con poco aire parece un error
       de carga, no un estado. */
    padding: var(--fz-space-7) var(--fz-space-4);
}

.fz-empty-icon {
    width: 2.5rem;
    height: 2.5rem;
    color: var(--bs-tertiary-color);
}

.fz-empty-title {
    font-size: 1.0625rem;
    font-weight: var(--fz-weight-heading);
    margin: 0;
}

.fz-empty-text {
    color: var(--bs-secondary-color);
    max-width: 32rem;
    margin: 0;
}

/* ===========================================================================
   14. ESQUELETO DE CARGA
   ===========================================================================
   Un esqueleto con la FORMA del contenido que viene, no un spinner centrado:
   el spinner no dice cuanto ni que llega.
   =========================================================================== */

.fz-skeleton {
    background-color: var(--fz-skeleton-base);
    background-image: linear-gradient(
        90deg,
        var(--fz-skeleton-base) 0%,
        var(--fz-skeleton-sheen) 50%,
        var(--fz-skeleton-base) 100%
    );
    background-size: 200% 100%;
    border-radius: var(--bs-border-radius-sm);
    animation: fz-sheen 1.4s ease-in-out infinite;
}

.fz-skeleton-text {
    height: 0.75rem;
}

.fz-skeleton-title {
    height: 1.125rem;
}

.fz-skeleton-amount {
    height: 1.25rem;
    width: 5.5rem;
}

.fz-skeleton-circle {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
}

/* --- Accion en curso -------------------------------------------------------

   El esqueleto de arriba es para contenido que ESTA LLEGANDO, y por eso tiene su
   forma. Esto es otro estado: una accion que el usuario acaba de lanzar y aun no
   ha respondido. Un boton no puede enseñar un esqueleto de si mismo -ya esta
   dibujado-, asi que aqui si toca el disco girando.

   `disabled` por si solo ya evitaba el doble envio, pero no decia nada: en una
   conexion lenta se pulsa Guardar, no pasa nada visible y se vuelve a pulsar.

   El disco entra como un hijo mas del flex del `.btn`, asi que hereda el `gap` y
   se separa del rotulo sin margenes a mano. */

.is-busy::before {
    content: '';
    width: 1rem;
    height: 1rem;
    flex: 0 0 auto;
    border: 2px solid currentColor;
    /* El lado transparente es lo que hace visible el giro. */
    border-inline-end-color: transparent;
    border-radius: 50%;
    animation: fz-spin 0.6s linear infinite;
}

@keyframes fz-spin {
    to {
        transform: rotate(1turn);
    }
}

.fz-w-40 {
    width: 40%;
}

.fz-w-60 {
    width: 60%;
}

.fz-w-80 {
    width: 80%;
}

@keyframes fz-sheen {
    from {
        background-position: 100% 0;
    }

    to {
        background-position: -100% 0;
    }
}

/*
 * `prefers-reduced-motion` no es opcional: la animacion se apaga y el esqueleto
 * se queda como un bloque de color, que sigue comunicando "esto esta cargando"
 * sin movimiento.
 */
@media (prefers-reduced-motion: reduce) {
    .fz-skeleton {
        animation: none;
        background-image: none;
    }

    /* El disco se queda quieto pero NO desaparece: sigue siendo un elemento que
       antes no estaba, o sea la señal de "esto esta en marcha", sin movimiento.
       Quitarlo dejaria el boton apagado sin explicacion. */
    .is-busy::before {
        animation: none;
    }

    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
    }
}

/*
 * Alto contraste de Windows.
 *
 * En `forced-colors` el sistema reemplaza colores de texto, fondo y borde por su
 * propia paleta. Eso deja sin efecto tres señales que aqui son importantes,
 * porque las tres se dicen con color de fondo o de borde:
 *
 *   - la baldosa de color elegida en el selector de categoria,
 *   - la pestaña actual de la barra inferior,
 *   - el disco de Capturar, que es un relleno de marca y se vuelve invisible.
 *
 * `outline` SI sobrevive -el sistema no lo reemplaza- y `Highlight` es el color
 * de seleccion del propio usuario, asi que se dice con lo que el sistema respeta
 * en vez de pelearse con el.
 *
 * Los doce tonos de categoria se pierden aqui, y esta bien: es exactamente lo
 * que el modo pide. La rejilla sigue siendo usable porque cada baldosa lleva su
 * nombre escrito debajo, que nunca fue decorativo.
 *
 * NO verificado en un Windows con alto contraste encendido: son las reglas
 * estandar para este medio y no afectan a nadie fuera de el, pero conviene
 * mirarlo el dia que se pruebe de verdad.
 */
@media (forced-colors: active) {
    .cat-input:checked + .cat-tile,
    .btn-check:checked + .fz-capture-type,
    .fz-quick-chip[aria-pressed='true'] {
        outline: 3px solid Highlight;
        outline-offset: -3px;
    }

    .fz-tab.is-current,
    .fz-nav-link.is-current {
        outline: 2px solid Highlight;
        outline-offset: -2px;
    }

    .fz-tab-capture-disc {
        border: 1px solid CanvasText;
    }
}

/* ===========================================================================
   15. GRAFICAS DEL SERVIDOR  (contrato de clases: no renombrar)
   ===========================================================================
   El servidor NO sabe que tema tiene el usuario, asi que ningun color de
   grafica puede ir literal en el atributo `fill`: todos salen de aqui.
   =========================================================================== */

.donut {
    width: 100%;
    height: auto;
    color: var(--bs-secondary-color);
}

.donut-slice {
    transform-box: view-box;
}

/*
 * La tendencia del PANEL y del reporte: barras y cifras, todo HTML (ADR 0028 §2,
 * ADR 0047).
 *
 * Ni un SVG, y es deliberado. Un SVG dibuja su texto DENTRO del viewBox, que
 * escala con el ancho del contenedor. Esta tarjeta va de 360 px en un movil a
 * mas de 1100 en un monitor y no hay cuerpo de letra que sirva en los dos
 * extremos: el del movil sale enorme en el monitor y al reves. El reporte lo
 * resolvia pintando dos graficas y escondiendo una; desde el ADR 0047 usa esta.
 *
 * Siendo HTML, cada cifra va pegada al borde superior de SU barra y sube y baja
 * con ella, que es lo unico que un texto dentro de un SVG estirado no puede
 * hacer sin deformarse. Y el texto sigue siendo texto: se escala con la
 * tipografia del usuario, se selecciona y lo lee un lector de pantalla.
 *
 * El alto de cada barra llega en una CLASE de lista cerrada -`fz-trend-h-N`- y
 * no en un `style=`: la CSP declara `style-src 'self'`, sin 'unsafe-inline'
 * (ADR 0021 §9). Es el mismo patron que los colores de categoria.
 */
.fz-trend-months {
    /*
     * Columnas iguales SIN saber cuantas son: `column` las va creando segun
     * llegan los meses, asi que el numero de columnas tampoco tiene que viajar
     * en un estilo en linea.
     */
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: var(--fz-space-2);
    /*
     * La banda que se reserva para la cifra de encima de cada barra.
     *
     * Es fija y se descuenta del alto disponible, y esa es la razon de que la
     * altura de una barra se calcule sobre `100% - esto`: si la banda creciera
     * con el texto, la barra mas alta empujaria su cifra fuera de la tarjeta.
     * Vive aqui —y no en `:root`— porque solo la usan las reglas de abajo.
     */
    --fz-trend-label: 1.15rem;
}

.fz-trend-months > li {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* El par de barras de un mes. El alto de la grafica se fija AQUI, en rem: no
   depende del ancho de la tarjeta ni de cuantos meses haya. */
.fz-trend-pair {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 8%;
    height: 8.5rem;
}

/*
 * El hueco de UNA barra: la cifra arriba y la barra abajo, pegadas.
 *
 * `justify-content: flex-end` es lo que hace que el par se apoye en el suelo y
 * que la cifra quede justo encima del borde de la barra en vez de flotando a una
 * altura fija.
 */
.fz-trend-slot {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    height: 100%;
    flex: 1 1 0;
    min-width: 0;
}

.fz-trend-value {
    flex: none;
    height: var(--fz-trend-label);
    line-height: var(--fz-trend-label);
    font-size: var(--fz-amount-sm);
    font-weight: var(--fz-weight-amount);
    font-variant-numeric: tabular-nums;
    /* Una cifra larga no ensancha su columna ni desalinea el mes de al lado. */
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
}

/* En un telefono, los cuatro meses mas recientes (ADR 0088): con seis, a 390
   px cada barra medía 22 px y «10.2k» (32 px) se cortaba en «10.2», y a 480
   todavia se cortaban las de cinco caracteres. El pie cambia con ellos, para
   que no diga «6 meses» con cuatro a la vista. */
.fz-trend-units-narrow {
    display: none;
}

@media (max-width: 575.98px) {
    .fz-trend-months > li.fz-trend-older,
    .fz-trend-units-wide {
        display: none;
    }

    .fz-trend-units-narrow {
        display: inline;
    }
}

.fz-trend-bar {
    display: block;
    width: 100%;
    flex: none;
    border-radius: 3px 3px 0 0;
}

/*
 * Los mismos tokens que las barras del reporte, y por el mismo motivo: los
 * `*-subtle` de Bootstrap no llegan al 3:1 que WCAG 1.4.11 pide a un elemento no
 * textual. Verde para lo que entra, terracota para lo que sale (ADR 0021 §4).
 */
.fz-trend-bar-in {
    background-color: var(--fz-state-ok-fill);
}

.fz-trend-bar-out {
    background-color: var(--fz-money-out);
}

.fz-trend-month {
    font-size: var(--fz-amount-sm);
    font-weight: var(--fz-weight-heading);
    text-align: center;
    margin-top: var(--fz-space-1);
}

/*
 * El alto de una barra, en porcentaje entero del mes mayor.
 *
 * Ciento una reglas mecanicas, y no hay forma mas corta que sea honesta: la CSP
 * prohibe el `style=` y `attr()` fuera de `content` todavia no se puede usar. Es
 * el mismo patron que `.cat-fill-N`, con mas escalones.
 *
 * El 1 % es la resolucion, no un capricho: dos meses de 14 200 y 14 600 sobre un
 * maximo de 18 500 caen en 77 y 79, y se distinguen. Con escalones de 5 % se
 * verian identicos, que es justo la comparacion que la tarjeta existe para
 * hacer.
 *
 * El cero no desaparece: deja un trazo minimo para que un mes sin movimientos se
 * lea como un cero y no como un fallo de dibujo.
 */
.fz-trend-h-0 { height: 2px; }
.fz-trend-h-1 { height: calc((100% - var(--fz-trend-label)) * 1 / 100); }
.fz-trend-h-2 { height: calc((100% - var(--fz-trend-label)) * 2 / 100); }
.fz-trend-h-3 { height: calc((100% - var(--fz-trend-label)) * 3 / 100); }
.fz-trend-h-4 { height: calc((100% - var(--fz-trend-label)) * 4 / 100); }
.fz-trend-h-5 { height: calc((100% - var(--fz-trend-label)) * 5 / 100); }
.fz-trend-h-6 { height: calc((100% - var(--fz-trend-label)) * 6 / 100); }
.fz-trend-h-7 { height: calc((100% - var(--fz-trend-label)) * 7 / 100); }
.fz-trend-h-8 { height: calc((100% - var(--fz-trend-label)) * 8 / 100); }
.fz-trend-h-9 { height: calc((100% - var(--fz-trend-label)) * 9 / 100); }
.fz-trend-h-10 { height: calc((100% - var(--fz-trend-label)) * 10 / 100); }
.fz-trend-h-11 { height: calc((100% - var(--fz-trend-label)) * 11 / 100); }
.fz-trend-h-12 { height: calc((100% - var(--fz-trend-label)) * 12 / 100); }
.fz-trend-h-13 { height: calc((100% - var(--fz-trend-label)) * 13 / 100); }
.fz-trend-h-14 { height: calc((100% - var(--fz-trend-label)) * 14 / 100); }
.fz-trend-h-15 { height: calc((100% - var(--fz-trend-label)) * 15 / 100); }
.fz-trend-h-16 { height: calc((100% - var(--fz-trend-label)) * 16 / 100); }
.fz-trend-h-17 { height: calc((100% - var(--fz-trend-label)) * 17 / 100); }
.fz-trend-h-18 { height: calc((100% - var(--fz-trend-label)) * 18 / 100); }
.fz-trend-h-19 { height: calc((100% - var(--fz-trend-label)) * 19 / 100); }
.fz-trend-h-20 { height: calc((100% - var(--fz-trend-label)) * 20 / 100); }
.fz-trend-h-21 { height: calc((100% - var(--fz-trend-label)) * 21 / 100); }
.fz-trend-h-22 { height: calc((100% - var(--fz-trend-label)) * 22 / 100); }
.fz-trend-h-23 { height: calc((100% - var(--fz-trend-label)) * 23 / 100); }
.fz-trend-h-24 { height: calc((100% - var(--fz-trend-label)) * 24 / 100); }
.fz-trend-h-25 { height: calc((100% - var(--fz-trend-label)) * 25 / 100); }
.fz-trend-h-26 { height: calc((100% - var(--fz-trend-label)) * 26 / 100); }
.fz-trend-h-27 { height: calc((100% - var(--fz-trend-label)) * 27 / 100); }
.fz-trend-h-28 { height: calc((100% - var(--fz-trend-label)) * 28 / 100); }
.fz-trend-h-29 { height: calc((100% - var(--fz-trend-label)) * 29 / 100); }
.fz-trend-h-30 { height: calc((100% - var(--fz-trend-label)) * 30 / 100); }
.fz-trend-h-31 { height: calc((100% - var(--fz-trend-label)) * 31 / 100); }
.fz-trend-h-32 { height: calc((100% - var(--fz-trend-label)) * 32 / 100); }
.fz-trend-h-33 { height: calc((100% - var(--fz-trend-label)) * 33 / 100); }
.fz-trend-h-34 { height: calc((100% - var(--fz-trend-label)) * 34 / 100); }
.fz-trend-h-35 { height: calc((100% - var(--fz-trend-label)) * 35 / 100); }
.fz-trend-h-36 { height: calc((100% - var(--fz-trend-label)) * 36 / 100); }
.fz-trend-h-37 { height: calc((100% - var(--fz-trend-label)) * 37 / 100); }
.fz-trend-h-38 { height: calc((100% - var(--fz-trend-label)) * 38 / 100); }
.fz-trend-h-39 { height: calc((100% - var(--fz-trend-label)) * 39 / 100); }
.fz-trend-h-40 { height: calc((100% - var(--fz-trend-label)) * 40 / 100); }
.fz-trend-h-41 { height: calc((100% - var(--fz-trend-label)) * 41 / 100); }
.fz-trend-h-42 { height: calc((100% - var(--fz-trend-label)) * 42 / 100); }
.fz-trend-h-43 { height: calc((100% - var(--fz-trend-label)) * 43 / 100); }
.fz-trend-h-44 { height: calc((100% - var(--fz-trend-label)) * 44 / 100); }
.fz-trend-h-45 { height: calc((100% - var(--fz-trend-label)) * 45 / 100); }
.fz-trend-h-46 { height: calc((100% - var(--fz-trend-label)) * 46 / 100); }
.fz-trend-h-47 { height: calc((100% - var(--fz-trend-label)) * 47 / 100); }
.fz-trend-h-48 { height: calc((100% - var(--fz-trend-label)) * 48 / 100); }
.fz-trend-h-49 { height: calc((100% - var(--fz-trend-label)) * 49 / 100); }
.fz-trend-h-50 { height: calc((100% - var(--fz-trend-label)) * 50 / 100); }
.fz-trend-h-51 { height: calc((100% - var(--fz-trend-label)) * 51 / 100); }
.fz-trend-h-52 { height: calc((100% - var(--fz-trend-label)) * 52 / 100); }
.fz-trend-h-53 { height: calc((100% - var(--fz-trend-label)) * 53 / 100); }
.fz-trend-h-54 { height: calc((100% - var(--fz-trend-label)) * 54 / 100); }
.fz-trend-h-55 { height: calc((100% - var(--fz-trend-label)) * 55 / 100); }
.fz-trend-h-56 { height: calc((100% - var(--fz-trend-label)) * 56 / 100); }
.fz-trend-h-57 { height: calc((100% - var(--fz-trend-label)) * 57 / 100); }
.fz-trend-h-58 { height: calc((100% - var(--fz-trend-label)) * 58 / 100); }
.fz-trend-h-59 { height: calc((100% - var(--fz-trend-label)) * 59 / 100); }
.fz-trend-h-60 { height: calc((100% - var(--fz-trend-label)) * 60 / 100); }
.fz-trend-h-61 { height: calc((100% - var(--fz-trend-label)) * 61 / 100); }
.fz-trend-h-62 { height: calc((100% - var(--fz-trend-label)) * 62 / 100); }
.fz-trend-h-63 { height: calc((100% - var(--fz-trend-label)) * 63 / 100); }
.fz-trend-h-64 { height: calc((100% - var(--fz-trend-label)) * 64 / 100); }
.fz-trend-h-65 { height: calc((100% - var(--fz-trend-label)) * 65 / 100); }
.fz-trend-h-66 { height: calc((100% - var(--fz-trend-label)) * 66 / 100); }
.fz-trend-h-67 { height: calc((100% - var(--fz-trend-label)) * 67 / 100); }
.fz-trend-h-68 { height: calc((100% - var(--fz-trend-label)) * 68 / 100); }
.fz-trend-h-69 { height: calc((100% - var(--fz-trend-label)) * 69 / 100); }
.fz-trend-h-70 { height: calc((100% - var(--fz-trend-label)) * 70 / 100); }
.fz-trend-h-71 { height: calc((100% - var(--fz-trend-label)) * 71 / 100); }
.fz-trend-h-72 { height: calc((100% - var(--fz-trend-label)) * 72 / 100); }
.fz-trend-h-73 { height: calc((100% - var(--fz-trend-label)) * 73 / 100); }
.fz-trend-h-74 { height: calc((100% - var(--fz-trend-label)) * 74 / 100); }
.fz-trend-h-75 { height: calc((100% - var(--fz-trend-label)) * 75 / 100); }
.fz-trend-h-76 { height: calc((100% - var(--fz-trend-label)) * 76 / 100); }
.fz-trend-h-77 { height: calc((100% - var(--fz-trend-label)) * 77 / 100); }
.fz-trend-h-78 { height: calc((100% - var(--fz-trend-label)) * 78 / 100); }
.fz-trend-h-79 { height: calc((100% - var(--fz-trend-label)) * 79 / 100); }
.fz-trend-h-80 { height: calc((100% - var(--fz-trend-label)) * 80 / 100); }
.fz-trend-h-81 { height: calc((100% - var(--fz-trend-label)) * 81 / 100); }
.fz-trend-h-82 { height: calc((100% - var(--fz-trend-label)) * 82 / 100); }
.fz-trend-h-83 { height: calc((100% - var(--fz-trend-label)) * 83 / 100); }
.fz-trend-h-84 { height: calc((100% - var(--fz-trend-label)) * 84 / 100); }
.fz-trend-h-85 { height: calc((100% - var(--fz-trend-label)) * 85 / 100); }
.fz-trend-h-86 { height: calc((100% - var(--fz-trend-label)) * 86 / 100); }
.fz-trend-h-87 { height: calc((100% - var(--fz-trend-label)) * 87 / 100); }
.fz-trend-h-88 { height: calc((100% - var(--fz-trend-label)) * 88 / 100); }
.fz-trend-h-89 { height: calc((100% - var(--fz-trend-label)) * 89 / 100); }
.fz-trend-h-90 { height: calc((100% - var(--fz-trend-label)) * 90 / 100); }
.fz-trend-h-91 { height: calc((100% - var(--fz-trend-label)) * 91 / 100); }
.fz-trend-h-92 { height: calc((100% - var(--fz-trend-label)) * 92 / 100); }
.fz-trend-h-93 { height: calc((100% - var(--fz-trend-label)) * 93 / 100); }
.fz-trend-h-94 { height: calc((100% - var(--fz-trend-label)) * 94 / 100); }
.fz-trend-h-95 { height: calc((100% - var(--fz-trend-label)) * 95 / 100); }
.fz-trend-h-96 { height: calc((100% - var(--fz-trend-label)) * 96 / 100); }
.fz-trend-h-97 { height: calc((100% - var(--fz-trend-label)) * 97 / 100); }
.fz-trend-h-98 { height: calc((100% - var(--fz-trend-label)) * 98 / 100); }
.fz-trend-h-99 { height: calc((100% - var(--fz-trend-label)) * 99 / 100); }
.fz-trend-h-100 { height: calc((100% - var(--fz-trend-label)) * 100 / 100); }

/* Los doce colores de categoria, como clase y como relleno SVG: el servidor
   emite `class="cat-fill-7"` en vez de un hex, y el tema decide el tono. */
.cat-fill-1 { fill: var(--fz-cat-1); }
.cat-fill-2 { fill: var(--fz-cat-2); }
.cat-fill-3 { fill: var(--fz-cat-3); }
.cat-fill-4 { fill: var(--fz-cat-4); }
.cat-fill-5 { fill: var(--fz-cat-5); }
.cat-fill-6 { fill: var(--fz-cat-6); }
.cat-fill-7 { fill: var(--fz-cat-7); }
.cat-fill-8 { fill: var(--fz-cat-8); }
.cat-fill-9 { fill: var(--fz-cat-9); }
.cat-fill-10 { fill: var(--fz-cat-10); }
.cat-fill-11 { fill: var(--fz-cat-11); }
.cat-fill-12 { fill: var(--fz-cat-12); }

.cat-stroke-1 { stroke: var(--fz-cat-1); }
.cat-stroke-2 { stroke: var(--fz-cat-2); }
.cat-stroke-3 { stroke: var(--fz-cat-3); }
.cat-stroke-4 { stroke: var(--fz-cat-4); }
.cat-stroke-5 { stroke: var(--fz-cat-5); }
.cat-stroke-6 { stroke: var(--fz-cat-6); }
.cat-stroke-7 { stroke: var(--fz-cat-7); }
.cat-stroke-8 { stroke: var(--fz-cat-8); }
.cat-stroke-9 { stroke: var(--fz-cat-9); }
.cat-stroke-10 { stroke: var(--fz-cat-10); }
.cat-stroke-11 { stroke: var(--fz-cat-11); }
.cat-stroke-12 { stroke: var(--fz-cat-12); }

.cat-text-1 { color: var(--fz-cat-1); }
.cat-text-2 { color: var(--fz-cat-2); }
.cat-text-3 { color: var(--fz-cat-3); }
.cat-text-4 { color: var(--fz-cat-4); }
.cat-text-5 { color: var(--fz-cat-5); }
.cat-text-6 { color: var(--fz-cat-6); }
.cat-text-7 { color: var(--fz-cat-7); }
.cat-text-8 { color: var(--fz-cat-8); }
.cat-text-9 { color: var(--fz-cat-9); }
.cat-text-10 { color: var(--fz-cat-10); }
.cat-text-11 { color: var(--fz-cat-11); }
.cat-text-12 { color: var(--fz-cat-12); }

/* La superficie de color, para una tarjeta que lleva texto encima. Fija el
   color del texto junto al fondo a proposito: separarlos permitiria que una
   tarjeta acabara con fondo de color y texto del tema.

   `--fz-surface-tone` es el MISMO color para lo que se dibuja alrededor de la
   superficie y no debajo del texto: el borde y el brillo de una tarjeta de
   cuenta (ADR 0080). Es el tono del tema, asi que en oscuro es el par claro,
   que es el que brilla sobre el fondo de la pagina. */
.cat-surface-1 { background-color: var(--fz-cat-surface-1); --fz-surface-tone: var(--fz-cat-1); }
.cat-surface-2 { background-color: var(--fz-cat-surface-2); --fz-surface-tone: var(--fz-cat-2); }
.cat-surface-3 { background-color: var(--fz-cat-surface-3); --fz-surface-tone: var(--fz-cat-3); }
.cat-surface-4 { background-color: var(--fz-cat-surface-4); --fz-surface-tone: var(--fz-cat-4); }
.cat-surface-5 { background-color: var(--fz-cat-surface-5); --fz-surface-tone: var(--fz-cat-5); }
.cat-surface-6 { background-color: var(--fz-cat-surface-6); --fz-surface-tone: var(--fz-cat-6); }
.cat-surface-7 { background-color: var(--fz-cat-surface-7); --fz-surface-tone: var(--fz-cat-7); }
.cat-surface-8 { background-color: var(--fz-cat-surface-8); --fz-surface-tone: var(--fz-cat-8); }
.cat-surface-9 { background-color: var(--fz-cat-surface-9); --fz-surface-tone: var(--fz-cat-9); }
.cat-surface-10 { background-color: var(--fz-cat-surface-10); --fz-surface-tone: var(--fz-cat-10); }
.cat-surface-11 { background-color: var(--fz-cat-surface-11); --fz-surface-tone: var(--fz-cat-11); }
.cat-surface-12 { background-color: var(--fz-cat-surface-12); --fz-surface-tone: var(--fz-cat-12); }

[class*='cat-surface-'] {
    color: var(--fz-on-accent);
}

/* La muestra de color de una fila compacta. Aqui SI es `--fz-cat-N`: es una
   mancha pequena sobre la superficie del tema, que es justo para lo que ese
   token esta calibrado (3:1 como elemento grafico). */
.cat-dot-1 { background-color: var(--fz-cat-1); }
.cat-dot-2 { background-color: var(--fz-cat-2); }
.cat-dot-3 { background-color: var(--fz-cat-3); }
.cat-dot-4 { background-color: var(--fz-cat-4); }
.cat-dot-5 { background-color: var(--fz-cat-5); }
.cat-dot-6 { background-color: var(--fz-cat-6); }
.cat-dot-7 { background-color: var(--fz-cat-7); }
.cat-dot-8 { background-color: var(--fz-cat-8); }
.cat-dot-9 { background-color: var(--fz-cat-9); }
.cat-dot-10 { background-color: var(--fz-cat-10); }
.cat-dot-11 { background-color: var(--fz-cat-11); }
.cat-dot-12 { background-color: var(--fz-cat-12); }

/* ===========================================================================
   16. ACCESO  (contrato de clases: no renombrar)
   =========================================================================== */

.auth-shell {
    display: flex;
    align-items: center;
    justify-content: center;
    /*
     * `dvh` y no `vh`, con `vh` de reserva para quien no lo entienda.
     *
     * En un movil, `100vh` es la altura de la ventana CON la barra de direccion
     * retraida, o sea mas alta que lo que de verdad se ve. Una pantalla que
     * centra su contenido sobre esa altura lo centra respecto a una caja mayor
     * que la visible: la tarjeta de acceso queda baja y el boton de entrar
     * termina debajo del borde, justo en la primera pantalla que ve alguien que
     * llega por primera vez. `dvh` mide el viewport de verdad.
     */
    min-height: 100vh;
    min-height: 100dvh;
    padding: var(--fz-space-5);
    /* En la app instalada del iPhone la pagina empieza bajo el reloj (seccion
       18): un formulario largo, como el registro, asomaba ahi su borde. */
    padding-top: max(var(--fz-space-5), env(safe-area-inset-top, 0px));
}

.auth-card {
    width: 100%;
    max-width: 26rem;
    border: 1px solid var(--bs-border-color);
    box-shadow: var(--fz-elev-2);
}

.auth-card-wide {
    max-width: 34rem;
}

/* Los enlaces de la tarjeta de acceso («¿Olvidaste tu contraseña?», «Crea
   una»), sin subrayado: el color ya dice que son enlaces. Vuelve al pasar el
   puntero o con el foco del teclado. */
.auth-link {
    text-decoration: none;
}

.auth-link:hover,
.auth-link:focus-visible {
    text-decoration: underline;
}

/*
 * La pagina de confirmar el correo (ADR 0131 y 0140): el correo grande, para
 * que un error al teclearlo salte a la vista, y las dos respuestas a «¿esta
 * bien escrito?». «No, corregirlo» es un `<details>`: plegado mientras hay
 * plazo, abierto cuando ya vencio. La linea mide 44 px de alto, como cualquier
 * boton tactil.
 */
.fz-verify-email {
    margin-bottom: var(--fz-space-3);
    font-size: 1.25rem;
    font-weight: 700;
    overflow-wrap: anywhere;
    color: var(--bs-emphasis-color);
}

.fz-verify-deletion {
    padding: var(--fz-space-3);
    border-radius: var(--bs-border-radius);
    background-color: var(--bs-danger-bg-subtle);
    color: var(--bs-danger-text-emphasis);
}

.fz-verify-fix {
    border-top: 1px solid var(--bs-border-color);
}

.fz-verify-fix > summary {
    display: flex;
    align-items: center;
    min-block-size: 44px;
    color: var(--bs-link-color);
    cursor: pointer;
}

/*
 * Contrasenas (ADR 0132): el ojo pegado al campo, con su mismo borde y su mismo
 * fondo, y la barra de seguridad debajo. El boton y la barra nacen con `hidden`
 * y los descubre `password.js`; el `display` de aqui no gana a `[hidden]`, que
 * en Bootstrap lleva `!important`.
 */
.fz-password-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
    min-height: var(--fz-control-height);
    border: var(--bs-border-width) solid var(--bs-border-color);
    background-color: var(--fz-surface);
    color: var(--bs-secondary-color);
}

.fz-password-toggle:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-emphasis-color);
}

.fz-password-toggle .icon {
    width: 1.25rem;
    height: 1.25rem;
}

.fz-password-toggle[aria-pressed='true'] .fz-password-icon-show,
.fz-password-toggle[aria-pressed='false'] .fz-password-icon-hide {
    display: none;
}

/* En las tarjetas de Ajustes, el borde y el fondo en el tono de la tarjeta, como el campo. */
.fz-field .fz-password-toggle {
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 32%, var(--bs-border-color));
}

[data-bs-theme='dark'] .fz-field .fz-password-toggle {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 5%, var(--fz-surface-sunken));
}

.is-invalid ~ .fz-password-toggle {
    border-color: var(--bs-form-invalid-border-color);
}

/*
 * «Instala Finanzas» en el panel (ADR 0133): una franja con el icono de la app,
 * el texto y los botones. Nace con `hidden` y la descubre `pwa.js`; el `display`
 * de aqui no gana a `[hidden]`, que en Bootstrap lleva `!important`. En el
 * telefono los botones bajan a su propia fila.
 */
.fz-install {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--fz-space-3);
    /* Arriba en el telefono: con los pasos de iPhone la franja es alta y el
       icono quedaba flotando a media altura. */
    align-items: start;
    margin-bottom: var(--fz-space-4);
    padding: var(--fz-space-3) var(--fz-space-4);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--fz-surface);
    box-shadow: var(--fz-elev-1);
}

.fz-install-icon {
    inline-size: 3rem;
    block-size: 3rem;
    border-radius: 0.75rem;
    background-color: var(--fz-rail-bg);
}

.fz-install-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
}

.fz-install-lead,
.fz-install-how {
    margin: 0.125rem 0 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-install-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
    grid-column: 1 / -1;
}

/* Los pasos de iPhone y iPad: son el boton que Apple no deja poner, asi que van
   en el color del texto y con el icono de cada boton de Safari. */
.fz-install-ios {
    margin-top: var(--fz-space-2);
}

.fz-install-ios-title {
    margin: 0 0 var(--fz-space-1);
    font-size: 0.875rem;
    font-weight: 700;
}

.fz-install-steps {
    display: grid;
    gap: var(--fz-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: fz-paso;
    font-size: 0.875rem;
}

.fz-install-steps > li {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--fz-space-2);
    align-items: start;
    counter-increment: fz-paso;
}

.fz-install-steps > li > span:last-child::before {
    content: counter(fz-paso) '. ';
    font-weight: 700;
}

.fz-install-step-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 1.75rem;
    block-size: 1.75rem;
    border-radius: 0.5rem;
    background-color: var(--bs-tertiary-bg);
    color: var(--fz-brand);
}

.fz-install-step-icon .icon {
    inline-size: 1.125rem;
    block-size: 1.125rem;
}

@media (min-width: 768px) {
    .fz-install {
        grid-template-columns: auto 1fr auto;
        align-items: center;
    }

    .fz-install-actions {
        grid-column: auto;
    }
}

.fz-strength {
    margin-top: var(--fz-space-2);
}

.fz-strength-bar {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.25rem;
}

.fz-strength-bar > span {
    block-size: 0.375rem;
    border-radius: 999px;
    background-color: var(--bs-secondary-bg);
}

/* Debil: un tramo rojo. Aceptable: dos amarillos. Fuerte: los tres verdes. */
.fz-strength[data-level='1'] .fz-strength-bar > span:nth-child(1) {
    background-color: var(--bs-danger);
}

.fz-strength[data-level='2'] .fz-strength-bar > span:nth-child(-n + 2) {
    background-color: var(--bs-warning);
}

.fz-strength[data-level='3'] .fz-strength-bar > span {
    background-color: var(--bs-success);
}

.fz-strength-label {
    margin: var(--fz-space-1) 0 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-strength[data-level='1'] .fz-strength-label {
    color: var(--bs-danger-text-emphasis);
}

.fz-strength[data-level='2'] .fz-strength-label {
    color: var(--bs-warning-text-emphasis);
}

.fz-strength[data-level='3'] .fz-strength-label {
    color: var(--bs-success-text-emphasis);
}

/*
 * La marca, encima del titulo.
 *
 * Es la unica pantalla del producto que se ve sin haber entrado, y hasta ahora
 * no decia de que producto era: empezaba directamente en "Inicia sesion", que
 * es lo que hace que un acceso parezca el formulario de cualquier cosa. El
 * logo va con `alt` vacio porque el nombre esta escrito al lado; anunciarlo
 * seria decir "imagen, Finanzas, Finanzas".
 */
.auth-brand {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-5);
    font-size: 1.125rem;
    font-weight: var(--fz-weight-heading);
    letter-spacing: -0.01em;
}

/* Lo que promete la landing -dias gratis y sin tarjeta-, repetido en el registro,
   que es donde se decide (ADR 0072). Una etiqueta tenue de la marca, no un enlace. */
.fz-auth-trial {
    display: inline-block;
    padding: var(--fz-space-1) var(--fz-space-3);
    border-radius: 999px;
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    font-size: 0.875rem;
    font-weight: 600;
}

/* Un desplegable estrecho corta la opcion por la mitad de una palabra. El
   arreglo de fondo es que lo importante vaya DELANTE: por eso las monedas
   empiezan por su codigo ISO. */
.form-select {
    text-overflow: ellipsis;
}

/* ===========================================================================
   17. FRANJA DE RESUMEN DEL PANEL  (ADR 0021 §4)
   ===========================================================================

   Responde las dos preguntas con las que se abre la aplicacion: cuanto tengo y
   como voy este mes. Antes esto vivia al final de la columna derecha, que en un
   telefono es debajo del formulario entero y de la lista de movimientos.

   En movil se apila -saldo grande arriba, las tres cifras del mes debajo-; a
   partir de 576px el mes se pone al lado, porque ya cabe sin apretar el saldo.
   =========================================================================== */

.fz-hero-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-4);
}

/* "Este mes" se lee y no se ve: en fila, tres cifras con su rotulo ya dicen que
   son el mes, y un renglon mas solo haria la franja mas alta. Recortado y no
   `display: none`, para que siga nombrando la seccion (`aria-labelledby`). Se
   ve cuando la franja pasa a ser tarjeta junto a la grafica (seccion 21). */
.fz-hero-title {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Las tres cifras del mes: en fila desde que hay sitio, cada una con su rotulo
   encima. `space-between` y no `gap` fijo para que en pantallas anchas no se
   amontonen a la izquierda. */
.fz-hero-month {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--fz-space-3);
}

/* Cada cifra del mes con su baldosa, un escalon mas pequeña que la de la
   cabecera, como los mosaicos del reporte (ADR 0088). */
.fz-hero-month dt {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    font-size: 0.8125rem;
    margin-bottom: 0.125rem;
}

.fz-hero-month .fz-tile {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 0.5rem;
}

.fz-hero-month .fz-tile-icon {
    width: 1rem;
    height: 1rem;
}

.fz-hero-link {
    align-self: flex-start;
    font-size: 0.875rem;
}

@media (min-width: 576px) {
    /* Las cifras y el enlace en la misma linea: el enlace al reporte es salida,
       no accion principal, y en la esquina no compite con los importes.
       Eran dos columnas cuando el saldo total compartia franja con el mes; al
       mudarse el saldo al bloque de cuentas, la segunda se quedo vacia. */
    .fz-hero-body {
        flex-direction: row;
        align-items: end;
        justify-content: space-between;
        column-gap: var(--fz-space-6);
    }

    .fz-hero-month {
        flex: 1 1 auto;
    }

    .fz-hero-link {
        align-self: start;
    }
}

/* ===========================================================================
   17 bis. MIS CUENTAS  (ADR 0021 §4)
   ===========================================================================

   Cuanto tengo y en que cuentas, en el mismo bloque. El total vivia en una
   franja aparte y las cuentas al final de la columna derecha: dos bloques
   diciendo lo mismo con media pantalla en medio.

   Las tres primeras van como TARJETA con color de fondo y el resto como fila
   compacta. La rejilla es de tres columnas, asi que las destacadas llenan la
   primera fila y las compactas caen debajo sin una sola regla que las separe:
   lo hace el orden del documento, que es tambien el orden de tabulacion.
   =========================================================================== */

/* El encabezado de la pagina: la fecha de hoy y, debajo, el patrimonio en tres
   tarjetas -activos, patrimonio y deudas- (ADR 0079). */

/* La fecha va centrada. Es el unico rotulo de la pantalla que no compite con
   nada a los lados, y centrado se lee como lo que es: el dia del que habla todo
   lo demas. */
.fz-panel-head h1 {
    text-align: center;
}

/*
 * La rejilla de las tres tarjetas.
 *
 * En el DOCUMENTO el patrimonio va primero y sus dos mitades despues: es lo que
 * lee un lector de pantalla y lo que se ve en un telefono, donde van apiladas.
 * Desde 576 px las dos mitades se ponen lado a lado bajo el patrimonio, y desde
 * 1200 px las tres comparten fila con el patrimonio EN MEDIO: activos, menos
 * deudas, igual a... escrito en el orden en que se lee la resta. Es la unica vez
 * que la rejilla cambia el orden del documento, y no hay nada enfocable dentro
 * que pudiera quedar con un orden de tabulacion distinto del que se ve.
 */
.fz-worth {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3);
}

@media (min-width: 576px) {
    .fz-worth {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-areas:
            'net net'
            'assets debts';
        gap: var(--fz-space-4);
    }

    .fz-worth > .fz-networth {
        grid-area: net;
    }

    .fz-worth > .fz-worth-assets {
        grid-area: assets;
    }

    .fz-worth > .fz-worth-debts {
        grid-area: debts;
    }
}

/* Las de los lados son mas bajas que la del medio y van centradas en su alto,
   como en la referencia: la del medio sobresale por arriba y por abajo, que es
   lo que la hace la principal sin gritar. */
@media (min-width: 1200px) {
    .fz-worth {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1fr);
        grid-template-areas: 'assets net debts';
        align-items: center;
    }
}

/*
 * La tarjeta del medio: superficie propia, oscura en los dos temas.
 *
 * Pizarra azulada con un brillo verde en la esquina de abajo, como la
 * referencia. Era verde entero (ADR 0035); el verde se queda para lo que sube
 * -la flecha, la insignia y la barra de activos-, que asi se distingue del fondo.
 * Los tres tonos del fondo son OSCUROS: el blanco pasa de 7:1 sobre cualquiera
 * de ellos, que es lo que se le pide a un importe, y lo mide una prueba sobre
 * este archivo. Es oscura en los dos temas por lo mismo que las tarjetas de
 * cuenta: una superficie de color se separa de la pagina por su propio color.
 */
.fz-networth {
    overflow: hidden;
    color: var(--fz-on-accent);
    background-color: var(--fz-networth-to);
    background-image:
        radial-gradient(120% 90% at 100% 100%, var(--fz-networth-glow) 0%, transparent 65%),
        linear-gradient(160deg, var(--fz-networth-from) 0%, var(--fz-networth-to) 100%);
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: 0 0.75rem 2rem rgba(8, 12, 20, 0.28);
}

/* Las cifras de dentro se escalan con el ancho de la TARJETA, no de la ventana:
   la misma tarjeta mide 1 000 px sola en una tableta y 420 en medio de la fila. */
.fz-networth-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-4);
    container-type: inline-size;
}

.fz-networth-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-3);
}

/* El rotulo en versalitas: dice de que es la cifra y no compite con ella. */
.fz-networth-label {
    font-size: 0.875rem;
    font-weight: var(--fz-weight-heading);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.78);
}

.fz-networth-period {
    font-size: 0.8125rem;
    color: rgba(255, 255, 255, 0.72);
    white-space: nowrap;
}

/*
 * Cada moneda en su fila: el importe y, a su derecha, su linea.
 *
 * Con `subgrid` las lineas de todas las monedas empiezan en la misma vertical
 * aunque los importes midan distinto, y se leen como una sola grafica partida
 * por moneda. En un telefono no caben al lado: la linea baja bajo su importe.
 */
.fz-networth-heroes {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--fz-space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-networth-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: center;
    gap: var(--fz-space-2) var(--fz-space-4);
}

@container (min-width: 22rem) {
    .fz-networth-heroes {
        grid-template-columns: auto minmax(6rem, 1fr);
    }

    .fz-networth-hero {
        grid-column: 1 / -1;
        grid-template-columns: subgrid;
    }
}

.fz-networth-amount {
    font-size: clamp(1.75rem, 8cqi, 2.5rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Las demas monedas, un escalon por debajo: siguen siendo su cifra entera, sin
   convertir, pero no compiten por el primer vistazo con la del espacio. */
.fz-networth-hero-minor .fz-networth-amount {
    font-size: clamp(1.25rem, 5.5cqi, 1.75rem);
    font-weight: 600;
    color: rgba(255, 255, 255, 0.88);
}

/* La linea: trazo con brillo y un degradado debajo que se apaga hacia abajo. El
   SVG se estira a lo ancho (`preserveAspectRatio="none"`) y el trazo no, gracias
   a `vector-effect` en el marcado. */
.fz-networth-trail {
    display: block;
    width: 100%;
    height: 2.75rem;
    overflow: visible;
}

.fz-networth-hero-minor .fz-networth-trail {
    height: 2rem;
}

.fz-trail-line {
    fill: none;
    stroke: var(--fz-networth-line);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    filter: drop-shadow(0 0 3px rgba(140, 184, 255, 0.65));
}

.fz-trail-stop-top {
    stop-color: var(--fz-networth-line);
    stop-opacity: 0.32;
}

.fz-trail-stop-bottom {
    stop-color: var(--fz-networth-line);
    stop-opacity: 0;
}

/* «Distribución»: una barra por moneda, con los dos porcentajes debajo. */
.fz-networth-split {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-2);
}

.fz-networth-sub {
    margin-bottom: 0;
    font-size: 0.875rem;
    font-weight: var(--fz-weight-heading);
    color: rgba(255, 255, 255, 0.86);
}

.fz-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.375rem;
}

/* Con varias monedas, el simbolo a la izquierda de cada barra: los porcentajes
   no llevan moneda que los distinga. */
.fz-split-labeled {
    grid-template-columns: 2rem minmax(0, 1fr);
    column-gap: var(--fz-space-2);
    align-items: center;
}

.fz-split-labeled .fz-split-legend {
    grid-column: 2;
}

.fz-split-symbol {
    font-size: 0.8125rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.78);
}

.fz-split-bar {
    display: block;
    width: 100%;
    height: 0.625rem;
    clip-path: inset(0 round 999px);
}

.fz-split-assets {
    fill: var(--fz-networth-accent);
}

.fz-split-debts {
    fill: rgba(255, 255, 255, 0.4);
}

.fz-split-legend {
    display: flex;
    justify-content: space-between;
    gap: var(--fz-space-3);
    font-size: 0.8125rem;
    color: rgba(255, 255, 255, 0.78);
}

.fz-split-share {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--fz-on-accent);
}

/* «Resumen del mes»: la franja de abajo, mas oscura, con la insignia de cada
   moneda. Mas oscura y no mas clara, por el mismo contraste de arriba. */
.fz-networth-foot {
    padding: var(--fz-space-3) var(--bs-card-spacer-x);
    background: rgba(0, 0, 0, 0.22);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.fz-networth-foot .fz-networth-sub {
    margin-bottom: var(--fz-space-2);
}

.fz-networth-months {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-networth-month {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-1) var(--fz-space-3);
}

.fz-networth-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.1875rem 0.625rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--fz-on-accent);
    background: rgba(255, 255, 255, 0.12);
}

.fz-networth-badge.up {
    color: var(--fz-networth-accent);
    background: rgba(123, 228, 149, 0.16);
}

.fz-networth-badge.down {
    color: var(--fz-networth-down);
    background: rgba(255, 201, 122, 0.16);
}

.fz-networth-change {
    font-size: 0.875rem;
    color: rgba(255, 255, 255, 0.88);
}

/*
 * La flecha es un triangulo de CSS, no un caracter.
 *
 * Un "▲" en la plantilla seria texto visible que no sale del catalogo, y ademas
 * los lectores de pantalla lo leen justo delante de una frase que ya dice lo que
 * pasa. Dibujado con bordes no es texto, no se lee y no se queda sin traducir.
 *
 * NUNCA rojo para la bajada: sobre fondo oscuro con verde al lado, el rojo es la
 * peor pareja posible para la forma mas comun de daltonismo. La caida va en
 * ambar, que se separa del verde por luminosidad y no solo por tono.
 */
.fz-networth-arrow {
    width: 0;
    height: 0;
    flex: 0 0 auto;
    border-left: 0.3125rem solid transparent;
    border-right: 0.3125rem solid transparent;
}

.fz-networth-arrow.up {
    border-bottom: 0.375rem solid currentColor;
}

.fz-networth-arrow.down {
    border-top: 0.375rem solid currentColor;
}

/* Sin movimiento no hay direccion: una raya, no un triangulo. */
.fz-networth-arrow.flat {
    width: 0.5rem;
    border: 0;
    border-top: 0.125rem solid currentColor;
}

/*
 * Las tarjetas de los lados: «Total activos» y «Total deudas».
 *
 * Tarjetas normales del tema, sin superficie de color: la unica con color es la
 * del medio. Cada moneda en su fila, con la muestra de su lado de la resta -un
 * mas verde, un menos gris- y su total. La deuda va en positivo y sin rojo: el
 * signo ya lo dicen el rotulo y la muestra, y deber no es un error (ADR 0021 §4).
 *
 * La cifra se escala con el ancho de la tarjeta (`cqi`), que entre 576 y 1199 px
 * es media fila y desde 1200 un tercio.
 */
.fz-worth-side .card-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-3);
    container-type: inline-size;
}

.fz-worth-title {
    margin-bottom: 0;
    font-size: 1.375rem;
    font-weight: 500;
    color: var(--bs-secondary-color);
}

.fz-worth-list {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-worth-row {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-width: 0;
}

.fz-worth-amount {
    min-width: 0;
    font-size: clamp(1.25rem, 9.5cqi, 2.25rem);
    font-weight: 600;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* La muestra: un circulo con un mas o un menos dibujados con dos barras de CSS.
   Decorativa (`aria-hidden`): lo que significa lo dice el titulo de la tarjeta. */
.fz-worth-sign {
    position: relative;
    flex: none;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    border-radius: 50%;
    background: var(--fz-worth-sign-bg);
}

.fz-worth-sign::before,
.fz-worth-sign::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    inline-size: 1.125rem;
    block-size: 0.1875rem;
    margin: -0.09375rem 0 0 -0.5625rem;
    border-radius: 2px;
    background: var(--fz-worth-sign-fg);
}

.fz-worth-assets {
    --fz-worth-sign-bg: var(--fz-worth-plus-bg);
    --fz-worth-sign-fg: var(--fz-worth-plus-fg);
}

.fz-worth-assets .fz-worth-sign::after {
    transform: rotate(90deg);
}

.fz-worth-debts {
    --fz-worth-sign-bg: var(--fz-worth-minus-bg);
    --fz-worth-sign-fg: var(--fz-worth-minus-fg);
}

.fz-worth-debts .fz-worth-sign::after {
    display: none;
}

/* En un telefono las tarjetas de los lados van a lo ancho, y la cifra, que se
   escala con la tarjeta, saldria mas grande que la del patrimonio: se fija un
   escalon por debajo de ella. */
@media (max-width: 575.98px) {
    .fz-worth-sign {
        inline-size: 2.25rem;
        block-size: 2.25rem;
    }

    .fz-worth-amount {
        font-size: 1.5rem;
    }
}

.fz-accounts-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-2);
}

/*
 * Aqui vivia la regla que apagaba el importe grande cuando faltaba una tasa.
 *
 * Ya no hace falta ninguna: la tarjeta no convierte nada. Cada moneda ensena lo
 * suyo -patrimonio, variacion, activos y deudas- y todo eso es cierto exista o
 * no la tasa del dia. Un estado menos que mantener, y no por haberlo escondido:
 * por haberse quedado sin causa (ADR 0035).
 */

/*
 * El resumen de /accounts (ADR 0081): disponible, deuda en tarjetas y ahorros.
 * La tarjeta es la comun (`.fz-kpi`, seccion 10 bis); aqui va lo que solo
 * tiene /accounts: el desglose y la barra de la deuda.
 *
 * Su fila de tres (`.fz-summary`) se fue con el ADR 0110: las cifras solo salen
 * como cabecera de su columna en el tablero de abajo, tambien en la pestaña de
 * un tipo, donde sale solo la suya.
 */

/*
 * El tablero (ADR 0110): cada cifra del resumen encabeza la columna de sus
 * cuentas. Disponible lleva el efectivo y los bancos, Deuda en tarjetas las
 * tarjetas de credito y Ahorros las cuentas de ahorro.
 *
 * Por debajo de 992 px cada grupo va a lo ancho, uno tras otro, y sus cuentas
 * en una columna (telefono) o dos. Desde 992 px, tres columnas: cada grupo
 * ocupa dos filas del tablero con `subgrid`, asi las tres cifras miden lo
 * mismo -la regla del resumen- y las tres listas empiezan a la misma altura.
 * Sin `subgrid` el tablero sigue funcionando; solo las cifras dejan de igualar
 * su alto.
 */
.fz-board {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-4);
    margin-bottom: var(--fz-space-4);
}

.fz-board-group {
    display: grid;
    align-content: start;
    gap: var(--fz-space-3);
    min-width: 0;
}

/* `align-content: start`: la lista se estira al alto de la columna mas larga
   y, sin esto, repartia ese alto entre sus filas y separaba las tarjetas. */
.fz-board-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    align-content: start;
    gap: var(--fz-space-3);
    margin: 0;
}

@media (min-width: 576px) and (max-width: 991.98px) {
    .fz-board-list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 992px) {
    .fz-board {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        grid-template-rows: auto auto;
        column-gap: var(--fz-space-3);
        row-gap: 0;
    }

    .fz-board-group {
        grid-row: span 2;
        grid-template-rows: subgrid;
        row-gap: var(--fz-space-3);
    }

    /* La pestaña de un tipo: su columna sola. La cifra se queda con el ancho de
       una columna del tablero, en la primera, y las cuentas ocupan las tres con
       las mismas medidas; cambiar de pestaña no cambia el tamaño de nada. */
    .fz-board-solo .fz-board-group {
        grid-column: 1 / -1;
        grid-template-columns: subgrid;
    }

    .fz-board-solo .fz-board-list {
        grid-column: 1 / -1;
        grid-template-columns: subgrid;
    }
}

/* El desglose de lo disponible: efectivo y bancos, rotulo a la izquierda y
   cifras a la derecha, bajo una raya como la que separa las monedas de la
   deuda. */
.fz-kpi-split {
    display: grid;
    gap: 0.25rem;
    margin: var(--fz-space-2) 0 0;
    padding-top: var(--fz-space-2);
    border-top: 1px solid var(--bs-border-color-translucent);
    font-size: 0.8125rem;
}

.fz-kpi-split div {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0 var(--fz-space-3);
}

.fz-kpi-split dt {
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-kpi-split dd {
    margin: 0;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--bs-body-color);
    text-align: end;
}

.fz-kpi-debt {
    display: grid;
    gap: 0.125rem;
}

.fz-kpi-debt + .fz-kpi-debt {
    margin-top: var(--fz-space-1);
    padding-top: var(--fz-space-2);
    border-top: 1px solid var(--bs-border-color-translucent);
}

.fz-kpi-debt-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0 var(--fz-space-3);
}

/* La barra no baja de 4 rem: con el texto en `auto`, a 768 px se quedaba en un
   punto. El texto puede partirse; la barra no puede desaparecer. */
.fz-kpi-debt-bar {
    display: grid;
    grid-template-columns: minmax(4rem, 1fr) minmax(0, auto);
    align-items: center;
    gap: var(--fz-space-3);
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-kpi-debt-bar .budget-bar {
    margin: 0;
}

.fz-account-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3);
    /* Sin esto (el default de grid es `stretch`), una tarjeta con mas
       contenido que sus vecinas de fila -una tarjeta de credito con deuda
       real, con su cuadricula de datos y su nota de proyeccion (ADR 0040)-
       las estira a todas a su misma altura, dejando un hueco vacio dentro de
       cada tarjeta corta en vez de simplemente ser mas alta que ellas. Cada
       tarjeta mide lo que necesita su propio contenido, no lo que necesita la
       mas larga de la fila. */
    align-items: start;
}

/* La fila compacta: el nombre con su muestra de color, el importe y que
   significa. Sin fondo propio -vive sobre la tarjeta- y con el hairline como
   unico limite, igual que una fila de listado. */
.fz-account {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: var(--fz-space-3);
    padding: var(--fz-space-3);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    min-width: 0;
}

.fz-account-name {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-width: 0;
    font-weight: 500;
}

/* `flex: none` y no un ancho a secas: dentro de un flex, la muestra se
   encogeria antes que el nombre y en un nombre largo acabaria en una raya. */
/* La muestra de color de una fila compacta y la de la leyenda del presupuesto
   (ADR 0029): misma mancha y mismo tamano, asi que una sola regla. Dos copias
   acabarian separandose en el primer retoque. */
.fz-account-dot,
.fz-budget-dot {
    flex: none;
    inline-size: 0.75rem;
    block-size: 0.75rem;
    border-radius: var(--bs-border-radius-sm);
}

.fz-account-amount {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    text-align: end;
    white-space: nowrap;
}

/* El subtitulo ocupa la primera columna de la segunda fila: debajo del nombre y
   no debajo del importe, porque describe la cuenta, no la cifra. */
.fz-account-state {
    grid-column: 1;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* Un sobregiro es de las pocas cosas del panel que estan MAL, y el rojo esta
   reservado justamente para eso (ADR 0021 §4). */
.fz-account-alert {
    color: var(--bs-danger-text-emphasis);
    font-weight: 500;
}

/* --- La destacada ---------------------------------------------------------

   Mismo marcado, otra jerarquia: el color pasa a ser el fondo, el importe sube
   de talla y el nombre se va arriba del todo. El fondo lo pone `cat-surface-N`
   desde el servidor. */

.fz-account-featured {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--fz-space-4);
    row-gap: var(--fz-space-1);
}

/*
 * La piel de una tarjeta de color (ADR 0080): la destacada, aqui y en el
 * panel, y en /accounts tambien la compacta (`.fz-account-colored`).
 *
 * El degradado de encima solo OSCURECE. La superficie ya esta medida a 7:1 con
 * blanco, y aclarar una esquina -como hacia la imagen de referencia- bajaria
 * el texto de ese minimo justo ahi. El brillo lo ponen el borde y el halo, en
 * el tono del mismo color (`--fz-surface-tone`, que fija `cat-surface-N`).
 *
 * En claro el borde es un filo blanco y el halo una sombra del color: un halo
 * luminoso sobre fondo claro se lee como una mancha.
 */
.fz-account-featured,
.fz-account-colored {
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 0.75rem;
    background-image: linear-gradient(145deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.36) 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.14),
        0 14px 26px -14px color-mix(in srgb, var(--fz-surface-tone) 90%, transparent);
}

[data-bs-theme='dark'] :is(.fz-account-featured, .fz-account-colored) {
    border-color: color-mix(in srgb, var(--fz-surface-tone) 45%, transparent);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.12),
        0 14px 30px -14px rgba(0, 0, 0, 0.7),
        0 0 28px -6px color-mix(in srgb, var(--fz-surface-tone) 45%, transparent);
}

.fz-account-featured .fz-account-amount {
    font-size: 1.5rem;
    font-weight: 700;
    text-align: start;
    line-height: 1.2;
}

/* Sobre un fondo de color mandan los tokens de encima, no los del tema: el
   `--bs-secondary-color` de la fila compacta es gris oscuro y sobre terracota
   no se leeria. El sobregiro tampoco se pinta de rojo aqui -rojo sobre color
   saturado es ilegible-: lo dice la palabra, que ya esta traducida. */
.fz-account-featured .fz-account-state,
.fz-account-featured .fz-account-alert,
.fz-account-colored .fz-account-state,
.fz-account-colored .fz-account-alert {
    color: var(--fz-on-accent-muted);
    font-weight: 400;
}

.fz-account-featured .fz-account-name {
    font-weight: 400;
    font-size: 0.875rem;
    color: var(--fz-on-accent-muted);
}

/* El importe de una destacada baja un escalon en pantalla estrecha, por la
   misma razon que la escala de importes: a 390px una cifra larga a 24px no
   cabe, y partir un numero se lee mal justo cuando importa. */
@media (max-width: 575.98px) {
    .fz-account-featured .fz-account-amount {
        font-size: 1.25rem;
    }
}

/*
 * De aqui para abajo, /accounts y no el panel: es la pantalla de GESTION, asi
 * que sus tarjetas llevan lo que la del panel no necesita -el tipo en la
 * destacada, "Editar"/"Archivar" en todas-. El panel no incluye este marcado
 * en su plantilla, asi que no le cambia una sola tarjeta.
 */

/* El tipo, con su icono, encima del nombre de una destacada. Sustituye a la
   muestra de color -aqui el fondo ENTERO ya es el color- por un dato mas util
   en la pantalla donde se administra: de que tipo es esta cuenta. */
.fz-account-type {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    font-size: 0.8125rem;
    color: var(--fz-on-accent-muted);
    margin-bottom: var(--fz-space-2);
}

/* Y la misma talla para el icono que el panel pone junto al nombre de una
   destacada (`.fz-account-icon`): es el mismo icono de tipo en otro sitio. */
.fz-account-type svg,
.fz-account-icon {
    width: 1.125rem;
    height: 1.125rem;
    flex: 0 0 auto;
}

/* El "X % de linea usada" de una tarjeta de credito (ADR 0040): mismo
   tratamiento tipografico que `.fz-account-state` de una destacada, porque es
   la misma clase de dato -texto de apoyo bajo el importe grande-. Solo
   aparece dentro de `.fz-account-featured`: el bloque entero se omite en la
   vista para cualquier otra cuenta. */
.fz-account-featured .fz-account-usage {
    display: block;
    font-size: 0.8125rem;
    color: var(--fz-on-accent-muted);
}

.fz-account-featured .budget-bar {
    margin-block: var(--fz-space-1);
}

/* La pista de la barra usa un token de tema pensado para una superficie
   neutra; sobre el fondo de color no se veia. Va HUNDIDA -negro translucido,
   como la franja del panel (ADR 0079)- y el relleno en tonos claros de su
   estado (ADR 0080): el indigo de siempre desaparecia sobre una tarjeta
   violeta. Los seis tonos pasan de 3:1 contra la pista de las doce
   superficies (`TarjetasDeCuentaTest`). */
.fz-account-featured .budget-track {
    fill: rgba(0, 0, 0, 0.3);
}

.fz-account-featured .budget-on-track {
    fill: url(#fz-grad-color-on-track) var(--fz-on-color-bar-on);
}

.fz-account-featured .budget-warning {
    fill: url(#fz-grad-color-warning) var(--fz-on-color-bar-warn);
}

.fz-account-featured .budget-exceeded {
    fill: url(#fz-grad-color-over) var(--fz-on-color-bar-over);
}

/* Los datos de apoyo de una tarjeta de credito -vencimiento, minimo, interes,
   saldo inicial- van en cuadricula de etiqueta+valor y no en frases sueltas
   (ADR 0040): cuatro oraciones apiladas se leen una por una, cuatro pares
   etiqueta/valor se leen de un vistazo, que es justo el problema que hizo
   pedir este rediseño. Dos columnas fijas: con cuatro datos como mucho, un
   ancho que se adapta solo (`auto-fit`) dejaba una sola columna en movil y una
   fila que no cuadraba con la de arriba en escritorio. */
.fz-account-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--fz-space-3);
    row-gap: var(--fz-space-2);
    margin-block: var(--fz-space-3) var(--fz-space-1);
}

.fz-account-stat {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

/* Mayuscula pequeña y muy tenue: es la etiqueta, no el dato -el ojo tiene que
   ir al VALOR de abajo primero en una segunda pasada, no leer la etiqueta
   como si fuera la respuesta. */
.fz-account-stat-label {
    font-size: 0.6875rem;
    line-height: 1.2;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--fz-on-accent-muted);
}

.fz-account-stat-value {
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
    color: var(--fz-on-accent);
    overflow-wrap: break-word;
}

/* La proyeccion de "pagando el minimo, terminarias en..." no es un dato mas:
   es la conclusion de todos los de arriba, y por eso no va en la cuadricula
   -ahi competiria con cuatro numeros por la atencion- sino como una nota
   aparte, con su propio fondo para que se note que es la frase que importa
   leer entera. */
.fz-account-insight {
    margin: 0;
    padding: var(--fz-space-2) var(--fz-space-3);
    /* Hundida, como la franja del panel (ADR 0079 y 0080): el blanco
       translucido de antes aclaraba el fondo justo debajo de la frase. */
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: var(--bs-border-radius-sm);
    background: rgba(0, 0, 0, 0.22);
    font-size: 0.8125rem;
    line-height: 1.3;
    color: var(--fz-on-accent);
}

/*
 * La meta de una cuenta (ADR 0110): «Meta 45.0 % de S/ 6,000.00», el estado y
 * la barra, en una franja hundida como la nota de la tarjeta de credito. Toda
 * la franja es UN enlace a la ficha de la meta, de mas de 44 px de alto.
 *
 * Los textos y el estado son los de /goals (`GoalPresenter`). El estado se dice
 * con la palabra; el color de la insignia y de la barra lo acompañan, en los
 * tonos claros que aguantan la tarjeta de color (`TarjetasDeCuentaTest`).
 */
.fz-account-goal {
    grid-column: 1 / -1;
    display: grid;
    gap: 0.375rem;
    margin-top: var(--fz-space-3);
    padding: var(--fz-space-2) var(--fz-space-3);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: var(--bs-border-radius-sm);
    background: rgba(0, 0, 0, 0.22);
    color: var(--fz-on-accent);
    text-decoration: none;
}

.fz-account-goal:hover {
    background: rgba(0, 0, 0, 0.32);
    color: var(--fz-on-accent);
}

.fz-account-goal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2);
    font-size: 0.8125rem;
    line-height: 1.3;
}

/* Si no cabe en una linea, se parte entre sus piezas -«Meta», el porcentaje y
   el objetivo- y la insignia se queda arriba a la derecha. Ninguna pieza se
   parte por dentro: «de S/ 25,000.00» cortado se lee mal. */
.fz-account-goal-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 0.375rem;
    min-width: 0;
    color: var(--fz-on-accent-muted);
}

.fz-account-goal-title svg {
    width: 1rem;
    height: 1rem;
    flex: none;
}

/* La meta que no se llama como su cuenta abre con su nombre en grande, como una
   tarjeta dentro de la tarjeta (ADR 0110), un escalon por debajo del nombre de
   la cuenta. Sus cifras bajan a su propia linea, alineadas con el nombre y no
   con la bandera. */
.fz-account-goal-name {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--fz-on-accent);
}

.fz-account-goal-name svg {
    width: 1rem;
    height: 1rem;
    flex: none;
}

.fz-account-goal-figures {
    display: flex;
    flex-wrap: wrap;
    gap: 0 0.375rem;
    padding-inline-start: 1.375rem;
    font-size: 0.8125rem;
    line-height: 1.3;
    color: var(--fz-on-accent-muted);
}

.fz-account-goal-share,
.fz-account-goal-target {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.fz-account-goal-share {
    font-weight: 600;
    color: var(--fz-on-accent);
}

.fz-account-goal-badge {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: 0.25rem;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    /* Al 10 % y no mas: al 14 % el rojo claro de «Atrasada» bajaba de 4.5:1
       sobre la superficie mas clara (`TarjetasDeCuentaTest`). */
    background: rgba(255, 255, 255, 0.1);
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.fz-account-goal-badge svg {
    width: 0.875rem;
    height: 0.875rem;
}

.fz-account-goal-achieved .fz-account-goal-badge {
    color: var(--fz-on-color-bar-ok);
}

.fz-account-goal-behind .fz-account-goal-badge,
.fz-account-goal-overdrawn .fz-account-goal-badge {
    color: var(--fz-on-color-bar-over);
}

.fz-account-goal .budget-bar {
    margin: 0;
}

/* La pista hundida y los rellenos claros de la barra del limite (ADR 0080),
   con el vocabulario de las metas: atrasada y en negativo en rojo, como en
   /goals, y alcanzada en verde. */
.fz-account-goal .budget-track {
    fill: rgba(0, 0, 0, 0.3);
}

.fz-account-goal .budget-on-track {
    fill: url(#fz-grad-color-on-track) var(--fz-on-color-bar-on);
}

.fz-account-goal .budget-behind,
.fz-account-goal .budget-overdrawn {
    fill: url(#fz-grad-color-over) var(--fz-on-color-bar-over);
}

.fz-account-goal .budget-achieved {
    fill: url(#fz-grad-color-ok) var(--fz-on-color-bar-ok);
}

/* Movimientos, Editar y Archivar (o Restaurar) de una tarjeta. Ocupan las dos
   columnas de la rejilla -`grid-column: 1 / -1`- y por eso caen en su propia
   fila tanto en la compacta como en la destacada, sin descuadrar el nombre ni
   el importe. Centradas y con forma de boton -borde, relleno al pasar el
   mouse- en vez de enlaces de texto sueltos: son las acciones de la tarjeta y
   tienen que leerse como tal, no como un pie de pagina.

   Desde el ADR 0080 miden los 44 px del objetivo tactil (ADR 0021 §6); eran
   de 30. Si no caben en una fila -cuatro columnas entre 1200 y 1439 px, o el
   riel desplegado-, Editar y Archivar bajan JUNTOS a la segunda: van en su
   propio grupo (`.fz-account-more`), y asi «Movimientos», que es la que se
   usa, nunca se queda partida de las otras dos por donde caiga. */
.fz-account-actions {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--fz-space-2);
    margin-top: var(--fz-space-2);
    padding-top: var(--fz-space-4);
    border-top: 1px solid var(--bs-border-color-translucent);
}

.fz-account-more {
    display: flex;
    gap: var(--fz-space-2);
}

.fz-account-actions a,
.fz-account-actions button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--fz-control-height);
    padding: 0.5rem 0.75rem;
    background: none;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    font: inherit;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
    cursor: pointer;
}

.fz-account-actions a:hover,
.fz-account-actions button:hover {
    color: var(--bs-body-color);
    background: var(--bs-secondary-bg);
    border-color: var(--bs-secondary-color);
}

/* Sobre el fondo de color mandan los tokens de encima (ADR 0021 §5): un gris
   de tema no se leeria sobre indigo. El boton es un vidrio -blanco al 6 %- con
   el borde del tono de la tarjeta en oscuro, como la referencia; en claro el
   tono es oscuro y se perderia, asi que ahi es blanco translucido. */
:is(.fz-account-featured, .fz-account-colored) .fz-account-actions {
    border-top-color: rgba(255, 255, 255, 0.24);
}

:is(.fz-account-featured, .fz-account-colored) .fz-account-actions :is(a, button) {
    color: var(--fz-on-accent);
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.34);
}

[data-bs-theme='dark'] :is(.fz-account-featured, .fz-account-colored) .fz-account-actions :is(a, button) {
    border-color: color-mix(in srgb, var(--fz-surface-tone) 62%, transparent);
}

:is(.fz-account-featured, .fz-account-colored) .fz-account-actions :is(a, button):hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.5);
}

/* El anillo de foco de la seccion 4 usa `--fz-brand`, que en tema claro es un
   indigo casi tan oscuro como estos fondos (contraste ~1.1:1 contra los doce
   `cat-surface-*`: invisible). El blanco si funciona contra los doce, en los
   dos temas, porque el fondo no cambia con el tema (ADR 0021 §5). */
:is(.fz-account-featured, .fz-account-colored) :where(a, button, [tabindex]):focus-visible {
    outline-color: var(--fz-on-accent);
}

@media (min-width: 576px) {
    .fz-account-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 992px) {
    .fz-account-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* Cuatro en pantalla ancha, y el podio sube a cuatro con ella (ADR 0026): el
   numero de destacadas y el de columnas van juntos para que las tarjetas
   grandes llenen la fila justa y no compartan linea con una fila compacta.
   A 1200 px cada columna pasa de 270 px, de sobra para un importe de 1.5 rem
   como "USD 38,867.47"; por debajo se queda en tres, que es donde ese importe
   empezaba a apretar.

   Solo las CUENTAS. Deudas y metas cortan a tres tarjetas, asi que con tres
   columnas ya llenan su fila; a cuatro dejarian un hueco fijo. */
@media (min-width: 1200px) {
    .fz-account-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* ===========================================================================
   «Mis cuentas» en el panel (ADR 0079)
   ===========================================================================

   Solo dentro de `.fz-accounts`, que es la tarjeta del panel: /accounts usa las
   mismas tarjetas con su tipo, su cuadricula de tarjeta y sus acciones, y nada
   de esto le aplica. */

.fz-accounts-head {
    align-items: center;
    margin-bottom: var(--fz-space-3);
}

.fz-accounts-title {
    font-size: 1.25rem;
    font-weight: 500;
}

/* Los bloques de debajo de «Mis cuentas» abren con la baldosa de su modulo
   y el titulo a la talla de «Mis cuentas» (ADR 0088), con los tonos del
   reporte (ADR 0087). El titulo puede partirse en un telefono: la baldosa
   se queda centrada con el. */
.fz-block-title {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-width: 0;
}

.fz-block-title h2 {
    min-width: 0;
    text-wrap: balance;
}

/* La cabecera de los movimientos se alineaba por la linea base; con la
   baldosa delante, el enlace «Ver todos» va centrado con ella. */
.fz-mov-card-head:has(.fz-block-title) {
    align-items: center;
}

.fz-accounts-all {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.875rem;
    white-space: nowrap;
}

.fz-accounts-all-icon {
    inline-size: 1.125rem;
    block-size: 1.125rem;
    flex: none;
}

/*
 * La destacada: nombre e icono arriba, la marca en la esquina, el saldo grande
 * y la franja al pie.
 *
 * La piel -degradado que solo oscurece, borde y halo del tono- ya no es suya:
 * es la de toda tarjeta de color (ADR 0080), la misma que en /accounts. Aqui
 * solo queda la composicion.
 *
 * `align-self: stretch` iguala las tres de la fila aunque una lleve dos lineas
 * de franja, y la franja baja al pie con la ultima fila en `1fr`.
 */
.fz-accounts .fz-account-featured {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto 1fr;
    align-items: center;
    align-self: stretch;
    row-gap: var(--fz-space-2);
    column-gap: var(--fz-space-3);
    padding: var(--fz-space-4);
}

.fz-accounts .fz-account-featured .fz-account-amount {
    grid-column: 1 / -1;
    font-size: 1.75rem;
}

@media (max-width: 575.98px) {
    .fz-accounts .fz-account-featured .fz-account-amount {
        font-size: 1.5rem;
    }
}

/* La marca de la esquina: el banco que escribio el usuario, con aire de rotulo;
   sin banco, el icono del tipo en grande y de adorno. */
.fz-account-mark {
    max-inline-size: 9rem;
    font-size: 1.0625rem;
    font-weight: 800;
    font-style: italic;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--fz-on-accent);
}

.fz-account-mark-icon {
    inline-size: 2rem;
    block-size: 2rem;
    color: var(--fz-on-accent-muted);
}

/* El estado solo se VE si es un sobregiro; «Disponible» o «Por pagar» los dice
   ya la franja, y se quedan para el lector de pantalla. El sobregiro va en una
   pastilla oscura: rojo sobre el color de la tarjeta no se leeria. */
.fz-accounts .fz-account-featured .fz-account-state:not(.fz-account-alert) {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.fz-accounts .fz-account-featured .fz-account-alert {
    grid-column: 1 / -1;
    justify-self: start;
    align-self: start;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--fz-on-accent);
    background: rgba(0, 0, 0, 0.3);
}

/* `position: relative` es el ancla del estado escondido. */
.fz-accounts .fz-account-featured {
    position: relative;
}

/*
 * La franja: un dato segun el tipo de cuenta, al pie de la tarjeta.
 *
 * Banda hundida -fondo mas oscuro, borde claro- con el rotulo a la izquierda y
 * la cifra a la derecha, como la referencia. La de la tarjeta de credito no
 * lleva banda: son dos lineas -cuando vence, y la barra del limite- y en una
 * banda no cabrian sin apretarse.
 */
.fz-account-glance {
    grid-column: 1 / -1;
    align-self: end;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-1) var(--fz-space-3);
    min-width: 0;
    padding: 0.5rem 0.75rem;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 0.5rem;
    background: rgba(0, 0, 0, 0.22);
    font-size: 0.8125rem;
    color: var(--fz-on-accent-muted);
}

.fz-glance-label {
    min-width: 0;
}

/* `margin-inline-start: auto`: si el rotulo es largo y la cifra baja de linea,
   sigue a la derecha, donde la busca el ojo. */
.fz-glance-value {
    margin-inline-start: auto;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--fz-on-accent);
}

.fz-glance-value:empty {
    display: none;
}

.fz-account-glance.fz-glance-card {
    flex-direction: column;
    align-items: stretch;
    gap: 0.375rem;
    padding: 0;
    border: 0;
    background: none;
}

.fz-glance-card .fz-glance-label {
    color: var(--fz-on-accent);
}

.fz-glance-usage {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--fz-space-2);
}

.fz-glance-usage .budget-bar {
    margin: 0;
}

.fz-glance-share {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--fz-on-accent);
}

/* Tres por fila desde 992 px y tambien en pantalla ancha: con la franja, a cuatro
   la tarjeta no cabe entre 1200 y 1399 px (ADR 0079). Las destacadas son tres
   para llenar la fila justa (ADR 0026). */
@media (min-width: 1200px) {
    .fz-accounts .fz-account-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* ===========================================================================
   17 ter. PRESTAMOS E HIPOTECAS, Y METAS
   ===========================================================================

   Misma rejilla que las cuentas, otra tarjeta. Deudas y metas usan LA MISMA
   porque responden la misma pregunta: cuanto llevas de algo que tarda meses
   (ADR 0024). Desde el ADR 0048 tiene tres pisos: el nombre; el anillo junto a
   la foto; y las dos cifras abajo.
   =========================================================================== */

/* Se agrupan los selectores en vez de copiar las reglas: dos copias acabarian
   separandose en el primer retoque. Los nombres siguen siendo los suyos para
   que el marcado se lea. */

.fz-financing-grid,
.fz-goals-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3);
}

/* `position: relative` es el ancla del `stretched-link` del nombre: sin ella,
   el enlace estirado cubriria la seccion entera y no su tarjeta.

   El borde va en el tono de su bloque, que la tarjeta hereda (`--fz-kpi-tone`):
   con el gris se leia como el mismo plano que el bloque (ADR 0089). Solo el
   borde; el fondo sigue siendo el del bloque. */
.fz-financing-card,
.fz-goal-card {
    position: relative;
    display: flex;
    flex-direction: column;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 55%, var(--bs-border-color));
    border-radius: var(--bs-border-radius);
    overflow: hidden;
    min-width: 0;
}

.fz-financing-card:hover,
.fz-goal-card:hover {
    border-color: var(--fz-kpi-tone);
}

/* `flex: 1` para que el cuerpo llene la tarjeta cuando la rejilla la estira a
   la altura de la mas alta de su fila; asi las cifras de abajo pueden bajar
   hasta el suelo (ver `.fz-financing-figures`). */
.fz-financing-body,
.fz-goal-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--fz-space-3);
    padding: var(--fz-space-3);
    min-width: 0;
}

/* El nombre es el titulo de la tarjeta, no un enlace mas: color del texto y
   subrayado solo al pasar, como el resto de titulos que llevan a una ficha.
   Que se pulsa ya lo dice la tarjeta entera. La meta lo llama `-heading`
   porque `.fz-goal-name` ya es el titulo de la tarjeta de /goals. */
.fz-financing-name,
.fz-goal-heading {
    color: var(--bs-emphasis-color);
    font-weight: 600;
    line-height: 1.3;
    text-decoration: none;
    overflow-wrap: anywhere;
}

.fz-financing-name:hover,
.fz-goal-heading:hover {
    text-decoration: underline;
}

/* `flex: 1`: la franja del anillo se queda con el alto que sobre en la tarjeta
   y lo centra. Sin foto, el anillo cae asi a la misma altura que el de sus
   vecinas con foto, y no pegado al nombre con un hueco debajo. */
.fz-financing-media,
.fz-goal-media {
    display: flex;
    flex: 1;
    align-items: center;
    gap: var(--fz-space-3);
    min-width: 0;
}

/* `flex: none` para que el anillo no se encoja antes que la foto: es una
   figura, y una figura aplastada deja de medir lo que dice medir. */
.fz-financing-ring,
.fz-goal-ring {
    flex: none;
}

/* 4.5rem: el anillo lleva el rotulo DENTRO ("Pagado", "Avance"), y a 48 px el
   rotulo saldria de 7 px. A 72 px el numero sale a 15 px y el rotulo a 11. */
.fz-financing-ring .fz-ring,
.fz-goal-ring .fz-ring {
    inline-size: 4.5rem;
    block-size: 4.5rem;
}

/* La foto se queda con lo que el anillo deja libre, y con esquinas: no toca el
   borde de la tarjeta, y un rectangulo recto dentro de un marco redondeado se
   ve pegado. `min-width: 0` para que una foto ancha no empuje al anillo.

   Proporcion fija y `cover`: las fotos de un usuario vendran de donde vengan,
   y sin esto una vertical estiraria su tarjeta al doble que las de al lado. El
   recorte se acepta a cambio de que la rejilla no baile. 16:9 porque es la del
   campo de foto (`.fz-photo-preview`): lo que se ve al subirla es lo que se ve
   aqui. */
.fz-financing-photo,
.fz-goal-photo {
    flex: 1;
    min-width: 0;
    inline-size: 100%;
    block-size: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    /* Mientras carga, el hueco no es blanco: en tema oscuro un rectangulo
       blanco de 200 px deslumbra hasta que llega la imagen. */
    background-color: var(--fz-surface-sunken);
}

/* El estado de la meta y su fecha, entre el anillo y las cifras: el mismo
   hueco que el escrow de una hipoteca. La insignia es la de /goals. */
.fz-goal-note {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-1) var(--fz-space-2);
    margin: 0;
    font-size: 0.875em;
    color: var(--bs-secondary-color);
}

/* Dos cifras en una linea: a la izquierda lo que queda o lo ahorrado, a la
   derecha cuando toca o lo que falta. Van las ULTIMAS de la tarjeta -escrow y
   estado van encima- y la franja del anillo se come el alto sobrante, asi que
   en una fila de tres quedan a la misma altura aunque un nombre ocupe dos
   lineas, o una tarjeta no tenga foto.

   `last baseline` alinea las dos cifras por su renglon de texto: el importe de
   la izquierda es mas grande, y alineados por el borde de abajo el de la
   derecha quedaria un pelo mas bajo. `flex-end` es el respaldo de quien no lo
   entienda. */
.fz-financing-figures,
.fz-goal-figures {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-end;
    align-items: last baseline;
    gap: var(--fz-space-1) var(--fz-space-3);
    margin: 0;
    min-width: 0;
}

.fz-financing-figure,
.fz-goal-figure {
    min-width: 0;
}

.fz-financing-figure dt,
.fz-goal-figure dt {
    font-size: 0.875em;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-financing-figure dd,
.fz-goal-figure dd {
    margin: 0;
}

.fz-financing-figure-end,
.fz-goal-figure-end {
    text-align: end;
}

/* --- El anillo ------------------------------------------------------------

   `stroke-linecap: round` en el arco y no en la pista: la pista es un circulo
   entero y el remate no se ve, pero el arco corto de un 3 % sin redondear
   parece un error de dibujo. */

.fz-ring {
    inline-size: 3rem;
    block-size: 3rem;
}

.fz-ring-track {
    stroke: var(--bs-secondary-bg);
    stroke-width: 5;
}

.fz-ring-value {
    stroke: var(--bs-primary);
    stroke-width: 5;
    stroke-linecap: round;
}

/* El numero de dentro se dibuja con `fill` y no con `color`: en SVG el color de
   un `<text>` es su relleno, y `color` no lo pinta. */
.fz-ring-text {
    fill: var(--bs-body-color);
    font-size: 9.5px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Tallas del numero segun sus cifras; las elige `ProgressRing` (ADR 0050).
   Como el rotulo, en unidades del lienzo. La base es 9.5 y no 10: a 10,
   "49.5 %" quedaba a 17,52 del centro con el borde interior del trazo en 17,5.
   Se mide en Chrome con rotulo debajo, que es el caso apretado, y se pide
   una unidad de holgura:
     9.5  "49.5 %"    (3 cifras)
     8.5  "100.0 %"   (4 cifras); a 9.5 se comeria el trazo
     7    "1,250.0 %" (5 o mas): una meta que pasa de largo su objetivo */
.fz-ring-text-long {
    font-size: 8.5px;
}

.fz-ring-text-xlong {
    font-size: 7px;
}

/* El rotulo bajo el numero ("Pagado"). Dentro de un SVG la talla va en
   unidades del lienzo (48 de lado), no en pixeles de pantalla: 7.5 es la que
   cabe en el hueco del anillo con "Es tuyo", y crece con el anillo. Si cambia,
   `ProgressRing` recoloca el numero y el rotulo con estas tallas en mente. */
.fz-ring-caption {
    fill: var(--bs-secondary-color);
    font-size: 7.5px;
}

@media (min-width: 576px) {
    .fz-financing-grid,
    .fz-goals-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 992px) {
    .fz-financing-grid,
    .fz-goals-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* --- El campo de foto de /loans y /mortgages -------------------------------

   Vive dentro de un `<details>` plegado: cambiar la foto es raro comparado con
   mirar la deuda, y desplegado empujaria el saldo fuera de la vista. */

.fz-photo-field {
    padding-top: var(--fz-space-3);
    max-inline-size: 24rem;
}

/* Misma proporcion que la tarjeta del panel: lo que se ve aqui es lo que se va
   a ver alli, no una version recortada de otra manera. */
.fz-photo-preview {
    inline-size: 100%;
    block-size: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
    margin-bottom: var(--fz-space-3);
}

/* --- La tarjeta de un prestamo en el listado (/loans) ----------------------

   Misma anatomia que la cabecera del detalle, en pequeño: foto, nombre, y la
   deuda como cifra grande a la derecha. La miniatura mide 8rem y no las 12 del
   detalle porque aqui comparte fila con dos bloques mas, no con uno. */
.fz-loan-thumb {
    inline-size: 8rem;
    block-size: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
    flex-shrink: 0;
}

/* El recuadro que ocupa el sitio de la foto cuando no hay. Hereda la talla, el
   radio y la superficie hundida de `.fz-loan-thumb` o `.fz-loan-header-photo`
   -va con una de las dos-, asi que el hueco mide exactamente lo mismo que una
   foto y las tarjetas con y sin foto tienen la misma forma.

   El icono crece con el recuadro (un 36 % de su ancho) en vez de tener talla
   fija: el mismo recuadro mide 64 px en un telefono, 128 en la lista y 192 en
   la cabecera del detalle. Y con el trazo afinado, porque el de 1.75 del set
   esta pensado para 20-24 px y a 70 se ve como un rotulador. */
.fz-loan-thumb-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--bs-tertiary-color);
}

.fz-loan-thumb-icon {
    inline-size: 36%;
    block-size: auto;
    aspect-ratio: 1;
    stroke-width: 1.25;
}

/* El nombre ES el enlace al detalle, pero se lee como titulo de la tarjeta: sin
   subrayado de serie ni color de enlace -los pone el hover-, porque una lista
   de cinco titulos azules subrayados se lee como un indice, no como fichas. */
.fz-loan-name {
    display: inline-block;
    color: var(--bs-body-color);
    font-size: 1.0625rem;
    font-weight: 600;
    text-decoration: none;
}

.fz-loan-name:hover {
    color: var(--fz-brand);
    text-decoration: underline;
}

/*
 * En un telefono, la deuda baja a su propia linea.
 *
 * Medido a 390 px: la miniatura -128 px que ademas no encogen- mas el nombre
 * mas el importe no caben en los 332 utiles de la tarjeta. Y lo que hacia el
 * navegador no era desbordar y ya: comprimia el bloque del nombre a 75 px
 * -titulo partido en tres lineas, metadatos en siete- y empujaba el importe
 * medio pixel por dentro del borde, con lo que las tres tarjetas dejaban de
 * tener su cifra a la misma altura, que es justo lo que las hace comparables.
 *
 * La miniatura baja a 4rem, la talla con la que se dibujo el movil, y la deuda
 * pasa a leerse como par rotulo/valor a lo ancho de la tarjeta.
 */
@media (max-width: 575.98px) {
    .fz-loan-thumb {
        inline-size: 4rem;
    }

    .fz-loan-head {
        flex-wrap: wrap;
    }

    /* Sin esto, lo que baja de linea no es la deuda sino el NOMBRE. Un hijo
       flexible envuelve entero cuando su tamaño de partida no cabe, y el del
       nombre es su linea de metadatos sin partir -contrato, tasa, convencion-,
       que no cabe al lado de ninguna miniatura: la foto quedaba sola en su fila
       y el titulo debajo. Con base cero cabe siempre junto a la foto y luego
       crece; `min-width: 0` es lo que deja partir el texto de dentro. */
    .fz-loan-title {
        flex-basis: 0;
        min-width: 0;
    }

    .fz-loan-debt {
        display: flex;
        flex-basis: 100%;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--fz-space-3);
    }

    /* El rotulo primero y la cifra al otro extremo. En el marcado el importe va
       antes porque en escritorio es quien manda; aqui se lee "Deuda pendiente
       ........ S/ 38,835.82", que es como se lee un par. */
    .fz-loan-debt > .fz-amount-lg {
        order: 2;
    }
}

/* --- El desplegable de la casa (`.fz-menu`) --------------------------------

   Un `<details>` nativo con el panel en un `<div>` aparte: abre y cierra con
   raton y con teclado sin una linea de JavaScript. Es la BASE de los tres
   desplegables de la aplicacion:

     .fz-menu                    las acciones de una tarjeta de /loans (tal cual)
     .fz-menu + .fz-year-picker  el selector de ano del calendario
     .fz-menu + .fz-more         el "Mas" de la barra inferior de movil

   Eran tres copias de las mismas diecisiete lineas con tres nombres, y ya
   habian empezado a separarse sin querer (z-index 1 en dos y 2 en el otro).
   Ahora lo comun vive aqui y cada uno declara SOLO en que se distingue:
   direccion, alineacion, ancho y altura maxima. Las clases propias se quedan
   por eso y porque `nav.js` busca `.fz-more` para cerrarlo con Escape.

   Por defecto el panel abre hacia abajo y pegado a la derecha, que es de donde
   cuelga el boton de una tarjeta. */
.fz-menu {
    position: relative;
}

/* Sin el triangulito del navegador: el boton ya dice que hay mas. */
.fz-menu > summary {
    list-style: none;
    cursor: pointer;
}

.fz-menu > summary::-webkit-details-marker {
    display: none;
}

.fz-menu-panel {
    position: absolute;
    top: calc(100% + var(--fz-space-2));
    right: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 11rem;
    padding: var(--fz-space-2);
    background-color: var(--fz-surface-raised);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--fz-elev-2);
}

.fz-menu-panel form {
    width: 100%;
}

/* La altura de control de la casa, no la de un enlace de texto: dentro del menu
   cada opcion sigue siendo un objetivo tactil. */
.fz-menu-item {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    width: 100%;
    min-height: var(--fz-control-height);
    padding: var(--fz-space-2) var(--fz-space-3);
    border: 0;
    border-radius: var(--bs-border-radius);
    background-color: transparent;
    color: var(--bs-body-color);
    font-family: inherit;
    font-size: 0.9375rem;
    text-align: start;
    /* Nacio para `<button>`; en un `<a>` -el menu de casas de /mortgages- heredaba
       el subrayado de los enlaces. */
    text-decoration: none;
}

.fz-menu-item:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    text-decoration: none;
}

/* --- Los prestamos archivados, plegados ------------------------------------

   Eran una segunda tarjeta grande, siempre abierta, para lo que casi nunca se
   mira. Ahora son una linea que se abre. El cuerpo va sobre superficie hundida
   porque dentro hay tarjetas: una tarjeta blanca sobre otra blanca no se ve. */
.fz-archived > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
    padding: var(--fz-space-4);
    list-style: none;
    cursor: pointer;
}

.fz-archived > summary::-webkit-details-marker {
    display: none;
}

.fz-archived-caret {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
}

.fz-archived[open] .fz-archived-caret {
    transform: rotate(180deg);
}

.fz-archived-body {
    padding: var(--fz-space-4);
    background-color: var(--fz-surface-sunken);
    border-top: 1px solid var(--bs-border-color);
    border-end-start-radius: var(--bs-border-radius-lg);
    border-end-end-radius: var(--bs-border-radius-lg);
}

.fz-archived-body > .card:last-child {
    margin-bottom: 0;
}

/* --- Mis metas (/goals, ADR 0044) ------------------------------------------

   Dos columnas desde 992: las metas y, a la derecha, el panel de aportar, las
   cifras por moneda y las archivadas. Por debajo, una sola columna y el panel
   convertido en hoja inferior que solo aparece cuando se pide.

   Todo color sale de un token y no hay un solo `style=""` en las plantillas:
   la CSP no lleva 'unsafe-inline'. */
.fz-goals-layout {
    display: grid;
    gap: var(--fz-space-4);
}

.fz-goals-list,
.fz-goals-aside {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-3);
    min-width: 0;
}

@media (min-width: 992px) {
    .fz-goals-layout {
        grid-template-columns: minmax(0, 1fr) 22.5rem;
        align-items: start;
        gap: var(--fz-space-5);
    }

    .fz-goals-aside {
        gap: var(--fz-space-4);
    }
}

/*
 * La tarjeta de una meta.
 *
 * En un telefono es una rejilla: la miniatura cuadrada al lado del nombre y el
 * resto -cifras, barra, pendiente, pie- a lo ancho. El cuerpo es
 * `display: contents` para que sus piezas entren en esa rejilla sin duplicar el
 * marcado. Desde 768 la foto crece y se queda a la izquierda, a toda la altura,
 * y el cuerpo vuelve a ser una columna: es la tarjeta del diseño aprobado.
 *
 * `.card` pone `display: flex` en columna; esta clase va despues en la cascada y
 * lo sustituye.
 */
.fz-goal-item {
    display: grid;
    grid-template-columns: 3rem minmax(0, 1fr);
    column-gap: var(--fz-space-3);
    row-gap: var(--fz-space-2);
    padding: var(--fz-space-3);
}

/* Refuerzo, no informacion: la etiqueta ya dice "Atrasada" con palabras. */
.fz-goal-item.is-alert {
    border-color: var(--fz-state-over-fill);
}

.fz-goal-item-body {
    display: contents;
}

.fz-goal-thumb {
    grid-column: 1;
    grid-row: 1;
    inline-size: 3rem;
    block-size: 3rem;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
}

.fz-goal-thumb-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--bs-tertiary-color);
}

.fz-goal-thumb-icon {
    inline-size: 50%;
    block-size: auto;
    aspect-ratio: 1;
    stroke-width: 1.5;
}

.fz-goal-head {
    grid-column: 2;
    grid-row: 1;
    align-self: center;
    min-width: 0;
}

.fz-goal-item-figures,
.fz-goal-bar,
.fz-goal-due,
.fz-goal-foot {
    grid-column: 1 / -1;
}

.fz-goal-title {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-width: 0;
}

.fz-goal-name {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.35;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* El nombre es el enlace a editar, pero se lee como titulo: mismo trato que el
   nombre de un prestamo en /loans. */
.fz-goal-name a {
    color: var(--bs-body-color);
    text-decoration: none;
}

.fz-goal-name a:hover {
    color: var(--fz-brand);
    text-decoration: underline;
}

.fz-goal-badge {
    flex: 0 0 auto;
    padding: 0.125rem var(--fz-space-2);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
}

/* `[data-state]`: la misma etiqueta en «Cuándo llegas» del alta (ADR 0099),
   donde el estado llega con la respuesta del servidor. */
.fz-goal-badge-on_track,
.fz-goal-badge[data-state='on_track'] {
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
}

.fz-goal-badge-behind,
.fz-goal-badge-overdrawn,
.fz-goal-badge[data-state='behind'],
.fz-goal-badge[data-state='overdrawn'] {
    background-color: var(--bs-danger-bg-subtle);
    color: var(--fz-state-over-text);
}

.fz-goal-badge-achieved,
.fz-goal-badge[data-state='achieved'] {
    background-color: var(--bs-success-bg-subtle);
    color: var(--fz-state-ok-text);
}

.fz-goal-subtitle {
    margin: 0;
    overflow: hidden;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-goal-item-figures {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-2);
}

.fz-goal-amount {
    min-width: 0;
    margin: 0;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.fz-goal-saved {
    margin-inline-end: var(--fz-space-1);
    color: var(--bs-emphasis-color);
    font-size: var(--fz-amount-md);
    font-weight: 700;
}

.fz-goal-share {
    flex: 0 0 auto;
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-goal-share-on_track {
    color: var(--fz-brand);
}

.fz-goal-share-behind,
.fz-goal-share-overdrawn {
    color: var(--fz-state-over-text);
}

.fz-goal-share-achieved {
    color: var(--fz-state-ok-text);
}

.fz-goal-bar .budget-bar {
    margin: 0;
}

/* En /goals "en curso" es la marca, igual que en el diseño: la barra ya era
   indigo, pero se deja dicho aqui porque es la que da color a toda la tarjeta. */
.fz-goal-bar .budget-on-track {
    fill: url(#fz-grad-on-track) var(--fz-brand-fill);
}

.fz-goal-due {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-2);
    padding: var(--fz-space-2) var(--fz-space-3);
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
}

.fz-goal-due-text {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-2);
    margin: 0;
    font-size: 0.8125rem;
}

.fz-goal-due-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
}

.fz-goal-foot {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--fz-space-2);
}

.fz-goal-message {
    margin: 0;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.fz-goal-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
}

/*
 * El boton de la accion de la tarjeta: contorno del color del texto fuerte y
 * negrita, como en el diseño. No es relleno a proposito: en una lista de cuatro
 * tarjetas, cuatro botones azules rellenos gritan mas que las cifras. El relleno
 * se reserva al aporte pendiente, que si pide hacerse hoy.
 *
 * Seleccionado -la meta cuyo panel esta abierto- toma el tono de marca.
 */
.fz-btn-strong {
    --bs-btn-color: var(--bs-emphasis-color);
    --bs-btn-bg: var(--fz-surface);
    --bs-btn-border-color: var(--bs-emphasis-color);
    --bs-btn-font-weight: 600;
    --bs-btn-hover-color: var(--bs-body-bg);
    --bs-btn-hover-bg: var(--bs-emphasis-color);
    --bs-btn-hover-border-color: var(--bs-emphasis-color);
    --bs-btn-active-color: var(--bs-body-bg);
    --bs-btn-active-bg: var(--bs-emphasis-color);
    --bs-btn-active-border-color: var(--bs-emphasis-color);
}

.fz-btn-strong.is-current {
    --bs-btn-color: var(--bs-primary-text-emphasis);
    --bs-btn-bg: var(--bs-primary-bg-subtle);
    --bs-btn-border-color: var(--fz-brand);
}

@media (min-width: 768px) {
    .fz-goal-item {
        display: flex;
        flex-direction: row;
        align-items: stretch;
        gap: var(--fz-space-4);
    }

    .fz-goal-thumb {
        flex: 0 0 8.25rem;
        inline-size: 8.25rem;
        block-size: auto;
        min-block-size: 7.75rem;
        align-self: stretch;
        border-radius: 0.625rem;
    }

    .fz-goal-thumb-icon {
        inline-size: 2.5rem;
        stroke-width: 1.25;
    }

    .fz-goal-item-body {
        display: flex;
        flex: 1 1 auto;
        flex-direction: column;
        gap: var(--fz-space-1);
        min-width: 0;
        padding: var(--fz-space-1) var(--fz-space-1) 0 0;
    }

    /* En la rejilla movil el `align-self: center` centra la cabecera en VERTICAL
       junto a la miniatura; en la columna flex el eje cruzado es el horizontal y
       la dejaba centrada a lo ancho. Aqui ocupa la fila entera. */
    .fz-goal-head {
        align-self: stretch;
    }

    .fz-goal-name {
        font-size: 1rem;
        white-space: normal;
    }

    .fz-goal-subtitle {
        white-space: normal;
    }

    .fz-goal-item-figures {
        margin-top: var(--fz-space-2);
    }

    .fz-goal-saved {
        font-size: 1.25rem;
    }

    .fz-goal-due {
        margin-top: var(--fz-space-2);
    }

    .fz-goal-foot {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        gap: var(--fz-space-4);
        margin-top: var(--fz-space-2);
    }

    .fz-goal-actions {
        flex: 0 0 auto;
        flex-wrap: nowrap;
    }
}

/* --- El panel de aportar y retirar ----------------------------------------- */
.fz-eyebrow {
    margin: 0;
    color: var(--bs-tertiary-color);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Desde el ADR 0101 el panel es una tarjeta de las altas (`fz-fcard`): su
   cabecera y sus campos son los de alli. El boton, con su icono y el degradado
   del de guardar, a lo ancho del panel. */
.fz-goal-panel-submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    border-radius: 0.875rem;
    font-weight: 600;
}

.fz-goal-panel-submit .icon {
    width: 1.25rem;
    height: 1.25rem;
}

.fz-amount-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
    margin-top: var(--fz-space-2);
}

/* Alto de control tactil (ADR 0021 §6): es un boton, aunque parezca una
   etiqueta. */
.fz-amount-chip {
    min-height: var(--fz-control-height);
    padding: 0 var(--fz-space-3);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-surface);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 500;
}

.fz-amount-chip:hover {
    border-color: var(--bs-secondary-color);
}

.fz-amount-chip[aria-pressed='true'] {
    border-color: var(--fz-brand);
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    font-weight: 600;
}

.fz-sheet-backdrop {
    display: none;
}

/*
 * Movil: el panel es una hoja inferior.
 *
 * Solo existe cuando se pidio (`.is-open`, que pone el servidor con
 * `?aportar=`/`?retirar=`): una tarjeta de formulario permanente entre la lista
 * y el resumen empujaria las metas fuera de la vista. Va por encima de la barra
 * de pestañas (1030) y su fondo es un enlace de vuelta a /goals, asi que abrir y
 * cerrar no necesitan JavaScript.
 */
@media (max-width: 991.98px) {
    .fz-goal-panel:not(.is-open) {
        display: none;
    }

    .fz-goal-panel.is-open {
        position: fixed;
        inset: auto 0 0 0;
        z-index: 1045;
        max-block-size: 90vh;
        max-block-size: 90dvh;
        overflow-y: auto;
        border-bottom: 0;
        border-radius: var(--bs-border-radius-xl) var(--bs-border-radius-xl) 0 0;
        box-shadow: var(--fz-elev-2);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .fz-sheet-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 1040;
        background-color: var(--fz-scrim);
    }
}

/* En escritorio el panel no se cierra: siempre hay una meta propuesta. */
@media (min-width: 992px) {
    .fz-goal-panel-close {
        display: none;
    }
}

/* --- La ficha de una meta (/goals/{id}) ------------------------------------ */
.fz-goal-details {
    display: grid;
    gap: var(--fz-space-2);
}

.fz-goal-details > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-3);
}

.fz-goal-details dt {
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    font-weight: 400;
}

.fz-goal-details dd {
    min-width: 0;
    margin: 0;
    font-size: 0.9375rem;
    text-align: end;
}

/* --- Por moneda y archivadas ----------------------------------------------- */
/* La tarjeta es la comun compacta (ADR 0084): la raya entre monedas la pone
   `.fz-kpi-group` y el aire entre bloques, la rejilla de la tarjeta. */
.fz-goal-currency-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-2);
    margin-bottom: var(--fz-space-1);
}

.fz-goal-currency-list {
    display: grid;
    gap: var(--fz-space-1);
    margin: 0;
}

.fz-goal-currency-list > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-3);
}

.fz-goal-currency-list dt {
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 400;
}

.fz-goal-currency-list dd {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-goal-archived-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
}

.fz-goal-archived-row + .fz-goal-archived-row {
    margin-top: var(--fz-space-3);
    padding-top: var(--fz-space-3);
    border-top: 1px solid var(--bs-border-color);
}

.fz-goal-archived-name {
    min-width: 0;
}

/* --- Alta: "¿donde se guarda?" y el aporte mensual ------------------------- */

/* La ayuda de una opcion y su bloque de campos arrancan donde arranca el texto
   del rotulo: el ancho del control mas el hueco de `.form-check`.
   `.fz-check-block` es el mismo bloque fuera de las metas: la confirmacion de
   archivar un prestamo cuelga de su opcion el select de la cuenta (ADR 0078). */
.fz-check-help,
.fz-check-block,
.fz-goal-mode-block {
    margin-left: calc(1.25rem + var(--fz-space-2));
}

.fz-check-help {
    margin-top: calc(-1 * var(--fz-space-2));
}

.fz-check-block,
.fz-goal-mode-block {
    margin-top: var(--fz-space-2);
    margin-bottom: var(--fz-space-2);
}

.fz-goal-plan {
    padding-top: var(--fz-space-3);
    border-top: 1px solid var(--bs-border-color-translucent);
}

/* --- El detalle de un prestamo (/loans/{id}) -------------------------------

   Miniatura fija en vez de `.fz-photo-preview`: esa ocupa el ancho entero de
   su columna, y en la cabecera del detalle tiene que caber al lado del titulo
   y los botones, no encima. */
.fz-loan-header-photo {
    inline-size: 12rem;
    block-size: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
    flex-shrink: 0;
}

/* En el panel el anillo comparte tarjeta con nombre, foto y cifras (4.5rem).
   Aqui tiene la tarjeta entera para el solo, asi que se dibuja mas grande. */
.fz-loan-progress-ring .fz-ring {
    inline-size: 6rem;
    block-size: 6rem;
}

/* Un `<summary>` de texto -"Gestionar" en /settings/members, "Compartir con el
   espacio" en la ficha de una cuenta, "Fecha y nota" en la captura del panel,
   "Tasa variable" en /loans/new- se ve como una linea discreta, pero se toca
   como un control: la altura de linea lo lleva a los 44 px del resto sin
   moverle el triangulo del navegador. Median entre 21 y 24 px. Quien lo usa
   recorta su margen de arriba lo que crece la linea, para no separarlo mas. */
.fz-disclosure-summary {
    line-height: var(--fz-control-height);
    cursor: pointer;
}

/* Un `<summary>` que se ve como un boton: `.btn` ya pone `display:
   inline-flex`, que le gana en especificidad al `list-item` del navegador, asi
   que solo falta quitarle el triangulito. Mismo truco que `.fz-more` en el
   menu "Mas" del riel, aqui suelto para poder pegarlo a cualquier `<details>`
   -"Cambiar foto" no necesita el panel flotante de `.fz-more-panel`, su
   contenido se despliega debajo tal cual. */
.fz-summary-btn {
    list-style: none;
}

.fz-summary-btn::-webkit-details-marker {
    display: none;
}

/* Cerrado, "Cambiar foto" es un boton mas de la fila. Abierto, el formulario
   de la foto necesita su propio ancho -no el que le tocaria como boton-, asi
   que el `<details>` pasa a ocupar la fila entera y empuja lo demas debajo. */
.fz-hero-actions > details[open] {
    flex-basis: 100%;
}

/* El selector de ano del calendario. Es un `.fz-menu` (seccion de las tarjetas
   de /loans): aqui solo va en lo que se distingue. */
.fz-year-picker-caret {
    inline-size: 1rem;
    block-size: 1rem;
    flex: 0 0 auto;
}

/* Pegado a la IZQUIERDA -su boton no esta en el borde derecho de nada-, mas
   estrecho, y con tope de alto: una hipoteca a 30 años son treinta opciones. */
.fz-year-picker-panel {
    right: auto;
    left: 0;
    min-width: 9rem;
    max-height: 16rem;
    overflow-y: auto;
}

.fz-year-picker-option {
    padding: var(--fz-space-2) var(--fz-space-3);
    border-radius: var(--bs-border-radius-sm);
    color: var(--bs-body-color);
    text-align: right;
    font-variant-numeric: tabular-nums;
    text-decoration: none;
}

.fz-year-picker-option:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    text-decoration: none;
}

.fz-year-picker-option[aria-current='page'] {
    background-color: var(--bs-primary-bg-subtle);
    color: var(--fz-brand);
    font-weight: 600;
}

/* La banda que abre el calendario con el ano y sus totales. Va dentro del
   `<tbody>` y no en el encabezado: alli seria una segunda fila `sticky` peleando
   por `top: 0` con la de los rotulos, y aqui ademas es lo correcto -es un titulo
   de grupo de filas, no una columna-.

   `white-space: normal` porque la regla de la tabla financiera deja todo en una
   linea: eso esta bien para una cifra y mal para una banda que ocupa el ancho
   entero y tiene que poder partirse en un movil. */
.fz-table-financial .fz-schedule-year > th {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: normal;
}

/* El estado de cada cuota, con la paleta de la casa.
 *
 * Sustituyen a `.table-secondary` y `.table-primary`, y no es cuestion de
 * gusto: esas dos traen el color COMPILADO -`#e2e3e5` y `#cfe2ff`, el azul de
 * fabrica- y no leen `--bs-primary`, asi que la fila de la proxima cuota era el
 * unico sitio de la aplicacion donde asomaba el azul de plantilla al lado del
 * indigo de marca. Ademas fijan `color: #000`, que en tema oscuro deja texto
 * negro sobre celda oscura.
 *
 * Se escriben como VARIABLE de la tabla y no como `background-color` de la
 * celda, que es lo que hace Bootstrap: asi el resaltado al pasar el raton
 * -`.fz-table-financial tbody tr:hover td`, que si pinta la propiedad- le sigue
 * ganando a la fila, y la realimentacion del cursor no se pierde justo en las
 * dos filas que mas se miran. */
.fz-schedule-paid {
    --bs-table-bg: var(--bs-tertiary-bg);
    --bs-table-color: var(--bs-secondary-color);
}

.fz-schedule-next {
    --bs-table-bg: var(--bs-primary-bg-subtle);
}

/* La etiqueta "Proxima". No `text-bg-primary`: esa pone blanco sobre
   `--bs-primary`, que en oscuro es el lavanda claro de los enlaces (#9DABFF) y
   dejaba el texto a 2.16:1. El relleno de marca es el que esta calibrado para
   llevar texto encima (`--fz-brand-on-fill`), en los dos temas. */
.fz-badge-next {
    --bs-badge-color: var(--fz-brand-on-fill);
    background-color: var(--fz-brand-fill);
}

/* --- Movil: el pago, siempre a mano ----------------------------------------
 *
 * La accion de esta pantalla es registrar la cuota, y en un telefono vivia al
 * final de la cabecera: con el calendario de un credito a 48 meses abierto
 * queda a varias pantallas de distancia, y volver a por ella es justo lo que
 * hace que la cuota se registre "luego".
 *
 * `sticky` y no `fixed`: al llegar al final de la pagina ocupa su sitio en el
 * flujo en vez de tapar la ultima fila, y no hay que reservarle hueco al body
 * como hubo que hacer con la barra de pestanas. El `bottom` no es cero sino la
 * altura de esa barra -que si es `fixed` y va por encima-, mas el area segura
 * del iPhone.
 *
 * Emitir el boton dos veces y ensenar uno es la tecnica del armazon
 * (`layouts/_nav.php` §), y `display: none` saca del arbol de accesibilidad el
 * que sobra: un lector de pantalla no anuncia la accion por duplicado. */
.fz-loan-paybar {
    position: sticky;
    bottom: calc(var(--fz-tabbar-h) + env(safe-area-inset-bottom, 0px));
    z-index: 1020;
    margin-top: var(--fz-space-4);
    padding-block: var(--fz-space-2);
    background-color: var(--bs-body-bg);
}

@media (min-width: 576px) {
    .fz-loan-paybar {
        display: none;
    }
}

/* Y al reves: donde hay barra abajo, el boton de la cabecera sobra. Se apunta
   al `form` hijo directo -el de la foto vive dentro de un `<details>`-.
   `.fz-hero-secondary` es la otra accion que la barra repite: "Refinanciar" en
   la ficha de una hipoteca. */
@media (max-width: 575.98px) {
    .fz-hero-actions > form,
    .fz-hero-actions > .fz-hero-secondary {
        display: none;
    }

    /* Al llegar al final de la pagina la barra deja de flotar y ocupa su sitio
       en el flujo, y debajo quedaba el relleno inferior del `main` (`py-4`,
       24 px): un hueco entre ella y la barra de pestañas, medido en /loans y en
       /mortgages. El margen negativo se come ese relleno, y solo ahi: mientras
       flota, `bottom` manda y el margen no se nota. */
    .fz-loan-paybar {
        margin-bottom: calc(-1 * var(--fz-space-5));
    }
}

/* --- La ficha de una casa (/mortgages, ADR 0043) ----------------------------

   Casi todo es Bootstrap y piezas del detalle de un prestamo: la cabecera, el
   anillo, las cifras, el calendario y la barra de pago son las mismas. Aqui
   solo lo que una casa tiene y un prestamo no. */

/* El selector de casa en escritorio. Envuelve en vez de desbordar: con cuatro
   casas la tira pasa a dos lineas, que se lee mejor que un scroll lateral donde
   la casa actual puede quedar fuera de la vista sin JavaScript que la traiga. */
.fz-house-switcher {
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-2);
    margin-bottom: var(--fz-space-5);
}

.fz-house-switcher-label {
    margin-inline-end: var(--fz-space-2);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
}

.fz-house-chip {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-height: 3.5rem;
    padding: var(--fz-space-1) var(--fz-space-4) var(--fz-space-1) var(--fz-space-1);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--fz-surface);
    color: var(--bs-body-color);
    text-decoration: none;
}

.fz-house-chip:hover {
    border-color: var(--bs-primary-border-subtle);
    color: var(--bs-body-color);
}

/* La casa que se esta viendo: borde de marca de dos pixeles sin mover el
   contenido -la sombra interior suma el segundo pixel sin cambiar la caja-. */
.fz-house-chip[aria-current='page'] {
    border-color: var(--fz-brand);
    box-shadow: inset 0 0 0 1px var(--fz-brand);
    background-color: var(--bs-primary-bg-subtle);
}

.fz-house-chip-thumb {
    inline-size: 2.625rem;
    block-size: 2.625rem;
    flex-shrink: 0;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
}

.fz-house-chip-body {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.25;
}

.fz-house-chip-name {
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-house-chip-meta {
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

/* "Registrar hipoteca" es una casa que todavia no existe: mismo tamano que las
   demas, borde discontinuo y el color de un enlace. El borde usa el terciario y
   no el de las tarjetas porque, siendo lo unico que lo dibuja, tiene que llegar
   al 3:1 de un componente. */
.fz-house-chip-add {
    padding-inline: var(--fz-space-4);
    border-style: dashed;
    border-color: var(--bs-tertiary-color);
    background-color: transparent;
    color: var(--fz-brand);
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-house-chip-add:hover {
    border-color: var(--fz-brand);
    color: var(--fz-brand);
}

.fz-house-chip-add-icon {
    inline-size: 1.125rem;
    block-size: 1.125rem;
    flex-shrink: 0;
}

.fz-house-switcher > .fz-house-archived {
    margin-inline-start: auto;
}

/* En un telefono el titulo es el selector: el nombre de la casa y un chevron,
   con la altura de un control aunque el texto sea un encabezado. */
.fz-house-menu > summary {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
}

.fz-house-menu-caret {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    flex-shrink: 0;
}

.fz-house-menu[open] .fz-house-menu-caret {
    transform: rotate(180deg);
}

/* Cuelga del titulo, que esta a la izquierda: abre hacia la derecha, y nunca
   mas ancho que la pantalla menos sus margenes. */
.fz-house-menu-panel {
    right: auto;
    left: 0;
    min-width: min(20rem, calc(100vw - 2rem));
}

.fz-house-option {
    justify-content: space-between;
}

.fz-house-option[aria-current='page'] {
    background-color: var(--bs-primary-bg-subtle);
}

.fz-house-option-check {
    inline-size: 1.125rem;
    block-size: 1.125rem;
    flex-shrink: 0;
    color: var(--fz-brand);
}

.fz-house-option-add,
.fz-house-option-add:hover {
    color: var(--fz-brand);
    font-weight: 600;
}

.fz-house-option-group {
    margin: var(--fz-space-2) var(--fz-space-3) 0;
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
    font-weight: 600;
}

/* Un hijo flex no encoge por debajo de su contenido mientras `min-width` valga
   `auto`: sin esto, un nombre de casa largo empuja la cabecera fuera de la
   pantalla (el mismo fallo que ya se vio en /accounts, ADR 0021). */
.fz-house-heading {
    min-width: 0;
}

/* "Cambiar foto", sobre la propia foto. Un disco con la altura de un control
   para que siga siendo un objetivo tactil aunque el icono sea pequeno. */
.fz-house-photo {
    position: relative;
    flex-shrink: 0;
}

.fz-house-photo-menu {
    position: absolute;
    inset-inline-end: var(--fz-space-2);
    inset-block-end: var(--fz-space-2);
}

.fz-house-photo-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--fz-control-height);
    block-size: var(--fz-control-height);
    border: 1px solid var(--bs-border-color);
    border-radius: 50%;
    background-color: var(--fz-surface-raised);
    box-shadow: var(--fz-elev-2);
    color: var(--bs-body-color);
}

.fz-house-photo-icon {
    inline-size: 1.25rem;
    block-size: 1.25rem;
}

/* Abre hacia la derecha desde el boton, que esta en la esquina de la foto: a la
   izquierda no hay sitio, la foto esta pegada al borde de la pagina. */
.fz-house-photo-panel {
    right: auto;
    left: 0;
    min-width: 20rem;
    padding: var(--fz-space-4);
}

/* La franja al pie de una tarjeta con la accion que toca a sus cifras:
   "Simular pagos extra" bajo el avance, "Pagar un recibo" bajo el escrow.
   Hundida para que se lea como parte de la tarjeta y no como otra tarjeta. */
.fz-house-aside {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
    padding: var(--fz-space-2) var(--fz-space-2) var(--fz-space-2) var(--fz-space-3);
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
}

/* "Pagar un recibo" y "Como solicitarlo" abren un panel flotante, no un bloque
   dentro de la fila. Desplegado en la fila, el `<details>` abierto pasaba a
   ocupar el ancho entero y el boton saltaba de sitio -medido: 1112 px a la
   izquierda en "Como solicitarlo"-, asi que para cerrarlo habia que buscarlo.
   Pegado a la derecha tambien cuando la fila se parte, para que el panel, que
   cuelga del borde derecho del boton, no se salga por la izquierda. */
.fz-house-pop {
    margin-inline-start: auto;
}

/* Los botones de la franja, con relleno y borde propios. Con el borde del sistema
   -casi invisible a proposito sobre una tarjeta- sobre el fondo hundido de la
   franja no se distinguia el control: 1.51:1 en oscuro y 1.17:1 en claro. El
   terciario da 6.3:1 y 4.1:1, y el relleno de superficie lo despega del fondo. */
.fz-house-aside .btn {
    --bs-btn-bg: var(--fz-surface-raised);
    --bs-btn-border-color: var(--bs-tertiary-color);
}

.fz-house-pop-panel {
    /* 4rem y no 2rem: el panel cuelga del borde derecho del boton, que ya esta
       metido dentro de la tarjeta y de su franja. Con 2rem llegaba a 1 px del
       borde izquierdo de un telefono de 390 (medido). */
    min-width: min(22rem, calc(100vw - 4rem));
    padding: var(--fz-space-4);
    /* Dentro del aviso verde heredaria su color de texto. */
    color: var(--bs-body-color);
}

/* El desglose de la cuota: un punto de color por concepto, el nombre y el
   importe alineado a la derecha. El punto es `cat-dot-N` (seccion 13): el
   color lo pone la hoja, asi que cambia con el tema. */
.fz-breakdown {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-2);
}

.fz-breakdown-item {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
}

.fz-breakdown-dot {
    inline-size: 0.625rem;
    block-size: 0.625rem;
    flex-shrink: 0;
    border-radius: 50%;
}

.fz-breakdown-total {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-3);
    margin-block: var(--fz-space-3);
    padding-top: var(--fz-space-3);
    border-top: 1px solid var(--bs-border-color);
}

/* Los avisos de la ficha: PMI, bajo el agua, archivada. El color lo ponen las
   utilidades `bg-*-subtle` / `text-*-emphasis`, que leen la paleta del tema. */
.fz-house-notice {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-3);
    padding: var(--fz-space-3) var(--fz-space-4);
    border-radius: var(--bs-border-radius-lg);
}

.fz-house-notice-icon {
    inline-size: 1.5rem;
    block-size: 1.5rem;
    flex-shrink: 0;
}

.fz-house-notice-body {
    flex: 1 1 18rem;
}

/* El boton del aviso verde: contorno del mismo verde que su texto.
   `.btn-outline-success` no sirve -trae el verde de Bootstrap compilado y no
   lee la paleta (ADR 0021, hechos del CSS de Bootstrap)-. */
.fz-btn-ok {
    --bs-btn-color: var(--fz-state-ok-text);
    --bs-btn-border-color: var(--fz-state-ok-text);
    --bs-btn-hover-color: var(--bs-body-bg);
    --bs-btn-hover-bg: var(--fz-state-ok-text);
    --bs-btn-hover-border-color: var(--fz-state-ok-text);
    --bs-btn-active-color: var(--bs-body-bg);
    --bs-btn-active-bg: var(--fz-state-ok-text);
    --bs-btn-active-border-color: var(--fz-state-ok-text);
}

/* La barra de pago de la ficha lleva dos acciones: pagar ocupa lo que sobre y
   refinanciar lo justo. */
.fz-house-paybar {
    display: flex;
    gap: var(--fz-space-2);
}

@media (min-width: 576px) {
    .fz-house-paybar {
        display: none;
    }
}

/* ===========================================================================
   17 quater. RESUMEN DEL PRESUPUESTO  (ADR 0029)
   ===========================================================================

   La dona con su leyenda al lado, la barra del tope debajo y el ritmo del mes
   al pie. Dos figuras que miden cosas distintas: el anillo reparte el gasto
   entre categorias -suma 100 % siempre- y la barra dice cuanto de ese gasto
   cabe en el tope.

   La cifra del hueco es HTML superpuesto, no `<text>` del SVG: dentro del
   `viewBox` escalaria con el ancho de la tarjeta, que va de 360 px a mas de
   1100 (misma razon que el ADR 0028 §2).
   =========================================================================== */

.fz-budget-figure {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-4);
    margin-bottom: var(--fz-space-3);
}

/* `position: relative` es lo que sostiene la cifra del hueco. El ancho fijo, y
   no un porcentaje: la dona es una figura y el texto de dentro esta calibrado
   contra este tamano. */
.fz-budget-donut {
    position: relative;
    flex: none;
    inline-size: 11rem;
    /* Un `<svg>` es inline: sin esto, el hueco de la linea base deja la caja
       unos pixeles mas alta que el dibujo y la cifra de dentro queda baja. Los
       dos renglones de la cifra traen su propio `line-height`. */
    line-height: 0;
}

/* El hueco del anillo mide el 57,5 % del dibujo. La caja del texto se centra en
   el, y solo mide lo que mide su contenido: estirada de arriba abajo taparia
   los arcos y habria que quitarle el puntero con `pointer-events: none`, que
   ademas dejaria la cifra sin poderse seleccionar. Un importe largo se sale por
   ABAJO -donde no hay nada- y no por los lados, que es donde esta el arco. */
.fz-budget-center {
    position: absolute;
    inset-inline: 22%;
    inset-block-start: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.125rem;
    text-align: center;
}

.fz-budget-spent {
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.fz-budget-limit {
    font-size: 0.75rem;
    line-height: 1.2;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

/* `1 1 16rem`: por debajo de esa base la leyenda se va a su propia linea y la
   dona queda arriba, que es lo unico que cabe en un movil. */
.fz-budget-legend {
    flex: 1 1 16rem;
    display: grid;
    gap: var(--fz-space-1);
    min-width: 0;
}

/* Punto, nombre e importe. El nombre es la unica columna elastica: lo que se
   recorta cuando falta sitio es el texto, nunca la cifra. */
.fz-budget-legend > li {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--fz-space-2);
}

.fz-budget-legend .fz-amount-md {
    text-align: end;
    white-space: nowrap;
}

.fz-budget-foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--fz-space-2);
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
}

/* ===========================================================================
   18. ARMAZON DE NAVEGACION  (ADR 0021 §7)
   ===========================================================================

   `body` es el contenedor: el riel y el `<main>` son hermanos directos, asi que
   la maquetacion sale sin envolver nada. Eso es lo que permite que las dieciocho
   pantallas que ya existian no cambien ni una linea: siguen emitiendo su
   `<nav>` y su `<main class="container py-4">` en ese orden.

   Se dibuja MOVIL PRIMERO -barra inferior- y el riel entra a partir de 768px,
   que es el orden en el que se usa el producto.
   =========================================================================== */

body {
    display: flex;
    flex-direction: column;
    /* Misma razon que en `.auth-shell`: con `vh`, en un movil el cuerpo nace mas
       alto que la pantalla y aparece un scroll que no lleva a ninguna parte. */
    min-height: 100vh;
    min-height: 100dvh;
}

body > main {
    flex: 1 1 auto;
    min-width: 0;
}

/* --- El area segura del iPhone ---------------------------------------------

   El layout pide `viewport-fit=cover`: la pagina llega a los bordes de la
   pantalla, y cada pieza que toca uno se aparta con `env(safe-area-inset-*)`.
   Abajo, la barra de pestañas y lo que se apoya en ella; arriba, la franja de
   aqui debajo, la cabecera de la landing y el acceso. Fuera del iPhone `env()`
   vale 0 y nada de esto mueve un pixel.

   Arriba va una banda navy del alto de la barra de estado -la del reloj y la
   isla- como primer hijo del body: el color de la franja de la marca y del
   `theme-color`, asi que sin avisos se lee como una sola pieza, y con un aviso
   del layout, este empieza debajo del reloj y no detras. Solo donde hay franja
   (las pantallas con sesion) y por debajo de 1024, donde el body es columna.
   ------------------------------------------------------------------------- */

@media (max-width: 1023.98px) {
    body:has(> .fz-topbar)::before {
        content: "";
        flex: 0 0 env(safe-area-inset-top, 0px);
        background-color: var(--fz-rail-bg);
    }
}

/* La barra de desplazamiento, solo con el dedo: en el telefono iOS la pinta
   sobre el borde derecho de cada pantalla al desplazar, y ahi no se arrastra.
   Con raton o trackpad (`hover: hover`) se queda: dice cuanto falta y se usa. */
@media (hover: none) and (pointer: coarse) {
    html {
        scrollbar-width: none;
    }
}

/* --- Movil: la franja de la marca (ADR 0094) -------------------------------

   Navy como el riel, al que sustituye como sitio de la marca por debajo de
   1024px, y oscura en los dos temas por lo mismo: el logo -cartera blanca,
   barras verdes- se penso sobre ese fondo. Por eso declara `color-scheme` y
   repinta el foco, igual que la seccion 19 hace con el riel.

   En el flujo y NO fija: se va al desplazar. El borde inferior es el que la
   separa de la pagina en tema oscuro, donde el navy y el fondo quedan a 1.11:1.
   ------------------------------------------------------------------------- */

/* La marca, centrada: es lo unico que lleva la franja. */
.fz-topbar {
    display: flex;
    justify-content: center;
    background-color: var(--fz-rail-bg);
    border-bottom: 1px solid var(--fz-rail-border);
    color-scheme: dark;
}

/* 48px de alto: el objetivo tactil, y lo que pide el logo de 36 con aire. */
.fz-topbar-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-height: 3rem;
    color: var(--fz-rail-text-strong);
    font-size: 1.0625rem;
    font-weight: 700;
    text-decoration: none;
}

.fz-topbar-brand:hover {
    color: var(--fz-rail-text-strong);
}

.fz-topbar :where(a):focus-visible {
    outline-color: var(--fz-rail-mark);
}

/* --- Movil: barra inferior fija -------------------------------------------

   Fija y no al final del documento: se llega a ella sin recorrer la pagina,
   que es justo lo que se pedia. Al estar fuera del flujo, el contenido necesita
   sitio reservado abajo o la ultima fila se queda debajo de la barra. */

.fz-rail {
    display: none;
}

.fz-tabbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 1030;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    /* La fila mide el alto DECLARADO menos el borde de arriba, y no lo que
       resulte de la pestaña mas alta: asi la barra mide `--fz-tabbar-h` por
       construccion, que es el numero con el que el body le reserva sitio y la
       barra de pago de /loans se apoya encima (ver el token). */
    grid-template-rows: calc(var(--fz-tabbar-h) - 1px);
    align-items: end;
    background-color: var(--fz-surface);
    border-top: 1px solid var(--bs-border-color);
    /* El area segura del iPhone: sin esto la barra queda bajo el indicador.
       Solo vale con `viewport-fit=cover` en el layout; sin el, iOS da 0. A los
       lados, el telefono acostado deja la isla a la izquierda o a la derecha. */
    padding-bottom: env(safe-area-inset-bottom, 0);
    padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px);
}

/*
 * Sitio para la barra, SOLO donde hay barra.
 *
 * Va en el BODY y no en el `<main>`, y esa es la correccion de un fallo real:
 * las dieciocho pantallas usan `<main class="container py-4">`, y las utilidades
 * de espaciado de Bootstrap llevan `!important`. `.py-4` ganaba siempre, asi que
 * el hueco reservado eran los 24px del propio `py-4` y no los 72 de aqui: la
 * barra tapaba el borde inferior de la ultima tarjeta.
 *
 * Pelearlo con otro `!important` habria sido empezar una guerra de prioridades
 * dentro de la hoja. El body no lo toca ninguna utilidad, asi que el espacio se
 * reserva ahi y `py-4` deja de estorbar.
 *
 * `:has(> .fz-tabbar)` y no a secas: el acceso -login y registro- no lleva
 * armazon, y ahi el hueco seria un espacio muerto bajo una tarjeta ya centrada.
 */
body:has(> .fz-tabbar) {
    /* El alto real de la barra, no una estimacion: `--fz-tabbar-h` explica de
       donde sale (seccion 2). Decia 3.5rem "porque la barra mide ~53px" y mide
       62.89: el hueco se quedaba 6.89 px corto y solo lo tapaba que el `py-4`
       del main regala 24 px por dentro. Cuadrado con lo que ve el navegador. */
    padding-bottom: calc(var(--fz-tabbar-h) + env(safe-area-inset-bottom, 0px));
}

.fz-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Abajo y no centrado: las cinco pestañas no miden lo mismo -"Capturar"
       lleva un disco de 40 px y mide 61.89, las demas 52-, y centrando cada una
       en su propio alto el rotulo de Capturar quedaba 4 px mas bajo que los
       otros cuatro. Pegado al fondo, los cinco rotulos comparten linea. */
    justify-content: flex-end;
    gap: 0.15rem;
    /* 44px: el objetivo tactil minimo, aqui con holgura. */
    min-height: 3.25rem;
    padding: var(--fz-space-1) 0.15rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
    text-align: center;
}

.fz-tab:hover {
    color: var(--bs-body-color);
}

/* El destino actual NO se marca solo con color: lleva ademas el peso en negrita
   y el icono relleno por el `is-current`, que es lo que ve quien no distingue
   el tinte del rotulo activo. */
.fz-tab.is-current {
    color: var(--fz-brand);
    font-weight: 600;
}

.fz-tab-icon {
    width: 1.375rem;
    height: 1.375rem;
    flex: 0 0 auto;
}

.fz-tab-text {
    font-size: 0.625rem;
    line-height: 1.15;
    /* Dos lineas como maximo: "Presupuestos" en aleman no cabe en una, y
       recortarlo con puntos suspensivos deja un rotulo que no se lee. */
    overflow-wrap: anywhere;
}

/* Capturar: el unico relleno de la barra. Es la tarea caliente del producto. */
.fz-tab-capture-disc {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

.fz-tab-capture {
    color: var(--bs-body-color);
}

/* --- Movil: el desplegable "Mas" ------------------------------------------

   Es un `.fz-menu` (seccion de las tarjetas de /loans). Lo propio: se despliega
   HACIA ARRIBA, porque nace en el borde inferior de la pantalla y hacia abajo no
   habria sitio; y es mas ancho, porque lleva los rotulos de los destinos.

   Sin separacion entre hijos: dentro van la lista de destinos y el boton de
   salir, y la lista ya pega sus enlaces sin hueco; 2 px solo antes del ultimo
   se verian como un descuido. */
.fz-more-panel {
    top: auto;
    bottom: calc(100% + var(--fz-space-2));
    gap: 0;
    min-width: 13rem;
}

/* --- Enlaces, comunes a riel y desplegable -------------------------------- */

.fz-nav-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.fz-nav-link {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    width: 100%;
    min-height: var(--fz-control-height);
    padding: var(--fz-space-2) var(--fz-space-3);
    border: 0;
    border-radius: var(--bs-border-radius);
    background-color: transparent;
    color: var(--bs-secondary-color);
    font-size: 0.9375rem;
    text-align: start;
    text-decoration: none;
}

.fz-nav-link:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

/* El actual: fondo, color Y peso. Tres senales, no solo el tinte. */
.fz-nav-link.is-current {
    background-color: var(--bs-primary-bg-subtle);
    color: var(--fz-brand);
    font-weight: 600;
}

.fz-nav-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
}

.fz-nav-signout {
    color: var(--bs-secondary-color);
    font-family: inherit;
    font-size: 0.9375rem;
}

.fz-nav-group {
    margin: var(--fz-space-4) 0 var(--fz-space-1);
    padding-inline: var(--fz-space-3);
    color: var(--bs-tertiary-color);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* --- Escritorio: el riel --------------------------------------------------

   Entra a 1024 y no a 768, y esto es la correccion de un diseño que no
   sobrevivio a la medida.

   La idea original era un riel intermedio de 72px con el rotulo debajo del
   icono. Medido en el navegador, de esos 72px quedaban 35 de texto util
   —descontando la barra de scroll del propio riel, su relleno y el del enlace—:
   con cuerpo de 10px son cinco o seis caracteres, y `overflow-wrap: anywhere`
   partia las palabras por la mitad ("Presup/uestos", "Categor/ias"). Y no era
   solo cuestion de ancho: el contenido del riel medido en vertical daba 838px
   contra los 734 de una ventana acoplada de portatil, asi que "Ajustes" y
   "Cerrar sesion" quedaban fuera del borde.

   Ensancharlo no arreglaba lo segundo, y el problema vuelve en cuanto el rotulo
   se traduce a un idioma mas largo. Asi que hasta 1024 manda la barra inferior,
   que ya funciona y no depende del largo del texto; el riel entra cuando hay
   sitio de verdad para el rotulo al lado del icono.
   ------------------------------------------------------------------------- */

@media (min-width: 1024px) {
    body {
        flex-direction: row;
    }

    /* Las franjas de aviso del layout -borrado pendiente (ADR 0039) y modo
       soporte (ADR 0065)- van ENCIMA del riel y el contenido, no como una
       columna mas de la fila: ocupan la fila entera y lo demas baja. */
    body:has(> .fz-page-banner) {
        flex-wrap: wrap;
    }

    .fz-page-banner {
        flex: 0 0 100%;
    }

    /* Con `wrap`, un `main` de base `auto` con una tabla ancha dentro bajaria a
       otra fila, debajo del riel. Base 0: se queda al lado y crece. */
    body:has(> .fz-page-banner) > main {
        flex-basis: 0;
    }

    body:has(> .fz-tabbar) {
        padding-bottom: 0;
    }

    .fz-tabbar,
    .fz-topbar {
        display: none;
    }

    .fz-rail {
        display: flex;
        flex-direction: column;
        flex: 0 0 14.5rem;
        gap: var(--fz-space-1);
        /* Pegado al borde y con su propio scroll: el contenido se desplaza sin
           llevarse la navegacion. */
        position: sticky;
        top: 0;
        align-self: flex-start;
        /* Alto de la ventana, no solo tope: con `max-height` el riel ocupaba lo que
           su contenido (747 px) y en una ventana mas alta debajo asomaba el fondo
           de la pagina. `dvh` con `vh` de reserva, como `.auth-shell`: en un
           movil `100vh` es mas alto que lo visible. */
        height: 100vh;
        height: 100dvh;
        overflow-y: auto;
        /*
         * 12px arriba y abajo, no 16, y el motivo esta MEDIDO (ADR 0030).
         *
         * Con 16 el riel ocupaba 739px de contenido en una ventana acoplada de
         * portatil de 734, o sea que se desplazaba por CINCO pixeles. Y lo que
         * cuestan esos cinco no son cinco: al aparecer la barra, de los 232px
         * del riel se van 15 a la barra y el rotulo de los diez destinos se
         * queda con 216. Un 6.5% de ancho permanente a cambio de cinco pixeles
         * de altura es mal negocio, y se paga en la unica pantalla donde el
         * ancho ya iba justo.
         *
         * Con esto y los 4px del pie el contenido baja a 727 y cabe con 7 de
         * margen. NO es una garantia: un idioma que parta un rotulo en dos
         * lineas vuelve a desbordar, y entonces el riel se desplaza, que es
         * correcto. Lo que se compra es el caso comun -espanol, portatil-, no
         * la inmunidad.
         *
         * El relleno lateral va en `--fz-rail-pad-x` porque el plegado lo
         * cambia (ADR 0093) y la marca del destino actual lo necesita para
         * llegar al filo.
         */
        --fz-rail-pad-x: var(--fz-space-3);

        padding: var(--fz-space-3) var(--fz-rail-pad-x);
        background-color: var(--fz-surface);
        border-inline-end: 1px solid var(--bs-border-color);
        /* Y cuando SI se desplace, que la barra cueste la mitad. */
        scrollbar-width: thin;
    }

    /* La separacion con la primera lista ya no la pone este relleno inferior:
       la pone `.fz-rail-head` (seccion 20), que es quien envuelve a la marca
       desde que comparte fila con el conmutador. Aqui dentro descuadraria el
       centrado vertical de los dos. */
    .fz-rail-brand {
        display: flex;
        align-items: center;
        gap: var(--fz-space-3);
        padding: var(--fz-space-1) var(--fz-space-3);
        color: var(--bs-body-color);
        font-size: 1.0625rem;
        font-weight: 700;
        text-decoration: none;
    }

    .fz-rail-foot {
        margin-top: auto;
        /* Los otros 4px de los que habla el bloque de arriba. Con la linea que
           ADR 0030 le puso encima, 12 separan igual de bien que 16. */
        padding-top: var(--fz-space-3);
    }

    .fz-rail form {
        width: 100%;
    }
}

/* ===========================================================================
   19. EL RIEL OSCURO  (ADR 0030)
   ===========================================================================

   El riel deja de ser "la pagina con un borde" y pasa a ser una superficie
   propia, oscura en los dos temas. Lo que se gana no es decoracion: hasta aqui
   la navegacion y el contenido eran del mismo color y solo los separaba una
   linea de 1px, que en tema oscuro aporta 1.08:1 -o sea, casi nada-.

   TRES COSAS SE MUEVEN Y UNA SE QUEDA COMO ESTABA:

     - La superficie es navy fijo. En claro da 15.85:1 contra el fondo de
       pagina. En oscuro da 1.11:1, y eso NO se arregla aclarandolo: es
       exactamente lo que ya le pasa a `.card` (1.08:1) y la seccion 1 deja
       escrito que ahi quien dibuja el limite es el borde. Por eso el borde del
       riel sube a un blanco al 9%, que si se ve sobre navy; el
       `--bs-border-color` del tema no se veria.
     - El destino actual pasa de `--bs-primary-bg-subtle` -un lavanda muy
       palido- a una pastilla con una marca al filo del riel. Desde ADR 0093 la
       pastilla ya no es un relleno plano: es navy con un brillo indigo debajo
       del icono, y los iconos pasan a indigo con halo (seccion 19.2).
     - El pie estrena conmutador de tema y bloque de usuario (seccion 19.3).
     - El ANCHO no se toca. La referencia que motivo esto usaba ~84px con el
       rotulo debajo del icono; ese diseno ya se midio y se tiro en este mismo
       proyecto, y el porque sigue escrito arriba, en la seccion 18.

   LOS TONOS, Y POR QUE ESTOS Y NO OTROS.

   Al ser una superficie permanentemente oscura, se escriben literales en los
   dos bloques de tema: en el bloque claro las variables de marca valen otra
   cosa. Los de ADR 0093 -icono, pastilla, brillo y marca del actual- salen de
   medir pixel a pixel la imagen de referencia que trajo el usuario.

   Medido con la formula WCAG 2.1, no estimado, y con una prueba que lo
   recalcula sobre este archivo en cada ejecucion:

     rotulo inactivo   #C7CEE0 sobre riel       10.79:1   AAA
     rotulo actual     #FFFFFF sobre el brillo   6.37:1   AA (el peor punto)
     encabezado grupo  #8792AD sobre riel        5.46:1   AA
     icono             #7488EE sobre riel        5.26:1   el 3:1 de WCAG 1.4.11
     marca del actual  #6178DC sobre riel        4.23:1   el 3:1 de WCAG 1.4.11
     anillo de foco    #9DABFF sobre riel        7.85:1   WCAG 2.4.11

   La pastilla ya NO llega a 3:1 contra el riel (1.30:1 el navy, 2.67:1 el
   centro del brillo), y es a sabiendas (ADR 0093):
   la referencia la quiere tenue, navy con un brillo, no un bloque relleno. Lo
   que dice "estas aqui" con contraste de forma es la MARCA lateral, que si
   pasa de 3:1, y ademas cambian el icono (indigo -> blanco con halo), el
   rotulo (10.79 -> 16.99), el peso (400 -> 600) y `aria-current`. La pastilla
   es la quinta senal, no la unica.

   Alto contraste de Windows: `forced-colors` sustituye fondo y texto por los
   del sistema -el riel deja de ser navy, y esta bien- y la seccion 14 ya le
   pone un `outline: Highlight` al destino actual, que es la unica senal que ahi
   sobrevive. Lo unico que hay que apagar a mano es el halo de los iconos
   (19.2): el sistema quita sombras, pero no filtros.
   =========================================================================== */

/* --- 19.1 La superficie --------------------------------------------------- */

.fz-rail {
    background-color: var(--fz-rail-bg);
    border-inline-end-color: var(--fz-rail-border);
    color: var(--fz-rail-text);
    /* El riel es oscuro pase lo que pase, asi que los controles nativos que
       caigan dentro -empezando por su propia barra de desplazamiento, que en
       este riel aparece- tienen que saberlo. Sin esto, en tema claro el riel
       navy luce una barra blanca pegada al borde. */
    color-scheme: dark;
}

/* El logo no se repinta aqui: la cartera blanca y las barras verdes ya
   destacan sobre el navy. Solo el nombre pasa al blanco del riel. */
.fz-rail .fz-rail-brand {
    color: var(--fz-rail-text-strong);
}

/* El logo del riel, mas grande que el de `.fz-mark` (ADR 0093): 42 x 30 desde
   que es la cartera apaisada (ADR 0095). La franja del movil (ADR 0094) lo
   lleva igual: es la misma marca en otro sitio. */
.fz-rail .fz-mark,
.fz-topbar .fz-mark {
    width: 2.625rem;
    height: 1.875rem;
}

/*
 * El foco. Lo mas facil de olvidar de toda la seccion y lo unico que seria un
 * fallo de accesibilidad de verdad.
 *
 * La seccion 5 pinta el anillo de foco con `--fz-brand`; en tema CLARO eso es
 * #2B3FB8, que sobre el navy da 2.03:1, por debajo del 3:1 que WCAG 2.4.11 le
 * pide a un indicador de foco. Es decir: llevar el riel a oscuro sin tocar esto
 * dejaria sin rastro visible a quien navega con teclado en tema claro. Dentro
 * del riel el anillo pasa al indigo claro, que da 7.85:1.
 */
.fz-rail :where(a, button, summary, [tabindex]):focus-visible {
    outline-color: var(--fz-rail-mark);
}

/* --- 19.2 Los enlaces ----------------------------------------------------- */

.fz-rail .fz-nav-link,
.fz-rail .fz-nav-signout {
    color: var(--fz-rail-text);
}

.fz-rail .fz-nav-link:hover,
.fz-rail .fz-nav-signout:hover {
    background-color: var(--fz-rail-hover-bg);
    color: var(--fz-rail-text-strong);
}

.fz-rail .fz-nav-group {
    color: var(--fz-rail-group);
}

/*
 * Los iconos, en indigo y con halo (ADR 0093). El rotulo NO cambia: sigue en el
 * gris claro de siempre, que es el que se lee a 10.79:1. El color va en el
 * icono y no en el enlace porque el icono pinta con `currentColor`.
 *
 * El halo es un `drop-shadow` y no un `box-shadow`: sigue el trazo del icono, no
 * la caja de 20px. Entra el conmutador del menu, que tambien es `.fz-nav-icon`.
 */
.fz-rail .fz-nav-icon {
    color: var(--fz-rail-icon);
    filter: drop-shadow(0 0 4px var(--fz-rail-icon-glow));
}

.fz-rail .fz-nav-link:hover .fz-nav-icon,
.fz-rail-toggle:hover .fz-nav-icon {
    color: var(--fz-rail-mark);
}

/*
 * La pastilla del destino actual (ADR 0093): navy, con un brillo indigo justo
 * debajo del icono que se apaga hacia los bordes, un filo de luz de 1px y un
 * resplandor leve por fuera. Todo medido sobre la referencia.
 *
 * El brillo se centra en el ICONO, no en la pastilla. Plegado son lo mismo
 * (50%); desplegado el icono va al principio y el brillo con el -12px de
 * relleno + 10 de medio icono-, y el rotulo queda sobre el navy, que es donde
 * mejor se lee. `--fz-rail-glow-x` lo cambia la seccion 20.4.
 */
.fz-rail .fz-nav-link.is-current,
.fz-rail .fz-nav-link.is-current:hover {
    --fz-rail-glow-x: 1.375rem;
    --fz-rail-glow-size: 1.75rem 1.375rem;

    position: relative;
    background-color: var(--fz-rail-current-bg);
    background-image: radial-gradient(
        var(--fz-rail-glow-size) at var(--fz-rail-glow-x) 50%,
        var(--fz-rail-current-glow),
        color-mix(in srgb, var(--fz-rail-current-glow) 55%, transparent) 50%,
        transparent
    );
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.06),
        0 0 0.375rem color-mix(in srgb, var(--fz-rail-current-glow) 30%, transparent);
    color: var(--fz-rail-current-text);
}

/* Las posiciones de un degradado no tienen version logica: en un idioma de
   derecha a izquierda el icono va al otro extremo y el brillo se espeja aqui. */
.fz-rail .fz-nav-link.is-current:dir(rtl) {
    --fz-rail-glow-x: calc(100% - 1.375rem);
}

.fz-rail .fz-nav-link.is-current .fz-nav-icon {
    color: var(--fz-rail-current-text);
    filter: drop-shadow(0 0 2px var(--fz-rail-mark));
}

/* Alto contraste: el sistema quita sombras y degradados, pero no los filtros, y
   el halo seguiria en indigo sobre su paleta. Va aqui y no en la seccion 14
   porque alli perderia contra las reglas de arriba, que vienen despues. */
@media (forced-colors: active) {
    .fz-rail .fz-nav-icon,
    .fz-rail .fz-nav-link.is-current .fz-nav-icon {
        filter: none;
    }
}

/*
 * La marca lateral, al borde del RIEL y no al borde de la pastilla.
 *
 * El desplazamiento negativo la saca del enlace y la lleva hasta el filo,
 * cancelando el relleno lateral del propio riel. Va en propiedades logicas
 * -`inset-inline-start`- y no en `left`: el dia que exista arabe el riel se
 * voltea entero y esto se voltea con el.
 */
.fz-rail .fz-nav-link.is-current::before {
    content: '';
    position: absolute;
    inset-block: 0.4rem;
    inset-inline-start: calc(-1 * var(--fz-rail-pad-x));
    width: 3px;
    border-start-end-radius: 3px;
    border-end-end-radius: 3px;
    background-color: var(--fz-rail-current-mark);
}

/* --- 19.3 El pie: tema y usuario ------------------------------------------

   Lo unico de la seccion que cambia la ESTRUCTURA de `_nav.php` y no solo su
   color. Se separa del resto con una linea porque son cosas de otra
   naturaleza: arriba se va a alguna parte, aqui se cambia algo de uno mismo.
   -------------------------------------------------------------------------- */

.fz-rail .fz-rail-foot {
    border-top: 1px solid var(--fz-rail-border);
}

/*
 * Conmutador de tema: un solo control, el que lleva al tema contrario (ADR 0070).
 *
 * Antes eran dos botones lado a lado -plegado, uno encima del otro- y ocupaban
 * dos filas de la columna para una accion que solo tiene un sentido posible: si
 * estas en claro, lo unico que puedes pedir es oscuro. Ahora es una fila mas del
 * riel, con el mismo aspecto que "Cerrar sesion" (`.fz-nav-link`).
 *
 * El HTML trae los dos y aqui se esconde el que pediria el tema que ya se ve.
 * Se lee de `data-bs-theme` en <html> porque es lo unico que sabe el tema real:
 * con la preferencia en automatico lo pone `theme.js` segun el sistema, y el
 * servidor no lo conoce. Sin el atributo -solo si el script no llega- se
 * pinta claro, asi que se ofrece oscuro.
 */
.fz-rail-theme button {
    font-family: inherit;
}

:root[data-bs-theme='dark'] .fz-rail-theme button[value='dark'],
:root:not([data-bs-theme='dark']) .fz-rail-theme button[value='light'] {
    display: none;
}

/*
 * El bloque de usuario ES el enlace a /settings. Por eso "Configuracion" sale
 * de la lista de arriba, donde era un destino mas entre diez, y queda donde ya
 * lo busca todo el mundo: pegado a su propio nombre.
 *
 * Sigue estando en la barra inferior de movil, dentro de "Mas": alli no hay pie
 * ni bloque de usuario, y quitarlo lo dejaria inalcanzable.
 */
.fz-rail-user {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    padding: var(--fz-space-2);
    border-radius: var(--bs-border-radius);
    color: var(--fz-rail-text);
    text-decoration: none;
}

.fz-rail-user:hover {
    background-color: var(--fz-rail-hover-bg);
    color: var(--fz-rail-text-strong);
}

/* En /settings el bloque es la pantalla actual, y se marca como tal. No lleva
   la pastilla rellena de un destino de la lista: es un elemento de otra forma y
   otro tamano, y el relleno se lo comeria. */
.fz-rail-user.is-current {
    background-color: var(--fz-rail-hover-bg);
}

/*
 * Iniciales, no foto.
 *
 * La foto es el caso raro: una cuenta nace sin ella y muchas se quedan asi. El
 * hueco gris con la silueta generica no distingue nada; las iniciales si, y se
 * leen a 7.85:1. Cuando haya foto de perfil, la misma caja la muestra con
 * `object-fit: cover` sin cambiar una linea de esto.
 */
.fz-rail-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background-color: var(--fz-rail-mark);
    color: var(--fz-rail-bg);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    object-fit: cover;
}

.fz-rail-user-body {
    min-width: 0;
    flex: 1 1 auto;
}

/* Un nombre largo se recorta en vez de partir el bloque en tres lineas. Se
   recorta con puntos suspensivos y no con `anywhere`, porque aqui el texto no
   es un rotulo de la interfaz sino lo que escribio el usuario: se reconoce por
   el principio. */
.fz-rail-user-name {
    display: block;
    color: var(--fz-rail-text-strong);
    font-size: 0.875rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-rail-user-hint {
    display: block;
    color: var(--fz-rail-group);
    font-size: 0.75rem;
}

/* La flecha no es un destino: se queda gris y sin el halo de los iconos. */
.fz-rail-user .fz-nav-icon {
    color: var(--fz-rail-group);
    filter: none;
}


/* ===========================================================================
   20. EL RIEL SE PLIEGA  (ADR 0031)
   ===========================================================================

   El riel nace PLEGADO -solo iconos- y se despliega con un conmutador propio.
   Al entrar a la aplicacion siempre esta plegado: el estado no se guarda en
   ninguna parte, asi que no hay nada que pueda contradecirlo.

   ESTO NO CONTRADICE LO QUE MIDIO LA SECCION 18. Lo que alli se descarto fue un
   riel estrecho PERMANENTE con el rotulo debajo del icono: de sus 72px quedaban
   35 de texto util y "Presup/uestos" se partia por la mitad. Aqui no hay rotulo
   estrecho que leer -no hay rotulo-, y el rotulo entero esta a un clic. Son dos
   problemas distintos con la misma medida de por medio.

   TRES COSAS SOSTIENEN QUE ESTO FUNCIONE SIN JAVASCRIPT Y SIN PERDER A NADIE:

     - El mecanismo es una casilla + `:has(.fz-rail-switch:checked)`. El
       navegador la conmuta con raton y con teclado; el CSS solo lee el
       resultado. `:has()` ya se usa en la seccion 18 (`body:has(> .fz-tabbar)`).
     - Los rotulos se RECORTAN, nunca se ocultan con `display: none`. El icono va
       `aria-hidden`, asi que el texto es lo unico que nombra al enlace: sin el,
       un riel plegado son diez enlaces sin nombre.
     - El globo con el rotulo lo pone `nav.js` con el atributo `title`, y solo
       mientras esta plegado. No se puede escribir en la plantilla porque
       desplegado sobraria, y no se puede dibujar con CSS porque el riel lleva
       `overflow-y: auto` y recortaria el globo contra su propio borde.

   Todo vive dentro del `@media (min-width: 1024px)`: por debajo no hay riel, hay
   barra inferior, y la casilla ni siquiera es enfocable porque su padre esta en
   `display: none`.
   =========================================================================== */

@media (min-width: 1024px) {
    /* --- 20.1 El mecanismo ------------------------------------------------ */

    .fz-rail-head {
        display: flex;
        align-items: center;
        gap: var(--fz-space-2);
        /* Los 16px que antes ponia el relleno inferior de la marca. */
        padding-bottom: var(--fz-space-4);
    }

    .fz-rail-brand {
        min-width: 0;
        flex: 1 1 auto;
    }

    /*
     * La casilla: recortada, no oculta.
     *
     * Con `display: none` dejaria de recibir el foco y el riel solo se podria
     * plegar con el raton. Recortada sigue en el orden de tabulacion, justo
     * detras de la marca, que es donde se la espera.
     */
    .fz-rail-switch {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .fz-rail-toggle {
        display: flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
        width: 2.25rem;
        height: 2.25rem;
        border-radius: var(--bs-border-radius);
        color: var(--fz-rail-text);
        cursor: pointer;
    }

    .fz-rail-toggle:hover {
        background-color: var(--fz-rail-hover-bg);
        color: var(--fz-rail-text-strong);
    }

    /*
     * El anillo de foco lo pinta la ETIQUETA, no la casilla.
     *
     * La casilla esta recortada a 1px: su anillo -el de la seccion 4- existiria
     * y no lo veria nadie. Quien navega con teclado se quedaria sin saber que
     * esta encima del conmutador. Mismo grosor y mismo desfase que la regla
     * general, con el indigo claro que la seccion 19 exige dentro del riel.
     */
    .fz-rail-switch:focus-visible + .fz-rail-toggle {
        outline: 2px solid var(--fz-rail-mark);
        outline-offset: 2px;
    }

    /* --- 20.2 La medida --------------------------------------------------- */

    /*
     * 6.25rem = 100px, el ancho de la referencia de ADR 0093 (antes 5rem). La
     * cuenta importa porque el riel puede llegar a llevar su propia barra de
     * desplazamiento:
     *
     *   100 - 32 (relleno del riel plegado, 16 por lado) = 68px de sitio util,
     *   que es el ancho de la pastilla del destino actual
     *   - el enlace mide 25 (icono) + 24 (su relleno) = 49
     *   - el disco del usuario mide 36 + 8 = 44
     *   - si aparece la barra fina (~11px) quedan 57, y los dos siguen entrando
     *
     * Por debajo de 5rem el bloque de usuario se recorta contra el borde en
     * cuanto el riel se desplaza, que es justo cuando nadie lo esta mirando.
     */
    .fz-rail {
        flex-basis: 6.25rem;
    }

    .fz-rail:not(:has(.fz-rail-switch:checked)) {
        --fz-rail-pad-x: 1rem;
    }

    .fz-rail:has(.fz-rail-switch:checked) {
        flex-basis: 14.5rem;
    }

    /* --- 20.3 Plegado: lo que se recorta ---------------------------------- */

    /*
     * Los rotulos se van de la vista pero NO del documento.
     *
     * Es la unica regla de esta seccion que es un asunto de accesibilidad y no
     * de maquetacion. Los dos son lo unico que nombra a su control: el enlace
     * -su icono va `aria-hidden`; el conmutador de tema es uno de ellos- y el
     * bloque de usuario, cuyo disco de iniciales tambien va `aria-hidden`. Con
     * `display: none` el riel plegado seria una columna de controles anonimos.
     */
    .fz-rail:not(:has(.fz-rail-switch:checked)) :is(
        .fz-nav-text,
        .fz-rail-user-body
    ) {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    /* La flecha del bloque de usuario si desaparece del todo: no nombra nada,
       solo decia "esto lleva a otra pantalla", y plegado no cabe. */
    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-rail-user .fz-nav-icon {
        display: none;
    }

    /* --- 20.4 Plegado: la columna ----------------------------------------- */

    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-rail-head {
        flex-direction: column;
        gap: var(--fz-space-1);
        padding-bottom: var(--fz-space-3);
    }

    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-rail-brand {
        flex: 0 0 auto;
        padding: 0 var(--fz-space-1);
    }

    .fz-rail:not(:has(.fz-rail-switch:checked)) :is(.fz-nav-link, .fz-rail-user) {
        justify-content: center;
        gap: 0;
    }

    /*
     * 2.5rem plegado contra los 2.75 de siempre.
     *
     * Los diez controles de la columna, el conmutador nuevo y el pie
     * suman mas alto que el riel desplegado, y el alto disponible en una
     * ventana acoplada de portatil son 734px (seccion 18). Estos 4px por fila
     * son los que evitan que el riel PLEGADO -el que se ve al entrar- nazca con
     * barra de desplazamiento. Sigue muy por encima del objetivo de 24x24 de
     * WCAG 2.5.8, y a 1024px de ancho ya se navega con raton.
     */
    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-link {
        min-height: 2.5rem;
    }

    /*
     * Plegado, a la medida de la referencia de ADR 0093: iconos de 25px, filas
     * de los destinos a 45px y la pastilla del actual de 68 x 46. Desplegado no
     * cambia: junto a un rotulo de 15px un icono de 25 pesa mas que el texto.
     *
     * Las filas grandes son solo las de los DESTINOS (`.fz-nav-list`): el tema
     * y cerrar sesion se quedan en 40, y con eso el riel cabe desde 821px de
     * alto, que es donde empieza este tamaño (por debajo manda la 20.5).
     */
    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-icon {
        width: 1.5625rem;
        height: 1.5625rem;
    }

    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-list .fz-nav-link {
        min-height: 2.8125rem;
    }

    /* El icono esta centrado y el brillo de la pastilla tambien, a la escala
       de la pastilla grande. */
    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-list .fz-nav-link.is-current {
        --fz-rail-glow-x: 50%;
        --fz-rail-glow-size: 2.1875rem 1.75rem;

        min-height: 2.875rem;
    }

    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-rail-user {
        padding: var(--fz-space-1);
    }

    /*
     * El encabezado de grupo se convierte en una raya.
     *
     * No se puede quitar: cada lista lo referencia con `aria-labelledby`, y sin
     * el, "Hipotecas" y "Prestamos" dejan de saberse parte de "Deudas". Se le
     * baja el alto a 1px con `overflow: hidden` -que esconde el texto sin
     * sacarlo del documento- y el fondo dibuja la separacion que antes hacian
     * las palabras.
     */
    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-group {
        height: 1px;
        margin: var(--fz-space-2);
        padding: 0;
        overflow: hidden;
        background-color: var(--fz-rail-border);
        color: transparent;
    }
}

/* --- 20.5 Ventanas bajas: filas de 36px ------------------------------------

   En la ventana maximizada de esta maquina (734px de alto, seccion 18) el riel
   no cabia en ninguno de sus dos estados. Medido en Chrome: el desplegado
   pedia 821px y el plegado 745. Son trece filas -once destinos, el tema y
   cerrar sesion- a 44 y a 40px, y la barra de desplazamiento salia en las dos
   formas.

   Por debajo de 821px de alto las trece filas bajan a 36px: el desplegado
   queda en 717 y el plegado en 693, los dos dentro de 734. Por encima no cambia
   nada, porque ahi ya cabian. 36px sigue muy por encima de los 24x24 de WCAG
   2.5.8, y a partir de 1024px de ancho se navega con raton.

   Bajar el minimo no basta: desplegado, la fila la fija el renglon de texto
   (22.5px) mas los 8px de relleno arriba y abajo, 38.5 en total, y seguia
   sobrando por 16px. Con 4px de relleno el minimo vuelve a mandar.

   El segundo selector repite el del plegado (20.4) con la misma especificidad:
   como este bloque va despues, gana el. Sin el, el plegado se quedaria en 40.

   Los destinos del plegado a la medida de ADR 0093 (filas de 45, pastilla de
   46) no caben aqui: a 734px pedirian unos 100px de mas. Las filas de los
   destinos se quedan en 38 y la pastilla del actual conserva sus 46, que es
   lo que la hace verse como en la referencia. Medido a 734: el plegado pide
   725 y cabe con 9 de margen. El desplegado no cambia (717).
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) and (max-height: 51.25rem) {
    .fz-rail .fz-nav-link,
    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-link {
        min-height: 2.25rem;
        padding-block: var(--fz-space-1);
    }

    .fz-rail:not(:has(.fz-rail-switch:checked)) .fz-nav-list .fz-nav-link {
        min-height: 2.375rem;
    }
}

/* ===========================================================================
   21. LA REJILLA DEL PANEL  (ADR 0033)
   ===========================================================================

   El panel eran once bloques a lo ancho, apilados. Cada tarjeta ocupaba los
   1320 px del `.container`, se dijera con ella tres cifras o seis meses de
   grafica, y el resultado era una pagina de cuatro pantallazos donde todo
   pesaba lo mismo: el aviso de un presupuesto excedido gritaba al mismo volumen
   que la lista de metas.

   Lo que se reparte aqui es el ANCHO, no el orden: el orden del documento sigue
   siendo el de lectura y el de tabulacion, igual que cuando las cuentas subieron
   a lo ancho (ADR 0021 §4). Aqui no hay una sola regla `order`.

   Tres decisiones que explican la forma de esto:

   1. Es `flex` y no `grid` de doce columnas. Casi todos los bloques del panel
      son CONDICIONALES -la tendencia no existe sin movimientos, el presupuesto
      sin tope, los avisos sin nada que avisar- y en una rejilla de columnas
      fijas un bloque que no se pinta deja un hueco del tamano de su vecino.
      Con `flex: 1 1 <base>` el que se queda solo en su linea CRECE y llena el
      ancho, asi que el panel de un espacio recien creado no se ve roto.

   2. Solo existe a partir de 1200 px. Por debajo el panel sigue siendo una
      columna, sin una regla nueva que pueda fallar: lo que se estaba
      desperdiciando era el ancho del escritorio, no el del telefono.

   3. Los bloques con rejilla PROPIA se quedan enteros. Las cuentas cortan a
      cuatro por fila (ADR 0026), las deudas y las metas a tres, y esos cortes
      son `@media` de VIEWPORT: meterlos en media tarjeta los dejaria pintando
      cuatro columnas en 640 px sin enterarse. Lo que se empareja son los
      bloques que no tienen nada dentro que repartir.
   =========================================================================== */

@media (min-width: 1200px) {
    .fz-bento {
        display: flex;
        flex-wrap: wrap;
        /* Solo la separacion horizontal: la vertical ya la pone el `mb-4` que
           cada tarjeta trae, y sumar `row-gap` la doblaria. */
        column-gap: var(--fz-space-4);
    }

    /*
     * Por defecto, ancho entero. Se declara sobre el hijo directo y no bloque a
     * bloque para que un bloque nuevo nazca a lo ancho, que es lo que no
     * sorprende; estrecharlo es la decision que hay que tomar a proposito.
     *
     * `min-width: 0` porque un hijo flex no baja del ancho de su contenido: sin
     * el, una tabla o un importe largo ensancha la tarjeta y saca la fila de la
     * pagina.
     */
    .fz-bento > * {
        flex: 1 1 100%;
        min-width: 0;
    }

    /*
     * Las cuatro tarjetas que se emparejan, de dos en dos y en el orden en que
     * ya estaban.
     *
     * "Este mes" con la tendencia: son la misma pregunta con distinto alcance
     * -cuanto llevas, y si eso es mucho o poco (ADR 0028)-, y separadas por
     * media pantalla habia que recordar la primera para entender la segunda.
     * El presupuesto con sus avisos, por lo mismo: cuanto te queda y que se te
     * paso.
     *
     * La base es la mitad menos medio hueco, para que dos sumen exactamente el
     * ancho disponible. Si una de las dos no se pinta, la otra crece sola.
     */
    .fz-bento > .fz-hero,
    .fz-bento > .fz-trend,
    .fz-bento > .fz-budget,
    .fz-bento > [data-budget-alerts] {
        flex-basis: calc(50% - (var(--fz-space-4) / 2));
    }

    /*
     * "Este mes" sola junto a la grafica (ADR 0076).
     *
     * Con una moneda la franja comparte fila con la tendencia -o con el
     * presupuesto, si aun no hay movimientos- y el `stretch` que iguala la fila
     * la estiraba hasta el alto de la grafica: 78 px de cifras en una tarjeta de
     * 260, el enlace arriba, las cifras abajo y 160 px vacios en medio. Ahi deja
     * de ser franja y pasa a ser tarjeta: la cabecera de su vecina -titulo y
     * enlace en la misma linea- y las tres cifras en filas que se reparten el
     * alto, como un estado de cuenta.
     *
     * El selector es la geometria: una franja en posicion impar -las franjas se
     * emparejan entre si, asi que se queda sola en su fila- seguida de una
     * tarjeta de media fila. Con dos monedas las franjas van juntas y no cambia
     * nada; sin tendencia ni presupuesto la franja crece a lo ancho y tampoco.
     */
    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-body {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-rows: auto 1fr;
        align-items: baseline;
        gap: var(--fz-space-2) var(--fz-space-3);
    }

    /* El titulo a la vista: deshace el recorte de `.fz-hero-title`. */
    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-title {
        position: static;
        width: auto;
        height: auto;
        overflow: visible;
        clip-path: none;
        white-space: normal;
    }

    /* En la linea del titulo, como el "Reporte" de la tendencia. */
    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-link {
        align-self: baseline;
    }

    /* Las cifras, en la segunda fila, a todo lo ancho y con todo el alto que
       sobra. Con la fila dicha, titulo y enlace se colocan solos en la primera. */
    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-month {
        grid-row: 2;
        grid-column: 1 / -1;
        align-self: stretch;
        display: flex;
        flex-direction: column;
        gap: 0;
    }

    /* Rotulo a la izquierda e importe a la derecha: los tres importes quedan en
       columna y se comparan de un vistazo. Cada fila se lleva un tercio del alto
       y centra lo suyo, asi que las rayas caen a medio camino entre cifras. */
    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-month > div {
        flex: 1 1 0;
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-content: center;
        /* Centrado y no por la linea base: el rotulo lleva su baldosa (ADR 0088). */
        align-items: center;
        column-gap: var(--fz-space-3);
    }

    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-month > div + div {
        border-top: 1px solid var(--bs-border-color-translucent);
    }

    .fz-bento > .fz-hero:nth-child(odd of .fz-hero):has(+ .fz-trend, + .fz-budget) .fz-hero-month dt {
        font-size: 0.875rem;
    }
}

/* ===========================================================================
   22. PRESUPUESTO DEL MES  (ADR 0045)
   ===========================================================================

   La pantalla de /budgets: las monedas juntas y sin sumarse, la prevision de
   cierre al ritmo del mes y el panel de alta y cambio. Todo `fz-bud-*`: los
   nombres `fz-budget-*` ya son de la tarjeta del panel de inicio, y reusar uno
   rompio /goals una vez (ver `.fz-goal-item-body`).

   Escritorio (>= 992 px): cuatro tarjetas de cifras, la barra del tope global
   y una tabla real. Por debajo, una tarjeta grande y la tabla convertida en
   tarjetas por CSS: el mismo marcado, sin duplicar filas.
   =========================================================================== */

.fz-bud-shrink {
    min-width: 0;
}

.fz-bud-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

.fz-bud-new {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
}

/* En un telefono el alta es un "+" sobre fondo suave, como en el diseño: el
   nombre accesible sigue en `aria-label`. */
@media (max-width: 575.98px) {
    .fz-bud-new {
        --bs-btn-bg: var(--bs-primary-bg-subtle);
        --bs-btn-color: var(--bs-primary-text-emphasis);
        --bs-btn-border-color: transparent;
        --bs-btn-hover-bg: var(--bs-primary-border-subtle);
        --bs-btn-hover-color: var(--bs-primary-text-emphasis);
        --bs-btn-hover-border-color: transparent;
        width: var(--fz-control-height);
        padding: 0;
    }

    .fz-bud-new-label {
        display: none;
    }
}

/* --- Barra de herramientas: mes, vista y la linea de monedas ---------------- */
.fz-bud-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

.fz-bud-month {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: var(--fz-control-height);
    background-color: var(--fz-surface);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

@media (min-width: 576px) {
    .fz-bud-month {
        width: 18.75rem;
    }
}

.fz-bud-month-step {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    min-height: calc(var(--fz-control-height) - 2px);
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
}

a.fz-bud-month-step:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

.fz-bud-month-step.is-disabled {
    color: var(--bs-border-color);
}

.fz-bud-step-icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-bud-month-label {
    flex: 1 1 auto;
    text-align: center;
    font-weight: 600;
}

.fz-bud-view {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    width: 100%;
}

.fz-bud-view .form-select {
    flex: 1 1 auto;
}

@media (min-width: 576px) {
    .fz-bud-view {
        width: auto;
    }

    .fz-bud-view .form-select {
        min-width: 12.5rem;
    }
}

.fz-bud-meta,
.fz-bud-readonly {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-bud-readonly {
    margin-bottom: var(--fz-space-4);
}

/* --- Tarjetas de cifras (escritorio, ADR 0083) ------------------------------ */
/* La tarjeta comun `fz-kpi` (seccion 10 bis). Solo desde 992 px: por debajo
   habla la tarjeta grande. Cuatro en fila, no las tres de `.fz-kpis`. */
.fz-bud-figures {
    display: none;
}

@media (min-width: 992px) {
    .fz-bud-figures {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* La prevision que rebasa el tope, en el color de excedido: `.fz-kpi-amount`
   va despues que `.budget-text-exceeded` en la hoja y, sin esto, le ganaria
   con su color de enfasis. */
.fz-bud-figures .budget-text-exceeded {
    color: var(--fz-state-over-text);
}

/* --- La tarjeta grande (movil) ---------------------------------------------- */
.fz-bud-hero {
    margin-bottom: var(--fz-space-3);
}

@media (min-width: 992px) {
    .fz-bud-hero {
        display: none;
    }
}

.fz-bud-hero-block + .fz-bud-hero-block {
    margin-top: var(--fz-space-3);
    padding-top: var(--fz-space-3);
    border-top: 1px solid var(--bs-border-color-translucent);
}

.fz-bud-hero-caption {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* El rotulo y, a su derecha, el cambio o el alta del tope global de la moneda
   (ADR 0104). El lapiz mide 44 px para el dedo, pero sus margenes negativos lo
   dejan en la altura del rotulo: el importe no baja. */
.fz-bud-hero-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2);
}

.fz-bud-hero-action {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    margin: calc(-1 * var(--fz-space-3)) calc(-1 * var(--fz-space-3)) calc(-1 * var(--fz-space-3)) 0;
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
}

.fz-bud-hero-action:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--fz-brand);
}

.fz-bud-hero-action-icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* El mismo blanco de 44 px que el lapiz, sin mover el rotulo. */
.fz-bud-hero-set {
    flex: 0 0 auto;
    margin: calc(-1 * var(--fz-space-3)) 0;
    padding: var(--fz-space-3) 0;
    font-size: 0.8125rem;
    font-weight: 600;
}

.fz-bud-hero-value {
    margin: 0 0 var(--fz-space-2);
    font-size: var(--fz-amount-hero);
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.fz-bud-hero-block.is-secondary .fz-bud-hero-value {
    font-size: var(--fz-amount-lg);
}

.fz-bud-hero-foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--fz-space-1) var(--fz-space-2);
    margin: var(--fz-space-2) 0 0;
    font-size: 0.8125rem;
}

.fz-bud-hero-forecast {
    margin: var(--fz-space-2) 0 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-bud-hero-forecast.budget-text-exceeded {
    color: var(--fz-state-over-text);
    font-weight: 600;
}

.fz-bud-hero-help {
    margin: var(--fz-space-3) 0 0;
    padding-top: var(--fz-space-2);
    border-top: 1px solid var(--bs-border-color-translucent);
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

/* --- La barra del tope global y su marca de "hoy" ---------------------------- */
.fz-bud-track {
    position: relative;
}

.fz-bud-track .budget-bar {
    height: 0.75rem;
    margin: 0;
    clip-path: inset(0 round 0.375rem);
}

/* La raya de hoy sobresale de la barra por arriba y por abajo; por eso es un
   SVG aparte y no un rectangulo dentro de la barra, que recorta su contorno
   (ver ProgressBar::marker). */
.fz-bud-marker {
    position: absolute;
    left: 0;
    top: -0.3125rem;
    width: 100%;
    height: calc(100% + 0.625rem);
    overflow: visible;
    pointer-events: none;
}

.fz-bud-marker line {
    stroke: var(--bs-emphasis-color);
    stroke-width: 2px;
}

.fz-bud-global {
    display: none;
    margin-bottom: var(--fz-space-4);
}

@media (min-width: 992px) {
    .fz-bud-global {
        display: block;
    }
}

.fz-bud-global .card-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-3);
}

.fz-bud-global-head,
.fz-bud-section-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2) var(--fz-space-3);
}

.fz-bud-section-head {
    margin-bottom: var(--fz-space-2);
}

.fz-bud-section-title {
    margin: 0;
    font-size: 0.9375rem;
    font-weight: 600;
}

.fz-bud-section-title-lg {
    font-size: 1.125rem;
    font-weight: 700;
}

.fz-bud-global-day {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-bud-global-row {
    display: grid;
    grid-template-columns: 3rem minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--fz-space-4);
}

/* Con el lapiz de su tope (ADR 0104), una columna mas. Sus margenes negativos
   lo dejan a la altura del texto: la tarjeta no crece por el. */
.fz-bud-global-row.has-change {
    grid-template-columns: 3rem minmax(0, 1fr) auto auto;
}

.fz-bud-global-row .fz-bud-change {
    margin: calc(-1 * var(--fz-space-3)) calc(-1 * var(--fz-space-3)) calc(-1 * var(--fz-space-3)) calc(-1 * var(--fz-space-2));
}

.fz-bud-global-currency {
    font-size: 0.8125rem;
    font-weight: 600;
}

.fz-bud-global-summary {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
    text-align: right;
    white-space: nowrap;
}

.fz-bud-global-help {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    margin: 0;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-bud-marker-key {
    flex-shrink: 0;
    width: 2px;
    height: 0.875rem;
    border-radius: 1px;
    background-color: var(--bs-emphasis-color);
}

/* --- El aviso ---------------------------------------------------------------- */
.fz-bud-alert {
    margin-bottom: var(--fz-space-4);
}

.fz-bud-alert-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-1);
    min-width: 0;
}

.fz-bud-alert strong {
    color: var(--fz-state-over-text);
}

.fz-bud-alert-note {
    margin: 0;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

/* --- La tabla por categoria --------------------------------------------------- */
.fz-bud-categories {
    margin-bottom: var(--fz-space-2);
}

.fz-bud-export {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-1);
    min-height: var(--fz-control-height);
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
}

.fz-bud-export-icon {
    width: 1rem;
    height: 1rem;
}

.fz-bud-table-card {
    overflow: hidden;
}

.fz-bud-table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.fz-bud-table thead th {
    padding: var(--fz-space-3);
    background-color: var(--bs-tertiary-bg);
    border-bottom: 1px solid var(--bs-border-color);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

.fz-bud-table tbody > tr > *,
.fz-bud-table tfoot > tr > * {
    padding: var(--fz-space-3);
    vertical-align: middle;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.fz-bud-table thead th:first-child,
.fz-bud-table tbody > tr > :first-child,
.fz-bud-table tfoot > tr > :first-child {
    padding-left: var(--fz-space-4);
}

.fz-bud-table tbody > tr > .fz-bud-cell-action,
.fz-bud-table tfoot > tr > .fz-bud-cell-action {
    width: 3.5rem;
    padding: var(--fz-space-1) var(--fz-space-2) var(--fz-space-1) 0;
    text-align: right;
}

.fz-bud-cell-name {
    font-weight: 600;
    text-align: left;
}

.fz-bud-name-wrap {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-width: 0;
}

.fz-bud-name {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.fz-bud-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-bud-name-note {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-bud-cell-limit {
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

.fz-bud-cell-spent {
    font-weight: 700;
    white-space: nowrap;
}

.fz-bud-cell-remaining {
    white-space: nowrap;
}

.fz-bud-cell-progress {
    width: 13rem;
}

.fz-bud-cell-progress .budget-bar {
    margin: 0 0 var(--fz-space-1);
}

.fz-bud-progress-foot {
    display: flex;
    gap: var(--fz-space-2);
    font-size: 0.75rem;
    font-weight: 600;
}

.fz-bud-progress-status {
    flex: 1 1 auto;
}

.fz-bud-progress-of {
    display: none;
}

.fz-bud-committed {
    display: block;
    margin-top: var(--fz-space-1);
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-bud-change {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
}

.fz-bud-change:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--fz-brand);
}

.fz-bud-change-icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-bud-table tfoot > tr > * {
    background-color: var(--bs-tertiary-bg);
    font-weight: 700;
}

.fz-bud-table tfoot .fz-bud-name-note {
    font-weight: 400;
}

.fz-bud-empty-row td {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* La cabecera de cada grupo (ADR 0103): el rotulo y el icono de la captura y
   de /categories, para reconocer aqui el mismo bloque. Icono gris: el color es
   de las baldosas de las filas. */
.fz-bud-table tbody > tr.fz-bud-group > th {
    padding: var(--fz-space-4) var(--fz-space-4) var(--fz-space-2);
    border-bottom: 1px solid var(--bs-border-color);
}

.fz-bud-group-head {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    font-size: 0.9375rem;
    font-weight: var(--fz-weight-heading);
}

.fz-bud-group-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
    color: var(--bs-secondary-color);
}

/*
 * Movil: cada fila es una tarjeta. El mismo `<tr>` pasa a rejilla -nombre y
 * gastado arriba, la barra debajo- y el enlace de cambiar se estira sobre la
 * tarjeta entera, que es como se toca en un telefono. El tope y lo restante
 * salen de la vista pero no del documento: el "de S/ 3 600" de la barra lo
 * dice igual.
 */
@media (max-width: 991.98px) {
    .fz-bud-table-card {
        overflow: visible;
        background-color: transparent;
        border: 0;
        box-shadow: none;
    }

    .fz-bud-table,
    .fz-bud-table tbody,
    .fz-bud-table tfoot {
        display: block;
    }

    .fz-bud-table thead {
        display: none;
    }

    .fz-bud-table tr {
        position: relative;
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            'name spent'
            'progress progress';
        align-items: center;
        gap: var(--fz-space-2) var(--fz-space-3);
        margin-bottom: var(--fz-space-3);
        padding: var(--fz-space-3);
        background-color: var(--fz-surface);
        border: 1px solid var(--bs-border-color);
        border-radius: var(--bs-border-radius-lg);
    }

    .fz-bud-table tbody > tr > *,
    .fz-bud-table tfoot > tr > *,
    .fz-bud-table tbody > tr > :first-child,
    .fz-bud-table tfoot > tr > :first-child {
        padding: 0;
        border: 0;
        background-color: transparent;
    }

    .fz-bud-table tfoot tr {
        background-color: var(--bs-tertiary-bg);
    }

    /* El pie no lleva acciones (ADR 0104): sus celdas vacias no ocupan una fila
       de la rejilla ni su hueco. */
    .fz-bud-table tfoot > tr > td:empty {
        display: none;
    }

    /* El avance del total y, a la derecha, su "de S/ 3,880.00" (ADR 0105),
       como el pie de la barra de cada fila. */
    .fz-bud-total-progress {
        display: flex;
        align-items: baseline;
        gap: var(--fz-space-2);
    }

    .fz-bud-total-progress .fz-bud-progress-of {
        font-size: 0.8125rem;
    }

    .fz-bud-cell-name {
        grid-area: name;
    }

    .fz-bud-cell-spent {
        grid-area: spent;
    }

    .fz-bud-cell-progress {
        grid-area: progress;
        width: auto;
    }

    .fz-bud-cell-limit,
    .fz-bud-cell-remaining {
        display: none;
    }

    /* Solo en /budgets: la fila es una tabla con seis columnas y la baldosa es
       lo unico que puede ceder sin perder un dato. En el resto de la aplicacion
       la baldosa mide lo mismo en todas las anchuras. */
    .fz-bud-row .fz-tile {
        width: 2rem;
        height: 2rem;
    }

    .fz-bud-progress-status {
        flex: 0 0 auto;
    }

    .fz-bud-progress-of {
        display: inline;
        margin-left: auto;
        font-weight: 400;
        color: var(--bs-secondary-color);
    }

    .fz-bud-table tbody > tr > .fz-bud-cell-action,
    .fz-bud-table tfoot > tr > .fz-bud-cell-action {
        width: auto;
        padding: 0;
    }

    /* El enlace cubre la tarjeta: un blanco de 44 px no hace falta buscarlo. */
    .fz-bud-change {
        position: absolute;
        inset: 0;
        width: auto;
        height: auto;
        border-radius: inherit;
    }

    .fz-bud-change:hover {
        background-color: transparent;
    }

    .fz-bud-change-icon {
        display: none;
    }

    .fz-bud-empty-row,
    .fz-bud-empty-row td {
        display: block;
    }

    /* La cabecera del grupo no es una tarjeta: un rotulo sobre las suyas. */
    .fz-bud-table tr.fz-bud-group {
        display: block;
        margin: var(--fz-space-4) 0 var(--fz-space-2);
        padding: 0;
        background-color: transparent;
        border: 0;
        border-radius: 0;
    }

    .fz-bud-table tbody:first-of-type > tr.fz-bud-group {
        margin-top: 0;
    }

    .fz-bud-table tbody > tr.fz-bud-group > th {
        display: block;
        padding: 0;
        border: 0;
    }
}

.fz-bud-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2) var(--fz-space-4);
    margin-top: var(--fz-space-2);
}

.fz-bud-committed-line {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-bud-committed-line strong {
    font-weight: 600;
    color: var(--bs-body-color);
}

.fz-bud-report-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--fz-control-height);
    font-size: 0.875rem;
    font-weight: 600;
}

/* Dos radios con aspecto de interruptor segmentado: nacio para la moneda del
   panel de alta (ADR 0045, retirado en el ADR 0102) y hoy lo usa el periodo de
   los precios de la landing. Siguen siendo radios: teclado y lector de pantalla
   los entienden como tales. */
.fz-bud-segmented {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: var(--fz-space-1);
    padding: 0.1875rem;
    background-color: var(--bs-secondary-bg);
    border-radius: var(--bs-border-radius);
}

.fz-bud-segment {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(var(--fz-control-height) - 0.375rem);
    border-radius: var(--bs-border-radius-sm);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
    cursor: pointer;
}

.fz-bud-segment input {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.fz-bud-segment:has(input:checked) {
    background-color: var(--fz-surface);
    color: var(--bs-body-color);
    box-shadow: var(--fz-elev-1);
}

.fz-bud-segment:has(input:focus-visible) {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

/* ===========================================================================
   REPORTE DEL MES  (ADR 0047)
   ===========================================================================
   Diez secciones de una moneda a la vez. Reutiliza lo que ya existe y tiene
   nombre: el paso de mes de /budgets (`.fz-bud-month*`), el menu nativo
   (`.fz-menu*`), la tendencia HTML del panel (`.fz-trend-*`), las barras y la
   raya del dia (`.budget-bar`, `.fz-bud-marker`) y los puntos de color
   (`.fz-budget-dot`, `.fz-account-dot`). Lo propio lleva el prefijo
   `fz-report-`, que no usaba nadie. Ni un `style=`: la CSP no lo admite
   (ADR 0021 §9). */

.fz-report-head {
    margin-bottom: var(--fz-space-4);
}

/* --- Barra de herramientas: mes, cuenta, moneda y CSV -------------------- */
.fz-report-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

/* Base cero: en un telefono filtro, moneda y CSV comparten fila y el filtro se
   queda con lo que sobre, en vez de empujar el CSV a una fila propia. */
.fz-report-filter {
    flex: 1 1 0;
    min-width: 7rem;
}

@media (min-width: 576px) {
    .fz-report-filter {
        min-width: 10rem;
        max-width: 15rem;
    }
}

/* Un `<summary>` que se ve como un select: la flecha la pone `.form-select`. El
   nombre va en su propio `<span>` porque un texto suelto dentro de un flex no
   hace elipsis y se montaba sobre la flecha. */
.fz-report-filter > summary.form-select {
    display: flex;
    align-items: center;
    min-height: var(--fz-control-height);
}

.fz-report-filter-label {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* El panel no se encoge con el boton: en un telefono el boton mide 10rem y los
   nombres de cuenta se partian en dos lineas. */
.fz-report-filter-panel {
    left: 0;
    right: auto;
    min-width: max(100%, 15rem);
    max-height: 22rem;
    overflow-y: auto;
}

/* De 576 a 767 la barra va en dos filas y el filtro cierra la primera, pegado
   al borde derecho: abierto hacia la derecha, sus 15rem se salian de la
   pantalla (a 576, 6 px cortados). Aqui se abre hacia la izquierda; el mes va
   delante, asi que sobra sitio. Por debajo el filtro empieza fila, y desde 768
   todo cabe en una y el panel tiene sitio a la derecha. */
@media (min-width: 576px) and (max-width: 767.98px) {
    .fz-report-filter-panel {
        left: auto;
        right: 0;
    }
}

.fz-report-check {
    width: 1rem;
    height: 1rem;
    margin-left: auto;
    flex: none;
    color: var(--fz-brand);
}

/* El conmutador de moneda: enlaces que se ven como un segmentado. */
/* Dos pixeles de relleno y no tres: cada opcion queda en 38 px, la misma altura
   que el segmentado de /budgets (`.fz-bud-segment`). */
.fz-report-currency {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    min-height: var(--fz-control-height);
    background-color: var(--fz-surface);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.fz-report-currency-option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-1);
    min-width: 3.5rem;
    padding: 0 var(--fz-space-3);
    border-radius: var(--bs-border-radius-sm);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--bs-body-color);
    text-decoration: none;
}

.fz-report-currency-option:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

.fz-report-currency-option.is-current,
.fz-report-currency-option.is-current:hover {
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

.fz-report-export {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
}

/* Hasta escritorio el CSV es solo el icono, para que mes, cuenta, moneda y CSV
   quepan en una o dos filas. El texto sigue ahi para el lector de pantalla,
   escondido a la vista y no con `display: none`. */
@media (max-width: 991.98px) {
    .fz-report-export {
        width: var(--fz-control-height);
        padding: 0;
        justify-content: center;
    }

    .fz-report-export > span {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
}

.fz-report-filtered {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-2);
    margin: 0 0 var(--fz-space-4);
    padding: var(--fz-space-2) var(--fz-space-3);
    background-color: var(--bs-primary-bg-subtle);
    border: 1px solid var(--bs-primary-border-subtle);
    border-radius: var(--bs-border-radius);
    font-size: 0.875rem;
}

.fz-report-filtered-icon {
    width: 1rem;
    height: 1rem;
    flex: none;
}

.fz-report-filtered a {
    margin-left: auto;
    font-weight: 600;
}

/* --- Resumen del mes: los mosaicos ---------------------------------------- */
.fz-report-summary {
    margin-bottom: var(--fz-space-4);
}

.fz-report-eyebrow {
    margin: 0 0 var(--fz-space-2);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
}

.fz-report-kpis {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--fz-space-3);
}

/* Cinco en un telefono: el que sobra -la prevision- ocupa la fila entera. */
.fz-report-kpi:last-child:nth-child(odd) {
    grid-column: 1 / -1;
}

@media (min-width: 992px) {
    .fz-report-kpis {
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
    }

    .fz-report-kpi:last-child:nth-child(odd) {
        grid-column: auto;
    }
}

/* El tono pone tres variables locales y la regla comun las usa: un color por
   familia en un solo sitio, y el tema oscuro cambia los tokens, no esto. */
.fz-report-kpi {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: var(--fz-space-3) var(--fz-space-4);
    background-color: var(--kpi-bg);
    border: 1.5px solid var(--kpi-border);
    border-radius: var(--bs-border-radius-lg);
    /* El brillo de la tarjeta comun de cifra resumen (ADR 0086), del color de
       su familia. El relleno se queda: aqui el color dice si es bueno o malo. */
    box-shadow: 0 8px 20px -14px color-mix(in srgb, var(--kpi-border) 60%, transparent);
}

[data-bs-theme='dark'] .fz-report-kpi {
    box-shadow: 0 0 26px -12px color-mix(in srgb, var(--kpi-border) 55%, transparent);
}

.fz-report-kpi-in {
    --kpi-bg: var(--fz-kpi-in-bg);
    --kpi-border: var(--fz-kpi-in-border);
    --kpi-text: var(--fz-kpi-in-text);
}

.fz-report-kpi-out {
    --kpi-bg: var(--fz-kpi-out-bg);
    --kpi-border: var(--fz-kpi-out-border);
    --kpi-text: var(--fz-kpi-out-text);
}

.fz-report-kpi-rate {
    --kpi-bg: var(--fz-kpi-rate-bg);
    --kpi-border: var(--fz-kpi-rate-border);
    --kpi-text: var(--fz-kpi-rate-text);
}

.fz-report-kpi-over {
    --kpi-bg: var(--fz-kpi-over-bg);
    --kpi-border: var(--fz-kpi-over-border);
    --kpi-text: var(--fz-kpi-over-text);
}

/* "Quedarian S/ 3.70": dentro del tope es verde de estado, como en /budgets. */
.fz-report-kpi-ok {
    --kpi-bg: var(--fz-kpi-in-bg);
    --kpi-border: var(--fz-kpi-in-border);
    --kpi-text: var(--fz-kpi-in-text);
}

.fz-report-kpi p {
    margin: 0;
}

/* El rotulo abre con una baldosa del color de la familia (ADR 0087), un
   escalon mas pequeña que la de las cabeceras: el mosaico es la cifra. */
.fz-report-kpi-label {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    font-size: 0.8125rem;
    font-weight: 600;
}

.fz-report-kpi-label .fz-tile {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 0.5rem;
}

.fz-report-kpi-label .fz-tile-icon {
    width: 1rem;
    height: 1rem;
}

.fz-report-kpi-value {
    font-size: 1.1875rem;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--kpi-text);
    overflow-wrap: anywhere;
}

@media (min-width: 576px) {
    .fz-report-kpi-value {
        font-size: 1.5rem;
    }
}

.fz-report-kpi-note {
    font-size: 0.75rem;
    color: var(--fz-kpi-note);
}

.fz-report-kpi-note.is-strong {
    font-weight: 600;
    color: var(--kpi-text);
}

/* --- La rejilla de tarjetas ------------------------------------------------- */
.fz-report-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-auto-flow: row dense;
    gap: var(--fz-space-4);
}

@media (min-width: 992px) {
    .fz-report-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .fz-report-wide {
        grid-column: 1 / -1;
    }
}

.fz-report-card {
    margin: 0;
}

.fz-report-card > .card-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-3);
    height: 100%;
}

/* La cabecera de cada tarjeta: el icono de su modulo -el mismo del menu- en un
   recuadro tintado, titulo y subtitulo, y a la derecha las unidades o el enlace
   al modulo. El icono es el ancla al recorrer el reporte. El color va en el y
   no en el titulo, que en indigo se leeria como enlace; y el titulo no va en
   mayusculas, que en esta pantalla marcan etiquetas ("Resumen del mes", las
   columnas de la tabla). ADR 0067. */
.fz-report-card-head {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    gap: 2px var(--fz-space-3);
}

/* El icono de cada tarjeta es la baldosa de color de su modulo (`View::tile()`,
   36 px), y la tarjeta lleva la superficie de ese tono (ADR 0087). Sustituye al
   recuadro indigo del ADR 0067. */

.fz-report-card-title {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.3;
}

.fz-report-card-sub {
    margin: 2px 0 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-report-card-units {
    margin: 0;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    text-align: end;
}

.fz-report-card-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2) var(--fz-space-3);
    margin-top: auto;
}

.fz-report-card-note {
    margin: 0;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-report-more {
    display: inline-flex;
    align-items: center;
    min-height: var(--fz-control-height);
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-report-card-head .fz-report-more {
    margin-top: calc(var(--fz-space-3) * -1);
}

/* En telefono las unidades bajan bajo el subtitulo: a su lado, con el icono,
   el titulo de flujo de efectivo se partia en dos lineas. */
@media (max-width: 575.98px) {
    .fz-report-card-units {
        grid-column: 2 / -1;
        text-align: start;
    }
}

/* --- Graficas --------------------------------------------------------------- */
.fz-report-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2) var(--fz-space-4);
    margin: 0;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-report-key {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
}

/* La muestra toma el color de la clase de barra que explica: la leyenda va del
   mismo color que la barra o deja de explicarla. */
.fz-report-swatch {
    display: inline-block;
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 2px;
}

.fz-report-flow .fz-trend-pair {
    height: 10rem;
}

/* La tendencia del reporte vive en media fila, no en la fila entera como en el
   panel: con menos ancho, barras mas juntas y cifra un punto mas pequeña para
   que "10.1k" quepa sobre su barra sin cortarse. */
.fz-report-trend .fz-trend-pair {
    gap: 4%;
}

.fz-report-trend .fz-trend-value {
    font-size: 0.75rem;
}

@media (min-width: 992px) and (max-width: 1199.98px) {
    .fz-report-trend .fz-trend-pair {
        gap: 2%;
    }

    .fz-report-trend .fz-trend-value {
        font-size: 0.6875rem;
    }
}

/* En un telefono estrecho seis meses dejan 22 px por barra: se ven los cuatro
   mas recientes, que es lo que se mira desde ahi. `display: none` los saca
   tambien del lector de pantalla, y la escala -la de la serie entera- no
   cambia, asi que las cifras son las mismas. */
@media (max-width: 479.98px) {
    .fz-report-trend > li:nth-child(-n+2) {
        display: none;
    }
}

.fz-report-flow-bar {
    max-width: 3.75rem;
    margin-inline: auto;
    border-radius: 6px 6px 0 0;
    background-color: var(--fz-brand-fill);
}

.fz-report-flow-bar.is-negative {
    background-color: var(--fz-money-out);
}

.fz-report-donut-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-4);
}

.fz-report-donut {
    position: relative;
    flex: none;
    width: 11rem;
    margin-inline: auto;
}

@media (min-width: 576px) {
    .fz-report-donut {
        margin-inline: 0;
    }
}

.fz-report-donut .donut {
    display: block;
}

.fz-report-donut-center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    margin: 0;
    pointer-events: none;
}

.fz-report-donut-total {
    font-size: 1.0625rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.fz-report-donut-caption {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-report-legend-list {
    flex: 1 1 16rem;
    min-width: 0;
}

.fz-report-legend-list li {
    display: grid;
    grid-template-columns: 0.75rem minmax(0, 1fr) auto 3.25rem;
    align-items: center;
    column-gap: var(--fz-space-2);
    min-height: 2rem;
    border-bottom: 1px solid var(--bs-border-color-translucent);
    font-size: 0.8125rem;
}

.fz-report-legend-name {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.fz-report-legend-amount {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: end;
}

.fz-report-legend-share {
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
    text-align: end;
}

/* El gasto por grupo (ADR 0069): la misma fila que la leyenda, con el icono del
   bloque de la captura en lugar del punto de color. */
.fz-report-groups-title {
    margin: var(--fz-space-4) 0 var(--fz-space-1);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
}

.fz-report-groups li {
    grid-template-columns: 1rem minmax(0, 1fr) auto 3.25rem;
}

.fz-report-groups-icon {
    width: 1rem;
    height: 1rem;
}

/* --- Filas con barra: presupuestos y metas ---------------------------------- */
.fz-report-budgets,
.fz-report-goals {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-3);
}

@media (min-width: 768px) {
    .fz-report-goals {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: var(--fz-space-6);
    }
}

.fz-report-row-head {
    display: flex;
    justify-content: space-between;
    gap: var(--fz-space-3);
    margin: 0 0 var(--fz-space-2);
    font-size: 0.8125rem;
}

.fz-report-row-name {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

a.fz-report-row-name {
    font-weight: 600;
    color: var(--bs-body-color);
    text-decoration: none;
}

a.fz-report-row-name:hover {
    text-decoration: underline;
}

.fz-report-row-amount {
    flex: none;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.fz-report-track .budget-bar {
    margin: 0;
}

.fz-report-row-status {
    margin: var(--fz-space-1) 0 0;
    font-size: 0.75rem;
    font-weight: 600;
}

.fz-report-goal {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
}

.fz-report-goal-photo {
    flex: none;
    width: 3.25rem;
    height: 3.25rem;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
}

.fz-report-goal-body {
    flex: 1 1 auto;
    min-width: 0;
}

/* --- Patrimonio ------------------------------------------------------------- */
.fz-report-pair {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
    min-height: 2.75rem;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.fz-report-pair dt {
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-report-pair dd {
    margin: 0;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: end;
}

.fz-report-change {
    font-weight: 600;
}

.fz-report-change-up {
    color: var(--fz-state-ok-text);
}

.fz-report-change-down {
    color: var(--fz-state-over-text);
}

.fz-report-change-flat {
    color: var(--bs-secondary-color);
}

/* --- Lineas con marca: deuda y comprometido --------------------------------- */
.fz-report-lines {
    display: flex;
    flex-direction: column;
}

.fz-report-line {
    display: grid;
    grid-template-columns: 0.625rem minmax(0, 1fr) auto;
    column-gap: var(--fz-space-3);
    row-gap: 2px;
    padding: var(--fz-space-3) 0;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.fz-report-mark {
    grid-row: span 3;
    width: 0.625rem;
    height: 0.625rem;
    margin-top: 0.375rem;
    border-radius: 2px;
}

.fz-report-line.is-compact .fz-report-mark {
    grid-row: span 2;
}

.fz-report-line-name {
    min-width: 0;
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-report-line-name a {
    color: var(--bs-body-color);
    text-decoration: none;
}

.fz-report-line-name a:hover {
    text-decoration: underline;
}

.fz-report-line-amount {
    font-size: 0.875rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: end;
    white-space: nowrap;
}

.fz-report-line-detail {
    font-size: 0.75rem;
    font-weight: 600;
}

.fz-report-line-side {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    text-align: end;
    white-space: nowrap;
}

.fz-report-line-note {
    grid-column: 2 / -1;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-report-line-wide {
    grid-column: 2 / -1;
}

/* La deuda abre cada fila con la foto de la casa o del prestamo, o con el icono
   de su tipo en el mismo recuadro hundido (`.fz-loan-thumb-empty`): con y sin
   foto la fila tiene la misma forma. La talla es la de las fotos de metas del
   mismo reporte. */
.fz-report-line.has-thumb {
    grid-template-columns: 3.25rem minmax(0, 1fr) auto;
}

.fz-report-thumb {
    grid-row: span 3;
    width: 3.25rem;
    height: 3.25rem;
    object-fit: cover;
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface-sunken);
}

.fz-report-thumb-icon {
    width: 1.5rem;
    height: 1.5rem;
}

.fz-report-mark-recurring {
    background-color: var(--fz-cat-5);
}

.fz-report-mark-installments {
    background-color: var(--fz-cat-4);
}

.fz-report-mark-contributions {
    background-color: var(--fz-state-ok-fill);
}

/* La barra apilada del comprometido: SVG del servidor, colores de aqui. */
.fz-report-stack {
    display: block;
    width: 100%;
    height: 0.625rem;
    clip-path: inset(0 round 0.3125rem);
}

.fz-report-stack-track {
    fill: var(--fz-track);
}

.fz-report-stack-recurring {
    fill: var(--fz-cat-5);
}

.fz-report-stack-installments {
    fill: var(--fz-cat-4);
}

.fz-report-stack-contributions {
    fill: var(--fz-state-ok-fill);
}

/* El recuadro de total: con el que cierran patrimonio, deuda, comprometido y
   gasto por cuenta (ADR 0066). Etiqueta, cifra y la nota que dice de donde
   sale. Va pegado a las filas que suma y no al pie de la tarjeta: en una fila
   de la rejilla la tarjeta corta se estira hasta la larga, y bajado al pie el
   total quedaba a un palmo de sus sumandos. */
.fz-report-aside {
    padding: var(--fz-space-3);
    background-color: var(--bs-tertiary-bg);
    border-radius: var(--bs-border-radius);
}

.fz-report-aside p {
    margin: 0;
}

/* Deuda: la deuda total y los intereses del año, lado a lado si caben. */
.fz-report-aside-split {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
    gap: var(--fz-space-3) var(--fz-space-4);
}

.fz-report-aside-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.fz-report-aside-value {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.3;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.fz-report-aside-note {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.fz-report-aside-strong {
    font-weight: 600;
    color: var(--bs-body-color);
}

/* --- Gasto por cuenta y descargas ------------------------------------------- */
.fz-report-table-wrap {
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
}

.fz-report-table {
    --bs-table-bg: transparent;
    font-size: 0.875rem;
}

.fz-report-table th,
.fz-report-table td {
    vertical-align: middle;
}

.fz-report-table thead th {
    background-color: var(--bs-tertiary-bg);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

.fz-report-table tbody th {
    font-weight: 400;
}

/* Sin fila de total, la ultima fila toca el marco: su raya lo doblaria. */
.fz-report-table tbody tr:last-child > * {
    border-bottom-width: 0;
}

.fz-report-account {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-width: 0;
}

.fz-report-account-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* El nombre se parte en dos lineas si hace falta: en una celda de tabla la
   elipsis no funciona sin fijar anchos, y sin ella la tabla pedia scroll lateral
   en un telefono. */
.fz-report-account-name {
    font-weight: 600;
    overflow-wrap: anywhere;
}

.fz-report-account-kind {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

/* En un telefono no caben cuatro columnas de cifras: la de movimientos se va,
   y con ella su cabecera y su total, para que la tabla no pida scroll lateral. */
@media (max-width: 575.98px) {
    .fz-report-col-count {
        display: none;
    }
}

.fz-report-exports {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
    margin-top: auto;
}

.fz-report-exports .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--fz-control-height);
}

@media (max-width: 575.98px) {
    .fz-report-exports .btn {
        flex: 1 1 100%;
    }
}

.fz-report-past {
    margin: var(--fz-space-4) 0 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* ===========================================================================
   MOVIMIENTOS: /transactions Y LA TARJETA DEL PANEL  (ADR 0051)
   ===========================================================================

   Una tabla agrupada por dia, con un `<tbody>` por dia y su encabezado con el
   total. El lenguaje es el de la tabla de /budgets -rotulos en versalitas,
   cuadro de color de la categoria, nombre con nota debajo- para que las dos
   tablas de la aplicacion se lean igual.

   Tres anchos:

     >= 992   las cinco columnas.
     576-991  sin la columna Tipo: el signo y el color del importe ya lo dicen,
              y lo que no cabe es la cuenta.
     < 576    cada fila es una ficha de dos lineas: titulo, y debajo categoria
              y cuenta; el importe a la derecha. Sin scroll lateral.

   Lo que se esconde y se ensena desde JavaScript usa `.fz-mov-hidden` y no el
   atributo `hidden`: un `display` de clase le gana a `[hidden]` (el `d-flex`
   de Bootstrap lleva `!important`).
   =========================================================================== */

.fz-mov-hidden {
    display: none !important;
}

.fz-mov-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

/* --- Filtros ------------------------------------------------------------- */

.fz-mov-filters {
    display: grid;
    grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)) auto;
    gap: var(--fz-space-2);
    margin-bottom: var(--fz-space-3);
}

.fz-mov-filters .form-control,
.fz-mov-filters .form-select,
.fz-mov-filters .btn {
    min-height: var(--fz-control-height);
}

.fz-mov-search {
    position: relative;
}

.fz-mov-search-icon {
    position: absolute;
    top: 50%;
    left: var(--fz-space-3);
    width: 1.125rem;
    height: 1.125rem;
    color: var(--bs-secondary-color);
    transform: translateY(-50%);
    pointer-events: none;
}

.fz-mov-search .form-control {
    padding-left: calc(var(--fz-space-3) * 2 + 1.125rem);
}

/* En dos renglones: la busqueda y el boton arriba, los tres desplegables
   abajo. Con el boton en un renglon propio quedaba suelto bajo la cuenta. */
@media (max-width: 991.98px) {
    .fz-mov-filters {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .fz-mov-search {
        grid-column: 1 / 3;
    }

    .fz-mov-filters .btn {
        grid-column: 3;
        grid-row: 1;
    }
}

@media (max-width: 575.98px) {
    .fz-mov-filters {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .fz-mov-search,
    .fz-mov-filters .btn {
        grid-column: 1 / -1;
    }

    .fz-mov-filters .btn {
        grid-row: auto;
    }
}

/* --- Pildoras de tipo y "Filtros activos" --------------------------------- */

.fz-mov-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2) var(--fz-space-4);
    margin-bottom: var(--fz-space-3);
}

.fz-mov-pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
}

.fz-mov-pill {
    display: inline-flex;
    align-items: center;
    min-height: var(--fz-control-height);
    padding: 0 var(--fz-space-4);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-surface);
    color: var(--bs-body-color);
    font-size: 0.9375rem;
    font-weight: 600;
    text-decoration: none;
}

.fz-mov-pill:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

.fz-mov-pill.is-current {
    border-color: var(--fz-brand-fill);
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

.fz-mov-active {
    margin: 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* Las cuatro pildoras en un renglon a 390: con el relleno de escritorio
   "Transferencias" bajaba sola al segundo. Va despues de la regla base para
   ganarle. */
@media (max-width: 575.98px) {
    .fz-mov-pills {
        gap: var(--fz-space-1);
    }

    .fz-mov-pill {
        padding: 0 var(--fz-space-3);
        font-size: 0.875rem;
    }
}

/* --- La tarjeta ------------------------------------------------------------ */

.fz-mov-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-3);
    padding: var(--fz-space-4) var(--fz-space-4) var(--fz-space-3);
}

.fz-mov-card > .fz-empty {
    padding-block: var(--fz-space-6);
}

/* Sin `overflow: hidden` en la tarjeta, a proposito: el menu "⋯" de la ultima
   fila se abre hacia abajo y quedaria cortado. En /transactions la tabla abre
   la tarjeta y sus esquinas de arriba las redondea el propio encabezado; en el
   panel va debajo del titulo, separada por una linea. */
.fz-mov-card-head ~ .fz-mov-wrap {
    border-top: 1px solid var(--bs-border-color);
}

.fz-mov-table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.fz-mov-table thead th {
    padding: var(--fz-space-3);
    background-color: var(--bs-tertiary-bg);
    border-bottom: 1px solid var(--bs-border-color);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
    text-align: left;
    white-space: nowrap;
}

.fz-mov-card-page .fz-mov-table thead th:first-child {
    border-top-left-radius: var(--bs-card-inner-border-radius);
}

.fz-mov-card-page .fz-mov-table thead th:last-child {
    border-top-right-radius: var(--bs-card-inner-border-radius);
}

.fz-mov-table thead th:first-child,
.fz-mov-row > :first-child,
.fz-mov-day-head > th {
    padding-left: var(--fz-space-4);
}

.fz-mov-table thead .fz-mov-col-amount {
    text-align: right;
}

.fz-mov-row > * {
    padding: var(--fz-space-3);
    vertical-align: middle;
    border-bottom: 1px solid var(--bs-border-color-translucent);
    font-size: 0.9375rem;
}

.fz-mov-row:hover > * {
    background-color: var(--bs-tertiary-bg);
}

.fz-mov-day:last-child .fz-mov-row:last-child > * {
    border-bottom: 0;
}

/* El encabezado del dia: la fecha a la izquierda y su total a la derecha, sobre
   la superficie hundida para que se lea como separador y no como una fila. */
.fz-mov-day-head > th {
    padding-top: var(--fz-space-2);
    padding-right: var(--fz-space-4);
    padding-bottom: var(--fz-space-2);
    background-color: var(--fz-surface-sunken);
    border-bottom: 1px solid var(--bs-border-color-translucent);
    font-weight: 400;
}

.fz-mov-day-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0 var(--fz-space-3);
}

.fz-mov-day-date {
    font-size: 0.875rem;
    font-weight: 700;
}

.fz-mov-day-total {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* --- La fila --------------------------------------------------------------- */

.fz-mov-cell-desc {
    width: 40%;
    max-width: 0;
    font-weight: 400;
    text-align: left;
}

.fz-mov-desc {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-width: 0;
}

.fz-mov-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.fz-mov-title {
    overflow: hidden;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-mov-sub,
.fz-mov-meta {
    overflow: hidden;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* La linea de categoria y cuenta es la de la ficha movil: en la tabla ya son
   columnas. */
.fz-mov-meta {
    display: none;
}

/* Categoria y cuenta con tope y puntos suspensivos: son las columnas que se
   pueden recortar sin perder el dato (el nombre completo de la cuenta queda en
   su `title`), y lo que ganan se lo lleva la descripcion. */
.fz-mov-cell-category {
    max-width: 11rem;
    overflow: hidden;
    color: var(--bs-secondary-color);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-mov-cell-account {
    max-width: 11rem;
    color: var(--bs-secondary-color);
}

.fz-mov-account {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-mov-type {
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
}

.fz-mov-type-expense {
    background-color: var(--bs-danger-bg-subtle);
    border-color: var(--bs-danger-border-subtle);
    color: var(--fz-state-over-text);
}

.fz-mov-type-income {
    background-color: var(--bs-success-bg-subtle);
    border-color: var(--bs-success-border-subtle);
    color: var(--fz-state-ok-text);
}

.fz-mov-type-transfer {
    background-color: rgba(var(--fz-brand-rgb), 0.1);
    border-color: rgba(var(--fz-brand-rgb), 0.25);
    color: var(--fz-brand);
}

.fz-mov-cell-amount {
    font-weight: 700;
    text-align: right;
    white-space: nowrap;
}

/* La transferencia sin filtro de cuenta: ni entra ni sale del espacio. */
.movement-neutral {
    color: var(--bs-body-color);
}

/* --- El menu "⋯" de cada fila ---------------------------------------------- */

.fz-mov-col-action,
.fz-mov-cell-action {
    width: 3rem;
}

.fz-mov-row > .fz-mov-cell-action {
    padding: var(--fz-space-1) var(--fz-space-2) var(--fz-space-1) 0;
    text-align: right;
}

.fz-mov-menu {
    display: inline-block;
}

.fz-mov-menu-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
}

.fz-mov-menu-btn:hover,
.fz-mov-menu[open] > .fz-mov-menu-btn {
    background-color: var(--bs-secondary-bg);
    color: var(--bs-body-color);
}

.fz-mov-menu-btn:focus-visible {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-mov-menu-icon {
    width: 1.25rem;
    height: 1.25rem;
}

.fz-mov-menu .fz-menu-panel {
    top: calc(100% + var(--fz-space-1));
    text-align: left;
}

/* --- El pie: cuantos se ven, cargar mas y exportar ------------------------- */

.fz-mov-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
    padding: var(--fz-space-3) var(--fz-space-4);
    border-top: 1px solid var(--bs-border-color);
    background-color: var(--bs-tertiary-bg);
    border-bottom-left-radius: var(--bs-card-inner-border-radius);
    border-bottom-right-radius: var(--bs-card-inner-border-radius);
}

.fz-mov-showing {
    margin: 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-mov-foot-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-2) var(--fz-space-4);
}

.fz-mov-foot-actions .btn {
    display: inline-flex;
    align-items: center;
    min-height: var(--fz-control-height);
}

.fz-mov-export {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-1);
    min-height: var(--fz-control-height);
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
}

.fz-mov-export-icon {
    width: 1rem;
    height: 1rem;
}

.fz-mov-card [data-movements-error]:not(:empty) {
    padding: 0 var(--fz-space-4) var(--fz-space-3);
}

/* --- El aviso tras capturar ------------------------------------------------ */

.fz-toast {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
    padding: var(--fz-space-3) var(--fz-space-4);
    border: 1px solid rgba(var(--fz-brand-rgb), 0.2);
    border-radius: var(--bs-border-radius-lg);
    background-color: rgba(var(--fz-brand-rgb), 0.08);
}

.fz-toast-text {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 0.9375rem;
}

.fz-toast-text strong {
    color: var(--fz-brand);
}

.fz-toast-undo {
    flex-shrink: 0;
    min-height: var(--fz-control-height);
}

/* --- Anchos intermedios: sin la columna Tipo -------------------------------- */

@media (max-width: 991.98px) {
    .fz-mov-col-type,
    .fz-mov-cell-type {
        display: none;
    }
}

/* Y en esa banda categoria y cuenta ceden mas: con 11rem cada una la
   descripcion se quedaba en 168 px y se cortaban dos de cada tres titulos. */
@media (min-width: 768px) and (max-width: 991.98px) {
    .fz-mov-cell-category,
    .fz-mov-cell-account {
        max-width: 8.5rem;
    }
}

/* --- Telefono y tableta vertical: cada fila es una ficha -------------------- */

/* Hasta 767 y no hasta 575: a 576 el contenedor mide 540 px y las columnas de
   categoria, cuenta e importe ya se comen 490; la descripcion se quedaba sin
   sitio y la tabla sacaba 133 px de scroll lateral a la pagina (medido). */
@media (max-width: 767.98px) {
    .fz-mov-table,
    .fz-mov-table tbody,
    .fz-mov-day-head,
    .fz-mov-day-head > th {
        display: block;
    }

    .fz-mov-table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .fz-mov-row {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto auto;
        align-items: center;
        border-bottom: 1px solid var(--bs-border-color-translucent);
    }

    .fz-mov-day:last-child .fz-mov-row:last-child {
        border-bottom: 0;
    }

    .fz-mov-row > * {
        display: block;
        border-bottom: 0;
    }

    .fz-mov-cell-desc {
        width: auto;
        max-width: none;
        padding-right: var(--fz-space-2);
    }

    /* Se repite `.fz-mov-cell-type` aunque ya se escondio arriba: la regla de
       `.fz-mov-row > *` de este bloque llega despues y lo volveria a mostrar. */
    .fz-mov-row > .fz-mov-cell-category,
    .fz-mov-row > .fz-mov-cell-account,
    .fz-mov-row > .fz-mov-cell-type {
        display: none;
    }

    .fz-mov-meta {
        display: block;
    }

    .fz-mov-row > .fz-mov-cell-amount {
        padding-inline: 0;
    }

    .fz-mov-row > .fz-mov-cell-action {
        width: auto;
        padding: 0 var(--fz-space-1);
    }
}

@media (max-width: 575.98px) {
    .fz-mov-foot {
        flex-direction: column;
        align-items: stretch;
    }

    .fz-mov-foot-actions {
        justify-content: space-between;
    }

    .fz-toast {
        flex-wrap: wrap;
    }

    .fz-toast-undo {
        margin-left: auto;
    }
}

/* --- Administracion de la plataforma (ADR 0058; consola 2026, ADR 0145) -------

   El lado del operador se reconoce sin leer: grafito y ambar en los DOS temas,
   cuando el cliente es navy e indigo. El armazon -franja, riel y barra
   inferior- es oscuro siempre, como el riel del cliente; el contenido sigue el
   tema. Lo que se ve en cada ancho:

     <1024   franja arriba y barra inferior de cuatro pestañas;
     >=1024  riel lateral (usa la fila del `body` de la seccion 18): solo iconos
             hasta 1279 para no apretar las tablas, desplegado desde 1280.

   Las barras y el anillo son SVG con atributos y el color por clase: la CSP no
   admite `style`. Cada objetivo tactil mide los 44 px de la casa. */

/* Los tonos de estado del operador: punto, icono de evento, aviso, cifra. El
   color nunca va solo: cada uso lleva su texto al lado. */
.fz-platform-tone-ok {
    --fz-platform-tone: var(--fz-state-ok-fill);
    --fz-platform-tone-text: var(--fz-state-ok-text);
}

.fz-platform-tone-warn {
    --fz-platform-tone: var(--fz-state-warn-fill);
    --fz-platform-tone-text: var(--fz-state-warn-text);
}

.fz-platform-tone-over {
    --fz-platform-tone: var(--fz-state-over-fill);
    --fz-platform-tone-text: var(--fz-state-over-text);
}

.fz-platform-tone-info {
    --fz-platform-tone: var(--fz-brand-fill);
    --fz-platform-tone-text: var(--fz-brand);
}

.fz-platform-tone-neutral {
    --fz-platform-tone: var(--fz-cat-11);
    --fz-platform-tone-text: var(--bs-secondary-color);
}

/* El chip «Plataforma»: en la superficie de la pagina sigue al tema; dentro
   del armazon grafito va siempre la version oscura. */
.fz-platform-shell {
    --fz-platform-chip-text: var(--fz-platform-accent);
    --fz-platform-chip-bg: var(--fz-platform-accent-soft);
    --fz-platform-chip-border: var(--fz-platform-accent-line);
}

.fz-platform-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.5rem;
    border: 1px solid var(--fz-platform-chip-border);
    border-radius: 999px;
    background-color: var(--fz-platform-chip-bg);
    color: var(--fz-platform-chip-text);
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.5;
    text-transform: uppercase;
    white-space: nowrap;
}

/* El foco dentro del armazon: el anillo indigo no se ve sobre el grafito. */
.fz-platform-shell a:focus-visible,
.fz-platform-shell button:focus-visible {
    outline: 2px solid var(--fz-platform-accent);
    outline-offset: 2px;
    box-shadow: none;
}

/* --- Franja del telefono ---------------------------------------------------- */
.fz-platform-top {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    padding: var(--fz-space-2) var(--fz-space-4);
    padding-top: max(var(--fz-space-2), env(safe-area-inset-top, 0px));
    border-top: 3px solid var(--fz-platform-accent);
    background-color: var(--fz-platform-bg);
    color: var(--fz-platform-text);
}

.fz-platform-top-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
    color: var(--fz-platform-text-strong);
    font-weight: var(--fz-weight-heading);
    text-decoration: none;
}

.fz-platform-top-brand:hover {
    color: var(--fz-platform-text-strong);
}

.fz-platform-top-end {
    display: flex;
    align-items: center;
    gap: var(--fz-space-1);
    margin-left: auto;
}

.fz-platform-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--fz-platform-text);
}

.fz-platform-icon-btn:hover {
    background-color: var(--fz-platform-hover);
    color: var(--fz-platform-text-strong);
}

.fz-platform-icon-btn .icon {
    width: 1.25rem;
    height: 1.25rem;
}

/* --- Barra inferior del telefono --------------------------------------------- */
.fz-platform-tabbar {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 30;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--fz-space-1);
    padding: 0.375rem var(--fz-space-2) calc(0.375rem + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--fz-platform-border);
    background-color: var(--fz-platform-bg);
}

.fz-platform-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.125rem;
    min-height: 3.25rem;
    border-radius: var(--fz-space-3);
    color: var(--fz-platform-text);
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
}

.fz-platform-tab .icon {
    width: 1.375rem;
    height: 1.375rem;
    color: var(--fz-platform-muted);
}

.fz-platform-tab:hover {
    color: var(--fz-platform-text-strong);
}

.fz-platform-tab[aria-current='page'] {
    background-color: var(--fz-platform-accent-soft);
    color: var(--fz-platform-accent-strong);
    font-weight: 600;
}

.fz-platform-tab[aria-current='page'] .icon {
    color: var(--fz-platform-accent);
}

body:has(> .fz-platform-tabbar) {
    padding-bottom: calc(4.25rem + env(safe-area-inset-bottom, 0px));
}

/* --- Riel --------------------------------------------------------------------- */
.fz-platform-rail {
    display: none;
}

@media (min-width: 1024px) {
    .fz-platform-top,
    .fz-platform-tabbar {
        display: none;
    }

    body:has(> .fz-platform-tabbar) {
        padding-bottom: 0;
    }

    /* El fondo grafito se estira con la fila del `body`; lo de dentro se queda
       pegado arriba al desplazar. */
    .fz-platform-rail {
        display: block;
        flex: 0 0 auto;
        width: 5rem;
        border-top: 3px solid var(--fz-platform-accent);
        border-right: 1px solid var(--fz-platform-border);
        background-color: var(--fz-platform-bg);
        color: var(--fz-platform-text);
    }

    .fz-platform-rail-inner {
        position: sticky;
        top: 0;
        display: flex;
        flex-direction: column;
        height: calc(100vh - 3px);
        height: calc(100dvh - 3px);
        padding: var(--fz-space-4) var(--fz-space-3);
        overflow-y: auto;
    }
}

@media (min-width: 1280px) {
    .fz-platform-rail {
        width: 15.5rem;
    }

    .fz-platform-rail-inner {
        padding: 1.25rem var(--fz-space-4);
    }
}

.fz-platform-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
    min-height: var(--fz-control-height);
    margin-bottom: var(--fz-space-2);
    color: var(--fz-platform-text-strong);
    font-weight: var(--fz-weight-heading);
    text-decoration: none;
}

.fz-platform-brand:hover {
    color: var(--fz-platform-text-strong);
}

.fz-platform-rail-chip {
    display: none;
}

.fz-platform-nav {
    display: grid;
    gap: var(--fz-space-1);
    margin: var(--fz-space-4) 0 0;
    padding: 0;
    list-style: none;
}

.fz-platform-link {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-3);
    width: 100%;
    min-height: 2.875rem;
    padding: 0;
    border: 0;
    border-radius: var(--fz-space-3);
    background: transparent;
    color: var(--fz-platform-text);
    font-size: 0.9375rem;
    font-weight: 500;
    text-align: left;
    text-decoration: none;
}

.fz-platform-link .icon {
    width: 1.375rem;
    height: 1.375rem;
    color: var(--fz-platform-muted);
}

.fz-platform-link:hover {
    background-color: var(--fz-platform-hover);
    color: var(--fz-platform-text-strong);
}

.fz-platform-link[aria-current='page'] {
    background-color: var(--fz-platform-accent-soft);
    color: var(--fz-platform-accent-strong);
    font-weight: 600;
}

.fz-platform-link[aria-current='page'] .icon {
    color: var(--fz-platform-accent);
}

/* La marca del actual: una raya ambar pegada al borde del riel. */
.fz-platform-link[aria-current='page']::before {
    content: '';
    position: absolute;
    top: 0.625rem;
    bottom: 0.625rem;
    left: calc(-1 * var(--fz-space-3));
    width: 3px;
    border-radius: 0 3px 3px 0;
    background-color: var(--fz-platform-accent);
}

.fz-platform-rail-foot {
    display: grid;
    gap: var(--fz-space-1);
    margin-top: auto;
    padding-top: var(--fz-space-4);
    border-top: 1px solid var(--fz-platform-border);
}

.fz-platform-me {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-3);
    min-height: 3.25rem;
    padding: 0.375rem;
    border-radius: var(--fz-space-3);
    color: var(--fz-platform-text-strong);
    text-decoration: none;
}

.fz-platform-me:hover,
.fz-platform-me[aria-current='page'] {
    background-color: var(--fz-platform-hover);
    color: var(--fz-platform-text-strong);
}

.fz-platform-me-body {
    display: grid;
    min-width: 0;
    line-height: 1.25;
}

.fz-platform-me-name {
    overflow: hidden;
    font-size: 0.875rem;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-platform-me-hint {
    color: var(--fz-platform-muted);
    font-size: 0.75rem;
}

/* Riel plegado (1024-1279): los rotulos quedan para el lector de pantalla y
   para el globo del navegador (`title`). */
@media (min-width: 1024px) and (max-width: 1279.98px) {
    .fz-platform-text {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
}

@media (min-width: 1280px) {
    .fz-platform-brand,
    .fz-platform-link,
    .fz-platform-me {
        justify-content: flex-start;
    }

    .fz-platform-link {
        padding: 0 0.875rem;
    }

    .fz-platform-link[aria-current='page']::before {
        left: calc(-1 * var(--fz-space-4));
    }

    .fz-platform-rail-chip {
        display: inline-flex;
        align-self: flex-start;
        margin-left: var(--fz-space-1);
    }
}

/* --- Contenido y cabecera --------------------------------------------------- */
.fz-platform-main {
    flex: 1 1 0;
    min-width: 0;
    padding: var(--fz-space-5) var(--fz-space-4) var(--fz-space-7);
}

@media (min-width: 768px) {
    .fz-platform-main {
        padding: var(--fz-space-6) var(--fz-space-6) 3.5rem;
    }
}

@media (min-width: 1280px) {
    .fz-platform-main {
        padding: 2.25rem 2.75rem 4rem;
    }
}

.fz-platform-wrap {
    max-width: 86rem;
    margin: 0 auto;
}

.fz-platform-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--fz-space-4) var(--fz-space-5);
    margin-bottom: var(--fz-space-5);
}

.fz-platform-head h1 {
    margin: 0;
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.fz-platform-head p {
    max-width: 64ch;
    margin: 0.375rem 0 0;
    color: var(--bs-secondary-color);
}

/* El buscador de espacios, el GET de /admin/spaces, en cada cabecera. */
.fz-platform-search {
    position: relative;
    flex: 0 1 24rem;
    min-width: min(100%, 16rem);
}

.fz-platform-search .icon {
    position: absolute;
    top: 50%;
    left: var(--fz-space-4);
    width: 1.125rem;
    height: 1.125rem;
    color: var(--bs-secondary-color);
    pointer-events: none;
    translate: 0 -50%;
}

.fz-platform-search .form-control {
    padding-left: 2.75rem;
    border-radius: 999px;
    background-color: var(--fz-surface);
}

@media (max-width: 767.98px) {
    .fz-platform-search {
        flex: 1 1 100%;
    }
}

/* --- Tarjetas ----------------------------------------------------------------- */
.fz-platform-card {
    height: 100%;
    border-radius: 1.125rem;
}

.fz-platform-card > .card-body {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-4);
    padding: 1.25rem;
}

@media (min-width: 768px) {
    .fz-platform-card > .card-body {
        padding: var(--fz-space-5);
    }
}

/* Sin `wrap`: un titulo largo («Accesos de clientes en las ultimas 24 horas»)
   parte su texto al lado del icono en vez de bajar entero a otra linea. */
.fz-platform-card-title {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}

.fz-platform-card-title .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    color: var(--bs-secondary-color);
}

/* El enlace del pie, al fondo de la tarjeta y del ancho de su texto: estirado,
   la flecha quedaba lejos de la palabra. */
.fz-platform-card-foot {
    align-self: flex-start;
    margin-top: auto;
}

.fz-platform-hint {
    margin: 0;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
}

/* Enlace con flecha: «Ver la lista →». En bloque en linea y no en flex: si el
   texto se parte en dos lineas, la flecha sigue a la ultima palabra en vez de
   irse al borde. El relleno le da los 44 px del objetivo tactil. */
.fz-platform-arrow {
    display: inline-block;
    padding-block: 0.625rem;
    color: var(--fz-brand);
    font-weight: 600;
    line-height: 1.5;
    text-decoration: none;
    /* Dos lineas parejas: la flecha no se queda sola en la segunda. */
    text-wrap: balance;
}

.fz-platform-arrow:hover {
    text-decoration: underline;
}

.fz-platform-arrow .icon {
    width: 1.125rem;
    height: 1.125rem;
    margin-left: 0.25rem;
    vertical-align: -0.2em;
    transition: transform 0.15s ease;
}

.fz-platform-arrow:hover .icon {
    transform: translateX(2px);
}

@media (prefers-reduced-motion: reduce) {
    .fz-platform-arrow .icon {
        transition: none;
    }
}

/* El icono de un evento: disco con el velo de su tono. */
.fz-platform-event-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background-color: color-mix(in srgb, var(--fz-platform-tone, var(--fz-cat-11)) 16%, var(--fz-surface));
    color: var(--fz-platform-tone-text, var(--bs-secondary-color));
}

.fz-platform-event-icon .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* --- Panel en rejilla bento ------------------------------------------------- */
.fz-platform-bento {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--fz-space-3);
}

.fz-platform-bento > * {
    min-width: 0;
}

.fz-platform-hero,
.fz-platform-attn,
.fz-platform-trial,
.fz-platform-stack {
    grid-column: 1 / -1;
}

/* Accesos y correos, juntos al lado de la prueba: dos tarjetas bajas al lado de
   una alta dejaban media tarjeta vacia. */
.fz-platform-stack {
    display: grid;
    gap: var(--fz-space-3);
}

@media (min-width: 768px) {
    .fz-platform-bento {
        grid-template-columns: repeat(6, minmax(0, 1fr));
        gap: var(--fz-space-4);
    }

    .fz-platform-kpi-cell {
        grid-column: span 3;
    }

    .fz-platform-stack {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--fz-space-4);
    }
}

@media (min-width: 1200px) {
    .fz-platform-bento {
        grid-template-columns: repeat(12, minmax(0, 1fr));
        gap: 1.25rem;
    }

    .fz-platform-hero {
        grid-column: span 7;
    }

    .fz-platform-attn {
        grid-column: span 5;
    }

    .fz-platform-trial {
        grid-column: span 5;
    }

    .fz-platform-stack {
        grid-column: span 7;
        gap: 1.25rem;
    }
}

/* El cobro, en una tarjeta oscura en los dos temas, como el patrimonio del
   cliente: las cifras van en blanco sobre su propio fondo, medido aparte del
   tema. */
.fz-platform-hero {
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-4);
    overflow: hidden;
    padding: var(--fz-space-5);
    border-radius: 1.25rem;
    background-color: #141A2A;
    background-image:
        radial-gradient(36rem 18rem at 100% 0%, rgba(116, 136, 238, 0.34), transparent 62%),
        radial-gradient(24rem 14rem at 0% 100%, rgba(242, 184, 75, 0.1), transparent 60%),
        linear-gradient(140deg, #131826 0%, #1B2350 100%);
    box-shadow: 0 24px 48px -28px rgba(17, 22, 44, 0.85), inset 0 0 0 1px rgba(255, 255, 255, 0.06);
    color: #E8ECFA;
}

@media (min-width: 768px) {
    .fz-platform-hero {
        padding: 1.75rem var(--fz-space-6);
    }
}

.fz-platform-hero-head {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0;
    color: #C9D3F5;
    font-size: 0.9375rem;
    font-weight: 600;
}

.fz-platform-hero-head .icon {
    width: 1.25rem;
    height: 1.25rem;
    color: var(--fz-platform-accent);
}

.fz-platform-hero-amounts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-3) 2.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Un importe no se parte nunca (ADR 0021). */
.fz-platform-hero-amount {
    display: block;
    color: #FFFFFF;
    font-size: clamp(2rem, 1.5rem + 1.6vw, 2.75rem);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.015em;
    line-height: 1.05;
    white-space: nowrap;
}

.fz-platform-hero-cur,
.fz-platform-hero-note,
.fz-platform-hero-none {
    color: #AEB9DE;
    font-size: 0.8125rem;
}

.fz-platform-hero-cur {
    display: block;
    margin-top: var(--fz-space-1);
}

.fz-platform-hero-note,
.fz-platform-hero-none {
    max-width: 62ch;
    margin: 0;
}

.fz-platform-hero-none {
    color: #E8ECFA;
    font-size: 1rem;
}

.fz-platform-hero-sub {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-2);
    margin: var(--fz-space-1) 0 0;
    color: #E8ECFA;
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-platform-hero-sub span {
    color: #AEB9DE;
    font-weight: 500;
}

/* La barra de estados: el SVG de `SegmentedBar`, redondo por su caja. */
.fz-platform-seg {
    height: 0.75rem;
    overflow: hidden;
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.08);
}

.fz-seg {
    display: block;
    width: 100%;
    height: 100%;
}

/* Los tramos de `SegmentedBar`: en una tarjeta, los tonos del tema y la paleta
   de categorias; sobre la tarjeta oscura del cobro, sus claros de siempre. */
.fz-seg-ok { fill: var(--fz-state-ok-fill); }
.fz-seg-info { fill: var(--fz-brand-fill); }
.fz-seg-warn { fill: var(--fz-state-warn-fill); }
.fz-seg-over { fill: var(--fz-state-over-fill); }
.fz-seg-neutral { fill: var(--fz-cat-11); }
.fz-seg-cat-4 { fill: var(--fz-cat-4); }
.fz-seg-cat-5 { fill: var(--fz-cat-5); }
.fz-seg-cat-6 { fill: var(--fz-cat-6); }
.fz-seg-cat-8 { fill: var(--fz-cat-8); }
.fz-seg-cat-11 { fill: var(--fz-cat-11); }

.fz-platform-hero .fz-seg-ok,
.fz-platform-dot-ok { fill: #47BC8A; background-color: #47BC8A; }

.fz-platform-hero .fz-seg-info,
.fz-platform-dot-info { fill: #8C9CFF; background-color: #8C9CFF; }

.fz-platform-hero .fz-seg-warn,
.fz-platform-dot-warn { fill: #F2B84B; background-color: #F2B84B; }

.fz-platform-hero .fz-seg-neutral,
.fz-platform-dot-neutral { fill: #8F99AB; background-color: #8F99AB; }

.fz-platform-hero .fz-seg-over,
.fz-platform-dot-over { fill: #F07B72; background-color: #F07B72; }

.fz-platform-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2) 1.25rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-platform-legend li {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    color: #D5DCF5;
    font-size: 0.8125rem;
}

.fz-platform-legend strong {
    color: #FFFFFF;
    font-variant-numeric: tabular-nums;
}

.fz-platform-legend-dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 3px;
}

/* «Requiere atencion»: solo lo que es mayor que cero (`Attention`). */
.fz-platform-attn-list {
    display: grid;
    gap: var(--fz-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-platform-attn-item {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-height: 3.5rem;
    padding: var(--fz-space-2) var(--fz-space-2) var(--fz-space-2) var(--fz-space-3);
    border: 1px solid color-mix(in srgb, var(--fz-platform-tone) 32%, var(--bs-border-color));
    border-radius: 0.875rem;
    background-color: color-mix(in srgb, var(--fz-platform-tone) 8%, var(--fz-surface));
}

.fz-platform-attn-text {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.9375rem;
    line-height: 1.35;
}

.fz-platform-attn-text strong {
    color: var(--fz-platform-tone-text);
    font-variant-numeric: tabular-nums;
}

.fz-platform-attn-text small {
    display: block;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.fz-platform-attn-go {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-1);
    flex: 0 0 auto;
    min-height: var(--fz-control-height);
    padding: 0 var(--fz-space-3);
    border-radius: 999px;
    color: var(--fz-brand);
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
}

.fz-platform-attn-go:hover {
    background-color: var(--bs-tertiary-bg);
    color: var(--fz-brand);
}

.fz-platform-attn-go .icon {
    width: 1rem;
    height: 1rem;
}

.fz-platform-attn-ok {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0;
    color: var(--fz-state-ok-text);
    font-size: 0.875rem;
    font-weight: 500;
}

.fz-platform-attn-ok .icon {
    width: 1.25rem;
    height: 1.25rem;
}

/* Cifra compacta: rotulo y baldosa arriba, la cifra y su nota debajo. La
   superficie es la comun (`fz-kpi-surface` + `fz-kpi-tone-N`). */
.fz-platform-kpis {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--fz-space-3);
    margin-bottom: 1.25rem;
}

@media (min-width: 992px) {
    .fz-platform-kpis {
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: var(--fz-space-4);
    }
}

.fz-platform-kpi {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    height: 100%;
    min-width: 0;
    padding: var(--fz-space-4) 1.125rem;
    border-radius: 1.125rem;
}

.fz-platform-kpi-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2);
}

.fz-platform-kpi-label {
    margin: 0;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.25;
}

.fz-platform-kpi .fz-tile {
    width: 2rem;
    height: 2rem;
    border-radius: 0.5625rem;
}

.fz-platform-kpi .fz-tile-icon {
    width: 1rem;
    height: 1rem;
}

.fz-platform-kpi-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-3);
}

.fz-platform-kpi-num {
    margin: 0;
    color: var(--bs-emphasis-color);
    font-size: 2rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.fz-platform-kpi-num small {
    margin-left: var(--fz-space-1);
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    font-weight: 500;
}

.fz-platform-kpi-foot {
    margin: auto 0 0;
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
    line-height: 1.35;
}

/* El anillo de activos (`ProgressRing`): en el verde de «bien». */
.fz-platform-kpi .fz-ring-value {
    stroke: var(--fz-state-ok-fill);
}

@media (max-width: 575.98px) {
    .fz-platform-kpi {
        padding: 0.875rem;
    }

    .fz-platform-kpi-num {
        font-size: 1.625rem;
    }
}

/* Prueba gratis y planes: rotulo y cifra arriba, la barra debajo. */
.fz-platform-bars {
    display: grid;
    gap: var(--fz-space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-platform-bar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    gap: 0.375rem var(--fz-space-3);
}

.fz-platform-bar-label {
    font-size: 0.875rem;
}

.fz-platform-bar-num {
    font-size: 0.9375rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.fz-platform-bar-track {
    grid-column: 1 / -1;
    height: var(--fz-space-2);
    overflow: hidden;
    border-radius: 999px;
    background-color: var(--fz-track);
}

/* Dos o cuatro cifras sobre lo hundido: accesos y correos. */
.fz-platform-pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--fz-space-3);
    margin: 0;
}

.fz-platform-pair > div {
    display: flex;
    flex-direction: column-reverse;
    justify-content: flex-end;
    gap: var(--fz-space-1);
    padding: 0.875rem;
    border-radius: 0.875rem;
    background-color: var(--fz-surface-sunken);
}

.fz-platform-pair dt {
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 500;
    line-height: 1.3;
}

.fz-platform-pair dd {
    margin: 0;
    color: var(--bs-emphasis-color);
    font-size: 1.75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

/* Hay algo que mirar: la cifra en su tono y un velo. El rotulo dice que es. */
.fz-platform-pair .fz-platform-tone-warn,
.fz-platform-pair .fz-platform-tone-over {
    background-color: color-mix(in srgb, var(--fz-platform-tone) 10%, var(--fz-surface-sunken));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fz-platform-tone) 30%, transparent);
}

.fz-platform-pair .fz-platform-tone-warn dd,
.fz-platform-pair .fz-platform-tone-over dd {
    color: var(--fz-platform-tone-text);
}

/* Las cuatro de correos, en fila solo con la tarjeta a lo ancho. */
@media (min-width: 576px) and (max-width: 767.98px) {
    .fz-platform-pair.fz-platform-pair-4 {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* --- Actividad: linea de tiempo por dia -------------------------------------- */
.fz-platform-days {
    display: grid;
    gap: var(--fz-space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* En su pantalla, cada dia es una tarjeta; dentro de la ficha, solo un bloque. */
.fz-platform-wrap > .fz-platform-days > .fz-platform-day {
    padding: var(--fz-space-4) 1.25rem var(--fz-space-2);
    border: 1px solid var(--bs-border-color);
    border-radius: 1.125rem;
    background-color: var(--fz-surface);
    box-shadow: var(--fz-elev-1);
}

.fz-platform-day-title {
    display: flex;
    align-items: baseline;
    gap: 0.625rem;
    margin: 0 0 var(--fz-space-1);
    font-size: 0.875rem;
    font-weight: 700;
}

.fz-platform-day-title span {
    color: var(--bs-secondary-color);
    font-weight: 500;
}

.fz-platform-events {
    position: relative;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* El hilo que une los puntos del dia. */
.fz-platform-events::before {
    content: '';
    position: absolute;
    top: 1.5rem;
    bottom: 1.5rem;
    left: calc(1.125rem - 1px);
    width: 2px;
    border-radius: 2px;
    background-color: var(--bs-border-color);
}

.fz-platform-event {
    display: grid;
    grid-template-columns: 2.25rem minmax(0, 1fr) auto;
    align-items: start;
    gap: 0.875rem;
    padding: 0.625rem 0;
}

.fz-platform-event .fz-platform-event-icon {
    position: relative;
    z-index: 1;
    box-shadow: 0 0 0 4px var(--fz-surface);
}

.fz-platform-event-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-1) var(--fz-space-2);
    margin: 0.375rem 0 0;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.35;
}

.fz-platform-event-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.125rem 0.875rem;
    margin: 0.125rem 0 0;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.fz-platform-event-meta > span {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.fz-platform-event-time {
    padding-top: var(--fz-space-2);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

@media (max-width: 575.98px) {
    .fz-platform-wrap > .fz-platform-days > .fz-platform-day {
        padding: 0.875rem 0.875rem 0.375rem;
    }

    .fz-platform-event {
        grid-template-columns: 2.25rem minmax(0, 1fr);
    }

    .fz-platform-event-time {
        grid-column: 2;
        padding-top: 0;
    }
}

.fz-platform-pages {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-2);
    margin-top: 1.25rem;
}

.fz-platform-pages .btn {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.fz-platform-pages .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* --- Listados ----------------------------------------------------------------- */
/* Las tablas del operador no llevan caja con scroll propio: son listados de
   una pagina, y dos barras de desplazamiento anidadas en un telefono estorban.
   Van sobre su superficie, con la elevacion de la tarjeta. */
.fz-platform-table {
    max-height: none;
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--fz-surface);
    box-shadow: var(--fz-elev-1);
}

.fz-platform-list td {
    vertical-align: middle;
}

.fz-platform-list tbody td {
    padding-block: var(--fz-space-3);
}

.fz-platform-list td.fz-col-text,
.fz-platform-list td.fz-platform-wrap-cell {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Quien: disco de iniciales y nombre, con una linea secundaria debajo. */
.fz-platform-who {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    min-width: 0;
    text-align: left;
}

.fz-platform-who-body {
    display: grid;
    min-width: 0;
}

.fz-platform-sub {
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

.fz-platform-muted {
    color: var(--bs-secondary-color);
}

.fz-platform-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-2) var(--fz-space-3);
}

.fz-platform-chips .icon {
    width: 0.875rem;
    height: 0.875rem;
}

/* Una cifra en un chip: pastilla, centrada y tabular. */
.fz-platform-count {
    justify-content: center;
    min-width: 2.25rem;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}

/* Un chip con una frase entera (el segundo factor del perfil) parte su texto en
   vez de ensanchar la pagina del telefono. */
.fz-chip.fz-platform-chip-text {
    align-items: flex-start;
    white-space: normal;
}

.fz-chip.fz-platform-chip-text .icon {
    flex: 0 0 auto;
    margin-top: 0.1875rem;
}

/* La IP: monoespaciada y partible. */
.fz-platform-mono {
    font-family: var(--bs-font-monospace);
    font-size: 0.8125rem;
    overflow-wrap: anywhere;
}

/* La fila entera lleva a la ficha: el enlace del nombre se estira sobre ella. */
.fz-platform-rows tbody tr {
    position: relative;
}

.fz-platform-rows .fz-platform-stretch {
    color: var(--bs-emphasis-color);
    font-weight: 600;
    text-decoration: none;
}

.fz-platform-rows .fz-platform-stretch::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.fz-platform-rows tbody tr:hover td {
    background-color: color-mix(in srgb, var(--fz-brand-fill) 6%, var(--fz-surface));
}

.fz-platform-rows tbody tr:hover .fz-platform-stretch {
    color: var(--fz-brand);
    text-decoration: underline;
}

.fz-platform-rows .fz-platform-go {
    width: 2.5rem;
    color: var(--bs-tertiary-color);
}

.fz-platform-rows .fz-platform-go .icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-platform-rows tbody tr:hover .fz-platform-go {
    color: var(--fz-brand);
}

/* La flecha de la fila es decorado: fuera cuando la tabla va justa. */
@media (max-width: 991.98px) {
    .fz-platform-rows .fz-platform-go {
        display: none !important;
    }
}

/* Los listados del operador pasan a fichas hasta 767 y no hasta 575 como el
   resto (`fz-table-stack`): con el disco y el chip de estado, la tabla de
   espacios pide 735 px y a 576 se desplazaba dentro de su caja. Mismas reglas
   que la ficha de la casa, un tramo mas. */
@media (max-width: 767.98px) {
    .fz-platform-list.fz-table-stack thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
    }

    .fz-platform-list.fz-table-stack,
    .fz-platform-list.fz-table-stack tbody {
        display: block;
    }

    .fz-platform-list.fz-table-stack tbody tr {
        display: block;
        margin-bottom: var(--fz-space-2);
        padding: var(--fz-space-3);
        border: 1px solid var(--bs-border-color);
        border-radius: var(--bs-border-radius);
        background-color: var(--bs-table-bg);
    }

    .fz-platform-list.fz-table-stack tbody td {
        display: flex;
        justify-content: space-between;
        gap: var(--fz-space-3);
        padding: var(--fz-space-1) 0;
        border: 0;
        white-space: normal;
        text-align: right;
    }

    .fz-platform-list.fz-table-stack tbody td::before {
        content: attr(data-label);
        color: var(--bs-secondary-color);
        font-size: 0.8125rem;
        font-weight: 500;
        text-align: left;
    }

    .fz-platform-list.fz-table-stack tbody td .fz-platform-who {
        justify-content: flex-end;
    }

    .fz-table-wrap.fz-platform-table {
        overflow: visible;
    }
}

/* --- Ficha de espacio y perfil ---------------------------------------------- */
.fz-platform-cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-4);
    align-items: start;
}

@media (min-width: 1200px) {
    .fz-platform-cols {
        grid-template-columns: minmax(0, 1fr) 23rem;
        gap: 1.25rem;
    }

    .fz-platform-side {
        position: sticky;
        top: var(--fz-space-5);
    }
}

.fz-platform-col {
    display: grid;
    gap: var(--fz-space-4);
    min-width: 0;
}

.fz-platform-entity {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-4) 1.25rem;
    margin-bottom: var(--fz-space-4);
    padding: 1.25rem var(--fz-space-5);
    border: 1px solid var(--bs-border-color);
    border-radius: 1.25rem;
    background-color: var(--fz-surface);
    background-image: radial-gradient(28rem 12rem at 100% 0%, color-mix(in srgb, var(--fz-brand-fill) 12%, transparent), transparent 70%);
    box-shadow: var(--fz-elev-1);
}

.fz-platform-col > .fz-platform-entity {
    margin-bottom: 0;
}

.fz-platform-entity-body {
    display: grid;
    flex: 1 1 16rem;
    gap: 0.375rem;
    min-width: 0;
}

.fz-platform-entity h1,
.fz-platform-entity-name {
    margin: 0;
    font-size: 1.625rem;
    font-weight: 700;
    letter-spacing: -0.015em;
    overflow-wrap: anywhere;
}

.fz-platform-entity-name {
    font-size: 1.375rem;
}

.fz-platform-entity-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem 0.625rem;
    margin: 0;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
}

.fz-platform-people {
    display: grid;
    gap: var(--fz-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-platform-person {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.875rem;
    padding: var(--fz-space-3) var(--fz-space-3) var(--fz-space-3) var(--fz-space-4);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--fz-space-4);
    background-color: var(--fz-surface);
}

/* El ⋯ de la casa trae `grid-area: menu` (la rejilla con nombre de
   /settings/members); aqui la rejilla no tiene areas y crearia una fila. */
.fz-platform-person .fz-person-menu {
    grid-area: auto;
}

.fz-platform-person .fz-menu-item .icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-platform-person-body {
    display: grid;
    gap: 0.125rem;
    min-width: 0;
}

.fz-platform-person-name {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-1) var(--fz-space-2);
    font-weight: 600;
}

.fz-platform-person-mail {
    overflow: hidden;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-platform-person-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.125rem 0.875rem;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

/* Datos sueltos: rotulo a la izquierda, valor a la derecha, una raya entre
   filas. */
.fz-platform-facts {
    display: grid;
    margin: 0;
}

.fz-platform-facts > div {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--fz-space-1) var(--fz-space-4);
    padding: 0.625rem 0;
    border-top: 1px solid var(--bs-border-color-translucent);
}

.fz-platform-facts > div:first-child {
    padding-top: 0;
    border-top: 0;
}

.fz-platform-facts dt {
    color: var(--bs-secondary-color);
    font-weight: 400;
}

.fz-platform-facts dd {
    margin: 0;
    font-weight: 600;
    text-align: right;
    overflow-wrap: anywhere;
}

.fz-platform-price {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem var(--fz-space-2);
    margin: 0;
}

.fz-platform-price strong {
    color: var(--bs-emphasis-color);
    font-size: 1.75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
    white-space: nowrap;
}

.fz-platform-price span {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
}

.fz-platform-grants {
    display: grid;
    gap: var(--fz-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-platform-grants li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--fz-space-2) var(--fz-space-3);
}

/* Zona de riesgo: borde rojo, y el <summary> que abre suspender como un boton
   con contorno rojo, de 44 px. */
.fz-platform-danger {
    border-color: color-mix(in srgb, var(--fz-state-over-fill) 45%, var(--bs-border-color));
}

.fz-platform-danger .fz-platform-card-title .icon {
    color: var(--fz-state-over-text);
}

.fz-platform-danger-open {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
    padding: 0 var(--fz-space-4);
    border: 1px solid color-mix(in srgb, var(--fz-state-over-fill) 55%, var(--bs-border-color));
    border-radius: 999px;
    color: var(--fz-state-over-text);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
}

.fz-platform-danger-open::-webkit-details-marker {
    display: none;
}

.fz-platform-danger-open:hover {
    background-color: color-mix(in srgb, var(--fz-state-over-fill) 8%, transparent);
}

.fz-platform-danger-open .icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-platform-privacy {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    margin: 0;
    padding: 0.875rem var(--fz-space-4);
    border-radius: var(--fz-space-4);
    background-color: color-mix(in srgb, var(--fz-state-ok-fill) 8%, var(--fz-surface));
    font-size: 0.875rem;
}

.fz-platform-privacy .icon {
    flex: 0 0 auto;
    width: 1.375rem;
    height: 1.375rem;
    color: var(--fz-state-ok-text);
}

.fz-platform-grid-2 {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--fz-space-4);
    align-items: start;
}

@media (min-width: 992px) {
    .fz-platform-grid-2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1.25rem;
    }
}

/* La clave TOTP y el id de Paddle: monoespaciados, partibles en cualquier punto
   para que no desborden un telefono, y seleccionables de un toque. */
.fz-platform-secret {
    font-family: var(--bs-font-monospace);
    overflow-wrap: anywhere;
    user-select: all;
}

/* --- La puerta, partida ---------------------------------------------------- */
.fz-platform-auth {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    min-height: 100vh;
    min-height: 100dvh;
}

@media (min-width: 992px) {
    .fz-platform-auth {
        grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    }
}

.fz-platform-auth-side {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--fz-space-5);
    overflow: hidden;
    padding: var(--fz-space-5) 1.25rem 1.75rem;
    padding-top: max(var(--fz-space-5), env(safe-area-inset-top, 0px));
    border-top: 3px solid var(--fz-platform-accent);
    background-color: var(--fz-platform-bg);
    background-image:
        radial-gradient(34rem 22rem at 0% 0%, rgba(242, 184, 75, 0.11), transparent 62%),
        radial-gradient(38rem 30rem at 100% 100%, rgba(116, 136, 238, 0.24), transparent 62%);
    color: var(--fz-platform-text);
}

/* La reticula tenue del fondo: decoracion, sin informacion. */
.fz-platform-auth-side::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
    background-size: 2rem 2rem;
    mask-image: radial-gradient(30rem 30rem at 30% 40%, #000, transparent 75%);
    pointer-events: none;
}

.fz-platform-auth-side > * {
    position: relative;
}

@media (min-width: 992px) {
    .fz-platform-auth-side {
        justify-content: space-between;
        gap: 2.5rem;
        padding: var(--fz-space-7);
        border-top-width: 3px;
    }
}

.fz-platform-auth-brand {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-3);
    margin: 0;
    color: var(--fz-platform-text-strong);
    font-size: 1.125rem;
    font-weight: var(--fz-weight-heading);
}

.fz-platform-auth-claim {
    max-width: 18ch;
    margin: 0;
    color: #FFFFFF;
    font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.12;
}

.fz-platform-auth-points {
    display: grid;
    gap: var(--fz-space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-platform-auth-points li {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    font-size: 0.9375rem;
    line-height: 1.4;
}

.fz-platform-point-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
    border: 1px solid var(--fz-platform-accent-line);
    border-radius: var(--fz-space-3);
    background-color: var(--fz-platform-accent-soft);
    color: var(--fz-platform-accent);
}

.fz-platform-point-icon .icon {
    width: 1.25rem;
    height: 1.25rem;
}

@media (max-width: 991.98px) {
    .fz-platform-auth-points {
        gap: 0.625rem;
    }

    .fz-platform-auth-points li {
        font-size: 0.875rem;
    }

    .fz-platform-point-icon {
        width: 2rem;
        height: 2rem;
        border-radius: 0.625rem;
    }

    .fz-platform-point-icon .icon {
        width: 1rem;
        height: 1rem;
    }
}

/* El lado del formulario conserva `auth-shell` (contrato de clases); aqui no
   necesita la altura entera: la pone la rejilla. */
.fz-platform-auth .auth-shell {
    min-height: 0;
    padding: var(--fz-space-5) var(--fz-space-4) 2.5rem;
}

@media (min-width: 992px) {
    .fz-platform-auth .auth-shell {
        padding: var(--fz-space-7);
    }
}

.fz-platform-auth .auth-card {
    border-radius: 1.25rem;
}

.fz-platform-auth-title {
    margin: 0 0 0.375rem;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.fz-platform-auth-hint {
    margin: 0 0 var(--fz-space-5);
    color: var(--bs-secondary-color);
}

/* El codigo de 6 cifras: grande, centrado y monoespaciado, solo con CSS. */
.fz-platform-code {
    height: 3.75rem;
    padding-left: 0.6em;
    font-family: var(--bs-font-monospace);
    font-size: 1.75rem;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.6em;
    text-align: center;
}

/* Modo soporte (ADR 0065): una franja arriba que no se confunde con nada del
   producto, con la salida a mano en cualquier ancho. No es `sticky`: el riel ya
   lo es desde 1024 y la franja le taparia la cabeza al desplazar. */
.fz-support-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-2) var(--fz-space-3);
    padding: var(--fz-space-2) var(--fz-space-3);
    background-color: var(--bs-dark);
    color: var(--bs-light);
    text-align: center;
}

/* ===========================================================================
   PERSONAS DEL ESPACIO  (ADR 0090)
   ===========================================================================

   /settings/members con la piel de la imagen que trajo el usuario: disco de
   iniciales por persona, rol en pildora, menu ⋮ por fila, buscador comun
   (`layouts/_list-search.php`) y una tarjeta de invitar con ilustracion.

   Reutiliza sin tocarlo: el menu de la casa (`.fz-menu*`), el `<summary>` de
   texto a 44 px (`.fz-disclosure-summary`), la superficie comun
   (`.fz-kpi-surface`) y las superficies de categoria para los discos. Lo propio
   lleva `fz-members-`, `fz-person`, `fz-invite` o `fz-avatar`, que no usaba
   nadie. Ni un `style=`: la CSP no lo admite. */

/* "Volver a Ajustes": enlace con flecha, a la altura de un control para que
   se pueda tocar en el telefono sin apuntar a una linea de 14 px. */
.fz-back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
    min-height: var(--fz-control-height);
    font-weight: 500;
    text-decoration: none;
}

.fz-back-link:hover {
    text-decoration: underline;
}

.fz-back-link-icon {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
}

.fz-members-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-2) var(--fz-space-3);
}

.fz-members-title {
    margin: 0;
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
}

@media (min-width: 992px) {
    .fz-members-title {
        font-size: 2.25rem;
    }
}

/* Cuantas personas hay, junto al titulo. El tope del plan no va aqui: es cosa
   de quien invita y vive en la tarjeta de invitar. */
.fz-members-count {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.75rem;
    border: 1px solid rgba(var(--fz-brand-rgb), 0.45);
    border-radius: 999px;
    background-color: rgba(var(--fz-brand-rgb), 0.1);
    color: var(--fz-brand);
    font-size: 0.9375rem;
    font-weight: 600;
    white-space: nowrap;
}

.fz-members-count-icon {
    width: 1.125rem;
    height: 1.125rem;
    flex: 0 0 auto;
}

.fz-members-subtitle {
    margin: var(--fz-space-2) 0 var(--fz-space-5);
    color: var(--bs-secondary-color);
    font-size: 1.0625rem;
}

.fz-members-card .card-body,
.fz-invite .card-body {
    padding: var(--fz-space-5);
}

.fz-members-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--fz-space-3);
    margin-bottom: var(--fz-space-4);
}

.fz-members-card-title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
}

/* El disco de iniciales (`View::avatar()`). El color lo pone `cat-surface-N`
   en el mismo atributo, con el blanco encima ya medido; aqui solo la forma y
   el brillo, que es el de la baldosa comun. */
.fz-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    background-image: linear-gradient(145deg, rgba(255, 255, 255, 0.22), transparent 65%);
    box-shadow: 0 6px 16px -8px var(--fz-surface-tone);
    font-size: 1.1875rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1;
}

.fz-people {
    margin: 0;
    padding: 0;
    list-style: none;
}

/*
 * Una persona: disco | nombre y correo | rol | ⋮, y debajo "Gestionar".
 *
 * Rejilla por areas y no flex: "Gestionar" cuelga de la columna del nombre, y
 * en las bandas estrechas el rol baja debajo del correo sin tocar el HTML.
 * La columna del rol crece con la fila (0.55fr) para que las pildoras queden a
 * la misma altura que en la imagen, lejos del ⋮; y la del menu es fija, haya
 * menu o no, para que todas las filas alineen sus pildoras.
 *
 * La raya va ARRIBA de cada fila: la primera hace de separador bajo la
 * cabecera, y al filtrar con el buscador no queda una raya suelta al final.
 */
.fz-person {
    display: grid;
    grid-template-columns: 3.5rem minmax(0, 1fr) minmax(6.75rem, 0.55fr) var(--fz-control-height);
    grid-template-areas:
        "avatar who role menu"
        ". manage manage manage";
    align-items: center;
    column-gap: 1.25rem;
    padding-block: 1.25rem;
    border-top: 1px solid var(--bs-border-color);
}

.fz-person > .fz-avatar {
    grid-area: avatar;
}

.fz-person-who {
    grid-area: who;
    min-width: 0;
    overflow-wrap: anywhere;
}

.fz-person-name {
    margin: 0;
    color: var(--bs-emphasis-color);
    font-size: 1.0625rem;
    font-weight: 600;
}

.fz-person-email {
    margin: 0.125rem 0 0;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
}

.fz-person-you {
    display: inline-block;
    margin-inline-start: 0.375rem;
    padding: 0.0625rem 0.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
    font-weight: 600;
    vertical-align: 0.125em;
}

.fz-person-role {
    grid-area: role;
    justify-self: start;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    min-width: 6.75rem;
    min-height: 2rem;
    padding: 0.25rem 0.875rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--bs-secondary-bg);
    color: var(--bs-emphasis-color);
    font-size: 0.9375rem;
    font-weight: 600;
    white-space: nowrap;
}

/* El titular, en la marca. Solida en claro; en oscuro la marca entera era el
   mismo azul del boton de invitar y competia con el, asi que va mezclada con
   la superficie. */
.fz-person-role-owner {
    border-color: transparent;
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

[data-bs-theme='dark'] .fz-person-role-owner {
    background-color: color-mix(in srgb, var(--fz-brand-fill) 60%, var(--fz-surface));
}

/* La corona rellena, como en la imagen. */
.fz-person-role-icon {
    width: 1.125rem;
    height: 1.125rem;
    flex: 0 0 auto;
    fill: currentColor;
}

.fz-person-menu {
    grid-area: menu;
    justify-self: end;
}

/* El ⋮: solo el icono, pero con los 44 px de cualquier control. */
.fz-person-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    border-radius: 50%;
    color: var(--bs-secondary-color);
}

.fz-person-more:hover,
.fz-person-menu[open] > .fz-person-more {
    background-color: var(--bs-tertiary-bg);
    color: var(--bs-emphasis-color);
}

/* El panel a la medida de su opcion mas larga: con el ancho minimo de la casa
   (11rem), "Quitar del espacio" se partia en dos lineas. */
.fz-person-menu .fz-menu-panel {
    width: max-content;
}

.fz-menu-item-danger,
.fz-menu-item-danger:hover {
    color: var(--bs-danger-text-emphasis);
}

.fz-person-manage {
    grid-area: manage;
}

/* "▶ Gestionar" en el color de los enlaces: es lo que se toca. El triangulo es
   el del navegador y toma el mismo color. */
.fz-person-manage-summary {
    width: fit-content;
    color: var(--bs-link-color);
    font-weight: 500;
}

/*
 * Bandas estrechas: el rol baja debajo del correo.
 *
 * Por debajo de 768 la tarjeta es de telefono, y entre 992 y 1199 la lista
 * comparte fila con la de invitar. En las dos, con el rol al lado, al correo
 * le quedaban unos 230 px y se partia a media palabra. No es una consulta de
 * contenedor a proposito: `container-type` hace de la lista un contexto de
 * apilamiento, y el panel del ⋮ de la ultima fila quedaria DEBAJO de la
 * tarjeta de invitar en el telefono.
 */
@media (max-width: 767.98px), (min-width: 992px) and (max-width: 1199.98px) {
    .fz-person {
        grid-template-columns: 3.5rem minmax(0, 1fr) var(--fz-control-height);
        grid-template-areas:
            "avatar who menu"
            ". role role"
            ". manage manage";
        column-gap: var(--fz-space-4);
    }

    .fz-person-role {
        margin-top: var(--fz-space-2);
    }
}

@media (max-width: 575.98px) {
    .fz-members-card .card-body,
    .fz-invite .card-body {
        padding: var(--fz-space-4);
    }

    /* El correo baja a su propia fila y usa tambien el ancho del ⋮: entre el
       disco y el menu le quedaban 222 px y "example.pe" se partia en dos. El
       contenedor del nombre se disuelve (`display: contents`) para que nombre y
       correo sean celdas de la rejilla; el disco abarca las dos filas. */
    .fz-person {
        grid-template-columns: 2.75rem minmax(0, 1fr) var(--fz-control-height);
        grid-template-areas:
            "avatar name menu"
            "avatar email email"
            ". role role"
            ". manage manage";
        column-gap: var(--fz-space-3);
        padding-block: var(--fz-space-4);
    }

    .fz-person-who {
        display: contents;
    }

    .fz-person-name {
        grid-area: name;
        align-self: end;
        min-width: 0;
        overflow-wrap: anywhere;
    }

    .fz-person-email {
        grid-area: email;
        align-self: start;
        min-width: 0;
        overflow-wrap: anywhere;
    }

    .fz-person > .fz-avatar {
        width: 2.75rem;
        height: 2.75rem;
        font-size: 1rem;
    }

    .fz-person-role {
        min-width: 0;
        min-height: 1.75rem;
        font-size: 0.875rem;
    }
}

/* --- Invitar a alguien ---------------------------------------------------- */

/* La ilustracion: una persona, la invitada con su eslabon y tres destellos.
   Todo con iconos del sprite y colores de la marca; nada que cargar. */
.fz-invite-art {
    position: relative;
    display: flex;
    align-items: center;
    height: 4.75rem;
    margin-bottom: var(--fz-space-4);
    padding-inline-start: 0.5rem;
}

.fz-invite-art-side,
.fz-invite-art-main {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    border-radius: 50%;
    color: var(--fz-brand);
}

.fz-invite-art-side {
    width: 3.375rem;
    height: 3.375rem;
    background-color: rgba(var(--fz-brand-rgb), 0.12);
}

.fz-invite-art-main {
    position: relative;
    width: 4.5rem;
    height: 4.5rem;
    margin-inline-start: -0.125rem;
    background-color: rgba(var(--fz-brand-rgb), 0.26);
}

/* El perfil del sprite, relleno: la cabeza y el arco cerrado dan la silueta. */
.fz-invite-art-icon {
    width: 55%;
    height: 55%;
    fill: currentColor;
}

.fz-invite-art-badge {
    position: absolute;
    top: 50%;
    inset-inline-end: -0.625rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background-image: linear-gradient(135deg, var(--fz-brand-fill), var(--fz-brand-fill-end));
    color: var(--fz-brand-on-fill);
    box-shadow: 0 0 0 3px var(--fz-surface), 0 6px 16px -6px rgba(var(--fz-brand-rgb), 0.8);
    transform: translateY(-50%);
}

.fz-invite-art-link {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-invite-spark {
    position: absolute;
    color: var(--fz-brand);
    fill: currentColor;
    stroke: none;
}

.fz-invite-spark-a {
    top: 0.125rem;
    left: 0.25rem;
    width: 1rem;
    height: 1rem;
}

.fz-invite-spark-b {
    top: 1.5rem;
    left: 11.25rem;
    width: 0.875rem;
    height: 0.875rem;
    opacity: 0.8;
}

.fz-invite-spark-c {
    bottom: 0.375rem;
    left: 9.25rem;
    width: 0.5rem;
    height: 0.5rem;
    opacity: 0.6;
}

.fz-invite-title {
    margin: 0 0 var(--fz-space-2);
    font-size: 1.5rem;
    font-weight: 700;
}

.fz-invite-hint {
    margin: 0 0 var(--fz-space-4);
    color: var(--bs-secondary-color);
}

.fz-invite-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-3);
    width: 100%;
    min-height: 3.375rem;
    font-size: 1.0625rem;
    font-weight: 600;
}

.fz-invite-btn-icon {
    width: 1.375rem;
    height: 1.375rem;
    flex: 0 0 auto;
}

/* Pasar al Familiar cuando el Individual ya esta lleno: en dorado, el tono de
   «mejorar el plan», para que no se confunda con el boton indigo apagado. */
.fz-invite-upsell {
    --fz-upsell: var(--fz-cat-10);
    --fz-upsell-on: #FFFFFF;

    display: grid;
    gap: var(--fz-space-3);
    margin-top: var(--fz-space-3);
    padding: var(--fz-space-3);
    border: 1px solid color-mix(in srgb, var(--fz-upsell) 45%, transparent);
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-upsell) 10%, transparent);
}

[data-bs-theme='dark'] .fz-invite-upsell {
    --fz-upsell-on: #1F1800;
}

.fz-invite-upsell-text {
    display: flex;
    align-items: center;
    gap: var(--fz-space-3);
    margin: 0;
    font-weight: 600;
}

.fz-invite-upsell-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    background-color: var(--fz-upsell);
    color: var(--fz-upsell-on);
}

.fz-invite-upsell-icon svg {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-invite-upsell-btn {
    --bs-btn-color: var(--fz-upsell-on);
    --bs-btn-bg: var(--fz-upsell);
    --bs-btn-border-color: var(--fz-upsell);
    --bs-btn-hover-color: var(--fz-upsell-on);
    --bs-btn-hover-bg: color-mix(in srgb, var(--fz-upsell) 85%, #000);
    --bs-btn-hover-border-color: color-mix(in srgb, var(--fz-upsell) 85%, #000);
    --bs-btn-active-color: var(--fz-upsell-on);
    --bs-btn-active-bg: color-mix(in srgb, var(--fz-upsell) 75%, #000);
    --bs-btn-active-border-color: color-mix(in srgb, var(--fz-upsell) 75%, #000);
    --bs-btn-focus-shadow-rgb: 122, 91, 0;

    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-2);
    width: 100%;
    min-height: 2.75rem;
    font-weight: 600;
}

.fz-invite-upsell-chevron {
    width: 1.125rem;
    height: 1.125rem;
    flex: 0 0 auto;
}

.fz-invite-notes {
    display: grid;
    gap: var(--fz-space-2);
    margin: var(--fz-space-4) 0 0;
    padding: 0;
    list-style: none;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
}

.fz-invite-notes li {
    display: flex;
    align-items: center;
    gap: var(--fz-space-2);
}

.fz-invite-note-icon {
    width: 1.125rem;
    height: 1.125rem;
    flex: 0 0 auto;
}

.fz-invite-pending-title {
    margin: var(--fz-space-5) 0 var(--fz-space-2);
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    font-weight: 600;
}

/* ===========================================================================
   Personas elegidas (ADR 0092): quien ve una cuenta.
   =========================================================================== */

/* El disco de iniciales (ADR 0090) a la altura de una linea de texto: donde se
   elige o se nombra a alguien, no en la lista de personas. */
.fz-avatar.fz-avatar-sm {
    width: 2rem;
    height: 2rem;
    box-shadow: none;
    font-size: 0.8125rem;
}

/* Mas tallas del disco (ADR 0145): a la altura de una linea de la actividad
   del operador, y el de la cabecera de una ficha o del perfil. */
.fz-avatar.fz-avatar-xs {
    width: 1.75rem;
    height: 1.75rem;
    box-shadow: none;
    font-size: 0.6875rem;
}

.fz-avatar.fz-avatar-lg {
    width: 4rem;
    height: 4rem;
    font-size: 1.375rem;
}

/* Quien ya no tiene nombre -un exmiembro purgado, un acceso sin cuenta-: un
   disco gris con «?», no un hueco. */
.fz-avatar.fz-avatar-unknown {
    background-color: var(--bs-tertiary-bg);
    background-image: none;
    box-shadow: none;
    color: var(--bs-secondary-color);
}

/* Las casillas de las personas cuelgan de su opcion: empiezan donde empieza el
   texto de "Yo y las personas que elija", no donde su radio. */
.fz-people-pick {
    display: grid;
    gap: var(--fz-space-1);
    margin: 0 0 var(--fz-space-2) 1.5em;
    padding: 0;
    border: 0;
}

/* Cada persona es un objetivo de 44 px, como cualquier control (ADR 0080). */
.fz-people-pick-item {
    display: flex;
    align-items: center;
    min-height: var(--fz-control-height);
    margin: 0;
}

.fz-people-pick-item > .form-check-input {
    margin-top: 0;
}

.fz-people-pick-label {
    align-items: center;
    gap: var(--fz-space-2);
}

/* Quienes ven la cuenta, en su tarjeta de la edicion: los discos en fila. */
.fz-audience-people {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fz-space-1);
    margin: var(--fz-space-2) 0;
}

/* ===========================================================================
   ALTA EN TARJETAS  (ADR 0096)
   ===========================================================================

   /mortgages/new con la piel de la imagen que trajo el usuario: cabecera azul
   marino con la casa ilustrada, pasos, tarjetas de color con su baldosa
   redonda, campos con icono o simbolo de moneda, «¿Quien la ve?» en tarjetas
   y el boton que guarda con su degradado.

   Las piezas tienen nombre generico (`fz-form-*`, `fz-fcard`, `fz-steps`,
   `fz-choice`) porque no son de la hipoteca: el dia que /loans/new tome este
   diseño, se usan tal cual. Las tarjetas se apoyan en la superficie comun
   (`fz-kpi-surface fz-kpi-tone-N`, ADR 0080): su tono pinta el borde, el
   degradado, el brillo, la franja de la cabecera y el icono de cada campo.
   =========================================================================== */

.fz-form-page {
    max-width: 74rem;
}

/* --- La cabecera: azul marino en los dos temas, como el riel -------------- */
.fz-form-hero {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    min-height: 7.5rem;
    margin-bottom: var(--fz-space-4);
    padding: 1.25rem 1.5rem;
    border: 1px solid var(--fz-form-hero-border);
    border-radius: 1rem;
    background:
        radial-gradient(90% 160% at 80% 0%, var(--fz-form-hero-glow), transparent 62%),
        linear-gradient(100deg, var(--fz-form-hero-from) 0%, var(--fz-form-hero-mid) 55%, var(--fz-form-hero-to) 100%);
    color: var(--fz-form-hero-text);
    box-shadow: 0 16px 36px -24px var(--fz-form-hero-glow);
}

.fz-form-hero-icon {
    position: relative;
    z-index: 1;
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 4.5rem;
    height: 4.5rem;
    border-radius: 1.125rem;
    background-color: var(--fz-form-hero-icon);
    background-image: linear-gradient(145deg, var(--fz-form-hero-icon-end), var(--fz-form-hero-icon));
    color: var(--fz-form-hero-text);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 0 28px -6px var(--fz-form-hero-icon-end);
}

.fz-form-hero-icon .icon {
    width: 2.25rem;
    height: 2.25rem;
    stroke-width: 2;
}

.fz-form-hero-text {
    position: relative;
    z-index: 1;
    min-width: 0;
    max-width: 36rem;
}

.fz-form-hero-title {
    margin: 0;
    font-size: 1.875rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--fz-form-hero-text);
}

/* El color va primero y el degradado encima: donde `background-clip: text` no
   llega, la palabra se lee en el azul claro y no desaparece. */
.fz-form-hero-accent {
    color: var(--fz-form-hero-accent);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .fz-form-hero-accent {
        background-image: linear-gradient(90deg, var(--fz-form-hero-accent), var(--fz-form-hero-accent-end));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
    }
}

.fz-form-hero-sub {
    margin: 0.375rem 0 0;
    color: var(--fz-form-hero-muted);
}

/* La casa, pegada a la esquina de abajo y fundida por la izquierda con el fondo:
   decoracion, asi que va detras del texto y sin texto alternativo. */
.fz-form-hero-art {
    position: absolute;
    z-index: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-width: 52%;
    height: calc(100% + 0.5rem);
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 24%);
    mask-image: linear-gradient(90deg, transparent 0, #000 24%);
    pointer-events: none;
}

@media (max-width: 767.98px) {
    .fz-form-hero {
        gap: 0.875rem;
        min-height: 0;
        padding: 1rem;
    }

    .fz-form-hero-art {
        display: none;
    }

    .fz-form-hero-icon {
        width: 3.25rem;
        height: 3.25rem;
        border-radius: 0.875rem;
    }

    .fz-form-hero-icon .icon {
        width: 1.625rem;
        height: 1.625rem;
    }

    .fz-form-hero-title {
        font-size: 1.375rem;
    }

    .fz-form-hero-sub {
        font-size: 0.9375rem;
    }
}

/* --- Los pasos: un indice de la pagina, no un asistente ---------------------
   Todas las tarjetas estan a la vista y cada paso enlaza a la suya.
   `form-cards.js` marca el actual -el que se esta leyendo- y los hechos -los
   que ya tienen sus campos obligatorios-. Sin JavaScript queda un indice. */
.fz-steps {
    margin-bottom: 1.25rem;
    padding: 0.75rem 1.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 1rem;
    background-color: var(--fz-surface);
    box-shadow: var(--fz-elev-1);
}

[data-bs-theme='dark'] .fz-steps {
    background-image: linear-gradient(180deg, rgba(var(--fz-brand-rgb), 0.1), transparent);
}

.fz-steps-list {
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-step {
    display: flex;
    flex: 1 1 0;
    align-items: center;
    min-width: 0;
}

.fz-step:last-child {
    flex: 0 0 auto;
}

.fz-step:not(:last-child)::after {
    content: '';
    flex: 1 1 auto;
    height: 2px;
    margin-inline: 1rem;
    border-radius: 2px;
    background-color: var(--bs-border-color);
}

.fz-step.is-done:not(:last-child)::after {
    background-image: linear-gradient(90deg, var(--fz-brand-fill), var(--fz-brand-fill-end));
}

.fz-step-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    min-height: var(--fz-control-height);
    color: var(--bs-secondary-color);
    text-decoration: none;
    white-space: nowrap;
}

/* Solo un enlace cambia al pasar por encima: los pasos de la importacion no lo
   son (ADR 0119). */
a.fz-step-link:hover {
    color: var(--bs-emphasis-color);
}

.fz-step-num {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 50%;
    background-color: color-mix(in srgb, var(--fz-brand) 10%, var(--fz-surface));
    font-weight: 600;
    color: var(--bs-body-color);
}

.fz-step-check {
    display: none;
    width: 1.125rem;
    height: 1.125rem;
    stroke-width: 2.25;
}

.fz-step.is-done .fz-step-num {
    border-color: transparent;
    background-color: rgba(var(--fz-brand-rgb), 0.16);
    color: var(--fz-brand);
}

.fz-step.is-done .fz-step-n {
    display: none;
}

.fz-step.is-done .fz-step-check {
    display: block;
}

.fz-step.is-current .fz-step-link {
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-step.is-current .fz-step-num {
    border-color: transparent;
    background-color: var(--fz-brand-fill);
    background-image: linear-gradient(145deg, var(--fz-brand-fill-end), var(--fz-brand-fill));
    color: var(--fz-brand-on-fill);
    box-shadow: 0 0 0 4px rgba(var(--fz-brand-rgb), 0.18), 0 0 18px -4px rgba(var(--fz-brand-rgb), 0.9);
}

/* La raya del paso actual cae sobre el borde de abajo de la tira. */
.fz-step.is-current .fz-step-link::after {
    content: '';
    position: absolute;
    right: 0;
    bottom: -0.8125rem;
    left: 0;
    height: 3px;
    border-radius: 3px 3px 0 0;
    background-image: linear-gradient(90deg, var(--fz-brand-fill), var(--fz-brand-fill-end));
}

/* En el telefono no caben cuatro rotulos: queda el del paso actual y los
   demas siguen ahi para el lector de pantalla. */
@media (max-width: 767.98px) {
    .fz-steps {
        padding: 0.5rem 1rem;
    }

    /* Ningun paso por debajo de lo que ocupa: con `min-width: 0` el rotulo del
       actual quedaba debajo del circulo siguiente. Medido a 390 con el rotulo
       mas largo, «Pago y visibilidad»: caben los cuatro. */
    .fz-step {
        min-width: auto;
    }

    .fz-step-link {
        gap: 0.5rem;
    }

    .fz-step.is-current .fz-step-label {
        font-size: 0.875rem;
    }

    .fz-step:not(:last-child)::after {
        margin-inline: 0.375rem;
    }

    .fz-step:not(.is-current) .fz-step-label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .fz-step.is-current .fz-step-link::after {
        bottom: -0.5625rem;
    }
}

/* --- Las tarjetas ---------------------------------------------------------- */
.fz-form-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
}

@media (min-width: 1200px) {
    .fz-form-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .fz-fcard-wide {
        grid-column: 1 / -1;
    }
}

.fz-fcard {
    display: flex;
    flex-direction: column;
    min-width: 0;
    border-radius: 1rem;
    scroll-margin-top: var(--fz-space-4);
}

.fz-fcard-head {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 28%, var(--bs-border-color));
    border-radius: 1rem 1rem 0 0;
    background-image: linear-gradient(90deg, color-mix(in srgb, var(--fz-kpi-tone) 14%, transparent), transparent 85%);
}

[data-bs-theme='dark'] .fz-fcard-head {
    background-image: linear-gradient(90deg, color-mix(in srgb, var(--fz-kpi-tone) 22%, transparent), transparent 85%);
}

/* Una tarjeta que no se estira a la altura de su vecina de fila (ADR 0097):
   la de pago del prestamo, junto a una cuota estimada que crece al llenarse. */
.fz-fcard-natural {
    align-self: start;
}

/* La baldosa de siempre (`View::tile()`, ADR 0053), redonda y con su brillo. */
.fz-fcard-head .fz-tile {
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    background-image: radial-gradient(circle at 30% 25%, rgba(255, 255, 255, 0.3), transparent 62%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 0 22px -6px var(--fz-surface-tone);
}

.fz-fcard-head .fz-tile-icon {
    width: 1.625rem;
    height: 1.625rem;
}

.fz-fcard-heading {
    flex: 1 1 auto;
    min-width: 0;
}

.fz-fcard-title {
    margin: 0;
    font-size: 1.1875rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.fz-fcard-sub {
    margin: 0.125rem 0 0;
    font-size: 0.9375rem;
    color: var(--bs-secondary-color);
}

.fz-fcard-body {
    flex: 1 1 auto;
    padding: 1.125rem 1.25rem 1.375rem;
}

.fz-fcard .form-label {
    margin-bottom: 0.375rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-field-hint {
    font-weight: 400;
    color: var(--bs-secondary-color);
}

/* Un apartado dentro de una tarjeta: «Con cada cuota», «Al firmar». */
.fz-fcard-section {
    margin: 0 0 0.75rem;
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.fz-fcard-section-next {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
}

/* El campo con su icono o su simbolo delante, en el tono de la tarjeta. */
.fz-field .input-group-text {
    justify-content: center;
    min-width: 2.75rem;
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 32%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 12%, var(--fz-surface));
    font-weight: 700;
    color: var(--fz-kpi-tone);
}

.fz-field .input-group-text .icon {
    width: 1.25rem;
    height: 1.25rem;
}

.fz-field .form-control,
.fz-field .form-select {
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 32%, var(--bs-border-color));
}

[data-bs-theme='dark'] .fz-field .form-control,
[data-bs-theme='dark'] .fz-field .form-select {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 5%, var(--fz-surface-sunken));
}

.fz-flag {
    display: block;
    width: 1.5rem;
    height: 1rem;
    clip-path: inset(0 round 3px);
}

/* La ayuda «?» de la cabecera de una tarjeta: `<details>`, como «Como
   solicitarlo» en la ficha, y sin JavaScript. */
.fz-help-pop {
    position: relative;
    flex: 0 0 auto;
}

.fz-help-pop > summary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    border-radius: 50%;
    list-style: none;
    color: var(--bs-secondary-color);
    cursor: pointer;
}

.fz-help-pop > summary::-webkit-details-marker {
    display: none;
}

.fz-help-pop > summary:hover,
.fz-help-pop[open] > summary {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 14%, transparent);
    color: var(--fz-kpi-tone);
}

.fz-help-pop > summary:focus-visible {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-help-pop > summary .icon {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-help-pop-panel {
    position: absolute;
    top: calc(100% + 0.25rem);
    right: 0;
    z-index: 5;
    width: min(20rem, 80vw);
    padding: 0.875rem 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.75rem;
    background-color: var(--fz-surface-raised);
    box-shadow: var(--fz-elev-2);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

/* Un interruptor con su explicacion. La casilla cubre la fila entera, como el
   radio de una tarjeta de «¿Quien la ve?»: el objetivo es la fila y no los 22 px
   del interruptor, que se dibuja aparte (`.fz-switch-track`) y sigue al estado
   de la casilla. */
.fz-switch {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    margin: 0.25rem 0 0;
    padding: 0.875rem 1rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 7%, transparent);
}

.fz-switch-input {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.fz-switch:has(.fz-switch-input:focus-visible) {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-switch-track {
    position: relative;
    flex: 0 0 auto;
    width: 2.5rem;
    height: 1.375rem;
    margin-top: 0.125rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-track);
    transition: background-color 0.15s ease;
}

.fz-switch-track::after {
    content: '';
    position: absolute;
    top: 0.1875rem;
    left: 0.1875rem;
    width: 0.875rem;
    height: 0.875rem;
    border-radius: 50%;
    background-color: var(--bs-secondary-color);
    transition: transform 0.15s ease;
}

.fz-switch:has(.fz-switch-input:checked) .fz-switch-track {
    border-color: transparent;
    background-color: var(--fz-brand-fill);
}

.fz-switch:has(.fz-switch-input:checked) .fz-switch-track::after {
    background-color: var(--fz-brand-on-fill);
    transform: translateX(1.125rem);
}

@media (prefers-reduced-motion: reduce) {
    .fz-switch-track,
    .fz-switch-track::after {
        transition: none;
    }
}

/* «Tu banco te da los porcentajes: al año | al mes» (ADR 0096). Dos pildoras
   de 44 px con el radio dentro; la elegida, rellena. */
.fz-period {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    min-width: 0;
    margin: 0 0 1rem;
    padding: 0;
    border: 0;
}

.fz-period-legend {
    float: left;
    width: auto;
    margin: 0;
    padding: 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-period-options {
    display: inline-flex;
    gap: 0.25rem;
    padding: 0.125rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 30%, var(--bs-border-color));
    border-radius: 999px;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 7%, transparent);
}

.fz-period-option {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: var(--fz-control-height);
    margin: 0;
    padding: 0 1rem;
    border-radius: 999px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
    cursor: pointer;
}

.fz-period-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.fz-period-option:has(.fz-period-input:checked) {
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

.fz-period-option:has(.fz-period-input:focus-visible) {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-switch-title {
    display: block;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-switch-hint {
    display: block;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* --- Tu cuota estimada ----------------------------------------------------- */
.fz-estimate-lines {
    margin: 0;
}

.fz-estimate-lines > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.3125rem 0;
}

.fz-estimate-lines dt {
    min-width: 0;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-estimate-lines dd {
    margin: 0;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    color: var(--bs-body-color);
}

.fz-estimate-lines > .fz-estimate-total {
    align-items: baseline;
    margin-top: 0.375rem;
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 12%, transparent);
}

.fz-estimate-total dt {
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-estimate-total dd {
    font-size: var(--fz-amount-lg);
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.fz-estimate-note {
    display: flex;
    gap: 0.5rem;
    margin: 1.25rem 0 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-estimate-note .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

.fz-estimate-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    min-height: 12rem;
    height: 100%;
    max-width: 22rem;
    margin-inline: auto;
    text-align: center;
    color: var(--bs-secondary-color);
}

.fz-estimate-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    border: 1px dashed color-mix(in srgb, var(--fz-kpi-tone) 50%, var(--bs-border-color));
    border-radius: 50%;
    color: var(--fz-kpi-tone);
}

.fz-estimate-empty-icon .icon {
    width: 1.75rem;
    height: 1.75rem;
}

/* --- «¿Quien la ve?» en tarjetas -------------------------------------------
   La pieza comun de las altas (`layouts/_visibility-field.php`, ADR 0055 y
   0092): una tarjeta por opcion, el radio dentro y cubriendola entera, de
   modo que toda la tarjeta es el objetivo. En una columna por defecto, que es
   lo que cabe en los formularios estrechos; `fz-choices-row` las pone en fila
   donde hay sitio. Elegida, lo dice el borde, el icono relleno y la marca de
   la esquina: el color no es la unica senal. */
.fz-choices {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.fz-choices-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
}

@media (min-width: 992px) {
    /* Una columna por opcion, sean dos o tres, todas del mismo ancho. Desde 992:
       a 768 cabian, pero de 226 px y con la consecuencia partida en ocho lineas. */
    .fz-choices-row .fz-choices-grid {
        grid-auto-columns: minmax(0, 1fr);
        grid-auto-flow: column;
    }
}

.fz-choice {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.875rem;
    min-height: 4.5rem;
    margin: 0;
    padding: 0.875rem 2.25rem 0.875rem 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.875rem;
    background-color: var(--fz-surface);
    cursor: pointer;
}

.fz-choice:hover {
    border-color: color-mix(in srgb, var(--fz-brand) 45%, var(--bs-border-color));
}

.fz-choice-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.fz-choice:has(.fz-choice-input:focus-visible) {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-choice:has(.fz-choice-input:checked) {
    border-color: var(--fz-brand-fill-end);
    background-image: linear-gradient(135deg, rgba(var(--fz-brand-rgb), 0.16), rgba(var(--fz-brand-rgb), 0.04));
    box-shadow: 0 0 0 1px var(--fz-brand-fill-end), 0 12px 28px -18px rgba(var(--fz-brand-rgb), 0.95);
}

.fz-choice-icon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background-color: var(--fz-surface-sunken);
    color: var(--bs-secondary-color);
}

.fz-choice-icon .icon {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-choice:has(.fz-choice-input:checked) .fz-choice-icon {
    background-color: var(--fz-brand-fill);
    background-image: linear-gradient(145deg, var(--fz-brand-fill-end), var(--fz-brand-fill));
    color: var(--fz-brand-on-fill);
    box-shadow: 0 0 18px -4px rgba(var(--fz-brand-rgb), 0.9);
}

.fz-choice-text {
    min-width: 0;
}

.fz-choice-title {
    display: block;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-choice-hint {
    display: block;
    font-size: 0.875rem;
    line-height: 1.35;
    color: var(--bs-secondary-color);
}

.fz-choice-check {
    position: absolute;
    top: 0.625rem;
    right: 0.625rem;
    display: none;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

.fz-choice-check .icon {
    width: 0.875rem;
    height: 0.875rem;
    stroke-width: 2.5;
}

.fz-choice:has(.fz-choice-input:checked) .fz-choice-check {
    display: inline-flex;
}

/* Una opcion que no paso la validacion lo dice en su borde, como un campo. */
.fz-choice:has(.fz-choice-input.is-invalid) {
    border-color: var(--bs-danger);
}

/* Opciones en baldosa (ADR 0097): icono encima y nombre debajo, siempre en una
   fila. Para pocas opciones cortas, como el tipo de prestamo. */
.fz-choices-tiles .fz-choices-grid {
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
}

.fz-choices-tiles .fz-choice {
    flex-direction: column;
    justify-content: center;
    gap: 0.5rem;
    min-height: 6rem;
    padding: 0.875rem 0.5rem;
    text-align: center;
}

.fz-choices-tiles .fz-choice-title {
    font-size: 0.875rem;
    line-height: 1.25;
}

/* Las personas elegidas, en pildoras bajo las tarjetas. Toda la pildora es el
   objetivo; elegida, se marca con borde y nombre en negrita, no solo color. */
.fz-choices .fz-people-pick {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0.75rem 0 0;
    padding: 0.75rem;
    border: 1px dashed color-mix(in srgb, var(--fz-brand) 45%, var(--bs-border-color));
    border-radius: 0.875rem;
}

.fz-choices .fz-people-pick-item {
    position: relative;
    min-height: 0;
    margin: 0;
    padding: 0;
}

.fz-choices .fz-people-pick-item > .form-check-input {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.fz-choices .fz-people-pick-label {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: var(--fz-control-height);
    padding: 0.25rem 1rem 0.25rem 0.3125rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-surface);
}

.fz-choices .fz-people-pick-item:has(:checked) .fz-people-pick-label {
    border-color: var(--fz-brand-fill-end);
    background-image: linear-gradient(135deg, rgba(var(--fz-brand-rgb), 0.18), rgba(var(--fz-brand-rgb), 0.05));
    box-shadow: 0 0 0 1px var(--fz-brand-fill-end);
    font-weight: 600;
}

.fz-choices .fz-people-pick-item:has(:focus-visible) .fz-people-pick-label {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-choices .fz-people-pick-item:has(.is-invalid) .fz-people-pick-label {
    border-color: var(--bs-danger);
}

/* --- El icono grande de la cabecera (ADR 0099) --------------------------------
   Como los de la imagen del alta de meta, y en las tres altas para que sigan
   iguales: decoracion en el tono de la tarjeta, detras de nada y sin texto. La
   cabecera le guarda su sitio a la derecha; en el telefono no cabe y se va. */
.fz-fcard-head:has(> .fz-fcard-mark) {
    position: relative;
    padding-right: 6rem;
}

.fz-fcard-mark {
    position: absolute;
    top: 50%;
    right: 1.25rem;
    width: 4.25rem;
    height: 4.25rem;
    color: var(--fz-kpi-tone);
    opacity: 0.2;
    stroke-width: 1.25;
    transform: translateY(-50%) rotate(-10deg);
    pointer-events: none;
}

[data-bs-theme='dark'] .fz-fcard-mark {
    opacity: 0.28;
}

@media (max-width: 575.98px) {
    .fz-fcard-head:has(> .fz-fcard-mark) {
        padding-right: 1.25rem;
    }

    .fz-fcard-mark {
        display: none;
    }
}

/* --- Una opcion con su campo dentro (ADR 0099) ----------------------------------
   «¿Donde se guarda el dinero?» del alta de meta: la tarjeta de la opcion es el
   contenedor y no el <label>, porque el radio cubre el rotulo entero y el
   desplegable de debajo tiene que poder usarse. El campo de la opcion que no se
   eligio se pliega aqui, sin JavaScript. */
.fz-where-option {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.875rem;
    background-color: var(--fz-surface);
}

.fz-where-option:hover {
    border-color: color-mix(in srgb, var(--fz-brand) 45%, var(--bs-border-color));
}

/* El borde y el brillo de la elegida los lleva la opcion entera, no su rotulo. */
.fz-where-option > .fz-choice,
.fz-where-option > .fz-choice:has(.fz-choice-input:checked) {
    border-color: transparent;
    background-color: transparent;
    background-image: none;
    box-shadow: none;
}

.fz-where-option:has(> .fz-choice .fz-choice-input:checked) {
    border-color: var(--fz-brand-fill-end);
    background-image: linear-gradient(135deg, rgba(var(--fz-brand-rgb), 0.16), rgba(var(--fz-brand-rgb), 0.04));
    box-shadow: 0 0 0 1px var(--fz-brand-fill-end), 0 12px 28px -18px rgba(var(--fz-brand-rgb), 0.95);
}

.fz-where-option:has(.fz-choice-input.is-invalid) {
    border-color: var(--bs-danger);
}

/* Alineado con el texto del rotulo: relleno + icono + hueco. */
.fz-where-more {
    padding: 0 1rem 1rem 4.625rem;
}

.fz-where-option:not(:has(> .fz-choice .fz-choice-input:checked)) > .fz-where-more {
    display: none;
}

@media (max-width: 575.98px) {
    .fz-where-more {
        padding-left: 1rem;
    }
}

/* Sin tarjeta de visibilidad al lado, las dos opciones van en fila. */
@media (min-width: 768px) {
    .fz-where-row .fz-choices-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* --- La visibilidad que hereda una meta (ADR 0099) ------------------------------
   Con una cuenta que ya existe, la meta se ve como ella: en vez de la pregunta,
   quien ve esa cuenta. La opcion que lo decide lleva `fz-where-inherits`. */
.fz-vis-body {
    display: flex;
    flex-direction: column;
}

.fz-vis-inherit {
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
    min-height: 12rem;
    max-width: 30rem;
    margin: auto;
    text-align: center;
    color: var(--bs-secondary-color);
}

.fz-form-grid:has(.fz-where-inherits:checked) .fz-vis-new {
    display: none;
}

.fz-form-grid:has(.fz-where-inherits:checked) .fz-vis-inherit {
    display: flex;
}

.fz-vis-inherit-title {
    margin: 0;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.fz-vis-inherit-who {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.625rem;
}

.fz-vis-inherit-account {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    padding: 0.375rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 35%, var(--bs-border-color));
    border-radius: 999px;
    background-color: var(--fz-surface);
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-vis-inherit-account .icon {
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

.fz-vis-inherit-people {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-vis-inherit-people li {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.25rem 0.75rem 0.25rem 0.3125rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-surface);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-vis-inherit-foot {
    margin: 0;
    font-size: 0.875rem;
}

/* En la edicion (ADR 0100) la cuenta no cambia: quien la ve se ensena siempre. */
.fz-vis-inherit.fz-vis-inherit-shown {
    display: flex;
}

/* --- La foto de una meta (ADR 0100) ----------------------------------------------
   La vista previa en miniatura 16:9 -la forma en que se guarda- y el campo al
   lado: a tamaño completo, la tarjeta doblaba en alto a «Objetivo y plazo», con
   la que comparte fila. En el telefono, una debajo de otra. */
.fz-photo-pick {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}

@media (min-width: 576px) {
    .fz-photo-pick {
        grid-template-columns: minmax(0, 12.5rem) minmax(0, 1fr);
    }
}

/* El nombre del archivo elegido no ensancha la tarjeta. */
.fz-photo-controls {
    min-width: 0;
}

.fz-photo-drop {
    overflow: hidden;
    aspect-ratio: 16 / 9;
    max-width: 100%;
    border: 1px dashed color-mix(in srgb, var(--fz-kpi-tone) 45%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 6%, var(--fz-surface-sunken));
}

.fz-photo-drop:has(.fz-photo-drop-img:not([hidden])) {
    border-style: solid;
}

.fz-photo-drop-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.fz-photo-drop-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    height: 100%;
    padding: 0.5rem;
    font-size: 0.875rem;
    text-align: center;
    color: var(--bs-secondary-color);
}

.fz-photo-drop-empty .icon {
    width: 1.75rem;
    height: 1.75rem;
    color: var(--fz-kpi-tone);
}

/* «Quitar la foto» marcada: la foto se apaga hasta guardar. */
.fz-fcard:has([data-photo-remove]:checked) .fz-photo-drop-img {
    opacity: 0.35;
    filter: grayscale(1);
}

/* --- Cuándo llegas (ADR 0099) --------------------------------------------------- */
.fz-arrival {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.75rem;
    padding: 0.875rem 1rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 12%, transparent);
}

.fz-arrival-label {
    flex: 1 0 100%;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.fz-arrival-value {
    font-size: var(--fz-amount-lg);
    font-weight: 700;
    line-height: 1.2;
    color: var(--bs-emphasis-color);
}

.fz-arrival-pace {
    margin: 0.875rem 0 0.5rem;
    color: var(--bs-body-color);
}

.fz-arrival-use {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: var(--fz-control-height);
    margin-top: 0.75rem;
    border-radius: 0.75rem;
    font-weight: 600;
}

.fz-arrival-use .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* --- Los botones del final -------------------------------------------------- */
.fz-form-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

/* El pie de una tarjeta que se guarda sola (ADR 0125) lleva los mismos botones. */
.fz-form-actions .btn,
.fz-fcard-actions .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding-inline: 1.5rem;
    border-radius: 0.875rem;
    font-weight: 600;
}

.fz-form-actions .btn .icon,
.fz-fcard-actions .btn .icon {
    width: 1.25rem;
    height: 1.25rem;
}

/* El de guardar, con el degradado de la marca alargado hasta el violeta. */
.fz-btn-cta {
    min-width: min(100%, 22rem);
    background-image: linear-gradient(90deg, var(--fz-brand-fill), var(--fz-cta-end));
}

@media (max-width: 575.98px) {
    .fz-form-actions .btn {
        padding-inline: 1rem;
    }

    .fz-btn-cta {
        flex: 1 1 auto;
        min-width: 0;
    }
}

/* --- La ficha de la casa: lo que el alta pide (ADR 0096) ------------------- */
.fz-house-facts-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
    gap: var(--fz-space-3) var(--fz-space-5);
    margin: 0;
}

.fz-house-facts-list dt {
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-house-facts-list dd {
    margin: 0;
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* «Editar los datos» (ADR 0098): un boton secundario con su icono, en la
   cabecera de la tarjeta. El de la ficha de un prestamo (ADR 0109) es el mismo
   boton, en la fila de acciones de la cabecera. */
.fz-house-facts-edit,
.fz-loan-edit {
    display: inline-flex;
    align-items: center;
    gap: var(--fz-space-2);
}

.fz-house-facts-edit .icon,
.fz-loan-edit .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* Un campo que se ensena sin poder tocarse: el contrato en la edicion de un
   prestamo (ADR 0109), la cuenta de una meta (ADR 0100). Tiene que leerse como
   un dato y no como un hueco para escribir, asi que va al reves que los
   editables de cada tema: en claro, donde los editables son blancos, hundido;
   en oscuro, donde ya son hundidos, al ras de la tarjeta. */
.fz-field .form-control[readonly] {
    background-color: var(--fz-surface-sunken);
}

[data-bs-theme='dark'] .fz-field .form-control[readonly] {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 10%, var(--fz-surface));
}

/* --- Archivar un prestamo o una casa, en tarjetas (ADR 0109) ---------------
   La cuenta de la que salio el pago sobra si se archiva sin registrarlo: se
   esconde, pero solo con `:has()`. Donde no llega, se ve siempre y el servidor
   la ignora, que es como funcionaba antes. */
.fz-close-payer {
    margin-top: 1.25rem;
}

.fz-close-how:has(.fz-close-none:checked) .fz-close-payer {
    display: none;
}

/* Lo que cambia al archivar: las notas de la cuota estimada, una por linea. */
.fz-close-effects .fz-estimate-note {
    margin-top: 0.875rem;
    font-size: 0.875rem;
}

.fz-close-effects .fz-estimate-note:first-child {
    margin-top: 0;
}

/* ===========================================================================
   PONER Y CAMBIAR UN TOPE, EN TARJETAS  (ADR 0102)
   ===========================================================================

   /budgets/new y /budgets/{id}/edit con las piezas de las otras altas
   (`fz-form-*`, `fz-fcard`, `fz-choice`, `fz-where-*`, `fz-arrival`). Aqui
   solo lo que es del tope: las tres opciones de «¿Qué vas a vigilar?», la
   moneda que pone la cuenta, la barra de «Cómo te va», el historial y quitar
   el tope. */

/* Las tres opciones de «¿Qué vas a vigilar?» en fila mientras la tarjeta va a lo
   ancho, entre 992 y 1199 px: a 768 cabian de 220 px y con la explicacion
   partida en cinco lineas, y desde 1200 la tarjeta va en media pagina. */
@media (min-width: 992px) and (max-width: 1199.98px) {
    .fz-bud-kinds .fz-choices-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* El alta, desde 1200 px: que vigilar y el tope a la izquierda, «Cómo te va» a
   la derecha en toda su altura y, en un espacio compartido, «¿De quién es?» a
   lo ancho arriba. Con el tope y «Cómo te va» en la misma fila, bajo el tope
   quedaba un hueco de 200 px. Por debajo de 1200, una columna en el orden del
   HTML. */
@media (min-width: 1200px) {
    .fz-bud-new-grid {
        grid-template-areas:
            'scope estimate'
            'amount estimate';
        grid-template-rows: auto 1fr;
    }

    .fz-bud-new-grid:has(> .fz-bud-new-owner) {
        grid-template-areas:
            'owner owner'
            'scope estimate'
            'amount estimate';
        grid-template-rows: auto auto 1fr;
    }

    .fz-bud-new-owner {
        grid-area: owner;
    }

    .fz-bud-new-scope {
        grid-area: scope;
    }

    .fz-bud-new-amount {
        grid-area: amount;
    }

    .fz-bud-new-estimate {
        grid-area: estimate;
    }
}

/* Una opcion sin nada que elegir -todas las categorias ya tienen tope- se
   queda, apagada y con su explicacion, en vez de desaparecer sin decir por
   que. Fondo hundido y borde discontinuo: no solo color. */
.fz-where-option:has(.fz-choice-input:disabled),
.fz-where-option:has(.fz-choice-input:disabled):hover {
    border-style: dashed;
    border-color: var(--bs-border-color);
    background-color: var(--fz-surface-sunken);
}

.fz-choice:has(.fz-choice-input:disabled),
.fz-choice-input:disabled {
    cursor: not-allowed;
}

.fz-choice:has(.fz-choice-input:disabled) .fz-choice-title {
    color: var(--bs-secondary-color);
}

/* Apagada, el circulo del icono se separa del fondo hundido. */
.fz-where-option:has(.fz-choice-input:disabled) .fz-choice-icon {
    border: 1px solid var(--bs-border-color);
    background-color: var(--fz-surface);
}

/* «Una cuenta» elegida: la moneda la pone la cuenta. El desplegable se va y
   queda la frase, sin JavaScript (el servidor la impone igual, ADR 0046). */
.fz-bud-currency-fixed {
    display: none;
    gap: 0.5rem;
    margin: 0;
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 10%, transparent);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-bud-currency-fixed .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

.fz-form-grid:has(.fz-bud-kind-account:checked) .fz-bud-currency {
    display: none;
}

.fz-form-grid:has(.fz-bud-kind-account:checked) .fz-bud-currency-fixed {
    display: flex;
}

/* --- Cómo te va ---------------------------------------------------------------
   La barra es la de la tabla (`.budget-bar`) con su relleno pintado por el
   estado que llega del servidor en `data-state`: el script no conoce las
   clases, solo copia el estado. */
.fz-bud-estimate-status {
    margin-top: 1rem;
}

.fz-bud-estimate-bar {
    height: 0.625rem;
}

.fz-bud-estimate-bar .budget-fill[data-state='on_track'] {
    fill: url(#fz-grad-on-track) var(--fz-brand-fill);
}

.fz-bud-estimate-bar .budget-fill[data-state='warning'] {
    fill: url(#fz-grad-warning) var(--fz-state-warn-fill);
}

.fz-bud-estimate-bar .budget-fill[data-state='exceeded'] {
    fill: url(#fz-grad-over) var(--fz-state-over-fill);
}

.fz-bud-estimate-line {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.25rem 1rem;
    margin: 0.5rem 0 0;
}

/* El estado tambien se dice con palabras y porcentaje, nunca solo color. */
.fz-bud-estimate-state {
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.fz-bud-estimate-state[data-state='warning'] {
    color: var(--fz-state-warn-text);
}

.fz-bud-estimate-state[data-state='exceeded'] {
    color: var(--fz-state-over-text);
}

.fz-bud-estimate-warn {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 1rem 0 0;
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-bud-estimate-warn .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-state-warn-text);
}

/* Lo que falta por pagar: la frase de la fila de la lista, y adonde se llega con
   ello. Neutro; en ambar si eso pasa el tope (`data-state='over'`), como un
   «cerca del limite» y no como el rojo de lo ya gastado (ADR 0008). */
.fz-bud-estimate-committed {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    margin: 1rem 0 0;
    padding: 0.75rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 28%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
}

.fz-bud-estimate-committed > .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

.fz-bud-estimate-committed[data-state='over'] {
    border-color: color-mix(in srgb, var(--fz-state-warn-text) 45%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
}

.fz-bud-estimate-committed[data-state='over'] > .icon {
    color: var(--fz-state-warn-text);
}

.fz-bud-estimate-committed-text {
    min-width: 0;
}

.fz-bud-estimate-committed-text p {
    margin: 0;
}

.fz-bud-estimate-committed-amount {
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-bud-estimate-committed-after {
    margin-top: 0.125rem;
    color: var(--bs-body-color);
}

.fz-bud-estimate-committed-help {
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* El cambio, desde 1200 px: el tope y su historial a la izquierda y «Cómo te
   va» a la derecha en las dos filas. Con el tope solo en la primera fila,
   junto a «Cómo te va» -que crece con lo que falta por pagar- quedaba un hueco
   de 230 px debajo. Por debajo de 1200, una columna en el orden del HTML: el
   tope, cómo te va y el historial. */
@media (min-width: 1200px) {
    .fz-bud-edit-grid {
        grid-template-areas:
            'amount estimate'
            'history estimate';
        grid-template-rows: auto 1fr;
    }

    .fz-bud-edit-amount {
        grid-area: amount;
    }

    .fz-bud-edit-estimate {
        grid-area: estimate;
    }

    .fz-bud-edit-history {
        grid-area: history;
    }
}

/* De quien es el tope que se cambia (ADR 0056), bajo el importe. */
.fz-bud-side-note {
    display: flex;
    gap: 0.5rem;
    margin: 1rem 0 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-bud-side-note .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

/* Lo que vigila el tope esta archivado: el mismo aviso que la fila de la lista,
   con el enlace para restaurarlo. Ambar: no es un error, pero el tope ya no se
   mueve. */
.fz-bud-archived-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 1rem 0 0;
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-bud-archived-note .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-state-warn-text);
}

/* --- El historial: una ficha por tope, la vigente marcada -------------------- */
.fz-bud-history {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-bud-history-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.125rem 0.75rem;
    padding: 0.75rem 1rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: var(--fz-surface);
}

.fz-bud-history-item.is-current {
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 55%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, var(--fz-surface));
}

.fz-bud-history-amount {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--bs-emphasis-color);
}

.fz-bud-history-badge {
    margin-left: auto;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 18%, transparent);
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-bud-history-period {
    flex: 1 0 100%;
    order: 3;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* --- Quitar el tope: su propio formulario, debajo de todo --------------------- */
/* Eliminar un movimiento desde su edicion (ADR 0113) es la misma franja. */
.fz-bud-stop,
.fz-mov-delete,
.fz-grp-delete {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    margin-top: 2rem;
    padding: 1rem 1.25rem;
    border: 1px solid color-mix(in srgb, var(--fz-state-over-text) 35%, var(--bs-border-color));
    border-radius: 1rem;
    background-color: color-mix(in srgb, var(--fz-state-over-text) 5%, var(--fz-surface));
}

.fz-bud-stop-text,
.fz-mov-delete-text,
.fz-grp-delete-text {
    flex: 1 1 18rem;
    min-width: 0;
    font-size: 0.9375rem;
    color: var(--bs-secondary-color);
}

.fz-bud-stop-title,
.fz-mov-delete-title,
.fz-grp-delete-title {
    margin: 0 0 0.25rem;
    font-size: 1rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.fz-bud-stop-button,
.fz-mov-delete-button,
.fz-grp-delete-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding-inline: 1.25rem;
    border-radius: 0.875rem;
    font-weight: 600;
}

.fz-bud-stop-button .icon,
.fz-mov-delete-button .icon,
.fz-grp-delete-button .icon {
    width: 1.125rem;
    height: 1.125rem;
}

@media (max-width: 575.98px) {
    .fz-bud-stop-button,
    .fz-mov-delete-button,
    .fz-grp-delete-button {
        flex: 1 1 auto;
    }
}

/* --- Refinanciar en tarjetas (ADR 0107) ----------------------------------------
   Desde 1200 px, el prestamo, los costos y el efectivo a la izquierda y «¿Sale a
   cuenta?» a la derecha en toda su altura, como el alta de un tope (ADR 0102).
   Por debajo, una columna en el orden del HTML. */
@media (min-width: 1200px) {
    .fz-refi-grid {
        grid-template-areas:
            'loan estimate'
            'costs estimate'
            'cash estimate';
        grid-template-rows: auto auto 1fr;
    }

    .fz-refi-loan {
        grid-area: loan;
    }

    .fz-refi-costs {
        grid-area: costs;
    }

    .fz-refi-cash {
        grid-area: cash;
    }

    .fz-refi-estimate {
        grid-area: estimate;
    }

    /* La tarjeta de la cuenta, de su altura y pegada al desplazarse
       (refinanciar y el simulador de abonos, ADR 0107 y 0108): las tarjetas de
       la izquierda miden mas que ella, y estirada dejaba 650 px vacios debajo.
       Asi la cuenta sigue a la vista mientras se llena lo de abajo. */
    .fz-fcard-sticky {
        position: sticky;
        top: var(--fz-space-4);
        align-self: start;
    }
}

/* --- El simulador de abonos en tarjetas (ADR 0108) ------------------------------
   El abono y lo que hace el banco a la izquierda, «¿Cuánto cambia?» a la derecha.
   Por debajo de 1200 px, una columna en el orden del HTML. */
@media (min-width: 1200px) {
    .fz-sim-grid {
        grid-template-areas:
            'extra estimate'
            'mode estimate';
        grid-template-rows: auto 1fr;
    }

    .fz-sim-extra {
        grid-area: extra;
    }

    .fz-sim-mode {
        grid-area: mode;
        align-self: start;
    }

    .fz-sim-estimate {
        grid-area: estimate;
    }
}

/* El plazo en anos y lo que le queda a la de hoy, en la misma ayuda. */
.fz-refi-term:not(:empty)::after {
    content: ' · ';
}

/* La cuenta donde cae el efectivo solo hace falta si se lleva efectivo: sin
   importe, el campo no se ensena. Sin JavaScript; el servidor la pide igual
   si hay importe (`loan.cash_out_account_missing`). */
.fz-refi-cash:has(#refi-cash:placeholder-shown) .fz-refi-cash-account {
    display: none;
}

/* El veredicto de una tarjeta de cuenta, justo debajo de la cifra grande: el
   punto de equilibrio de refinanciar (ADR 0107) y lo que el abono le hace al
   prestamo (ADR 0108). En el tono de la tarjeta; en ambar si lo que dice
   juega en contra (`data-state='over'`). */
.fz-estimate-verdict {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    margin: 1rem 0 0;
    padding: 0.75rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 28%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
}

.fz-estimate-verdict > .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

.fz-estimate-verdict[data-state='over'] {
    border-color: color-mix(in srgb, var(--fz-state-warn-text) 45%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
}

.fz-estimate-verdict[data-state='over'] > .icon {
    color: var(--fz-state-warn-text);
}

.fz-estimate-verdict-text {
    min-width: 0;
}

.fz-estimate-verdict-text p {
    margin: 0;
}

.fz-estimate-verdict-title {
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-estimate-verdict-after {
    margin-top: 0.125rem;
    color: var(--bs-body-color);
}

.fz-estimate-verdict-help {
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* Un hecho suelto de la cuenta: lo que se ahorra de intereses, el plazo que
   se alarga. Lo que sale caro va en ambar (`fz-estimate-warn`). */
.fz-estimate-fact,
.fz-estimate-warn {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0.75rem 0 0;
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-estimate-fact .icon,
.fz-estimate-warn .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

.fz-estimate-fact-good .icon {
    color: var(--fz-state-ok-text);
}

.fz-estimate-warn {
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
}

.fz-estimate-warn .icon {
    color: var(--fz-state-warn-text);
}

/* ===========================================================================
   ALTA Y EDICION DE UNA CUENTA, EN TARJETAS  (ADR 0111, ADR 0112)
   ===========================================================================

   /accounts/new y /accounts/{id}/edit con las piezas de las otras altas
   (`fz-form-*`, `fz-fcard`, `fz-choice`, `fz-switch`). Aqui solo lo que es de
   la cuenta: que tarjeta va donde segun el tipo, la vista previa, «Dónde
   suma» y el logo, que tambien sale en /accounts y en el inicio. */

/* --- Lo que es de un solo tipo -------------------------------------------------
   Una regla por tipo: se esconde lo que no lleva el tipo marcado. Sin `:has()`
   se ve todo, y el servidor solo lee lo del tipo que llega: mas ruido, cero
   rotura. */
.fz-acct-form:has(#acct-type-cash:checked) [data-for-type]:not([data-for-type~='cash']),
.fz-acct-form:has(#acct-type-bank:checked) [data-for-type]:not([data-for-type~='bank']),
.fz-acct-form:has(#acct-type-credit_card:checked) [data-for-type]:not([data-for-type~='credit_card']),
.fz-acct-form:has(#acct-type-savings:checked) [data-for-type]:not([data-for-type~='savings']),
.fz-acct-form:has(#acct-type-loan:checked) [data-for-type]:not([data-for-type~='loan']),
.fz-acct-form:has(#acct-type-escrow:checked) [data-for-type]:not([data-for-type~='escrow']) {
    display: none;
}

/* El efectivo no lleva logo (ADR 0112): ni el campo, ni la esquina de la vista
   previa, ni «Quitar el logo». El servidor tampoco lo guarda. */
.fz-acct-form:has(#acct-type-cash:checked) :is(.fz-acct-logo, .fz-acct-logo-remove, [data-preview-badge]) {
    display: none;
}

/* --- Donde va cada tarjeta, desde 1200 px ---------------------------------------
   Arriba los datos y, al lado, como se ve: la vista previa cambia junto a lo
   que se escribe. Debajo el saldo y lo propio del tipo; «Visibilidad» a lo
   ancho. Efectivo, ahorros, prestamo y escrow no tienen tarjeta propia: el
   saldo va a lo ancho, con el campo y «Dónde suma» lado a lado. Junto a
   «Visibilidad» se estiraba hasta su altura y le sobraba el pie. En la edicion
   «¿Quién la ve?» va fuera del formulario, asi que la rejilla no la tiene. Por
   debajo de 1200, una columna en el orden del DOM. */
@media (min-width: 1200px) {
    .fz-acct-grid {
        grid-template-areas:
            'info look'
            'balance extra'
            'who who';
    }

    .fz-acct-grid:has(#acct-type-cash:checked, #acct-type-savings:checked, #acct-type-loan:checked,
    #acct-type-escrow:checked) {
        grid-template-areas:
            'info look'
            'balance balance'
            'who who';
    }

    /* Sin «¿Quién la ve?» la fila de abajo sobra: vacia, dejaria su separacion
       antes de los botones. */
    .fz-acct-grid:not(:has(#acct-who)) {
        grid-template-areas:
            'info look'
            'balance extra';
    }

    /* Con `:has(#id)` la especificidad es la de un id: esta regla necesita las dos
       condiciones para ganarle a las de arriba. */
    .fz-acct-grid:not(:has(#acct-who)):has(#acct-type-cash:checked, #acct-type-savings:checked,
    #acct-type-loan:checked, #acct-type-escrow:checked) {
        grid-template-areas:
            'info look'
            'balance balance';
    }

    /* El saldo a lo ancho: el campo con su ayuda a la izquierda y «Dónde suma» a
       la derecha, a la misma altura. */
    .fz-acct-grid:has(#acct-type-cash:checked, #acct-type-savings:checked, #acct-type-loan:checked,
    #acct-type-escrow:checked) #acct-balance-card .fz-fcard-body {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 1.5rem;
        align-items: start;
    }

    .fz-acct-grid:has(#acct-type-cash:checked, #acct-type-savings:checked, #acct-type-loan:checked,
    #acct-type-escrow:checked) #acct-balance-card .fz-fcard-body > * {
        grid-column: 1;
    }

    .fz-acct-grid:has(#acct-type-cash:checked, #acct-type-savings:checked, #acct-type-loan:checked,
    #acct-type-escrow:checked) #acct-balance-card .fz-acct-lands {
        grid-column: 2;
        grid-row: 1 / span 3;
        margin-top: 0;
    }

    /* Lado a lado no hace falta el hueco de debajo de la ayuda: alargaria la
       columna del campo y dejaria aire al pie. */
    .fz-acct-grid:has(#acct-type-cash:checked, #acct-type-savings:checked, #acct-type-loan:checked,
    #acct-type-escrow:checked) #acct-balance-card .form-text {
        margin-bottom: 0;
    }

    #acct-info {
        grid-area: info;
    }

    #acct-look {
        grid-area: look;
    }

    #acct-balance-card {
        grid-area: balance;
    }

    #acct-bank-card,
    #acct-card-card {
        grid-area: extra;
    }

    .fz-acct-grid > #acct-who {
        grid-area: who;
    }
}

/* --- Datos de la cuenta -------------------------------------------------------- */
.fz-acct-types .fz-choice {
    min-width: 0;
}

.fz-acct-type-hint {
    margin: 0.5rem 0 0;
}

/* Tambien la nota del alta de categoria con ingreso (ADR 0114). */
.fz-acct-elsewhere,
.fz-cat-income-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0.75rem 0 0;
    padding: 0.625rem 0.75rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-acct-elsewhere .icon,
.fz-cat-income-note .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.125rem;
    color: var(--fz-kpi-tone);
}

/* Tambien «No se puede cambiar después» bajo el tipo de una categoria (ADR 0114). */
.fz-acct-lock,
.fz-cat-lock {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

.fz-acct-lock .icon,
.fz-cat-lock .icon {
    flex: 0 0 auto;
    width: 0.9375rem;
    height: 0.9375rem;
}

/* --- El logo de una cuenta en su tarjeta (ADR 0112) ------------------------------
   Una pastilla blanca: un logo se dibuja para ir sobre blanco, y sobre el color
   de la tarjeta perderia el suyo. `contain`: entero, sin recortar. */
.fz-account-logo {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 2.5rem;
    block-size: 2.5rem;
    overflow: hidden;
    border-radius: 0.625rem;
    background-color: #ffffff;
    box-shadow: 0 6px 14px -6px rgba(0, 0, 0, 0.55);
}

.fz-account-logo img {
    display: block;
    inline-size: 100%;
    block-size: 100%;
    padding: 0.1875rem;
    object-fit: contain;
}

/* La compacta de /accounts: el logo chico, delante del nombre. */
.fz-account-logo-sm {
    inline-size: 1.5rem;
    block-size: 1.5rem;
    border-radius: 0.375rem;
}

.fz-account-logo-sm img {
    padding: 0.125rem;
}

/* La destacada de /accounts y la vista previa son de una columna: el logo va en
   la esquina, sin empujar nada, y lo que va arriba le deja su sitio. En el
   inicio ocupa la celda de la marca (ADR 0079). */
.fz-account-featured:has(> .fz-account-logo-corner) {
    position: relative;
}

.fz-account-featured > .fz-account-logo-corner {
    position: absolute;
    inset-block-start: var(--fz-space-3);
    inset-inline-end: var(--fz-space-3);
}

.fz-account-featured:has(> .fz-account-logo-corner:not([hidden])) :is(.fz-account-type, .fz-account-name) {
    padding-inline-end: 3.25rem;
}

/* --- Como se ve: la vista previa y el logo ----------------------------------------- */
.fz-acct-look-top {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1rem 1.25rem;
    margin-bottom: 1.25rem;
}

.fz-acct-preview {
    display: flex;
    flex: 1 1 17rem;
    flex-direction: column;
    gap: 0.375rem;
    min-width: 0;
}

.fz-acct-preview-label {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-acct-preview .fz-account {
    min-height: 9rem;
}

.fz-acct-preview-icon {
    display: inline-flex;
}

.fz-acct-preview .fz-account-name .is-empty {
    font-style: italic;
    opacity: 0.8;
}

.fz-acct-preview-usage .fz-account-usage {
    display: block;
    font-size: 0.8125rem;
    color: var(--fz-on-accent-muted);
}

/* La barra de la linea usada: el estado llega del servidor en `data-state`,
   con los tonos de una barra sobre una tarjeta de color (ADR 0080). */
.fz-acct-preview-usage .budget-bar {
    margin-block: var(--fz-space-1);
}

.fz-acct-preview-usage .budget-track {
    fill: rgba(0, 0, 0, 0.3);
}

.fz-acct-preview-usage .budget-fill[data-state='on_track'] {
    fill: url(#fz-grad-color-on-track) var(--fz-on-color-bar-on);
}

.fz-acct-preview-usage .budget-fill[data-state='warning'] {
    fill: url(#fz-grad-color-warning) var(--fz-on-color-bar-warn);
}

.fz-acct-preview-usage .budget-fill[data-state='exceeded'] {
    fill: url(#fz-grad-color-over) var(--fz-on-color-bar-over);
}

/* La zona de subida de una imagen -el logo de una cuenta (ADR 0112), la imagen
   de una categoria (ADR 0116)-: un cuadro que se pulsa o sobre el que se suelta.
   El campo de archivo lo cubre entero y es el que recibe el foco y el archivo. */
.fz-acct-logo {
    display: flex;
    flex: 0 0 9rem;
    flex-direction: column;
    gap: 0.375rem;
    min-width: 0;
}

.fz-acct-logo .form-label {
    margin-bottom: 0;
}

.fz-upload-box {
    position: relative;
}

.fz-upload-drop {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    width: 100%;
    margin: 0;
    overflow: hidden;
    border: 1px dashed color-mix(in srgb, var(--fz-kpi-tone) 55%, var(--bs-border-color));
    border-radius: 0.875rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 6%, var(--fz-surface-sunken));
    text-align: center;
    cursor: pointer;
}

.fz-upload-drop:hover,
.fz-upload-drop.is-dragging {
    border-color: var(--fz-kpi-tone);
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 14%, var(--fz-surface-sunken));
}

.fz-upload-drop:has(.fz-upload-img:not([hidden])) {
    border-style: solid;
    background-color: #ffffff;
}

.fz-upload-drop:focus-within {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-upload-drop.is-invalid {
    border-color: var(--bs-danger);
}

.fz-upload-input {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.fz-upload-img {
    width: 100%;
    height: 100%;
    padding: 0.875rem;
    object-fit: contain;
}

/* «Quitar el logo» marcado: el logo se apaga hasta guardar, como la foto de una
   meta (ADR 0100). */
.fz-acct-form:has([data-logo-remove]:checked) .fz-upload-img {
    opacity: 0.35;
    filter: grayscale(1);
}

.fz-upload-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    padding: 0.5rem;
    font-size: 0.8125rem;
    line-height: 1.3;
    color: var(--bs-secondary-color);
}

.fz-upload-empty .icon {
    width: 1.75rem;
    height: 1.75rem;
    margin-bottom: 0.25rem;
    color: var(--fz-kpi-tone);
}

.fz-upload-cta {
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

/* Deshacer la eleccion: la cruz de la esquina, 44 px de objetivo con un circulo
   de 28 dentro, por encima del campo de archivo que cubre el cuadro. */
.fz-upload-clear {
    position: absolute;
    top: -0.875rem;
    right: -0.875rem;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    padding: 0;
    border: 0;
    background: none;
}

.fz-upload-clear[hidden] {
    display: none;
}

.fz-upload-clear-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border: 2px solid var(--fz-surface);
    border-radius: 50%;
    background-color: var(--bs-emphasis-color);
    color: var(--fz-surface);
}

.fz-upload-clear-dot .icon {
    width: 0.875rem;
    height: 0.875rem;
    stroke-width: 2.5;
}

.fz-upload-clear:focus-visible .fz-upload-clear-dot {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

/* En el telefono el logo va debajo de la vista previa, en una fila baja: un
   cuadro de 9rem a lo ancho empujaria los colores fuera de la pantalla. */
@media (max-width: 575.98px) {
    .fz-acct-logo {
        flex: 1 1 100%;
    }

    .fz-upload-drop {
        aspect-ratio: auto;
        min-height: 4.5rem;
    }

    .fz-upload-drop:has(.fz-upload-img:not([hidden])) {
        height: 6rem;
    }

    .fz-upload-empty {
        flex-direction: row;
        flex-wrap: wrap;
        justify-content: center;
        column-gap: 0.5rem;
    }

    .fz-upload-empty .icon {
        margin-bottom: 0;
    }
}

/* Los doce colores en dos filas de seis, y en tres de cuatro en el telefono. Con
   `auto-fill` y 5.5rem quedaban cinco por fila y una ultima fila de dos. */
#acct-look .cat-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (min-width: 576px) {
    #acct-look .cat-grid {
        grid-template-columns: repeat(6, minmax(0, 1fr));
    }
}

/* `!important` porque `mb-3` es una utilidad de Bootstrap, que lo lleva. */
#acct-look fieldset.mb-3 {
    margin-bottom: 0 !important;
}

/* --- Ninguna tarjeta con el pie vacio ------------------------------------------
   Dos tarjetas de una fila miden lo que la mas alta, y la otra se estira: la
   vista previa de una tarjeta de credito hace mas alta a «Cómo se ve», las
   ayudas de la tarjeta a «Datos de la tarjeta»... Lo que sobra va antes del
   ultimo bloque de cada tarjeta, nunca al pie. Sin estirar -en el telefono, o
   cuando la tarjeta es la mas alta- todo queda como siempre: el hueco minimo es
   el de la rejilla. */
#acct-look .fz-fcard-body,
#acct-info .fz-fcard-body,
#acct-bank-card .fz-fcard-body {
    display: flex;
    flex-direction: column;
}

#acct-look .fz-fcard-body > fieldset:last-child {
    margin-top: auto;
}

/* Las filas de Bootstrap de estas dos tarjetas son de una sola columna: en
   columna, el ultimo bloque se puede empujar abajo. Su separacion pasa del
   margen al relleno, que el `auto` no se come. */
#acct-info .fz-fcard-body > .row,
#acct-bank-card .fz-fcard-body > .row {
    flex: 1 1 auto;
    flex-direction: column;
    flex-wrap: nowrap;
}

#acct-info .fz-fcard-body > .row > :last-child,
#acct-bank-card .fz-fcard-body > .row > :last-child {
    margin-top: auto;
    padding-top: var(--bs-gutter-y);
}

/* --- Saldo de hoy: donde suma la cuenta -------------------------------------------
   La columna del tablero (ADR 0110) en la que entra y como cambia su cifra, en
   SU moneda: nunca se suman monedas (ADR 0036). Sin cambio queda la cifra de hoy
   sola, en grande. */
/* «Saldo de hoy» se estira hasta la altura de su vecina de fila -los datos de la
   tarjeta, con ayudas de dos y tres lineas, la sacaban 47 px mas alta-: «Dónde
   suma» baja al pie y el aire queda entre el campo y la cifra, no debajo de todo.
   El hueco minimo lo pone la ayuda, y solo si «Dónde suma» se ve: sin el (un
   prestamo) el pie quedaria vacio. */
#acct-balance-card .fz-fcard-body {
    display: flex;
    flex-direction: column;
}

#acct-balance-card .form-text:has(+ .fz-acct-lands:not([hidden])) {
    margin-bottom: 1.25rem;
}

.fz-acct-lands {
    margin: auto 0 0;
    padding: 0.875rem 1rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 10%, transparent);
}

.fz-acct-lands-label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.fz-acct-lands-text {
    margin: 0.125rem 0 0.375rem;
    font-size: 0.9375rem;
    color: var(--bs-body-color);
}

.fz-acct-lands-figures {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.625rem;
    margin: 0;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.fz-acct-lands-before {
    color: var(--bs-secondary-color);
}

.fz-acct-lands-change {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
}

.fz-acct-lands-change[hidden] {
    display: none;
}

.fz-acct-lands-arrow {
    display: inline-flex;
    color: var(--fz-kpi-tone);
}

.fz-acct-lands-arrow .icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-acct-lands-after,
.fz-acct-lands-figures:not(:has(.fz-acct-lands-change:not([hidden]))) .fz-acct-lands-before {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

/* «¿Quién la ve?» de la edicion, fuera del formulario y debajo de sus botones.
   Igual en la de una categoria (ADR 0114). */
.fz-acct-share,
.fz-cat-share {
    margin-top: 1.5rem;
}

/* El fieldset de «¿Quién la ve?» trae su margen de abajo; dentro de su tarjeta
   sobra: el pie ya lo pone la tarjeta. */
.fz-acct-grid > #acct-who .fz-choices {
    margin-bottom: 0 !important;
}

/* ===========================================================================
   EDITAR UN MOVIMIENTO, EN TARJETAS  (ADR 0113)
   ===========================================================================

   /transactions/{id}/edit con las piezas de las altas en tarjetas (`fz-form-*`,
   `fz-fcard`, `fz-field`) y la rejilla de baldosas de la captura
   (`layouts/_category-tiles.php`). Aqui solo lo que es de la edicion: donde va
   cada tarjeta, la fila de «Cómo queda», el recuadro del saldo, el reparto en
   solo lectura y la confirmacion de eliminar. La franja de eliminar comparte
   las reglas de «Quitar el tope» (`.fz-bud-stop`, ADR 0102). */

/* Desde 1200 px, las tarjetas a la izquierda y «Cómo queda» a la derecha en toda
   la altura, pegada al desplazarse (`fz-fcard-sticky`): la de las categorias es
   alta y la vista previa tiene que seguir a la vista mientras se elige. Por
   debajo, una columna en el orden del HTML, con la vista previa justo antes de
   guardar. */
@media (min-width: 1200px) {
    .fz-mov-edit-grid-simple {
        grid-template-areas:
            'amount preview'
            'category preview'
            'details preview';
        grid-template-rows: auto auto 1fr;
    }

    .fz-mov-edit-grid-transfer,
    .fz-mov-edit-grid-split {
        grid-template-areas:
            'amount preview'
            'details preview';
        grid-template-rows: auto 1fr;
    }

    .fz-mov-edit-amount,
    .fz-mov-edit-split {
        grid-area: amount;
    }

    .fz-mov-edit-category {
        grid-area: category;
    }

    .fz-mov-edit-details {
        grid-area: details;
    }

    .fz-mov-edit-preview {
        grid-area: preview;
    }
}

/* La categoria que falto al guardar: el aviso de arriba lo dice y el recuadro lo
   senala. */
.fz-mov-categories.is-invalid {
    border-radius: 0.875rem;
    outline: 2px solid var(--bs-danger);
    outline-offset: 0.375rem;
}

/* --- «Cómo queda»: la fila, como en la lista -------------------------------- */
.fz-mov-preview {
    padding: 0.875rem 1rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 12%, transparent);
}

.fz-mov-preview-day {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.125rem 0.75rem;
    margin: 0 0 0.625rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.fz-mov-preview-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

.fz-mov-preview-tile {
    display: inline-flex;
    flex: 0 0 auto;
}

.fz-mov-preview-text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-width: 0;
}

.fz-mov-preview-title {
    overflow: hidden;
    font-weight: 600;
    color: var(--bs-emphasis-color);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-mov-preview-sub,
.fz-mov-preview-meta {
    overflow: hidden;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* El importe con su signo, que ya pone el servidor; el color sigue al sentido
   (`data-state`), como `movement-out` y `movement-in` en la lista. */
.fz-mov-preview-amount {
    flex: 0 0 auto;
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--bs-body-color);
    white-space: nowrap;
}

.fz-mov-preview-amount[data-state='out'] {
    color: var(--fz-money-out);
}

.fz-mov-preview-amount[data-state='in'] {
    color: var(--fz-money-in);
}

/* --- El saldo de cada cuenta tocada ----------------------------------------- */
.fz-mov-preview-balances {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    margin: 1rem 0 0;
    padding: 0.75rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 28%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
}

.fz-mov-preview-balances > .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

.fz-mov-preview-balances-text {
    flex: 1 1 auto;
    min-width: 0;
}

.fz-mov-preview-balances-title {
    margin: 0 0 0.125rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-mov-preview-balances-note,
.fz-mov-preview-unchanged {
    margin: 0.25rem 0 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* Las dos listas -saldo y cambios- pueden partir la linea: «Efectivo, en soles»
   y «S/ 1,240.00 → S/ 1,255.00» no caben juntos en un telefono. El valor pasa
   entonces a su propia linea, a la derecha. */
.fz-mov-preview-lines > div {
    flex-wrap: wrap;
    row-gap: 0;
}

.fz-mov-preview-lines dd {
    margin-left: auto;
    text-align: end;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* --- El reparto, en solo lectura -------------------------------------------- */
.fz-mov-split-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 10%, transparent);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-mov-split-note .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

.fz-mov-split-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: 0.75rem 1.5rem;
    margin: 0 0 1rem;
}

.fz-mov-split-facts dt {
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-mov-split-facts dd {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin: 0;
    font-weight: 600;
    color: var(--bs-emphasis-color);
    overflow-wrap: anywhere;
}

.fz-mov-split-facts dd .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

.fz-mov-split-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-mov-split-list li {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding-block: 0.5rem;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 18%, var(--bs-border-color));
}

.fz-mov-split-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
}

.fz-mov-split-amount {
    flex: 0 0 auto;
    font-weight: 600;
    white-space: nowrap;
}

/* --- Eliminar: abrir y confirmar, sin JavaScript ------------------------------
   El `summary` es el boton que abre; dentro, el aviso y el que borra. */
/* A la derecha, encima de la confirmacion que abre. `display: flex` va en el
   `summary` y no en el `details`, que no lo admite en todos los navegadores. */
.fz-mov-delete-confirm > summary,
.fz-grp-delete-confirm > summary {
    display: flex;
    width: fit-content;
    margin-left: auto;
    list-style: none;
}

.fz-mov-delete-confirm > summary::-webkit-details-marker,
.fz-grp-delete-confirm > summary::-webkit-details-marker {
    display: none;
}

.fz-mov-delete-panel,
.fz-grp-delete-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem 1rem;
    margin-top: 0.75rem;
}

.fz-mov-delete-warning,
.fz-grp-delete-warning {
    margin: 0;
    font-size: 0.875rem;
    color: var(--fz-state-over-text);
}

@media (max-width: 575.98px) {
    .fz-mov-delete-confirm,
    .fz-grp-delete-confirm {
        flex: 1 1 100%;
    }

    .fz-mov-delete-confirm > summary,
    .fz-mov-delete-panel .btn,
    .fz-grp-delete-confirm > summary,
    .fz-grp-delete-panel .btn {
        width: 100%;
    }
}

/* ===========================================================================
   ALTA DE CATEGORÍA EN TARJETAS  (ADR 0114)
   ===========================================================================

   /categories/new con las piezas de las demas altas (ADR 0096-0111): cabecera
   ilustrada, «Datos de la categoría» junto a «Cómo se ve» desde 1200 px,
   «Icono» a lo ancho y «Visibilidad» a lo ancho solo en un espacio compartido.
   Por debajo de 1200, una columna en el orden del DOM.

   El color elegido pinta la vista previa y la rejilla de iconos sin JavaScript:
   `:has()` sobre el radio marcado deja el tono en dos variables de la pagina.
   `--fz-pick-tone` es el tono del tema, para un trazo sobre la superficie;
   `--fz-pick-surface`, la superficie oscura del mismo color, para un fondo con
   texto blanco encima (`ColorToken::strokeClass()` y `surfaceClass()`).
   =========================================================================== */

.fz-cat-form {
    --fz-pick-tone: var(--fz-cat-11);
    --fz-pick-surface: var(--fz-cat-surface-11);
}

.fz-cat-form:has(input[name='color'][value='1']:checked) { --fz-pick-tone: var(--fz-cat-1); --fz-pick-surface: var(--fz-cat-surface-1); }
.fz-cat-form:has(input[name='color'][value='2']:checked) { --fz-pick-tone: var(--fz-cat-2); --fz-pick-surface: var(--fz-cat-surface-2); }
.fz-cat-form:has(input[name='color'][value='3']:checked) { --fz-pick-tone: var(--fz-cat-3); --fz-pick-surface: var(--fz-cat-surface-3); }
.fz-cat-form:has(input[name='color'][value='4']:checked) { --fz-pick-tone: var(--fz-cat-4); --fz-pick-surface: var(--fz-cat-surface-4); }
.fz-cat-form:has(input[name='color'][value='5']:checked) { --fz-pick-tone: var(--fz-cat-5); --fz-pick-surface: var(--fz-cat-surface-5); }
.fz-cat-form:has(input[name='color'][value='6']:checked) { --fz-pick-tone: var(--fz-cat-6); --fz-pick-surface: var(--fz-cat-surface-6); }
.fz-cat-form:has(input[name='color'][value='7']:checked) { --fz-pick-tone: var(--fz-cat-7); --fz-pick-surface: var(--fz-cat-surface-7); }
.fz-cat-form:has(input[name='color'][value='8']:checked) { --fz-pick-tone: var(--fz-cat-8); --fz-pick-surface: var(--fz-cat-surface-8); }
.fz-cat-form:has(input[name='color'][value='9']:checked) { --fz-pick-tone: var(--fz-cat-9); --fz-pick-surface: var(--fz-cat-surface-9); }
.fz-cat-form:has(input[name='color'][value='10']:checked) { --fz-pick-tone: var(--fz-cat-10); --fz-pick-surface: var(--fz-cat-surface-10); }
.fz-cat-form:has(input[name='color'][value='11']:checked) { --fz-pick-tone: var(--fz-cat-11); --fz-pick-surface: var(--fz-cat-surface-11); }
.fz-cat-form:has(input[name='color'][value='12']:checked) { --fz-pick-tone: var(--fz-cat-12); --fz-pick-surface: var(--fz-cat-surface-12); }

/* --- Ninguna tarjeta con el pie vacio ----------------------------------------
   Como en el alta de cuenta (ADR 0111): dos tarjetas de una fila miden lo que la
   mas alta, y lo que sobra va antes del ultimo bloque de cada una -el grupo, o la
   nota del ingreso, y los colores-, nunca al pie. La separacion minima es el
   `gap`, que el `auto` no se come. */
#cat-info .fz-fcard-body,
#cat-look .fz-fcard-body {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

#cat-info [data-group-field],
#cat-info .fz-cat-income-note {
    margin-top: auto;
}

/* En «Cómo se ve» lo que sobra no queda en blanco entre la vista previa y los
   colores: lo toma el escenario de la vista previa, con las dos muestras al
   centro. Los colores quedan al pie, a la altura del grupo de al lado. */
#cat-look .fz-cat-preview,
#cat-look .fz-cat-preview-stage {
    flex: 1 1 auto;
}

/* `!important` porque `mb-3` es una utilidad de Bootstrap, que lo lleva. */
#cat-look fieldset.mb-3,
#cat-icon-card fieldset.mb-3,
#cat-who .fz-choices.mb-3 {
    margin-bottom: 0 !important;
}

/* --- Datos de la categoria ----------------------------------------------------- */
.fz-cat-kinds .fz-choice,
.fz-cat-group-pick .fz-choice {
    min-width: 0;
}

.fz-cat-lock,
.fz-cat-hint {
    margin: 0.5rem 0 0;
}

/* Cada grupo en el tono de su bloque de la captura (ADR 0068): el icono siempre,
   y entera la elegida. «Sin grupo» va en gris, como «Otras». La elegida se
   reconoce tambien por el borde doble y la marca de la esquina. */
.fz-cat-group-pick .fz-choice-icon {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 16%, var(--fz-surface-sunken));
    color: var(--fz-kpi-tone);
}

.fz-cat-group-pick .fz-choice:hover {
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 55%, var(--bs-border-color));
}

.fz-cat-group-pick .fz-choice:has(.fz-choice-input:checked) {
    border-color: var(--fz-kpi-tone);
    background-image: linear-gradient(135deg, color-mix(in srgb, var(--fz-kpi-tone) 20%, transparent),
        color-mix(in srgb, var(--fz-kpi-tone) 5%, transparent));
    box-shadow: 0 0 0 1px var(--fz-kpi-tone), 0 12px 28px -18px var(--fz-kpi-tone);
}

.fz-cat-group-pick .fz-choice:has(.fz-choice-input:checked) .fz-choice-icon {
    background-color: var(--fz-kpi-tone);
    background-image: none;
    color: var(--fz-surface);
    box-shadow: 0 0 18px -4px var(--fz-kpi-tone);
}

.fz-cat-group-pick .fz-choice-check {
    background-color: var(--fz-kpi-tone);
    color: var(--fz-surface);
}

/* Solo un gasto tiene grupo: con ingreso se pliega, y en su sitio sale la nota
   que dice por que. Sin `:has()` se ve el grupo y no la nota, y el servidor
   descarta el grupo de un ingreso. */
.fz-cat-income-note {
    display: none;
}

.fz-cat-form:has(#cat-kind-income:checked) .fz-cat-income-note,
.fz-cat-income-note.is-fixed {
    display: flex;
}

.fz-cat-form:has(#cat-kind-income:checked) :is([data-group-field], .fz-cat-preview-group) {
    display: none;
}

/* --- Como se ve: la vista previa ------------------------------------------------
   Los dos sitios donde se busca una categoria, uno junto al otro: la baldosa de
   la captura y la fila de una lista. */
.fz-cat-preview {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.fz-cat-preview-label {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

/* Una rejilla de dos filas -los rotulos arriba y las muestras abajo- para que las
   dos muestras midan lo mismo aunque el nombre parta en varias lineas, centrada
   cuando el escenario crece. */
.fz-cat-preview-stage {
    display: grid;
    grid-template-rows: auto auto;
    grid-template-columns: 6.5rem minmax(0, 1fr);
    grid-auto-flow: column;
    align-content: center;
    gap: 0.375rem 1rem;
    padding: 0.875rem;
    border: 1px dashed color-mix(in srgb, var(--fz-kpi-tone) 40%, var(--bs-border-color));
    border-radius: 0.875rem;
    background-color: var(--fz-surface-sunken);
}

/* Cada muestra con su rotulo solo agrupa el marcado: sus piezas van a la rejilla. */
.fz-cat-preview-spot {
    display: contents;
}

.fz-cat-preview-caption {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* La baldosa de la captura tal cual sale ahi (`.fz-cat-group .cat-tile`): el
   icono en el color elegido y el nombre debajo. */
.fz-cat-preview-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--fz-space-1);
    min-width: 0;
    min-height: 5.25rem;
    padding: var(--fz-space-2) 0.25rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface);
    text-align: center;
}

.fz-cat-preview-glyph {
    display: inline-flex;
    color: var(--fz-pick-tone);
}

.fz-cat-preview-tile .cat-icon {
    width: 1.75rem;
    height: 1.75rem;
}

.fz-cat-preview-tile .cat-name {
    font-size: 0.8125rem;
    overflow-wrap: anywhere;
}

/* La fila de una lista: la baldosa solida (ADR 0053) y el nombre con su tipo y
   su grupo, que es donde caera en la captura. */
.fz-cat-preview-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
    padding: 0.75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background-color: var(--fz-surface);
}

.fz-cat-preview-badge {
    display: inline-flex;
    flex: 0 0 auto;
}

.fz-cat-preview-badge .fz-tile {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 0.75rem;
    background-color: var(--fz-pick-surface);
    box-shadow: 0 0 18px -6px var(--fz-pick-tone);
}

.fz-cat-preview-badge .fz-tile-icon {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-cat-preview-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.fz-cat-preview-name {
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-cat-preview-meta {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* Sin nombre todavia: el rotulo de ejemplo, en cursiva y en gris. */
.fz-cat-preview .is-empty {
    font-style: italic;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

@media (max-width: 575.98px) {
    .fz-cat-preview-stage {
        grid-template-columns: 5.75rem minmax(0, 1fr);
        gap: 0.375rem 0.625rem;
        padding: 0.625rem;
    }

    .fz-cat-preview-row {
        gap: 0.625rem;
        padding: 0.625rem;
    }
}

/* Los doce colores en dos filas de seis, y en tres de cuatro en el telefono,
   como en el alta de cuenta. */
#cat-look .cat-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (min-width: 576px) {
    #cat-look .cat-grid {
        grid-template-columns: repeat(6, minmax(0, 1fr));
    }
}

/* --- Icono: la rejilla de la captura, en el color elegido -------------------------
   Las tallas de las baldosas de la captura (`.fz-cat-group .cat-tile`): asi se
   elige el icono viendolo como se vera al registrar. La elegida se ve como en las
   listas: la superficie solida del color, con el glifo y el nombre en blanco. */
#cat-icon-card .cat-grid {
    grid-template-columns: repeat(auto-fill, minmax(6.25rem, 1fr));
}

#cat-icon-card .cat-tile {
    min-height: 5.25rem;
}

#cat-icon-card .cat-icon {
    width: 1.75rem;
    height: 1.75rem;
    color: var(--fz-pick-tone);
}

#cat-icon-card .cat-name {
    overflow-wrap: anywhere;
}

#cat-icon-card .cat-input:checked + .cat-tile {
    border-color: var(--fz-pick-tone);
    background-color: var(--fz-pick-surface);
    box-shadow: 0 0 18px -4px var(--fz-pick-tone);
}

#cat-icon-card .cat-input:checked + .cat-tile :is(.cat-icon, .cat-name) {
    color: var(--fz-on-accent);
}

/* --- Los colores: cada muestra en su tono (ADR 0114) ------------------------------
   Para todos los selectores de color -categoria y cuenta-: fondo, borde e icono
   del tono de la muestra (`fz-kpi-tone-N` en la etiqueta). La elegida lleva el
   borde doble del tono, el nombre en negrita y la marca de la esquina. */
.cat-swatch {
    position: relative;
    border-color: color-mix(in srgb, var(--fz-kpi-tone) 45%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 12%, var(--fz-surface-sunken));
}

.cat-swatch:hover {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 20%, var(--fz-surface-sunken));
}

.cat-input:checked + .cat-swatch {
    border-color: var(--fz-kpi-tone);
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 24%, var(--fz-surface-sunken));
    box-shadow: 0 0 18px -6px var(--fz-kpi-tone);
}

.cat-swatch-check {
    position: absolute;
    top: 0.3125rem;
    right: 0.3125rem;
    display: none;
    align-items: center;
    justify-content: center;
    width: 1.125rem;
    height: 1.125rem;
    border-radius: 50%;
    background-color: var(--fz-kpi-tone);
    color: var(--fz-surface);
}

.cat-swatch-check .icon {
    width: 0.75rem;
    height: 0.75rem;
    stroke-width: 2.75;
}

.cat-input:checked + .cat-swatch .cat-swatch-check {
    display: inline-flex;
}

/* ===========================================================================
   GRUPOS PROPIOS  (ADR 0115)
   ===========================================================================

   Los grupos del espacio: en baldosas en el alta y la edicion de una categoria,
   con «+ Nuevo grupo» al final; con «Editar» en su seccion de /categories; y
   sus propias paginas de alta y edicion, en las tarjetas de una categoria. */

/* Las baldosas de los grupos bajan de fila: hay tantas como grupos tenga el
   espacio, mas «Sin grupo» y «+ Nuevo grupo». */
.fz-cat-group-pick .fz-choices-grid {
    grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
    grid-auto-flow: row;
}

/* En el telefono, dos por fila: con tres, «Vivienda y servicios» se partia en tres
   lineas. */
@media (max-width: 575.98px) {
    .fz-cat-group-pick .fz-choices-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* «+ Nuevo grupo»: el borde discontinuo dice que todavia no existe. */
.fz-cat-group-new {
    border-style: dashed;
}

/* El nombre del grupo nuevo, solo con esa opcion elegida. Sin `:has()` se ve
   siempre: el servidor solo lo lee con «+ Nuevo grupo». */
.fz-cat-group-name {
    margin-top: 0.75rem;
}

@supports selector(:has(*)) {
    .fz-cat-group-name {
        display: none;
    }

    .fz-cat-form:has(#cat-grp-new:checked) .fz-cat-group-name {
        display: block;
    }
}

/* --- /categories: «Editar» en la cabecera de cada grupo --------------------------- */
.fz-cat-actions-top {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.fz-cat-actions-top .btn {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

.fz-cat-actions-top .btn .icon,
.fz-cat-section-edit .icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-cat-section-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding-bottom: var(--fz-space-2);
    border-bottom: 1px solid var(--bs-border-color);
}

.fz-cat-section-bar .fz-cat-section-head {
    flex: 1 1 auto;
    min-width: 0;
    padding-bottom: 0;
    border-bottom: 0;
}

.fz-cat-section-edit {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.375rem;
}

.fz-cat-section-empty {
    margin: var(--fz-space-2) 0 0;
    font-size: 0.9375rem;
    color: var(--bs-secondary-color);
}

/* --- Las paginas de un grupo: una columna, mas estrecha ------------------------------ */
.fz-grp-form {
    max-width: 56rem;
}

/* Una columna tambien desde 1200 px: con dos, «Datos del grupo» -un nombre y sus
   categorias- quedaba con medio cuerpo vacio junto a los colores. */
.fz-grp-form .fz-form-grid {
    grid-template-columns: minmax(0, 1fr);
}

/* La vista previa: el bloque de la captura con su cabecera en el color elegido,
   y debajo todas sus categorias en las baldosas de la captura
   (`.fz-cat-preview-tile`). En el alta, solo la cabecera. */
.fz-grp-preview {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    border: 1px solid color-mix(in srgb, var(--fz-pick-tone) 45%, var(--bs-border-color));
    border-radius: 0.875rem;
    background-color: var(--fz-surface-sunken);
    background-image: linear-gradient(160deg, color-mix(in srgb, var(--fz-pick-tone) 12%, transparent) 0%, transparent 75%);
}

.fz-grp-preview-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-grp-preview-head .is-empty {
    font-style: italic;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-grp-preview-icon {
    display: inline-flex;
    color: var(--fz-pick-tone);
}

.fz-grp-preview-icon .icon {
    width: 1.5rem;
    height: 1.5rem;
}

/* La rejilla de la captura (`.fz-cat-group .cat-grid`): de 6.25rem como minimo
   y estiradas a lo ancho. A 6.25rem justos «Entretenimiento» se partia en dos
   lineas; estiradas, no. En el telefono quedan dos por fila. */
.fz-grp-preview-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(6.25rem, 1fr));
    gap: var(--fz-space-2);
}

/* Las categorias que junta, en pildoras. */
.fz-grp-members-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-grp-members-list li {
    padding: 0.25rem 0.75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    background-color: var(--fz-surface);
    font-size: 0.875rem;
}

/* ===========================================================================
   IMAGEN PROPIA DE UNA CATEGORIA  (ADR 0116)
   ===========================================================================

   La imagen sale en lugar del icono: llena la baldosa solida de las listas, con
   el color de la categoria en su borde, y ocupa el sitio del glifo en la
   baldosa de la captura. Se sube arriba de la rejilla de iconos, con la misma
   zona de subida que el logo de una cuenta (`fz-upload-*`). */

/* La baldosa de las listas con imagen (`View::tile()`): la imagen la llena, y
   el color de la categoria queda en el borde, que es lo que la distingue de un
   logo suelto. */
.fz-tile-image {
    overflow: hidden;
    border: 2px solid var(--fz-surface-tone, var(--bs-border-color));
    background-color: #ffffff;
}

.fz-tile-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* En la baldosa de la captura, en el sitio del glifo (`View::glyph()`). */
.cat-image {
    border-radius: 0.375rem;
    background-color: #ffffff;
    object-fit: cover;
}

/* La fila de subida, arriba de la rejilla: el cuadro del tamaño de una baldosa
   y lo que dice al lado. */
.fz-cat-image {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.25rem;
    padding-bottom: 1.25rem;
    border-bottom: 1px dashed color-mix(in srgb, var(--fz-kpi-tone) 30%, var(--bs-border-color));
}

.fz-cat-image-box {
    flex: 0 0 6.25rem;
}

.fz-cat-image-text {
    flex: 1 1 auto;
    min-width: 0;
}

.fz-cat-image-text .form-label {
    display: block;
    margin-bottom: 0;
}

.fz-cat-image-text .fz-cat-hint {
    margin-top: 0.25rem;
}

.fz-cat-image-remove {
    margin-top: 0.5rem;
}

/* «Quitar la imagen» marcado: la imagen se apaga hasta guardar. */
.fz-cat-form:has([data-image-remove]:checked) .fz-upload-img {
    opacity: 0.35;
    filter: grayscale(1);
}

/* La vista previa con imagen: el borde sigue al color elegido. */
.fz-cat-preview-badge .fz-tile-image {
    border-color: var(--fz-pick-tone);
}

.fz-cat-preview-tile .cat-image {
    width: 1.75rem;
    height: 1.75rem;
}

/* ===========================================================================
   ALTA Y EDICION DE UNA RECURRENTE, EN TARJETAS  (ADR 0117)
   ===========================================================================

   /recurring/new y /recurring/{id}/edit con las piezas de las altas en tarjetas
   (`fz-form-*`, `fz-fcard`, `fz-field`, `fz-choices-tiles`), la rejilla de
   baldosas de la captura y la fila de «Cómo queda» de la edicion de un
   movimiento (`fz-mov-preview-*`, ADR 0113). Aqui solo lo que es de la
   recurrente: donde va cada tarjeta, el ciclo en una pieza, el chip junto al
   importe y el aviso de «Toca pagar». */

/* Desde 1200 px, las tarjetas a la izquierda y «Cómo queda» a la derecha en toda
   la altura, pegada al desplazarse (`fz-fcard-sticky`): la de las categorias es
   alta y la vista previa tiene que seguir a la vista mientras se elige. Por
   debajo, una columna en el orden del HTML, con la vista previa justo antes de
   guardar. */
@media (min-width: 1200px) {
    .fz-rec-form-grid {
        grid-template-areas:
            'what preview'
            'amount preview'
            'when preview'
            'category preview';
        grid-template-rows: auto auto auto 1fr;
    }

    .fz-rec-form-what {
        grid-area: what;
    }

    .fz-rec-form-amount {
        grid-area: amount;
    }

    .fz-rec-form-category {
        grid-area: category;
    }

    .fz-rec-form-when {
        grid-area: when;
    }

    .fz-rec-form-preview {
        grid-area: preview;
    }
}

/* El tipo en dos baldosas, como el de una categoria (ADR 0114), y debajo el
   nombre y la nota. */
.fz-rec-kinds {
    margin-bottom: 1rem;
}

.fz-rec-kinds .fz-choice {
    min-width: 0;
}

/* «No se puede cambiar después», con su candado: bajo el tipo y bajo la cuenta. */
.fz-rec-lock {
    display: flex;
    align-items: flex-start;
    gap: 0.375rem;
    margin: 0.5rem 0 0;
}

/* Arriba y no al centro: la frase parte en dos lineas en el telefono. */
.fz-rec-lock .icon {
    flex: 0 0 auto;
    width: 0.9375rem;
    height: 0.9375rem;
    margin-top: 0.125rem;
}

/* «Cada [2] [Semanas]»: el numero estrecho, el desplegable con el resto. */
.fz-rec-form .fz-rec-interval {
    flex: 0 0 4.5rem;
    width: 4.5rem;
    text-align: center;
}

/* --- «Cómo queda» --------------------------------------------------------- */

/* La linea de la fila puede ser larga («Servicios · Cada 2 semanas · Toca el
   27/10/26»): aqui parte en dos en vez de cortarse, que es lo que se esta
   comprobando. */
.fz-rec-preview-meta {
    white-space: normal;
}

/* El importe y, debajo, el chip del ciclo, como al final de la fila de la lista. */
.fz-rec-preview-end {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.25rem;
}

/* Cuando sale en «Toca pagar»: el recuadro de lo que falta por pagar de un tope
   (`fz-bud-estimate-committed`, ADR 0102), en ambar si ya sale pendiente y en
   coral si no saldra nunca. */
.fz-rec-preview-status {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    margin: 1rem 0 0;
    padding: 0.75rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 28%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
}

.fz-rec-preview-status > .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

.fz-rec-preview-status p {
    margin: 0;
    color: var(--bs-body-color);
}

.fz-rec-preview-status[data-state='due'] {
    border-color: color-mix(in srgb, var(--fz-state-warn-text) 45%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
}

.fz-rec-preview-status[data-state='due'] > .icon {
    color: var(--fz-state-warn-text);
}

.fz-rec-preview-status[data-state='warn'] {
    border-color: color-mix(in srgb, var(--fz-state-over-text) 45%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-state-over-text) 12%, transparent);
}

.fz-rec-preview-status[data-state='warn'] > .icon {
    color: var(--fz-state-over-text);
}

.fz-rec-preview-status-text {
    min-width: 0;
}

/* Al editar: desde donde se vuelve a contar si el cambio mueve el proximo cobro. */
.fz-rec-preview-status .fz-rec-preview-reset {
    margin-top: 0.375rem;
    font-size: 0.875rem;
    font-weight: 600;
}

.fz-rec-preview-none {
    margin: 0.25rem 0 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* Lo que suma en doce meses, en el recuadro del total de una cuota
   (`fz-estimate-total`). */
.fz-rec-preview-year {
    margin-top: 0.75rem;
}

/* Las dos notas del pie -el fin y la moneda- van juntas. */
.fz-rec-form-preview .fz-estimate-note + .fz-estimate-note {
    margin-top: 0.5rem;
}

/* ===========================================================================
   IMPORTAR MOVIMIENTOS, EN TARJETAS  (ADR 0119)
   ===========================================================================

   Las tres pantallas de /import con las piezas de las altas en tarjetas
   (`fz-form-*`, `fz-fcard`, `fz-field`, `fz-steps`, `fz-upload-*`,
   `fz-estimate-*`). Aqui solo lo que es de la importacion: donde va cada
   tarjeta, la zona de subida a lo ancho, los lotes con su «Deshacer», la tabla
   del archivo con el uso de cada columna, las filas de «Cómo se lee» y las de la
   revision. Por debajo de 1200 px, una columna en el orden del HTML. */

/* --- Subir: la cuenta y el archivo a la izquierda, las recientes y las reglas
   (ADR 0121) a la derecha. El boton va en la rejilla para quedar, en el
   telefono, antes de las recientes. */
.fz-imp-start-grid {
    grid-template-areas:
        'account'
        'file'
        'actions'
        'recent'
        'rules';
}

.fz-imp-start-account {
    grid-area: account;
}

.fz-imp-start-file {
    grid-area: file;
}

.fz-imp-start-recent {
    grid-area: recent;
}

.fz-imp-start-rules {
    grid-area: rules;
}

.fz-imp-start-actions {
    grid-area: actions;
}

@media (min-width: 1200px) {
    .fz-imp-start-grid {
        grid-template-areas:
            'account recent'
            'file rules'
            'actions actions';
    }
}

/* Dentro de la rejilla el hueco ya lo pone ella; con un solo boton, a la derecha. */
.fz-imp-actions {
    justify-content: flex-end;
    margin-top: 0;
}

/* --- La zona de subida, a lo ancho y baja: el cuadro del logo de una cuenta
   (`fz-upload-drop`, ADR 0112) sin su proporcion cuadrada. */
.fz-imp-drop {
    aspect-ratio: auto;
    min-height: 9rem;
    padding: 1rem;
}

.fz-imp-drop-empty,
.fz-imp-drop-chosen {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
    max-width: 100%;
    font-size: 0.875rem;
    line-height: 1.35;
    color: var(--bs-secondary-color);
}

.fz-imp-drop-empty .fz-upload-cta {
    font-size: 1rem;
}

.fz-imp-drop-chosen[hidden],
.fz-imp-drop-empty[hidden] {
    display: none;
}

.fz-imp-drop-chosen > .icon {
    width: 2rem;
    height: 2rem;
    margin-bottom: 0.25rem;
    color: var(--fz-kpi-tone);
}

/* Un nombre de archivo largo parte la linea en vez de ensanchar la tarjeta. */
.fz-imp-drop-name {
    max-width: 100%;
    font-weight: 600;
    color: var(--bs-emphasis-color);
    overflow-wrap: anywhere;
}

.fz-imp-drop.is-chosen {
    border-style: solid;
}

.fz-imp-drop-sub {
    font-size: 0.8125rem;
}

/* Lo que hay que saber antes de subir, una regla por linea con su icono. */
.fz-imp-rules {
    display: grid;
    gap: 0.625rem;
    margin: 1.25rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-imp-rules li {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
}

.fz-imp-rules .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

/* --- Las importaciones recientes, con «Deshacer» en dos toques ---------------- */
.fz-imp-batches {
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-imp-batch {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    padding: 0.75rem 0;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 18%, var(--bs-border-color));
}

.fz-imp-batch:first-child {
    padding-top: 0;
    border-top: 0;
}

.fz-imp-batch-text {
    display: flex;
    flex: 1 1 10rem;
    flex-direction: column;
    min-width: 0;
}

.fz-imp-batch-name {
    font-weight: 600;
    color: var(--bs-emphasis-color);
    overflow-wrap: anywhere;
}

.fz-imp-batch-meta {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* El `summary` es el boton que abre; abierto, la confirmacion ocupa la linea
   entera debajo del archivo. `display: flex` en el `summary` y no en el
   `details`, que no lo admite en todos los navegadores. */
.fz-imp-undo {
    flex: 0 0 auto;
}

.fz-imp-undo[open] {
    flex-basis: 100%;
}

.fz-imp-undo > summary {
    display: flex;
    width: fit-content;
    margin-left: auto;
    list-style: none;
}

.fz-imp-undo > summary::-webkit-details-marker {
    display: none;
}

.fz-imp-undo-open,
.fz-imp-undo-confirm {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: var(--fz-control-height);
    border-radius: 0.75rem;
    font-weight: 600;
}

.fz-imp-undo-open .icon,
.fz-imp-undo-confirm .icon {
    width: 1.125rem;
    height: 1.125rem;
}

.fz-imp-undo-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem 1rem;
    margin-top: 0.75rem;
    padding: 0.75rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-state-over-text) 35%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-state-over-text) 6%, var(--fz-surface));
}

.fz-imp-undo-warning {
    flex: 1 1 12rem;
    margin: 0;
    font-size: 0.875rem;
    color: var(--fz-state-over-text);
}

@media (max-width: 575.98px) {
    .fz-imp-undo-confirm {
        flex: 1 1 100%;
    }
}

/* --- Columnas: el archivo a lo ancho, lo que se elige a la izquierda y «Cómo se
   lee» a la derecha en toda su altura, pegada al desplazarse. */
@media (min-width: 1200px) {
    .fz-imp-map-grid {
        grid-template-areas:
            'file file'
            'columns reading'
            'defaults reading';
        grid-template-rows: auto auto 1fr;
    }

    .fz-imp-map-file {
        grid-area: file;
    }

    .fz-imp-map-columns {
        grid-area: columns;
    }

    .fz-imp-map-defaults {
        grid-area: defaults;
    }

    .fz-imp-map-reading {
        grid-area: reading;
    }
}

/* El archivo, sus filas y adonde va, en pildoras. */
.fz-imp-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0;
    list-style: none;
}

.fz-imp-facts li {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-width: 0;
    max-width: 100%;
    padding: 0.25rem 0.75rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 30%, var(--bs-border-color));
    border-radius: 999px;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, var(--fz-surface));
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-imp-facts .icon {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    color: var(--fz-kpi-tone);
}

.fz-imp-fact-file span {
    font-weight: 600;
    overflow-wrap: anywhere;
}

/* La tabla de las primeras filas: tal cual vienen, sin alinear cifras -todavia
   no se sabe cual es la del importe-. Con muchas columnas se desplaza ella, no
   la pagina. */
.fz-imp-sample {
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
    border-radius: 0.75rem;
}

.fz-imp-sample:focus-visible {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-imp-sample-table {
    --bs-table-bg: transparent;
    margin: 0;
    font-size: 0.875rem;
}

.fz-imp-sample-table th,
.fz-imp-sample-table td {
    max-width: 16rem;
    padding: 0.5rem 0.75rem;
    overflow: hidden;
    text-align: start;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-imp-sample-table th {
    vertical-align: top;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-imp-sample-table tbody tr:last-child td {
    border-bottom: 0;
}

.fz-imp-col-name {
    display: block;
}

/* Para que se usa la columna: el rotulo de su desplegable, en su color. */
.fz-imp-col-role {
    display: inline-block;
    margin-top: 0.25rem;
    padding: 0.0625rem 0.5rem;
    border-radius: 999px;
    background-color: var(--fz-imp-role);
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--fz-surface);
}

.fz-imp-col-role[hidden] {
    display: none;
}

.fz-imp-sample-table [data-role='date'] {
    --fz-imp-role: var(--fz-cat-2);
}

.fz-imp-sample-table [data-role='amount'] {
    --fz-imp-role: var(--fz-cat-6);
}

.fz-imp-sample-table [data-role='note'] {
    --fz-imp-role: var(--fz-cat-3);
}

.fz-imp-sample-table [data-role='category'] {
    --fz-imp-role: var(--fz-cat-1);
}

.fz-imp-sample-table [data-role] {
    background-color: color-mix(in srgb, var(--fz-imp-role) 12%, transparent);
}

.fz-imp-sample-table th[data-role] {
    box-shadow: inset 0 3px 0 var(--fz-imp-role);
}

/* --- «Cómo se lee»: las filas como se importaran ------------------------------ */
.fz-imp-read {
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-imp-read-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 0;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 18%, var(--bs-border-color));
}

.fz-imp-read-row:first-of-type {
    padding-top: 0;
    border-top: 0;
}

/* El sentido que le da el signo: la flecha de gasto o de ingreso, o el aviso. */
.fz-imp-read-kind {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background-color: color-mix(in srgb, var(--fz-imp-kind, var(--bs-secondary-color)) 14%, transparent);
    color: var(--fz-imp-kind, var(--bs-secondary-color));
}

.fz-imp-read-kind .icon {
    display: none;
    width: 1.25rem;
    height: 1.25rem;
}

.fz-imp-read-kind[data-state='out'] {
    --fz-imp-kind: var(--fz-money-out);
}

.fz-imp-read-kind[data-state='in'] {
    --fz-imp-kind: var(--fz-money-in);
}

.fz-imp-read-kind[data-state=''] {
    --fz-imp-kind: var(--fz-state-over-text);
}

.fz-imp-read-kind[data-state='out'] .fz-imp-kind-out,
.fz-imp-read-kind[data-state='in'] .fz-imp-kind-in,
.fz-imp-read-kind[data-state=''] .fz-imp-kind-error {
    display: block;
}

.fz-imp-read-text,
.fz-imp-row-text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-width: 0;
}

.fz-imp-read-title,
.fz-imp-row-title {
    overflow: hidden;
    font-weight: 600;
    color: var(--bs-emphasis-color);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fz-imp-read-meta,
.fz-imp-row-meta {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-imp-read-end,
.fz-imp-row-end {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.25rem;
}

/* Con error no hay importe: el motivo, en la linea de abajo, va en coral. */
.fz-imp-read-row[data-state='error'] .fz-imp-read-meta,
.fz-imp-row[data-state='error'] .fz-imp-row-meta {
    color: var(--fz-state-over-text);
}

/* El importe con su signo, que ya pone el servidor; el color sigue al sentido. */
.fz-imp-amount {
    font-weight: 700;
    color: var(--bs-body-color);
    white-space: nowrap;
}

.fz-imp-amount[data-state='out'] {
    color: var(--fz-money-out);
}

.fz-imp-amount[data-state='in'] {
    color: var(--fz-money-in);
}

/* El chip del estado, de los colores de `fz-chip-ok/warn/over` pero por
   `data-state`: en «Cómo se lee» lo pone `form-estimate.js`. */
.fz-imp-status[data-state='ok'] {
    border-color: var(--bs-success-border-subtle);
    background-color: var(--bs-success-bg-subtle);
    color: var(--fz-state-ok-text);
}

.fz-imp-status[data-state='duplicate'] {
    border-color: var(--bs-warning-border-subtle);
    background-color: var(--bs-warning-bg-subtle);
    color: var(--fz-state-warn-text);
}

.fz-imp-status[data-state='error'] {
    border-color: var(--bs-danger-border-subtle);
    background-color: var(--bs-danger-bg-subtle);
    color: var(--fz-state-over-text);
}

.fz-imp-note-next {
    margin-top: 0.5rem;
}

/* --- Revisar: la categoria por descripcion (ADR 0121) y las filas a la izquierda,
   «Qué se importa» a la derecha en toda su altura. Por debajo de 1200 px, una
   columna en el orden del HTML. */
@media (min-width: 1200px) {
    .fz-imp-review-grid {
        grid-template-areas:
            'groups summary'
            'list summary';
        grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr);
        grid-template-rows: auto 1fr;
    }

    .fz-imp-review-groups {
        grid-area: groups;
    }

    .fz-imp-review-list {
        grid-area: list;
    }

    .fz-imp-review-summary {
        grid-area: summary;
    }
}

.fz-imp-rows {
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-imp-row + .fz-imp-row {
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 18%, var(--bs-border-color));
}

/* La fila entera es la etiqueta de su casilla: 44 px de alto como minimo. */
.fz-imp-row-main {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: var(--fz-control-height);
    margin: 0;
    padding: 0.625rem 0.5rem;
    border-radius: 0.75rem;
}

label.fz-imp-row-main {
    cursor: pointer;
}

label.fz-imp-row-main:hover {
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 8%, transparent);
}

.fz-imp-row-main:has(.form-check-input:focus-visible) {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-imp-row-check {
    display: inline-flex;
    flex: 0 0 1.25rem;
    justify-content: center;
}

.fz-imp-row-check .form-check-input {
    width: 1.25rem;
    height: 1.25rem;
    margin: 0;
    cursor: pointer;
}

/* Sin marcar, la fila se apaga un poco: lo que no se importa se lee menos. */
.fz-imp-row:has(.form-check-input:not(:checked)) .fz-imp-row-text,
.fz-imp-row:has(.form-check-input:not(:checked)) .fz-imp-amount,
.fz-imp-row:has(.form-check-input:not(:checked)) .fz-tile {
    opacity: 0.6;
}

.fz-imp-row[data-state='duplicate'] .fz-imp-row-main {
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 7%, transparent);
}

.fz-imp-row[data-state='error'] .fz-imp-row-main {
    background-color: color-mix(in srgb, var(--fz-state-over-text) 6%, transparent);
}

.fz-imp-row-alert {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 0.625rem;
    background-color: color-mix(in srgb, var(--fz-state-over-text) 14%, transparent);
    color: var(--fz-state-over-text);
}

.fz-imp-row-alert .icon {
    width: 1.25rem;
    height: 1.25rem;
}

/* En el telefono el titulo parte en dos lineas antes que cortarse a 8 letras. */
@media (max-width: 575.98px) {
    .fz-imp-row-main {
        gap: 0.625rem;
        padding-inline: 0.25rem;
    }

    .fz-imp-row-title,
    .fz-imp-read-title {
        white-space: normal;
        overflow-wrap: anywhere;
    }
}

/* «Qué se importa»: adonde va y cuantas, con un punto del color de su estado. */
.fz-imp-destination {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    max-width: 100%;
    margin: 0 0 1rem;
    padding: 0.375rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 35%, var(--bs-border-color));
    border-radius: 999px;
    background-color: var(--fz-surface);
    font-weight: 600;
    color: var(--bs-emphasis-color);
    overflow-wrap: anywhere;
}

.fz-imp-destination .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-kpi-tone);
}

.fz-imp-counts > div:not(.fz-estimate-total) dt {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.fz-imp-dot {
    flex: 0 0 auto;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background-color: currentcolor;
}

.fz-imp-counts [data-state='ok'] .fz-imp-dot {
    color: var(--fz-state-ok-text);
}

.fz-imp-counts [data-state='duplicate'] .fz-imp-dot {
    color: var(--fz-state-warn-text);
}

.fz-imp-counts [data-state='error'] .fz-imp-dot {
    color: var(--fz-state-over-text);
}

.fz-imp-review-summary .fz-estimate-note + .fz-estimate-note {
    margin-top: 0.5rem;
}

/* --- Lo que propone la pantalla y lo que no ofrece (ADR 0120) ------------------ */

/* «Las columnas que reconocimos ya están elegidas»: arriba de los campos, en el
   tono de su tarjeta, para que se revise antes de seguir. */
.fz-imp-guess-note {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0.625rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 30%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 9%, transparent);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-imp-guess-note .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.0625rem;
    color: var(--fz-kpi-tone);
}

/* Por que faltan cuentas en el desplegable, con su icono arriba: parte en dos
   lineas en el telefono. */
.fz-imp-filter-hint {
    display: flex;
    align-items: flex-start;
    gap: 0.375rem;
    margin: 0.5rem 0 0;
}

.fz-imp-filter-hint .icon {
    flex: 0 0 auto;
    width: 0.9375rem;
    height: 0.9375rem;
    margin-top: 0.125rem;
}

/* --- Duplicados y categorias por descripcion (ADR 0121) ------------------------- */

/* De vuelta de una confirmacion que no se pudo hacer: algo que revisar, no un
   error. */
.fz-imp-notice {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
}

.fz-imp-notice .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.0625rem;
}

/* Ese archivo ya se importo a esta cuenta, arriba de sus pildoras. */
.fz-imp-previous {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0 0 1rem;
    padding: 0.625rem 0.875rem;
    border: 1px solid color-mix(in srgb, var(--fz-state-warn-text) 40%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 10%, transparent);
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-imp-previous .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    margin-top: 0.0625rem;
    color: var(--fz-state-warn-text);
}

/* Con que choca una posible duplicada, debajo de su fecha. */
.fz-imp-row-match {
    display: flex;
    align-items: flex-start;
    gap: 0.375rem;
    margin-top: 0.125rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--fz-state-warn-text);
}

.fz-imp-row-match .icon {
    flex: 0 0 auto;
    width: 0.9375rem;
    height: 0.9375rem;
    margin-top: 0.125rem;
}

.fz-imp-row-tile {
    display: inline-flex;
    flex: 0 0 auto;
}

/* De donde salio la categoria: una pastilla discreta junto a la fecha. Las que
   piden una mirada -por defecto, sugerida- en el color del aviso; la palabra
   siempre dice cual es. */
.fz-imp-source {
    display: inline-block;
    margin-left: 0.25rem;
    padding: 0 0.4375rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

.fz-imp-source:empty {
    display: none;
}

.fz-imp-source[data-source='default'] {
    border-color: color-mix(in srgb, var(--fz-state-warn-text) 45%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 10%, transparent);
    color: var(--fz-state-warn-text);
}

.fz-imp-source[data-source='suggested'] {
    border-color: color-mix(in srgb, var(--fz-brand) 40%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-brand) 10%, transparent);
    color: var(--fz-brand);
}

.fz-imp-source[data-source='rule'],
.fz-imp-source[data-source='chosen'] {
    border-color: color-mix(in srgb, var(--fz-state-ok-text) 40%, var(--bs-border-color));
    background-color: color-mix(in srgb, var(--fz-state-ok-text) 10%, transparent);
    color: var(--fz-state-ok-text);
}

/* «Categoría por descripción»: cada descripcion con su categoria y, si se
   quiere, la regla que la recuerda. */
.fz-imp-groups {
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-imp-group {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.625rem;
    padding: 0.875rem 0;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 18%, var(--bs-border-color));
}

.fz-imp-group:first-child {
    padding-top: 0;
    border-top: 0;
}

@media (min-width: 768px) {
    .fz-imp-group {
        grid-template-columns: minmax(0, 1fr) minmax(0, 15rem);
        align-items: center;
    }

    .fz-imp-group-rule {
        grid-column: 1 / -1;
    }
}

.fz-imp-group-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.fz-imp-group-name {
    font-weight: 600;
    color: var(--bs-emphasis-color);
    overflow-wrap: anywhere;
}

.fz-imp-group-name.is-empty {
    font-style: italic;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.fz-imp-group-meta {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

/* El desplegable no ensancha la rejilla con una categoria de nombre largo. */
.fz-imp-group-pick {
    min-width: 0;
}

/* Compacto: solo el interruptor; su explicacion sale con el texto al encenderlo. */
.fz-imp-remember {
    align-items: center;
    margin: 0;
    padding: 0.5rem 0.875rem;
    min-height: var(--fz-control-height);
}

.fz-imp-remember .fz-switch-track {
    margin-top: 0;
}

.fz-imp-remember .fz-switch-title {
    font-size: 0.9375rem;
}

/* El texto que recordar, solo con «Recordar» encendido. Sin `:has()` se ve
   siempre, y el servidor lo ignora con el interruptor apagado. */
.fz-imp-pattern {
    margin-top: 0.625rem;
}

.fz-imp-group-rule:not(:has(.fz-switch-input:checked)) .fz-imp-pattern {
    display: none;
}

/* --- Las reglas de categoria, en la pagina de subir ---------------------------- */
.fz-imp-rules-empty {
    margin: 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-imp-rule-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.fz-imp-rule {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.625rem 0;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 18%, var(--bs-border-color));
}

.fz-imp-rule:first-child {
    padding-top: 0;
    border-top: 0;
}

.fz-imp-rule-text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 0;
}

.fz-imp-rule-pattern {
    font-weight: 600;
    color: var(--bs-emphasis-color);
    overflow-wrap: anywhere;
}

.fz-imp-rule-category {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.fz-imp-rule-category .fz-tile {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 0.4375rem;
}

.fz-imp-rule-category .fz-tile-icon {
    width: 0.9375rem;
    height: 0.9375rem;
}

/* Una regla hacia una categoria archivada no se aplica: se apaga. */
.fz-imp-rule.is-archived .fz-imp-rule-text {
    opacity: 0.6;
}

.fz-imp-rule-delete {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: var(--fz-control-height);
    height: var(--fz-control-height);
    padding: 0;
    border-radius: 0.75rem;
}

.fz-imp-rule-delete .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* --- Formatos de extracto (ADR 0122) y transferencias (ADR 0123) --------------- */

/* Sin cabecera (el interruptor encendido), las columnas se nombran por su numero y
   la primera fila sale como un movimiento mas; con cabecera, al reves. Sin
   `:has()` se ven las dos cosas, y el servidor lee lo que diga el interruptor. */
.fz-imp-col-numbered,
.fz-imp-first-line {
    display: none;
}

form:has(#imp-no-header:checked) .fz-imp-col-named {
    display: none;
}

form:has(#imp-no-header:checked) .fz-imp-col-numbered {
    display: block;
}

form:has(#imp-no-header:checked) .fz-imp-first-line {
    display: table-row;
}

.fz-imp-no-header {
    margin-top: 1rem;
}

/* Como viene el importe: las dos opciones, cada una con sus desplegables. */
.fz-imp-amount-mode {
    margin: 0;
}

.fz-imp-amount-mode > legend {
    float: none;
    width: auto;
    margin-bottom: 0.5rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-imp-invert {
    margin-top: 0.75rem;
}

/* Los roles nuevos en la tabla del archivo. */
.fz-imp-sample-table [data-role='debit'] {
    --fz-imp-role: var(--fz-money-out);
}

.fz-imp-sample-table [data-role='credit'] {
    --fz-imp-role: var(--fz-money-in);
}

/* Una transferencia no se recuerda como regla: las reglas son de categorias. */
.fz-imp-group:has(option[value^='acc:']:checked) .fz-imp-group-rule {
    display: none;
}

/* --- La categoria que sugiere la nota de una captura (ADR 0124) -------------------- */
.fz-capture-suggest {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 0.375rem;
    margin: 0.375rem 0 0;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.fz-capture-suggest-icon {
    flex: 0 0 auto;
    width: 0.9375rem;
    height: 0.9375rem;
    color: var(--fz-brand);
}

/* «Usar «Comer fuera»»: 44 px de objetivo aunque se lea como un enlace. */
.fz-capture-suggest-use {
    display: inline-flex;
    align-items: center;
    min-height: var(--fz-control-height);
    padding: 0 0.25rem;
    font-size: 0.8125rem;
    font-weight: 600;
}

/* --- Ajustes en tarjetas (ADR 0125) ---------------------------------------------
   La piel de las altas (ADR 0096-0102) sobre los formularios de /settings, cada
   uno con su boton al pie porque se guardan por separado. Desde 1200 px, lo de
   cada persona en filas 7:5 -el perfil con «Así se verá», la contrasena con la
   apariencia- que se estiran a la mas alta, con el boton al pie. El espacio, el
   acceso de soporte y la zona de peligro van debajo, a lo ancho. */

/* Personas y suscripcion: enlaces con forma de opcion, no formularios. */
.fz-set-links {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

@media (min-width: 768px) {
    .fz-set-links {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.fz-set-link {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    min-height: 4.5rem;
    padding: 0.875rem 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.875rem;
    background-color: var(--fz-surface);
    box-shadow: var(--fz-elev-1);
    color: var(--bs-body-color);
    text-decoration: none;
}

[data-bs-theme='dark'] .fz-set-link {
    background-image: linear-gradient(180deg, rgba(var(--fz-brand-rgb), 0.1), transparent);
}

.fz-set-link:hover {
    border-color: color-mix(in srgb, var(--fz-brand) 45%, var(--bs-border-color));
    color: var(--bs-body-color);
}

.fz-set-link:focus-visible {
    outline: 2px solid var(--fz-brand);
    outline-offset: 2px;
}

.fz-set-link-icon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background-color: rgba(var(--fz-brand-rgb), 0.14);
    color: var(--fz-brand);
}

.fz-set-link-icon .icon {
    width: 1.375rem;
    height: 1.375rem;
}

.fz-set-link-text {
    flex: 1 1 auto;
    min-width: 0;
}

.fz-set-link-title {
    display: block;
    font-weight: 600;
    color: var(--bs-emphasis-color);
}

.fz-set-link-hint {
    display: block;
    font-size: 0.875rem;
    line-height: 1.35;
    color: var(--bs-secondary-color);
}

.fz-set-link-go {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    color: var(--bs-secondary-color);
}

.fz-set-link:hover .fz-set-link-go {
    color: var(--fz-brand);
}

/* Las filas de dos. Cada fila mide lo que su tarjeta mas alta y las dos se
   estiran a ella: se emparejan las que miden parecido, y la vista previa, que no
   tiene boton, es la que se queda con aire debajo, como «Cómo te va». */
.fz-set-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
}

/* Desde 1200, como las altas (`fz-form-grid`): por debajo, el perfil ya no cabe
   con los campos de dos en dos al lado de otra tarjeta. */
@media (min-width: 1200px) {
    .fz-set-grid {
        grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    }
}

/* Las de lo ancho, debajo de las filas. */
.fz-set-wide {
    margin-top: 1.25rem;
}

/* El formulario llena su tarjeta y deja el boton abajo: en la tarjeta estirada,
   el pie cae a la misma altura que el de su vecina. */
.fz-set-grid .fz-fcard-body {
    display: flex;
    flex-direction: column;
}

/* «Así se verá»: la lista debajo del importe, y un valor que no cabe al lado de
   su rotulo baja de linea en vez de salirse (la hora en un telefono). */
.fz-set-preview-lines {
    margin-top: 0.875rem;
}

.fz-set-preview-lines > div {
    flex-wrap: wrap;
    column-gap: 1rem;
    row-gap: 0;
}

.fz-set-preview-lines dd {
    margin-left: auto;
}

.fz-set-form {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 1.25rem;
}

.fz-set-form > .fz-fcard-actions {
    margin-top: auto;
}

/* Los campos, de dos en dos donde caben 17rem por campo y uno por fila donde no.
   Nunca tres: el pais va a lo ancho y una tercera pista vacia no se colapsa. */
.fz-set-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, max(17rem, calc((100% - 1.25rem) / 2))), 1fr));
    gap: 1rem 1.25rem;
}

.fz-set-field-wide {
    grid-column: 1 / -1;
}

/* Lo que se ensena y no se cambia aqui: el correo y, para un miembro, la moneda.
   Con forma de campo pero sin serlo, para que un correo largo baje de linea en
   vez de cortarse. */
.fz-field .form-control.fz-set-value,
[data-bs-theme='dark'] .fz-field .form-control.fz-set-value {
    display: flex;
    align-items: center;
    overflow-wrap: anywhere;
    background-color: var(--fz-surface-sunken);
}

/* El pie de cada tarjeta: el boton a la derecha, tras una raya en su tono. */
.fz-fcard-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.75rem;
    margin: 0;
    padding-top: 1.125rem;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
}

.fz-fcard-actions .fz-btn-cta {
    min-width: min(100%, 14rem);
}

@media (max-width: 575.98px) {
    .fz-fcard-actions .btn {
        flex: 1 1 auto;
        padding-inline: 1rem;
    }
}

/* Lo que se lee a la izquierda y lo que se decide a la derecha. */
.fz-set-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem 2.5rem;
}

.fz-set-row + .fz-set-row {
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
}

@media (min-width: 992px) {
    .fz-set-row {
        grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    }
}

/* Dentro de una franja el boton ya tiene su columna: sin raya. */
.fz-set-row .fz-fcard-actions {
    padding-top: 0;
    border-top: 0;
}

.fz-set-row-text {
    min-width: 0;
    font-size: 0.9375rem;
    color: var(--bs-secondary-color);
}

.fz-set-row-text > p {
    margin-bottom: 0.75rem;
}

.fz-set-row-text > p:last-child {
    margin-bottom: 0;
}

.fz-set-row-title {
    margin: 0 0 0.25rem;
    font-size: 1rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.fz-set-row-action {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}

.fz-set-row-action > .alert {
    margin-bottom: 0;
}

/* El acceso de soporte vigente, en el tono de su tarjeta. */
.fz-set-status {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    margin: 0;
    padding: 0.875rem 1rem;
    border: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 35%, var(--bs-border-color));
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 10%, var(--fz-surface));
    color: var(--bs-emphasis-color);
}

.fz-set-status .icon {
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    margin-top: 0.125rem;
    color: var(--fz-kpi-tone);
}

/* La actividad de soporte: la accion y su fecha, sin cruzar toda la tarjeta. */
.fz-set-history {
    max-width: 36rem;
}

.fz-set-history li {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.25rem;
}

/* --- /billing en tarjetas (ADR 0127) ------------------------------------------
   «Tu plan» con la forma de «Cómo te va» y los planes como las opciones de las
   altas, cada uno con sus botones. Desde 1200, el estado a la izquierda y los
   planes a la derecha, estirados a la mas alta; con una sola tarjeta (suscrito
   sin cobro configurado), a lo ancho. */
.fz-bill-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
}

@media (min-width: 1200px) {
    .fz-bill-grid:has(> :nth-child(2)) {
        grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    }
}

/* El estado llena su tarjeta y deja los botones abajo. */
.fz-bill-state {
    display: flex;
    flex-direction: column;
}

.fz-bill-state > .fz-fcard-actions {
    margin-top: auto;
}

.fz-bill-state > .fz-estimate-note + .fz-fcard-actions,
.fz-bill-state > .fz-bill-lines + .fz-fcard-actions {
    padding-top: 1.125rem;
}

.fz-bill-state > .fz-estimate-note {
    margin-bottom: 1.25rem;
}

/* Cancelar (o seguir) a la izquierda, lejos del portal, que se queda a la derecha.
   En el telefono, a todo lo ancho como los demas botones del pie: su formulario
   no dejaba crecer al boton. */
.fz-bill-state-actions > form {
    margin-inline-end: auto;
}

@media (max-width: 575.98px) {
    .fz-bill-state-actions > form {
        display: flex;
        flex: 1 1 100%;
    }
}

.fz-bill-lines {
    margin-top: 1.25rem;
    margin-bottom: 1.25rem;
}

.fz-bill-lines a {
    font-weight: 600;
    text-decoration: none;
}

.fz-bill-lines a:hover {
    text-decoration: underline;
}

/* El estado de la suscripcion junto a su plan: verde al dia, ambar con el pago
   pendiente y neutro pausada o cancelada (ADR 0008). */
.fz-bill-status {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.625rem;
    border-radius: 999px;
    background-color: var(--fz-surface-sunken);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.fz-bill-status[data-state='active'],
.fz-bill-status[data-state='trialing'] {
    background-color: color-mix(in srgb, var(--fz-state-ok-text) 16%, transparent);
    color: var(--fz-state-ok-text);
}

.fz-bill-status[data-state='past_due'] {
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 16%, transparent);
    color: var(--fz-state-warn-text);
}

/* Los planes: dos columnas donde caben, una en el telefono. */
.fz-bill-plans {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
}

@media (min-width: 768px) {
    .fz-bill-plans {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.fz-bill-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
    padding: 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.875rem;
    background-color: var(--fz-surface);
}

.fz-bill-plan:hover {
    border-color: color-mix(in srgb, var(--fz-brand) 45%, var(--bs-border-color));
}

/* El plan que ya se paga, como la opcion elegida de las altas. */
.fz-bill-plan.is-current {
    border-color: var(--fz-brand-fill-end);
    background-image: linear-gradient(135deg, rgba(var(--fz-brand-rgb), 0.16), rgba(var(--fz-brand-rgb), 0.04));
    box-shadow: 0 0 0 1px var(--fz-brand-fill-end), 0 12px 28px -18px rgba(var(--fz-brand-rgb), 0.95);
}

.fz-bill-plan.is-current .fz-choice-icon {
    background-color: var(--fz-brand-fill);
    background-image: linear-gradient(145deg, var(--fz-brand-fill-end), var(--fz-brand-fill));
    color: var(--fz-brand-on-fill);
    box-shadow: 0 0 18px -4px rgba(var(--fz-brand-rgb), 0.9);
}

.fz-bill-plan-head {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    padding-right: 1.5rem;
}

.fz-bill-plan-title {
    margin: 0;
    font-size: 1.0625rem;
}

.fz-bill-plan-check {
    position: absolute;
    top: 0.625rem;
    right: 0.625rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background-color: var(--fz-brand-fill);
    color: var(--fz-brand-on-fill);
}

.fz-bill-plan-check .icon {
    width: 0.875rem;
    height: 0.875rem;
    stroke-width: 2.5;
}

/* El precio en su recuadro, como «Llevas en octubre». */
.fz-bill-plan-price {
    padding: 0.875rem 1rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-kpi-tone) 12%, transparent);
}

.fz-bill-price {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 0.375rem;
    margin: 0;
}

.fz-bill-price-amount {
    font-size: var(--fz-amount-lg);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
    color: var(--bs-emphasis-color);
}

.fz-bill-price-per {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.fz-bill-save {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0.625rem 0 0;
    padding-top: 0.625rem;
    border-top: 1px solid color-mix(in srgb, var(--fz-kpi-tone) 22%, var(--bs-border-color));
    font-size: 0.8125rem;
    color: var(--bs-body-color);
}

.fz-bill-save .icon {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    margin-top: 0.0625rem;
    color: var(--fz-state-ok-text);
}

.fz-bill-features {
    display: grid;
    gap: 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
}

.fz-bill-features li {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
}

.fz-bill-features .icon {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    margin-top: 0.125rem;
    color: var(--fz-kpi-tone);
    stroke-width: 2.25;
}

/* Un plan donde no cabe el espacio: apagado, con la razon en ambar. */
.fz-bill-plan.is-off .fz-bill-plan-head,
.fz-bill-plan.is-off .fz-bill-plan-price,
.fz-bill-plan.is-off .fz-bill-features {
    opacity: 0.6;
}

.fz-bill-plan-warn {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin: 0;
    padding: 0.75rem 0.875rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--fz-state-warn-text) 12%, transparent);
    font-size: 0.8125rem;
    color: var(--bs-body-color);
}

.fz-bill-plan-warn .icon {
    flex: 0 0 auto;
    width: 1.125rem;
    height: 1.125rem;
    color: var(--fz-state-warn-text);
}

/* Los botones abajo del plan, a la misma altura en los dos. */
.fz-bill-plan-actions {
    display: grid;
    gap: 0.5rem;
    margin-top: auto;
}

.fz-bill-plan-actions form {
    display: grid;
}

.fz-bill-plan-actions .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-width: 0;
    min-height: 2.75rem;
    margin: 0;
    border-radius: 0.75rem;
    font-weight: 600;
}

.fz-bill-plan-actions .btn .icon {
    width: 1.125rem;
    height: 1.125rem;
}

/* La nota del portal pegada a la lista: el hueco ya lo pone la lista. */
.fz-bill-lines + .fz-estimate-note {
    margin-top: 0;
}

/* Un periodo a la vez (ADR 0127): el segmentado de la tarjeta decide que precio
   y que boton ensena cada plan. El mensual se ve si no hay `:has()`. Los
   selectores llevan el id para ganarle a los `display` de cada pieza. */
.fz-bill-period {
    max-width: 20rem;
    margin: 0 0 1rem;
    border: 0;
}

/* Cada opcion con el objetivo tactil entero, no el alto del control menos el carril. */
.fz-bill-period .fz-bud-segment {
    min-height: var(--fz-control-height);
}

.fz-bill-plans-card:not(:has(#billing-period-year:checked)) [data-period='year'],
.fz-bill-plans-card:has(#billing-period-year:checked) [data-period='month'] {
    display: none;
}

/* El ahorro del pago anual, en verde como lo que juega a favor. */
.fz-bill-save-year {
    font-weight: 600;
    color: var(--fz-state-ok-text);
}

/* --- El checkout de Paddle dentro de la pagina (ADR 0143) -----------------------
   paddle.js mete su iframe en `.fz-checkout-frame` con la clase
   `paddle-frame-inline`. El ancho se lo daria `frameStyle`, que llega por
   setAttribute('style') y la CSP sin 'unsafe-inline' lo descarta: va aqui. El
   alto lo pone Paddle con el atributo `height`, que la CSP no toca; el hueco
   guarda el inicial (`frameInitialHeight`) para que la pagina no salte mientras
   carga. */
.fz-checkout-frame {
    min-height: 450px;
}

/* `color-scheme: light`, el que usa el documento de Paddle (no declara ninguno,
   y su fondo es transparente): si el iframe heredara el `dark` de la pagina, el
   navegador le pintaria debajo un fondo blanco opaco por tener esquemas
   distintos, y en oscuro los campos de Paddle, oscuros y con letra clara,
   quedaban sobre blanco. `normal` no basta: con la meta `color-scheme: dark` de
   la pagina se resuelve a oscuro. Con el mismo esquema, se ve la tarjeta. */
.paddle-frame-inline {
    display: block;
    width: 100%;
    min-width: 286px;
    border: 0;
    background-color: transparent;
    color-scheme: light;
}

/* --- La ventana de version de demostracion (ADR 0129) ---------------------------
   Sin JavaScript es una capa fija abierta (`open`); con JavaScript, el mismo
   elemento como modal (`showModal()`). Las dos ocupan la pantalla entera y
   centran la tarjeta, asi que se ven igual. Encima del riel y de los avisos. */
.fz-demo[open] {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: grid;
    place-items: center;
    width: 100%;
    max-width: none;
    height: 100%;
    max-height: none;
    margin: 0;
    padding: var(--fz-space-4);
    overflow-y: auto;
    border: 0;
    background-color: var(--fz-scrim);
    color: inherit;
}

/* El velo lo pinta la propia ventana: el del navegador se queda transparente. */
.fz-demo::backdrop {
    background: transparent;
}

.fz-demo-card {
    width: 100%;
    max-width: 30rem;
    padding: var(--fz-space-5);
    border-radius: 1rem;
    background-color: var(--fz-surface-raised);
    color: var(--bs-body-color);
    box-shadow: var(--fz-elev-2);
}

/* La etiqueta de arriba: lo primero que se lee, en el color de la marca. */
.fz-demo-tag {
    display: inline-block;
    margin-bottom: var(--fz-space-3);
    padding: 0.125rem 0.625rem;
    border-radius: 999px;
    background-color: rgba(var(--fz-brand-rgb), 0.12);
    color: var(--fz-brand);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.fz-demo-title {
    margin-bottom: var(--fz-space-2);
    font-size: 1.375rem;
    font-weight: 700;
}

.fz-demo-lead {
    margin-bottom: var(--fz-space-3);
}

.fz-demo-points {
    display: grid;
    gap: var(--fz-space-2);
    margin-bottom: var(--fz-space-5);
    padding-left: 1.25rem;
    color: var(--bs-secondary-color);
}

/* El boton a todo el ancho: es la unica salida y tiene que poder tocarse sin apuntar. */
.fz-demo-ack {
    display: block;
    width: 100%;
    min-height: var(--fz-control-height);
}
