/* =====================================================================
 * app.css — CeibeCASH
 * Capa de marca: se carga DESPUÉS de tailwind.min.css y define los
 * componentes con personalidad propia (header, homescreen tipo iOS,
 * cards de escritorio, formularios). Ámbar/dorado sobre lienzo slate.
 * ===================================================================== */

/* ── Tipografía autoalojada (cero orígenes externos: la PWA instalada
      debe funcionar sin red) ──────────────────────────────────────── */
@font-face {
    font-family: 'Inter';
    src: url('../webfonts/inter-var.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

:root {
    --cash-primary: #f59e0b;        /* amber-500 */
    --cash-primary-dark: #d97706;   /* amber-600 */
    --cash-primary-deep: #b45309;   /* amber-700 */
    --cash-primary-soft: #fef3c7;   /* amber-100 */
    --cash-primary-wash: #fffbeb;   /* amber-50  */

    --cash-ink: #0f172a;            /* slate-900 — texto principal */
    --cash-ink-soft: #475569;       /* slate-600 — texto secundario */
    --cash-ink-faint: #94a3b8;      /* slate-400 — texto terciario */
    --cash-line: #e2e8f0;           /* slate-200 — bordes */
    --cash-bg: #f8fafc;             /* slate-50  — lienzo */
    --cash-surface: #ffffff;

    --cash-danger: #e11d48;         /* rose-600 */
    --cash-importe: #9f1239;        /* rose-800 — el importe de un gasto: sale dinero */
    --cash-success: #059669;        /* emerald-600 */

    --cash-radius: 0.875rem;
    --cash-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 8px 24px -12px rgba(15, 23, 42, .12);
    --cash-shadow-lg: 0 2px 4px rgba(15, 23, 42, .05), 0 18px 40px -18px rgba(15, 23, 42, .25);

    /* Alto real del header: lo usan el padding del contenido y el scroll-margin */
    --cash-header-h: 3.5rem;         /* 56 px en móvil */
    --cash-safe-top: env(safe-area-inset-top, 0px);
    --cash-safe-bottom: env(safe-area-inset-bottom, 0px);
}

@media (min-width: 1024px) {
    :root { --cash-header-h: 4rem; }  /* 64 px en escritorio */
}

/* ── Lienzo ──────────────────────────────────────────────────────────
   html lleva el MISMO fondo que body: en iOS standalone, si la página es
   más corta que la pantalla, la franja del área segura muestra el canvas
   y un fondo distinto se ve como una barra blanca. */
html {
    background: var(--cash-bg);
    -webkit-text-size-adjust: 100%;
}

body {
    background: var(--cash-bg);
    color: var(--cash-ink);
    font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    min-height: 100vh;
    min-height: 100dvh;
    overflow-x: hidden;
}

* { -webkit-tap-highlight-color: transparent; }

[x-cloak] { display: none !important; }

/* Ocultar SIEMPRE gana.
   Esta hoja se carga después de Tailwind, así que a igual especificidad manda
   ella: sin estas dos reglas, un `.cash-modal-overlay` con la clase `.hidden`
   seguiría en `display:flex` (el modal nacía abierto y no había forma de
   cerrarlo), y el atributo `hidden` del HTML perdía ante cualquier clase que
   declarase display —`.cash-menu-item`, `.cash-btn`, `.flex`—, dejando a la
   vista controles que debían aparecer solo en ciertos casos. */
[hidden] { display: none !important; }
.hidden { display: none !important; }

/* Mostrar u ocultar por tramo. Van aquí y no con `lg:hidden` por lo mismo
   de arriba: la utilidad de Tailwind pierde contra cualquier `.cash-*` que
   declare `display` —`.cash-springboard`, `.cash-segment`—, así que un
   bloque marcado como «solo móvil» seguía viéndose en el escritorio. */
@media (min-width: 1024px)   { .cash-hasta-pc { display: none !important; } }
@media (max-width: 1023.98px) { .cash-desde-pc { display: none !important; } }
/* Y el tramo pequeño: lo que solo cabe a partir de una tablet (640 px). */
@media (max-width: 639.98px)  { .cash-desde-sm { display: none !important; } }

/* ── AlexAlertUI: piel de CeibeCASH ──────────────────────────────────
   La librería (assets/js/alexalertui.js) inyecta su propio CSS y se viste
   entera con estas variables. Sustituye a SweetAlert2: mismo contrato de
   resultado, sin dependencias y 108 KB menos que descargar y cachear. */
:root {
    --aa-radius: 1rem;
    --aa-font: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

    --aa-accent: #f59e0b;
    --aa-confirm-bg: #f59e0b;
    --aa-confirm-color: #fff;
    --aa-cancel-bg: #f1f5f9;
    --aa-cancel-color: #475569;
    --aa-danger: #e11d48;

    /* Cabecera del diálogo. SIN estas cuatro, la librería se queda con sus
       defaults —índigo #6366f1 y texto #1e1b4b— y el título salía morado.
       Mismo lavado ámbar sobre blanco que .cash-modal-head de la app. */
    --aa-head-bg: linear-gradient(to bottom, rgba(245, 158, 11, .13), rgba(245, 158, 11, 0)), #fff;
    --aa-head-color: var(--cash-ink);
    --aa-head-border: var(--cash-line);
    --aa-head-badge-bg: rgba(255, 255, 255, .6);

    /* El botón «No» de las confirmaciones de tres opciones: gris del sistema
       por defecto, slate del proyecto ahora. */
    --aa-deny-bg: #f1f5f9;
    --aa-deny-color: var(--cash-ink-soft);

    --aa-popup-bg: #fff;
    --aa-popup-color: var(--cash-ink-soft);
    --aa-title-color: var(--cash-ink);
    --aa-popup-border: var(--cash-line);
    --aa-shadow: 0 24px 60px -20px rgba(15, 23, 42, .45);

    /* Fondo tintado del ámbar de la marca, no gris neutro */
    --aa-backdrop: rgba(69, 39, 8, .38);
    --aa-backdrop-blur: 3px;

    --aa-success: var(--cash-success);
    --aa-error: var(--cash-danger);
    --aa-warning: #f59e0b;
    --aa-info: #0ea5e9;
    --aa-question: #f59e0b;
}

/* Foco visible y coherente en toda la app (accesibilidad) */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--cash-primary);
    outline-offset: 2px;
    border-radius: 6px;
}

/* =====================================================================
 * HEADER STICKY
 * Móvil  : hamburguesa · título · avatar
 * PC     : marca a la izquierda · opciones centradas · avatar a la derecha
 *          (sin hamburguesa)
 * ===================================================================== */
.cash-header {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(255, 255, 255, .88);
    backdrop-filter: blur(14px) saturate(1.6);
    -webkit-backdrop-filter: blur(14px) saturate(1.6);
    border-bottom: 1px solid var(--cash-line);
    padding-top: var(--cash-safe-top);      /* notch de iOS */
}

.cash-header-inner {
    height: var(--cash-header-h);
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 0 .875rem;
}

@media (min-width: 1024px) {
    .cash-header-inner {
        max-width: 1400px;
        margin: 0 auto;
        padding: 0 1.5rem;
        gap: 1.25rem;
    }
}

/* Los dos bloques laterales (marca a un lado, avatar al otro). Crecen lo
   mismo —`1 1 0`, no `auto`—, así el hueco sobrante se reparte a partes
   iguales y la navegación del medio queda centrada en la barra de verdad,
   no a medio camino entre la marca y el avatar, que miden muy distinto. */
.cash-header-lado {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex: 1 1 0;
    min-width: 0;
}
/* En móvil no hay navegación central y el lado derecho es solo el avatar:
   ahí NO debe crecer, o se llevaría la mitad del hueco y dejaría el título
   a media anchura. Crece igual que el izquierdo solo a partir de 1024 px,
   que es donde aparece el menú que hay que centrar. */
.cash-header-lado.is-fin {
    flex: none;
    justify-content: flex-end;
}
@media (min-width: 1024px) {
    .cash-header-lado.is-fin { flex: 1 1 0; }
}

/* Marca */
.cash-brand {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    font-weight: 700;
    letter-spacing: -.015em;
    color: var(--cash-ink);
    font-size: 1.0625rem;
    white-space: nowrap;
}
.cash-brand-mark {
    width: 1.875rem;
    height: 1.875rem;
    border-radius: .625rem;
    display: grid;
    place-items: center;
    color: #fff;
    font-size: .8125rem;
    background: linear-gradient(145deg, var(--cash-primary), var(--cash-primary-deep));
    box-shadow: 0 2px 8px -2px rgba(217, 119, 6, .55);
    flex: none;
}
.cash-brand-sub { color: var(--cash-primary-dark); }

/* Botón de icono del header (hamburguesa, atrás, acciones) */
/* Identidad de la página en la barra: icono de marca + nombre. Ocupa el hueco
   de la marca en las páginas de detalle, así el contenido no repite el nombre. */
.cash-header-title {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    /* `0 1 auto` y NO `1`: el título se queda pegado a la flecha de volver
       en vez de estirarse y acabar flotando en medio de su lado. Encoge (y
       recorta con puntos suspensivos) cuando no cabe. */
    flex: 0 1 auto;
    min-width: 0;
    font-size: .9375rem;
    font-weight: 600;
    letter-spacing: -.01em;
    color: var(--cash-ink);
}
/* El mismo icono de marca que en la rejilla del inicio: cash_icono_style() solo
   deja las variables del degradado (--icon-from/--icon-to), la forma y el color
   los tiene que poner la clase. Sin esto salía transparente y con el color del
   texto, que es justo lo que se veía. */
.cash-header-title-icon {
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 22.5%;
    color: #fff;
    font-size: .75rem;
    background: linear-gradient(160deg, var(--icon-from, #fbbf24), var(--icon-to, #b45309));
    box-shadow: 0 2px 6px -2px rgba(15, 23, 42, .35), inset 0 1px 0 rgba(255, 255, 255, .28);
    flex: none;
}
.cash-header-title-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
@media (min-width: 1024px) {
    .cash-header-title { font-size: 1rem; }
    .cash-header-title-icon { width: 2rem; height: 2rem; font-size: .875rem; }
}

.cash-icon-btn {
    width: 2.375rem;
    height: 2.375rem;
    border-radius: .75rem;
    display: inline-grid;
    place-items: center;
    color: var(--cash-ink-soft);
    font-size: 1.0625rem;
    transition: background-color .15s ease, color .15s ease;
    flex: none;
}
.cash-icon-btn:hover { background: #f1f5f9; color: var(--cash-ink); }
/* En la barra, el mismo anillo ámbar que los enlaces del menú */
.cash-header .cash-icon-btn:hover, .cash-burger:hover {
    box-shadow: inset 0 0 0 1px var(--cash-primary);
}
.cash-icon-btn:active { background: var(--cash-line); }

/* Navegación en la barra, centrada (solo escritorio) */
.cash-nav {
    display: none;
    align-items: center;
    gap: .25rem;
    flex: none;
}
@media (min-width: 1024px) { .cash-nav { display: flex; } }

.cash-nav-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .875rem;
    border-radius: .625rem;
    font-size: .875rem;
    font-weight: 500;
    color: var(--cash-ink-soft);
    transition: color .15s ease, background-color .15s ease;
}
.cash-nav-link i { font-size: .8125rem; opacity: .75; }
/* El anillo va por `box-shadow` y no por `border`: un borde real ensancharía
   el enlace al pasar el ratón y movería de sitio a los de al lado. */
.cash-nav-link:hover {
    color: var(--cash-ink);
    background: #f1f5f9;
    box-shadow: inset 0 0 0 1px var(--cash-primary);
}
.cash-nav-link.is-active {
    color: var(--cash-primary-deep);
    background: var(--cash-primary-wash);
}
.cash-nav-link.is-active i { opacity: 1; }

/* Avatar del usuario */
.cash-avatar {
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    object-fit: cover;
    background: var(--cash-primary-soft);
    color: var(--cash-primary-deep);
    display: grid;
    place-items: center;
    font-weight: 600;
    font-size: .8125rem;
    border: 2px solid #fff;
    box-shadow: 0 0 0 1px var(--cash-line);
    flex: none;
    overflow: hidden;
}
.cash-avatar-btn { border-radius: 50%; transition: box-shadow .15s ease; }
.cash-avatar-btn:hover .cash-avatar { box-shadow: 0 0 0 2px var(--cash-primary); }

/* Panel desplegable (user menu) */
.cash-menu {
    position: absolute;
    right: 0;
    top: calc(100% + .5rem);
    min-width: 15rem;
    background: #fff;
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow-lg);
    padding: .375rem;
    z-index: 50;
    overflow: hidden;
}
/* Ficha de quien ha entrado: tintada de ámbar para separarla de las
   opciones. El radio es el del panel menos su padding, si no la esquina
   del tinte se ve desalineada con la del borde. */
.cash-menu-head {
    padding: .75rem .75rem .625rem;
    margin-bottom: .375rem;
    border: 1px solid var(--cash-primary-soft);
    border-radius: calc(var(--cash-radius) - .375rem);
    background: linear-gradient(160deg, var(--cash-primary-wash), #fef6e0);
}
.cash-menu-nombre {
    font-size: .875rem;
    font-weight: 600;
    color: var(--cash-primary-deep);
}
.cash-menu-meta {
    font-size: .75rem;
    color: var(--cash-primary-dark);
    opacity: .8;
}
.cash-menu-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    padding: .625rem .75rem;
    border-radius: .5rem;
    font-size: .875rem;
    color: var(--cash-ink-soft);
    text-align: left;
    transition: background-color .12s ease, color .12s ease;
}
.cash-menu-item i { width: 1.125rem; text-align: center; font-size: .875rem; opacity: .7; }
.cash-menu-item:hover { background: var(--cash-primary-wash); color: var(--cash-primary-deep); }
.cash-menu-item:hover i { opacity: 1; }
.cash-menu-item.is-danger:hover {
    background: #ffe4e6;                /* rose-100 */
    color: var(--cash-danger);
}

/* ── Botón hamburguesa animado ───────────────────────────────────────
   Tres barras que se pliegan en aspa. Va por encima del menú (z-index
   mayor) para que el mismo botón abra y cierre: al abrirse el panel el
   icono ya es una X, así que pulsarlo otra vez es el gesto natural. */
.cash-burger {
    position: relative;
    z-index: 71;
    width: 2.375rem;
    height: 2.375rem;
    border-radius: .75rem;
    display: inline-grid;
    place-items: center;
    flex: none;
    transition: background-color .15s ease;
}
.cash-burger:hover { background: #f1f5f9; }
/* En escritorio no hay hamburguesa: las opciones ya están en la barra.
   Se oculta desde aquí y NO con `lg:hidden`, porque app.css carga después
   de Tailwind y a igual especificidad el `display: inline-grid` de arriba
   ganaba a la utilidad. */
@media (min-width: 1024px) { .cash-burger { display: none; } }

.cash-burger-caja {
    position: relative;
    width: 1.125rem;
    height: .875rem;
}
.cash-burger-barra {
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: var(--cash-ink-soft);
    transition: transform .38s cubic-bezier(.68, -.55, .27, 1.55),
                opacity .2s ease,
                background-color .2s ease,
                width .3s ease;
}
.cash-burger-barra:nth-child(1) { top: 0; }
.cash-burger-barra:nth-child(2) { top: 50%; margin-top: -1px; width: 72%; }
.cash-burger-barra:nth-child(3) { bottom: 0; }

/* Abierto: la de en medio se desvanece y las otras dos cruzan */
.cash-burger.is-open .cash-burger-barra:nth-child(1) {
    transform: translateY(6px) rotate(45deg);
}
.cash-burger.is-open .cash-burger-barra:nth-child(2) {
    opacity: 0;
    transform: translateX(-8px);
}
.cash-burger.is-open .cash-burger-barra:nth-child(3) {
    transform: translateY(-6px) rotate(-45deg);
}

/* ── Menú flotante ───────────────────────────────────────────────────
   Panel centrado de cristal ámbar. No tapa la app: el fondo se ve, solo
   se atenúa y se desenfoca un poco, para no perder de vista dónde estás. */
.cash-menuf {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

/* Velo: lo justo para despegar el panel del fondo sin ocultarlo */
.cash-menuf-cristal {
    position: absolute;
    inset: 0;
    background: rgba(28, 16, 2, .28);
    backdrop-filter: blur(6px) saturate(120%);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
    animation: cashVeloIn .32s ease both;
}
@keyframes cashVeloIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* El cristal ámbar. El relieve sale de tres capas: el degradado de marca,
   un brillo interior arriba (inset blanco) que simula el canto del vidrio,
   y una sombra larga y cálida debajo. */
.cash-menuf-panel {
    position: relative;
    width: 100%;
    max-width: 20rem;
    padding: 1.25rem;
    border-radius: 1.75rem;
    background:
        linear-gradient(160deg, rgba(253, 230, 138, .40), rgba(245, 158, 11, .26) 55%, rgba(217, 119, 6, .30));
    backdrop-filter: blur(28px) saturate(200%);
    -webkit-backdrop-filter: blur(28px) saturate(200%);
    border: 1px solid rgba(255, 255, 255, .55);
    box-shadow:
        inset 0 1px 1px rgba(255, 255, 255, .75),
        inset 0 -1px 1px rgba(180, 83, 9, .18),
        0 24px 60px -18px rgba(120, 53, 15, .5);
    animation: cashPanelIn .42s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes cashPanelIn {
    from { opacity: 0; transform: translateY(14px) scale(.94); }
    to   { opacity: 1; transform: none; }
}

.cash-menuf-nav {
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

/* Cada opción: icono y texto centrados en fila, sobre su propio vidrio.
   Entran escalonadas con --i. */
.cash-menuf-link {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .625rem;
    padding: .875rem 1rem;
    border-radius: 1.125rem;
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: -.01em;
    text-align: center;
    color: #451a03;                       /* amber-950: legible sobre el ámbar */
    background: rgba(255, 255, 255, .42);
    border: 1px solid rgba(255, 255, 255, .6);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .6);
    animation: cashPanelIn .45s cubic-bezier(.16, 1, .3, 1) both;
    animation-delay: calc(var(--i, 0) * 45ms + 90ms);
    transition: background-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.cash-menuf-link i { font-size: .9375rem; opacity: .85; }
.cash-menuf-link:hover {
    background: rgba(255, 255, 255, .68);
    transform: translateY(-1px);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7), 0 8px 20px -10px rgba(120, 53, 15, .45);
}
.cash-menuf-link:active { transform: scale(.97); }

/* La página en la que ya estás: sólida, sin transparencia */
.cash-menuf-link.is-active {
    background: linear-gradient(150deg, #f59e0b, #b45309);
    border-color: rgba(255, 255, 255, .35);
    color: #fff;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 6px 18px -8px rgba(120, 53, 15, .6);
}
.cash-menuf-link.is-active i { opacity: 1; }

/* Pie: perfil y salir, más discretos y también centrados */
.cash-menuf-foot {
    margin-top: .875rem;
    padding-top: .875rem;
    border-top: 1px solid rgba(255, 255, 255, .45);
    display: flex;
    flex-direction: column;
    gap: .25rem;
    animation: cashPanelIn .45s cubic-bezier(.16, 1, .3, 1) both;
    animation-delay: 240ms;
}
.cash-menuf-sec {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .625rem 1rem;
    border-radius: .875rem;
    font-size: .875rem;
    font-weight: 500;
    color: rgba(69, 26, 3, .78);
    transition: background-color .15s ease, color .15s ease;
}
.cash-menuf-sec i { font-size: .8125rem; opacity: .7; }
.cash-menuf-sec:hover { background: rgba(255, 255, 255, .45); color: #451a03; }
.cash-menuf-sec.is-danger:hover { background: rgba(225, 29, 72, .14); color: #9f1239; }

.cash-menuf-version {
    margin-top: .75rem;
    text-align: center;
    font-size: .625rem;
    color: rgba(69, 26, 3, .5);
    animation: cashPanelIn .45s ease both;
    animation-delay: 300ms;
}

/* Firma del pie. El tono es el del panel (ámbar) y no el slate del login: aquí
   el fondo es cálido y un gris frío se vería sucio encima. */
.cash-menuf-firma {
    margin-top: .1875rem;
    text-align: center;
    font-size: .625rem;
    color: rgba(69, 26, 3, .42);
    animation: cashPanelIn .45s ease both;
    animation-delay: 350ms;
}

/* Donde no hay backdrop-filter, el panel se vuelve sólido: sin él, el
   degradado translúcido dejaría el texto sobre el contenido de la app. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .cash-menuf-panel { background: #fde9bd; }
    .cash-menuf-cristal { background: rgba(28, 16, 2, .55); }
}

@media (prefers-reduced-motion: reduce) {
    .cash-menuf-cristal,
    .cash-menuf-panel,
    .cash-menuf-link,
    .cash-menuf-foot,
    .cash-menuf-version,
    .cash-menuf-firma { animation: none; }
}

/* =====================================================================
 * CONTENIDO
 * Móvil : ancho completo con aire lateral corto (la rejilla manda)
 * PC    : centrado al 60% del ancho, con techo para pantallas enormes
 * ===================================================================== */
.cash-main {
    padding: 1rem .875rem calc(2.5rem + var(--cash-safe-bottom));
}
/* $mainCompacto: el aire entre bloques se recorta y el contenido se acerca al
   borde de la pantalla. Lo que se viene a hacer aquí es leer filas: cada
   milímetro de margen es una fila menos.
   Va ANTES del tramo de escritorio a propósito: una media query no suma
   especificidad, así que si estuviera después le ganaría al `padding-inline`
   de .cash-ancho y el explorador del inicio se quedaría pegado al borde. */
.cash-main.cash-compacto { padding: .5rem .5rem calc(2.5rem + var(--cash-safe-bottom)); }
.cash-compacto .cash-resumen { margin-bottom: .5rem; padding: .625rem .875rem; }
.cash-compacto .cash-pagos { margin-bottom: .5rem; }
.cash-compacto .cash-resumen-importe { font-size: 1.375rem; }
.cash-compacto .cash-aviso { margin-bottom: .5rem; }

@media (min-width: 1024px) {
    .cash-main {
        width: 60%;
        max-width: 1100px;
        min-width: 42rem;
        margin-inline: auto;
        padding: 1.75rem 0 4rem;
    }
    /* Páginas de dos paneles ($mainAncho en la vista): el árbol y la lista
       necesitan todo el ancho, no la columna de lectura del 60%. */
    .cash-main.cash-ancho {
        width: 100%;
        max-width: 1980px;
        min-width: 0;
        padding-inline: 1.5rem;
    }
    /* Solo el eje vertical: así no pisa el `padding-inline` de arriba. */
    .cash-main.cash-compacto { padding-top: 1rem; padding-bottom: 3rem; }
    .cash-compacto .cash-ajustes { gap: 1rem; }
}

/* =====================================================================
 * HOMESCREEN TIPO iOS (móvil / tablet)
 * 4 iconos por fila en vertical; al girar el móvil pasa a 6 y en tablet
 * a 6-8, para que el espacio ganado se llene en vez de estirar el icono.
 * ===================================================================== */
.cash-springboard {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1.25rem .5rem;
    padding: .5rem .25rem 1rem;
}

/* Móvil en horizontal: más columnas, no iconos más grandes */
@media (orientation: landscape) and (max-width: 1023.98px) {
    .cash-springboard { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
@media (min-width: 640px) and (orientation: portrait) {
    .cash-springboard { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 1.5rem .75rem; }
}
@media (min-width: 640px) and (orientation: landscape) and (max-width: 1023.98px) {
    .cash-springboard { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 1.5rem .75rem; }
}

.cash-app {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .5rem;
    text-align: center;
    -webkit-user-select: none;
    user-select: none;
}

/* El squircle: cuadrado perfecto con el radio de iOS (~22,5%) */
.cash-app-icon {
    position: relative;
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: 22.5%;
    display: grid;
    place-items: center;
    color: #fff;
    font-size: clamp(1.125rem, 6.5vw, 1.75rem);
    background: linear-gradient(160deg, var(--icon-from, #fbbf24), var(--icon-to, #b45309));
    box-shadow: 0 4px 12px -4px rgba(15, 23, 42, .3), inset 0 1px 0 rgba(255, 255, 255, .28);
    transition: transform .18s cubic-bezier(.34, 1.56, .64, 1), box-shadow .18s ease;
}
@media (min-width: 640px) {
    .cash-app-icon { font-size: clamp(1.25rem, 3.2vw, 2rem); }
}
.cash-app:hover .cash-app-icon { transform: translateY(-2px); }
.cash-app:active .cash-app-icon { transform: scale(.92); box-shadow: 0 2px 6px -3px rgba(15, 23, 42, .35); }

/* Brillo sutil en la mitad superior, como los iconos del sistema */
.cash-app-icon::after {
    content: '';
    position: absolute;
    inset: 0 0 55% 0;
    border-radius: 22.5% 22.5% 40% 40% / 30% 30% 100% 100%;
    background: linear-gradient(to bottom, rgba(255, 255, 255, .22), rgba(255, 255, 255, 0));
    pointer-events: none;
}

.cash-app-label {
    font-size: .6875rem;
    line-height: 1.25;
    font-weight: 500;
    color: var(--cash-ink-soft);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}
@media (min-width: 640px) { .cash-app-label { font-size: .75rem; } }

/* Globo con el gasto del mes, como el badge de notificaciones */
.cash-app-badge {
    position: absolute;
    top: -.375rem;
    right: -.375rem;
    min-width: 1.5rem;
    padding: 0 .375rem;
    height: 1.375rem;
    border-radius: 999px;
    background: var(--cash-ink);
    color: #fff;
    font-size: .625rem;
    font-weight: 600;
    display: grid;
    place-items: center;
    border: 2px solid var(--cash-bg);
    letter-spacing: -.02em;
}

/* =====================================================================
 * CARDS DE ESCRITORIO — una por local
 * ===================================================================== */
.cash-card {
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow);
    /* `clip` y NO `hidden`: hidden convierte la card en contenedor de scroll y
       entonces el `.cash-day-sep` sticky de dentro deja de tomar como referencia
       la ventana — se descolgaba hacia abajo, encima de los gastos, en vez de
       quedarse arriba. `clip` recorta igual a las esquinas pero no crea scroll.
       La primera declaración es el respaldo para Safari < 16. */
    overflow: hidden;
    overflow: clip;
}

.cash-local-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.125rem;
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow);
    transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.cash-local-card:hover {
    transform: translateY(-1px);
    box-shadow: var(--cash-shadow-lg);
    border-color: #cbd5e1;
}
.cash-local-card-icon {
    width: 3rem;
    height: 3rem;
    border-radius: .9375rem;
    display: grid;
    place-items: center;
    color: #fff;
    font-size: 1.125rem;
    background: linear-gradient(160deg, var(--icon-from, #fbbf24), var(--icon-to, #b45309));
    box-shadow: 0 3px 10px -4px rgba(15, 23, 42, .35), inset 0 1px 0 rgba(255, 255, 255, .28);
    flex: none;
}
.cash-local-card-name {
    font-weight: 600;
    font-size: .9375rem;
    color: var(--cash-ink);
    letter-spacing: -.01em;
}
.cash-local-card-meta { font-size: .8125rem; color: var(--cash-ink-faint); }
.cash-local-card-total {
    font-size: 1.0625rem;
    font-weight: 700;
    color: var(--cash-ink);
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}

/* =====================================================================
 * LISTA DE GASTOS
 * ===================================================================== */
.cash-expense {
    display: flex;
    align-items: center;
    gap: .875rem;
    padding: .875rem 1rem;
    border-bottom: 1px solid #f1f5f9;
    /* Opaco a propósito: en la lista de gastos resbala por encima del fondo de
       color del gesto y tiene que taparlo del todo. */
    background: var(--cash-surface);
    transition: background-color .12s ease;
}
.cash-expense:last-child { border-bottom: 0; }
.cash-expense:hover { background: #fafbfc; }

.cash-expense-pay {
    width: 2.375rem;
    height: 2.375rem;
    border-radius: .75rem;
    display: grid;
    place-items: center;
    font-size: .875rem;
    flex: none;
}
.cash-pay-efectivo      { background: #ecfdf5; color: #047857; }
.cash-pay-tarjeta       { background: #eff6ff; color: #1d4ed8; }
.cash-pay-transferencia { background: #f5f3ff; color: #6d28d9; }
.cash-pay-otro          { background: #f1f5f9; color: #475569; }

.cash-expense-desc {
    font-size: .9375rem;
    font-weight: 500;
    color: var(--cash-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cash-expense-meta {
    font-size: .75rem;
    color: var(--cash-ink-faint);
    display: flex;
    align-items: baseline;
    gap: .5rem;
    min-width: 0;
}
/* Importe: al final de la SEGUNDA línea, la de la forma de pago —la primera es
   toda para la descripción—. `margin-left:auto` lo empuja al borde derecho y
   `flex:none` impide que se encoja o se parta cuando el resto de la línea
   viene largo. Mono y tabular para que las cifras de todas las filas caigan en
   la misma columna aunque cambien de largo. La mono es la del sistema: no hay
   que descargar nada, que la PWA instalada tiene que pintar esto sin red. */
.cash-expense-amount {
    margin-left: auto;
    flex: none;
    text-align: right;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: .875rem;
    font-weight: 700;
    color: var(--cash-importe);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* Lo demás de esa línea sí cede: se recorta antes que empujar al importe. */
.cash-expense-meta > span:not(.cash-expense-amount) {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Editar y eliminar ya no ocupan sitio: en táctil se hacen con el gesto y en
   cualquier puntero abriendo el detalle de la fila. Siguen en el árbol de
   accesibilidad —no `display:none`— para quien navegue con lector de pantalla. */
.cash-expense-acciones {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Menú de clic derecho sobre una fila (escritorio) ─────────────────
   Mismo aspecto que el menú del avatar —reutiliza .cash-menu-item— pero
   colocado donde se hizo clic. `fixed` y no `absolute`: las coordenadas que
   da el ratón son de la ventana, y así no hay que sumar el scroll. */
.cash-ctx {
    position: fixed;
    z-index: 75;
    min-width: 12rem;
    max-width: 18rem;
    padding: .375rem;
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: .875rem;
    box-shadow: var(--cash-shadow-lg);
}
/* El menú se lleva el foco para poder cerrarse con Escape, pero sin aro: el
   indicador visible aquí es su propia caja, que acaba de aparecer. */
.cash-ctx:focus { outline: none; }

/* Filete fino al pasar por encima. El borde transparente está SIEMPRE puesto:
   si apareciera solo en el hover, la opción crecería 2 px y el texto bailaría. */
.cash-ctx .cash-menu-item { border: 1px solid transparent; }
.cash-ctx .cash-menu-item:hover { border-color: var(--cash-primary); }
.cash-ctx .cash-menu-item.is-danger:hover { border-color: var(--cash-danger); }

/* ── Gestos de la fila ───────────────────────────────────────────────
   Deslizar a la derecha edita (verde) y a la izquierda elimina (rojo). El
   fondo de color se queda quieto y la fila resbala por encima; por eso la
   fila necesita fondo opaco propio y la envoltura recorta lo que sobresale. */
.cash-swipe {
    position: relative;
    overflow: hidden;
}
.cash-swipe-fondo {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 1.375rem;
    background: #f1f5f9;
    transition: background-color .14s ease;
}
.cash-swipe.is-editar   .cash-swipe-fondo { background: var(--cash-success); }
.cash-swipe.is-eliminar .cash-swipe-fondo { background: var(--cash-danger); }

.cash-swipe-accion {
    color: #fff;
    font-size: 1.0625rem;
    opacity: 0;
    transform: scale(.7);
    transition: opacity .14s ease, transform .14s ease;
}
.cash-swipe.is-editar   .cash-swipe-editar,
.cash-swipe.is-eliminar .cash-swipe-eliminar { opacity: 1; }
/* Pasado el umbral el icono crece: es el aviso de que al soltar SÍ va a pasar. */
.cash-swipe.is-armado .cash-swipe-editar,
.cash-swipe.is-armado .cash-swipe-eliminar { transform: scale(1.25); }

.cash-swipe .cash-expense {
    position: relative;
    cursor: pointer;
    /* pan-y: el navegador se queda el desplazamiento vertical (la lista tiene
       que seguir rodando con el dedo) y a nosotros nos deja el horizontal. */
    touch-action: pan-y;
    /* Dentro de la envoltura la fila es SIEMPRE el último hijo, así que
       `.cash-expense:last-child` se comería el borde de todas: aquí se
       devuelve y lo gobierna la envoltura, dos reglas más abajo. */
    border-bottom: 1px solid #f1f5f9;
}
.cash-swipe:last-child .cash-expense { border-bottom: 0; }
/* Solo al soltar: durante el arrastre la fila tiene que ir pegada al dedo. */
.cash-swipe.is-soltando .cash-expense {
    transition: transform .22s cubic-bezier(.22, .61, .36, 1);
}

@media (prefers-reduced-motion: reduce) {
    .cash-swipe .cash-expense,
    .cash-swipe-accion,
    .cash-swipe-fondo { transition: none; }
}

/* Miniatura del ticket */
.cash-thumb {
    width: 2.375rem;
    height: 2.375rem;
    border-radius: .5rem;
    object-fit: cover;
    border: 1px solid var(--cash-line);
    background: #f8fafc;
    flex: none;
}

/* Separador de día dentro de la lista */
.cash-day-sep {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .625rem 1rem;
    background: #f8fafc;
    border-bottom: 1px solid var(--cash-line);
    font-size: .75rem;
    font-weight: 600;
    color: var(--cash-ink-soft);
    text-transform: capitalize;
    position: sticky;
    top: calc(var(--cash-header-h) + var(--cash-safe-top));
    z-index: 10;
}
/* La pila de días: cada uno es su propia tarjeta, separadas por lo justo para
   que se lean como bloques distintos sin gastar pantalla. */
.cash-lista-dias {
    display: flex;
    flex-direction: column;
    gap: .5rem;
}
.cash-compacto .cash-lista-dias { gap: .375rem; }

/* Cada día, su tarjeta: cabecera pegajosa mientras dura el día y sus filas
   debajo. Siempre abierta y sin control para cerrarla (ver lista_gastos.php).
   `clip` y NO `hidden`, por lo mismo que en .cash-card: `hidden` la convertiría
   en contenedor de scroll y la cabecera sticky dejaría de tomar la ventana
   como referencia. */
.cash-dia {
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow);
    overflow: hidden;
    overflow: clip;
}
/* Sin borde bajo la última fila del día: el borde de la tarjeta ya cierra. */
.cash-dia .cash-expense:last-child,
.cash-dia .cash-swipe:last-child .cash-expense { border-bottom: 0; }

/* Mono como los importes de las filas: caen en la misma columna y con otra
   tipografía el total del día se veía descuadrado respecto a ellos. */
.cash-day-sep-total {
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-variant-numeric: tabular-nums;
    color: var(--cash-ink-faint);
    text-transform: none;
}
.cash-compacto .cash-day-sep { padding: .5rem .875rem; }
.cash-compacto .cash-expense { padding: .625rem .875rem; }

/* =====================================================================
 * FORMULARIOS Y BOTONES
 * ===================================================================== */
.cash-label {
    display: block;
    font-size: .8125rem;
    font-weight: 500;
    color: var(--cash-ink-soft);
    margin-bottom: .375rem;
}
.cash-input {
    display: block;
    width: 100%;
    padding: .625rem .75rem;
    border: 1.5px solid var(--cash-line);
    border-radius: .625rem;
    background: #fff;
    font-size: .9375rem;   /* ≥16px en móvil evitaría el zoom de iOS: ver .cash-input-lg */
    color: var(--cash-ink);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.cash-input:focus {
    outline: none;
    border-color: var(--cash-primary);
    box-shadow: 0 0 0 3px rgba(245, 158, 11, .15);
}
.cash-input::placeholder { color: var(--cash-ink-faint); }
/* background-COLOR y no el shorthand: el shorthand se llevaría por delante la
   flecha de los <select> (es un background-image). Y -webkit-text-fill-color
   porque iOS ignora `color` en los campos apagados y los pinta a su manera. */
.cash-input:disabled {
    background-color: #f8fafc;
    color: var(--cash-ink-faint);
    -webkit-text-fill-color: var(--cash-ink-faint);
    opacity: 1;
}

/* Hueco para el adorno (lupa, €, ojo de la contraseña).
   El hueco lo reserva SIEMPRE una de estas clases, NUNCA las utilidades de
   Tailwind (pl-9, pr-10, pr-11): esta hoja se carga después de Tailwind y su
   `padding` shorthand las pisa a igual especificidad, así que el texto y el
   cursor acababan debajo del icono. */
.cash-input-icono-izq { padding-left: 2.25rem; }
.cash-input-icono-der { padding-right: 2.75rem; }
.cash-input-boton-der { padding-right: 2.75rem; }   /* el ojo mide w-11 */

/* iOS hace zoom al enfocar un input de menos de 16 px: en móvil, 16 px. */
@media (max-width: 1023.98px) {
    .cash-input, .cash-input-lg { font-size: 1rem; }
}

/* Importe: grande, tabular y protagonista en el formulario de alta */
.cash-input-amount {
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
    text-align: right;
    /* Padding por lados y NO en shorthand: `padding` va después de
       .cash-input-icono-der y le reseteaba el hueco del €, así que el importe
       —alineado a la derecha— se metía justo debajo del símbolo. */
    padding-top: .625rem;
    padding-bottom: .625rem;
    padding-left: .875rem;
}

/* ── Controles nativos: correcciones de WebKit / iOS ─────────────────
   Safari pinta date, select y search con su propio box model y se saltan el
   padding, la altura y el radio de .cash-input. En iOS es donde más canta: el
   campo de fecha salía con otra altura que el resto y el valor descolocado
   dentro de la caja. Con `appearance: none` el control vuelve a ser una caja
   normal y todo lo gobierna esta hoja.
   El preflight de Tailwind deja los search en `-webkit-appearance: textfield`
   y los botones en `button`, así que hay que deshacerlo aquí. */
.cash-input,
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="search"],
select.cash-input {
    -webkit-appearance: none;
    appearance: none;
    /* iOS mete una sombra interior propia en los campos: esto la corta. */
    background-clip: padding-box;
}

/* El valor de una fecha no es texto del input: vive en su propio pseudo, que
   en iOS viene centrado y con márgenes. Eso es lo que se veía deforme. */
input[type="date"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value,
input[type="month"]::-webkit-date-and-time-value {
    text-align: left;
    margin: 0;
    /* Sin valor el pseudo no ocupa nada y el campo se encoge de golpe. */
    min-height: 1.2em;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
    /* El control nativo no se estira solo: sin esto se queda con el ancho
       intrínseco del formato y deja media caja muerta. */
    min-width: 0;
    /* La misma caja que un campo de texto, que si no cada uno mide una cosa. */
    min-height: 2.625rem;
    text-align: left;
}
/* En Safari de escritorio el icono del calendario se pinta pegado al texto. */
input[type="date"]::-webkit-calendar-picker-indicator {
    opacity: .45;
    cursor: pointer;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: .75; }

/* Con la flecha nativa fuera hay que poner una propia, o el desplegable no se
   distingue de un campo de texto. SVG en línea: nada que descargar, que la
   PWA instalada tiene que pintar esto sin red. */
select.cash-input {
    padding-right: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .75rem center;
    background-size: 1rem 1rem;
    /* iOS centra el texto de los select largos si no se le dice lo contrario. */
    text-align: left;
}

/* La lupa y el aspa que Safari pinta por su cuenta en los buscadores se
   comen el padding y el radio del campo. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration {
    -webkit-appearance: none;
    appearance: none;
}

/* Sin esto, un <button> sin fondo propio (.cash-btn-ghost, .cash-icon-btn)
   se lleva en iOS el chrome nativo: borde gris y esquinas de sistema. */
.cash-btn,
.cash-icon-btn,
button,
input[type="submit"] {
    -webkit-appearance: none;
    appearance: none;
}

.cash-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .625rem 1.125rem;
    border-radius: .625rem;
    font-size: .875rem;
    font-weight: 600;
    transition: background-color .15s ease, box-shadow .15s ease, transform .1s ease, color .15s ease;
    white-space: nowrap;
}
.cash-btn:active { transform: translateY(1px); }
.cash-btn:disabled { opacity: .55; pointer-events: none; }

.cash-btn-primary {
    background: linear-gradient(160deg, var(--cash-primary), var(--cash-primary-dark));
    color: #fff;
    box-shadow: 0 2px 8px -2px rgba(217, 119, 6, .5);
}
.cash-btn-primary:hover {
    background: linear-gradient(160deg, var(--cash-primary-dark), var(--cash-primary-deep));
    box-shadow: 0 4px 14px -4px rgba(217, 119, 6, .6);
}
.cash-btn-secondary {
    background: #fff;
    color: var(--cash-ink-soft);
    border: 1.5px solid var(--cash-line);
}
.cash-btn-secondary:hover { background: #f8fafc; color: var(--cash-ink); border-color: #cbd5e1; }
.cash-btn-ghost { color: var(--cash-ink-soft); }
.cash-btn-ghost:hover { background: #f1f5f9; color: var(--cash-ink); }
.cash-btn-danger { background: var(--cash-danger); color: #fff; }
.cash-btn-danger:hover { background: #be123c; }

/* Segmentado (formas de pago, filtros de periodo) */
.cash-segment {
    display: inline-flex;
    padding: .25rem;
    background: #f1f5f9;
    border-radius: .75rem;
    gap: .125rem;
}
.cash-segment-item {
    flex: 1;
    padding: .5rem .875rem;
    border-radius: .5rem;
    font-size: .8125rem;
    font-weight: 500;
    color: var(--cash-ink-soft);
    text-align: center;
    transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
    white-space: nowrap;
}
.cash-segment-item.is-active {
    background: #fff;
    color: var(--cash-ink);
    font-weight: 600;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .12);
}

/* Botón flotante de alta (móvil) */
.cash-fab {
    position: fixed;
    right: 1.125rem;
    bottom: calc(1.125rem + var(--cash-safe-bottom));
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    color: #fff;
    font-size: 1.25rem;
    background: linear-gradient(160deg, var(--cash-primary), var(--cash-primary-dark));
    box-shadow: 0 6px 20px -6px rgba(217, 119, 6, .75), 0 2px 6px rgba(15, 23, 42, .12);
    z-index: 30;
    transition: transform .16s cubic-bezier(.34, 1.56, .64, 1);
}
.cash-fab:active { transform: scale(.92); }
@media (min-width: 1024px) { .cash-fab { display: none; } }

/* ── Interruptor iOS ─────────────────────────────────────────────────── */
.ios-toggle {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    width: 2.875rem;
    height: 1.625rem;
    border-radius: 999px;
    background: #cbd5e1;
    cursor: pointer;
    transition: background-color .2s ease;
    flex: none;
}
.ios-toggle::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .3);
    transition: transform .2s cubic-bezier(.4, 0, .2, 1);
}
.ios-toggle:checked { background: var(--cash-primary); }
.ios-toggle:checked::after { transform: translateX(1.25rem); }
.ios-toggle:disabled { opacity: .5; cursor: not-allowed; }

/* ── Estado vacío ────────────────────────────────────────────────────── */
.cash-empty {
    text-align: center;
    padding: 3rem 1.5rem;
    color: var(--cash-ink-faint);
}
.cash-empty i { font-size: 2.25rem; opacity: .35; margin-bottom: .875rem; display: block; }
.cash-empty-title { font-size: .9375rem; font-weight: 600; color: var(--cash-ink-soft); margin-bottom: .25rem; }
.cash-empty-text { font-size: .8125rem; }

/* ── Modales ─────────────────────────────────────────────────────────
   Dos formatos, y ninguno es ya la hoja inferior con tirador:

     · Centrado (por defecto) — tarjeta en medio de la pantalla, igual en
       móvil que en escritorio. La usan el alta de gasto y el selector de mes.
     · Pantalla completa (.is-full en el overlay) — ocupa todo y se comporta
       como una página: cabecera con flecha atrás, cuerpo que rueda y pie de
       botones anclado abajo. La usan usuario, local, perfil y contraseña.

   En los dos, la estructura es flex en columna y SOLO rueda el cuerpo: la
   cabecera y el pie no se van de la vista, así el botón Guardar está siempre
   a mano por largo que sea el formulario. */
.cash-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 70;
    background: rgba(15, 23, 42, .45);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.cash-modal {
    display: flex;
    flex-direction: column;
    background: #fff;
    width: 100%;
    max-width: 30rem;
    max-height: 100%;
    border-radius: 1.125rem;
    overflow: hidden;
    box-shadow: 0 24px 60px -20px rgba(15, 23, 42, .45);
}

/* Casi todos los modales meten cuerpo y pie dentro de un <form>: si el form
   no es flex, el cuerpo no sabe cuánto puede rodar y el pie se va fuera. */
.cash-modal > form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.cash-modal-head {
    flex: none;
    padding: 1rem 1.25rem .875rem;
    border-bottom: 1px solid var(--cash-line);
    background:
        linear-gradient(to bottom, rgba(245, 158, 11, .13), rgba(245, 158, 11, 0)),
        #fff;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
}
.cash-modal-title {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--cash-ink);
}
.cash-modal-title i { color: var(--cash-primary-dark); font-size: .9375rem; }
/* El título puede ser el nombre de un local: que se corte, no que empuje a la
   flecha de volver fuera de la cabecera. */
.cash-modal-title > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cash-modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 1.25rem;
}

.cash-modal-foot {
    flex: none;
    display: flex;
    gap: .625rem;
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--cash-line);
    background: #fff;
}
.cash-modal-foot .cash-btn { flex: 1; }

/* ── Formato pantalla completa ───────────────────────────────────────
   Sin velo ni sombra: no hay nada detrás que enseñar, es una pantalla. */
.cash-modal-overlay.is-full {
    padding: 0;
    align-items: stretch;
    background: #fff;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}
.cash-modal-overlay.is-full .cash-modal {
    max-width: none;
    max-height: none;
    height: 100%;
    border-radius: 0;
    box-shadow: none;
}
/* La flecha de volver va primero y el título a continuación, como en la
   cabecera de cualquier pantalla de app. */
.cash-modal-overlay.is-full .cash-modal-head {
    justify-content: flex-start;
    padding-top: calc(1rem + var(--cash-safe-top));
}
.cash-modal-overlay.is-full .cash-modal-foot {
    padding-bottom: calc(1rem + var(--cash-safe-bottom));
}

/* En pantalla ancha la página sigue ocupándolo todo, pero el formulario no se
   estira de lado a lado: se queda en una columna legible y centrada. El hueco
   va en el padding y no en un max-width para que la línea de la cabecera y la
   del pie sigan llegando a los dos bordes. */
@media (min-width: 640px) {
    .cash-modal-overlay.is-full .cash-modal-head,
    .cash-modal-overlay.is-full .cash-modal-body,
    .cash-modal-overlay.is-full .cash-modal-foot {
        padding-inline: max(1.5rem, calc((100% - 36rem) / 2));
    }
}

/* ── Desglose por forma de pago ──────────────────────────────────────
   Tres tarjetas SIEMPRE en una fila, también en el móvil más estrecho.
   El importe es lo que se lee, así que manda: la etiqueta se encoge y, si
   aun así no cabe, se recorta ella. */
.cash-pagos {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .375rem;
    margin-bottom: 1rem;
}

/* Una sola línea: icono e importe. La etiqueta se fue —el icono con su color
   ya dice de qué forma de pago se trata— y la tarjeta baja a la mitad de alto. */
.cash-pago-card {
    min-width: 0;                /* sin esto, el contenido impide encoger */
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .3125rem;
    padding: .375rem .5rem;
    border: 1px solid var(--cash-line);
    border-radius: .5rem;
    background: #fff;
}
.cash-pago-card.is-vacio { opacity: .45; }
.cash-pago-card > i { flex: none; font-size: .6875rem; color: var(--cash-ink-faint); }

/* El color del icono es el de su forma de pago, el mismo de las filas */
.cash-pago-card.is-efectivo > i      { color: #047857; }
.cash-pago-card.is-tarjeta > i       { color: #1d4ed8; }
.cash-pago-card.is-transferencia > i { color: #6d28d9; }

/* Mono y estrechado: en tres columnas de móvil, un importe de cinco cifras
   solo cabe si las cifras ocupan lo justo. */
.cash-pago-total {
    min-width: 0;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: .75rem;
    font-weight: 700;
    font-stretch: condensed;
    letter-spacing: -.06em;
    color: var(--cash-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* De 380 px para arriba ya sobra sitio: se puede respirar */
@media (min-width: 380px) {
    .cash-pagos { gap: .5rem; }
    .cash-pago-card { padding: .4375rem .625rem; }
    .cash-pago-total { font-size: .8125rem; }
}
@media (min-width: 1024px) {
    .cash-pago-card { padding: .5rem .875rem; gap: .5rem; }
    .cash-pago-card > i { font-size: .8125rem; }
    .cash-pago-total { font-size: .9375rem; letter-spacing: -.04em; }
}


/* ── Detalle de un gasto ─────────────────────────────────────────────
   Lo que la fila de la lista no tiene sitio para enseñar, en un modal
   centrado y estrecho. Clases propias y no utilidades de Tailwind: este
   markup lo construye lista_gastos.js y así no depende del build. */
.cash-detalle-importe {
    text-align: center;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--cash-ink);
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
}
.cash-detalle-desc {
    margin-top: .375rem;
    text-align: center;
    font-size: .9375rem;
    color: var(--cash-ink-soft);
    overflow-wrap: anywhere;
}
.cash-detalle-lista {
    margin-top: 1.125rem;
    border-top: 1px solid var(--cash-line);
}
.cash-detalle-lista > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .5625rem 0;
    border-bottom: 1px solid #f1f5f9;
    font-size: .8125rem;
}
.cash-detalle-lista > div:last-child { border-bottom: 0; }
.cash-detalle-lista dt { color: var(--cash-ink-faint); flex: none; }
.cash-detalle-lista dd {
    min-width: 0;
    text-align: right;
    font-weight: 500;
    color: var(--cash-ink);
    overflow-wrap: anywhere;
}
.cash-detalle-lista dd i { margin-right: .375rem; font-size: .75rem; }
.cash-detalle-ticket { width: 100%; margin-top: 1rem; }

/* ── Resumen del mes (inicio) ────────────────────────────────────────
   Contenedor suave: el selector de mes a un lado y el total del mes al otro.
   Sustituye al título «Gastos» con el mes debajo — el mes ya lo dice el
   propio selector y decirlo dos veces solo gastaba altura de pantalla. */
.cash-resumen {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
    padding: .75rem 1rem;
    background: linear-gradient(to bottom, var(--cash-primary-wash), var(--cash-surface));
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow);
}

/* Sin flechas el nav es solo el rótulo: que ocupe lo suyo y no se estire. */
.cash-resumen .cash-mes-nav { flex: 0 1 auto; min-width: 0; justify-content: flex-start; }
.cash-resumen .cash-mes-actual {
    flex: 0 1 auto;
    max-width: none;
    min-width: 0;
    /* El botón tiene padding propio: sin este tirón el rótulo se vería
       descolgado hacia dentro respecto al borde de la tarjeta. */
    margin-left: -.875rem;
}
.cash-resumen .cash-mes-actual span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cash-resumen-total { flex: none; text-align: right; }
.cash-resumen-label {
    font-size: .6875rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--cash-ink-faint);
}
.cash-resumen-importe {
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.15;
    color: var(--cash-ink);
    font-variant-numeric: tabular-nums;
}
/* En un móvil estrecho el mes y el importe se pelean por el ancho. */
@media (max-width: 380px) {
    .cash-resumen-importe { font-size: 1.25rem; }
}

/* Zona del gesto de cambio de mes. pan-y por lo mismo que en las filas de
   gastos: el desplazamiento vertical sigue siendo del navegador. */
.cash-mes-swipe {
    touch-action: pan-y;
}
.cash-mes-swipe.is-soltando {
    transition: transform .24s cubic-bezier(.22, .61, .36, 1);
}
@media (prefers-reduced-motion: reduce) {
    .cash-mes-swipe.is-soltando { transition: none; }
}

/* =====================================================================
 * ESQUELETO DE CARGA
 * Al cambiar de pantalla, en vez de un modal encima de lo que había, los
 * bloques de lo que va a llegar, en gris y latiendo. Va por ENCIMA del botón
 * flotante (30) y por DEBAJO de la barra superior (40): la app no se va a
 * ninguna parte, solo se está pintando su contenido.
 * ===================================================================== */
.cash-esqueleto {
    position: fixed;
    left: 0;
    right: 0;
    top: calc(var(--cash-header-h) + var(--cash-safe-top));
    bottom: 0;
    z-index: 35;
    background: var(--cash-bg);
    overflow: hidden;
}
.cash-esqueleto-caja { padding: .5rem .5rem 0; }
@media (min-width: 1024px) {
    .cash-esqueleto-caja {
        width: 60%;
        max-width: 1100px;
        min-width: 42rem;
        margin-inline: auto;
        padding: 1rem 0 0;
    }
}

/* El latido: una banda clara que cruza el gris. Con `background-size` grande
   y moviendo la posición se anima sin repintar layout. */
.cash-esq {
    border-radius: .625rem;
    background-color: #e8edf3;
    background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 20%,
                                              rgba(255, 255, 255, .65) 50%,
                                              rgba(255, 255, 255, 0) 80%);
    background-size: 220% 100%;
    background-repeat: no-repeat;
    animation: cash-latido 1.25s ease-in-out infinite;
}
@keyframes cash-latido {
    0%   { background-position: 140% 0; }
    100% { background-position: -40% 0; }
}
/* Sin animación: el gris se queda quieto. Sigue diciendo lo mismo. */
@media (prefers-reduced-motion: reduce) {
    .cash-esq { animation: none; }
}

.cash-esq-cabecera { height: 4rem; margin-bottom: .5rem; border-radius: var(--cash-radius); }

.cash-esq-pagos { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; margin-bottom: .5rem; }
.cash-esq-pago { height: 1.875rem; border-radius: .5rem; }

.cash-esq-card {
    padding: 0 0 .5rem;
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    overflow: hidden;
}
.cash-esq-dia { height: 2rem; border-radius: 0; margin-bottom: .25rem; }

.cash-esq-fila { display: flex; align-items: center; gap: .875rem; padding: .625rem .875rem; }
.cash-esq-icono { flex: none; width: 2.375rem; height: 2.375rem; border-radius: .75rem; }
.cash-esq-txt { flex: 1; min-width: 0; }
.cash-esq-linea { height: .75rem; margin-bottom: .375rem; }
.cash-esq-corta { height: .625rem; margin-bottom: 0; opacity: .7; }

/* El inicio en el móvil no es una lista, son iconos: su esqueleto también. */
.cash-esq-rejilla {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1.25rem .5rem;
    padding: .5rem .25rem;
}
.cash-esq-app { display: flex; flex-direction: column; align-items: center; gap: .5rem; }
.cash-esq-cuadro { width: 100%; aspect-ratio: 1 / 1; border-radius: 22.5%; }
.cash-esq-app .cash-esq-linea { width: 70%; margin-bottom: 0; }

/* Contenido que se va: al soltar el deslizamiento con viaje, la pantalla se
   apaga y vuelve a su sitio ANTES de que salga el loader; si no, el aviso de
   «cargando» aparecía sobre todo corrido a medio deslizar. Lo lleva el <main>
   entero, no solo la zona del gesto. `pointer-events: none` porque a partir de
   ahí ya no hay nada que tocar. */
.cash-saliendo {
    transition: opacity .16s ease-out, transform .16s ease-out;
    opacity: 0;
    pointer-events: none;
}
/* Sin animación, pero apagándose igual: lo que evita el efecto feo es que no
   se vea, no el adorno de la transición. */
@media (prefers-reduced-motion: reduce) {
    .cash-saliendo { transition: none; }
}

/* ── Selector de mes ─────────────────────────────────────────────────
   Flechas para ir de uno en uno; el rótulo central abre el panel. */
.cash-mes-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .25rem;
}

.cash-mes-actual {
    flex: 1;
    max-width: 15rem;
    min-height: 2.5rem;          /* blanco cómodo para el pulgar */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .375rem .875rem;
    border-radius: .625rem;
    font-size: .875rem;
    font-weight: 600;
    color: var(--cash-ink-soft);
    text-transform: capitalize;
    transition: background-color .15s ease, color .15s ease;
}
.cash-mes-actual i {
    font-size: .625rem;
    opacity: .5;
    text-transform: none;
    transition: transform .15s ease;
}
.cash-mes-actual:hover { background: #f1f5f9; color: var(--cash-ink); }
.cash-mes-actual:hover i { opacity: .8; transform: translateY(1px); }
.cash-mes-actual:active { background: var(--cash-line); }

/* Panel más estrecho que un modal normal: solo lleva 12 botones */
.cash-modal-estrecho { max-width: 22rem; }
@media (min-width: 640px) {
    .cash-modal-estrecho { max-width: 20rem; }
}

.cash-mes-anio {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: 1rem;
}
.cash-mes-anio-caja {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1.1;
}
.cash-mes-anio-valor {
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--cash-ink);
    font-variant-numeric: tabular-nums;
}
/* Lo gastado en el año, bajo su cifra. Mono y compacto: es un dato para
   comparar de un vistazo, no un rótulo. */
.cash-mes-anio-total {
    margin-top: .125rem;
    min-height: .875rem;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: .6875rem;
    font-weight: 600;
    color: var(--cash-primary-dark);
    font-variant-numeric: tabular-nums;
}

.cash-mes-rejilla {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .5rem;
}

.cash-mes-btn {
    min-height: 3rem;            /* por encima del mínimo táctil de 44 px */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .0625rem;
    padding: .375rem .25rem;
    border-radius: .75rem;
    border: 1.5px solid var(--cash-line);
    background: #fff;
    font-size: .875rem;
    font-weight: 500;
    color: var(--cash-ink-soft);
    transition: background-color .15s ease, border-color .15s ease, color .15s ease, transform .1s ease;
}
.cash-mes-btn-txt { text-transform: capitalize; line-height: 1.1; }
/* El importe del mes, al pie del propio botón. Reserva su alto aunque el mes
   esté vacío: si no, los botones con gasto serían más altos que el resto y la
   rejilla bailaría al cambiar de año. */
.cash-mes-btn-total {
    min-height: .8125rem;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: .625rem;
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--cash-ink-faint);
    font-variant-numeric: tabular-nums;
}
.cash-mes-btn:hover:not(:disabled) {
    border-color: var(--cash-primary);
    background: var(--cash-primary-wash);
    color: var(--cash-primary-deep);
}
.cash-mes-btn:active:not(:disabled) { transform: scale(.95); }

.cash-mes-btn.is-elegido {
    background: linear-gradient(160deg, var(--cash-primary), var(--cash-primary-dark));
    border-color: transparent;
    color: #fff;
    font-weight: 700;
    box-shadow: 0 2px 8px -2px rgba(217, 119, 6, .5);
}
.cash-mes-btn.is-elegido .cash-mes-btn-total { color: rgba(255, 255, 255, .85); }
.cash-mes-btn:hover:not(:disabled) .cash-mes-btn-total { color: var(--cash-primary-dark); }

/* Apagado, no escondido: así se ve que el año tiene doce meses */
.cash-mes-btn.is-futuro {
    opacity: .3;
    cursor: not-allowed;
    background: #f8fafc;
}

/* ── Visor de ticket (lightbox) ──────────────────────────────────────
   Una foto de ticket se abre para LEERLA: pantalla completa sobre fondo
   oscuro, sin marco ni botonera que le quiten sitio. */
.cash-visor {
    position: fixed;
    inset: 0;
    z-index: 80;
    background: rgba(9, 9, 11, .93);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3.5rem 1rem calc(1rem + var(--cash-safe-bottom));
}
.cash-visor-img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: .5rem;
    /* La foto se mira, no se arrastra sin querer al hacer scroll */
    -webkit-user-select: none;
    user-select: none;
}
.cash-visor-barra {
    position: absolute;
    top: calc(.75rem + var(--cash-safe-top));
    right: .75rem;
    display: flex;
    gap: .5rem;
}
.cash-visor-btn {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    color: #fff;
    font-size: 1rem;
    background: rgba(255, 255, 255, .14);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition: background-color .15s ease;
}
.cash-visor-btn:hover { background: rgba(255, 255, 255, .26); }

/* =====================================================================
 * AJUSTES A DOS PANELES (escritorio)
 * Izquierda las secciones, derecha el contenido de la elegida. En móvil
 * no hay sitio para dos columnas: allí manda el segmentado de arriba.
 * ===================================================================== */
.cash-ajustes { display: grid; gap: 1rem; }

@media (min-width: 1024px) {
    .cash-ajustes {
        grid-template-columns: 16rem minmax(0, 1fr);
        gap: 1.5rem;
        /* `start` y no el `stretch` por defecto: sin esto la columna de las
           secciones se estiraría hasta el alto de la lista de la derecha. */
        align-items: start;
    }
}

.cash-ajustes-nav {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    padding: .5rem;
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow);
    position: sticky;
    top: calc(var(--cash-header-h) + var(--cash-safe-top) + 1.75rem);
}

.cash-ajustes-op {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    padding: .75rem .875rem;
    border: 1px solid transparent;
    border-radius: var(--cash-radius);
    text-align: left;
    color: var(--cash-ink-soft);
    transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.cash-ajustes-op:hover { background: #f8fafc; border-color: var(--cash-line); }
/* Dentro de un panel que ya tiene sombra, la sección elegida se marca con el
   lavado ámbar y su filete; otra sombra encima ensuciaría. */
.cash-ajustes-op.is-active {
    background: var(--cash-primary-wash);
    border-color: var(--cash-primary-soft);
    color: var(--cash-primary-deep);
}

.cash-ajustes-op-icono {
    flex: none;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: .75rem;
    display: grid;
    place-items: center;
    font-size: .875rem;
    background: #f1f5f9;
    color: var(--cash-ink-soft);
    transition: background-color .15s ease, color .15s ease;
}
.cash-ajustes-op.is-active .cash-ajustes-op-icono {
    background: var(--cash-primary-soft);
    color: var(--cash-primary-deep);
}

.cash-ajustes-op-txt { min-width: 0; }
.cash-ajustes-op-nombre { font-size: .875rem; font-weight: 600; color: inherit; }
.cash-ajustes-op-sub { font-size: .75rem; color: var(--cash-ink-faint); }

/* Etiqueta pálida para un dato de apoyo dentro de una línea (el recuento de
   locales de un usuario, por ejemplo). No es un estado ni una acción: por eso
   ni color de marca ni borde fuerte. */
.cash-badge {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .0625rem .4375rem;
    border-radius: 999px;
    background: #f1f5f9;
    font-size: .625rem;
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--cash-ink-soft);
    white-space: nowrap;
    flex: none;
}

/* ── Avisos en pastilla ──────────────────────────────────────────────
   El texto que explica una sección va en su propia línea y sobre fondo
   pálido: así se lee como una nota y no compite con los controles. */
.cash-aviso {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    margin-bottom: .75rem;
    padding: .625rem .875rem;
    border: 1px solid var(--cash-primary-soft);
    border-radius: .75rem;
    background: var(--cash-primary-wash);
    color: var(--cash-primary-deep);
    font-size: .8125rem;
    line-height: 1.45;
}
.cash-aviso i { flex: none; margin-top: .15rem; color: var(--cash-primary); font-size: .8125rem; }

/* Variante apagada para las notas al pie, que no piden atención */
.cash-aviso.is-neutro {
    border-color: var(--cash-line);
    background: #f8fafc;
    color: var(--cash-ink-soft);
    font-size: .75rem;
}
.cash-aviso.is-neutro i { color: var(--cash-ink-faint); }

/* =====================================================================
 * EXPLORADOR DEL INICIO (escritorio)
 * Árbol de años y meses a la izquierda, gastos del periodo a la derecha.
 * En móvil no existe: allí la pantalla de inicio es la rejilla de iconos.
 * ===================================================================== */
.cash-explorador {
    display: grid;
    grid-template-columns: 17.5rem minmax(0, 1fr);
    gap: 1.25rem;
    align-items: start;
}
@media (min-width: 1600px) {
    .cash-explorador { grid-template-columns: 20rem minmax(0, 1fr); gap: 1.75rem; }
}

/* La cabecera del periodo cruza las dos columnas: así el árbol y la lista
   arrancan a la misma altura justo debajo. El margen inferior lo pone ya el
   `gap` de la rejilla; el propio de .cash-resumen sobraría. */
.cash-explorador-cab { grid-column: 1 / -1; margin-bottom: 0; }

/* ── El árbol de carpetas ─────────────────────────────────────────────
   Se maneja como el de un explorador de archivos —años que se pliegan y
   despliegan, meses dentro— pero vestido como el resto de la app: tarjeta
   blanca, ámbar para lo elegido y la misma tipografía. */
.cash-arbol {
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    box-shadow: var(--cash-shadow);
    overflow: hidden;
    overflow: clip;
    position: sticky;
    top: calc(var(--cash-header-h) + var(--cash-safe-top) + 1.75rem);
}

.cash-arbol-barra {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--cash-line);
    background: linear-gradient(to bottom, var(--cash-primary-wash), var(--cash-surface));
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--cash-ink-faint);
}
.cash-arbol-barra i { color: var(--cash-primary); font-size: .75rem; }

/* Atajo al mes en curso: el árbol solo enseña meses con gastos, así que sin
   esto no habría forma de volver a hoy cuando el mes está a cero. */
.cash-arbol-hoy {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .1875rem .5rem;
    border: 1px solid var(--cash-primary-soft);
    border-radius: 999px;
    background: var(--cash-surface);
    font-size: .625rem;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--cash-primary-deep);
    transition: background-color .15s ease, border-color .15s ease;
}
.cash-arbol-hoy:hover { background: var(--cash-primary-wash); border-color: var(--cash-primary); }
.cash-arbol-hoy.is-active { background: var(--cash-primary-wash); border-color: var(--cash-primary); }
.cash-arbol-hoy i { font-size: .625rem; }

.cash-arbol-caja {
    padding: .5rem;
    /* Que el árbol nunca empuje la página: si hay muchos años, scroll suyo. */
    max-height: calc(100vh - var(--cash-header-h) - 11rem);
    overflow: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
}
.cash-arbol-caja::-webkit-scrollbar { width: 10px; }
.cash-arbol-caja::-webkit-scrollbar-track { background: transparent; }
.cash-arbol-caja::-webkit-scrollbar-thumb {
    background: var(--cash-line);
    border: 3px solid var(--cash-surface);
    border-radius: 999px;
}

.cash-arbol-lista, .cash-arbol-hijos { list-style: none; margin: 0; padding: 0; }
.cash-arbol-fila { display: flex; align-items: center; }

/* El triángulo de plegar: gira 90° al abrirse, como en cualquier árbol. */
.cash-arbol-toggle {
    flex: none;
    width: 1.375rem;
    height: 1.75rem;
    display: grid;
    place-items: center;
    border-radius: .5rem;
    color: var(--cash-ink-faint);
    font-size: .625rem;
    transition: color .15s ease, background-color .15s ease;
}
.cash-arbol-toggle:hover { color: var(--cash-ink); background: #f1f5f9; }
.cash-arbol-toggle i { transition: transform .18s ease; }
.cash-arbol-toggle.is-open i { transform: rotate(90deg); }

.cash-arbol-nombre {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex: 1;
    min-width: 0;
    padding: .375rem .5rem;
    border-radius: .625rem;
    text-align: left;
    font-size: .8125rem;
    font-weight: 500;
    color: var(--cash-ink-soft);
    transition: background-color .15s ease, color .15s ease;
}
.cash-arbol-nombre:hover { background: #f8fafc; color: var(--cash-ink); }
.cash-arbol-nombre.is-active {
    background: var(--cash-primary-wash);
    color: var(--cash-primary-deep);
    font-weight: 600;
    box-shadow: inset 0 0 0 1px var(--cash-primary-soft);
}
/* El año, un peldaño por encima de sus meses */
.cash-arbol-anio { font-weight: 600; color: var(--cash-ink); }

.cash-arbol-icono { flex: none; width: 1rem; text-align: center; color: var(--cash-primary); font-size: .8125rem; }
.cash-arbol-nombre.is-active .cash-arbol-icono { color: var(--cash-primary-dark); }
.cash-arbol-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cash-arbol-total {
    margin-left: auto;
    padding-left: .5rem;
    font-size: .6875rem;
    font-weight: 500;
    color: var(--cash-ink-faint);
    font-variant-numeric: tabular-nums;
}
.cash-arbol-nombre.is-active .cash-arbol-total { color: var(--cash-primary-dark); }

/* Sin gastos no hay carpetas: se dice, en vez de dejar la caja en blanco. */
.cash-arbol-vacio {
    padding: .5rem .25rem;
    font-size: .75rem;
    line-height: 1.5;
    color: var(--cash-ink-faint);
}

/* Los meses cuelgan del año con una guía fina, lo justo para leer la jerarquía */
.cash-arbol-hijos {
    margin-left: 1.375rem;
    padding-left: .5rem;
    border-left: 1px solid var(--cash-line);
}

/* ── Pastillas de local ──────────────────────────────────────────────
   Todas del mismo ancho y llenando el panel: rejilla de columnas iguales
   que se parten en las líneas que hagan falta. `auto-fit` para que las
   pistas sobrantes se colapsen y las que quedan se repartan el ancho. */
.cash-pills {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: .5rem;
    margin-bottom: .875rem;
}

.cash-pill {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
    padding: .5rem .75rem;
    border: 1px solid var(--cash-line);
    border-radius: 999px;
    background: var(--cash-surface);
    font-size: .8125rem;
    color: var(--cash-ink-soft);
    transition: border-color .15s ease, background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.cash-pill:hover { border-color: var(--cash-primary); color: var(--cash-ink); }
.cash-pill.is-active {
    border-color: var(--cash-primary);
    background: var(--cash-primary-wash);
    color: var(--cash-primary-deep);
    box-shadow: 0 0 0 1px var(--cash-primary) inset;
    font-weight: 600;
}

.cash-pill-icono {
    flex: none;
    width: 1.375rem;
    height: 1.375rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: .625rem;
    color: #fff;
    background: linear-gradient(160deg, var(--icon-from, #fbbf24), var(--icon-to, #b45309));
}
.cash-pill-txt { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cash-pill-num {
    flex: none;
    font-size: .6875rem;
    font-weight: 600;
    color: var(--cash-ink-faint);
    font-variant-numeric: tabular-nums;
}
.cash-pill.is-active .cash-pill-num { color: var(--cash-primary-dark); }

/* Cabecera del panel derecho: periodo y local a un lado, total y alta al otro */
.cash-panel-titulo {
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -.015em;
    color: var(--cash-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cash-panel-acciones { display: flex; align-items: center; gap: 1rem; flex: none; }

/* =====================================================================
 * REGISTRO DE ACTIVIDAD (pages/logs.php · solo administradores)
 * Filas grandes y tocables: en el móvil se abren con el pulgar sin apuntar.
 * ===================================================================== */
.cash-log {
    display: flex;
    align-items: center;
    gap: .875rem;
    width: 100%;
    /* 3,5 rem de alto mínimo: el blanco de toque cómodo en táctil. */
    min-height: 3.5rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid #f1f5f9;
    text-align: left;
    background: var(--cash-surface);
    transition: background-color .12s ease;
}
.cash-log:last-child { border-bottom: 0; }
.cash-log:hover { background: #fafbfc; }
.cash-log:active { background: #f1f5f9; }

.cash-log-icono {
    flex: none;
    width: 2.375rem;
    height: 2.375rem;
    border-radius: .75rem;
    display: grid;
    place-items: center;
    font-size: .875rem;
}
/* Un tono por tipo de hecho: lo bueno, lo que cambia, lo que quita y lo neutro */
.cash-log-icono.is-ok      { background: #ecfdf5; color: #047857; }
.cash-log-icono.is-aviso   { background: var(--cash-primary-wash); color: var(--cash-primary-deep); }
.cash-log-icono.is-peligro { background: #fff1f2; color: var(--cash-danger); }
.cash-log-icono.is-neutro  { background: #f1f5f9; color: var(--cash-ink-soft); }

.cash-log-txt { min-width: 0; flex: 1; }
.cash-log-resumen {
    display: block;
    font-size: .9375rem;
    color: var(--cash-ink);
    line-height: 1.35;
}
.cash-log-meta {
    display: flex;
    align-items: center;
    gap: .375rem;
    margin-top: .125rem;
    font-size: .75rem;
    color: var(--cash-ink-faint);
    min-width: 0;
}
.cash-log-chip {
    flex: none;
    padding: .0625rem .375rem;
    border-radius: 999px;
    background: #f1f5f9;
    font-size: .625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--cash-ink-soft);
}
.cash-log-flecha { flex: none; font-size: .75rem; color: #cbd5e1; }

/* ── Ficha de una línea ─────────────────────────────────────────────── */
.cash-log-detalle-resumen {
    font-size: .9375rem;
    color: var(--cash-ink);
    line-height: 1.45;
    margin-bottom: 1rem;
}
.cash-log-datos { display: flex; flex-direction: column; gap: .5rem; }
.cash-log-dato {
    display: flex;
    align-items: baseline;
    gap: .75rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid #f1f5f9;
    font-size: .8125rem;
}
.cash-log-dato:last-child { border-bottom: 0; padding-bottom: 0; }
.cash-log-dato dt {
    flex: none;
    width: 6rem;
    color: var(--cash-ink-faint);
    font-weight: 500;
}
/* Un user-agent no tiene espacios donde partir: se corta por donde sea antes
   de desbordar la ficha a lo ancho. */
.cash-log-dato dd { min-width: 0; color: var(--cash-ink); overflow-wrap: anywhere; }

.cash-log-seccion {
    margin: 1.25rem 0 .5rem;
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--cash-ink-faint);
}
.cash-log-pre {
    margin: 0;
    padding: .75rem .875rem;
    border: 1px solid var(--cash-line);
    border-radius: .75rem;
    background: #f8fafc;
    font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
                 'Liberation Mono', 'Courier New', monospace;
    font-size: .75rem;
    line-height: 1.5;
    color: var(--cash-ink-soft);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 18rem;
    overflow: auto;
}

/* ── Paginación ─────────────────────────────────────────────────────── */
.cash-paginacion {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-top: 1rem;
}
.cash-paginacion-pos { font-size: .8125rem; color: var(--cash-ink-faint); text-align: center; }
/* El extremo de la lista: el botón sigue ahí para que la fila no baile, pero
   ni se pulsa ni se lleva el foco. */
.cash-paginacion .is-inerte { opacity: .35; pointer-events: none; }

/* =====================================================================
 * ACTIVOS Y FONDOS
 * Las dos fichas comparten la rejilla del inicio, así que lo que las
 * distingue tiene que ser la CIFRA, no el hueco: un activo enseña lo
 * gastado en un badge sobre el icono y un fondo su saldo debajo, en una
 * línea propia. El saldo es el dato principal de un fondo; el gasto del
 * mes es un apunte sobre el icono de un activo.
 * ===================================================================== */

/* Rótulo que separa los dos grupos de la rejilla. Solo aparece cuando hay
   los dos: con un grupo solo, titularlo sobra. */
.cash-grupo-titulo {
    display: flex;
    align-items: center;
    gap: .375rem;
    margin: 1.25rem .5rem .5rem;
    font-size: .6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--cash-ink-faint);
}
.cash-grupo-titulo:first-child { margin-top: .25rem; }
.cash-grupo-titulo i { font-size: .75rem; opacity: .8; }

/* El saldo, bajo el nombre del fondo. A cero también se pinta: «no queda
   nada» es información, a diferencia de un mes sin gastos. */
.cash-app-saldo {
    display: block;
    margin-top: .0625rem;
    font-size: .6875rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--cash-success);
    line-height: 1.2;
}
.cash-app-saldo.is-negativo { color: var(--cash-danger); }

/* Un activo desactivado sigue saliendo si tuvo gastos en el mes que se
   mira —su histórico cuenta—, pero se ve que ya no está de alta. */
.cash-app.is-inactivo .cash-app-icon { filter: grayscale(1); opacity: .5; }
.cash-app.is-inactivo .cash-app-label { color: var(--cash-ink-faint); }

/* Saldo en cualquier otro sitio (cabecera de la ficha, Ajustes). */
.cash-saldo { color: var(--cash-success); font-variant-numeric: tabular-nums; }
.cash-saldo.is-negativo { color: var(--cash-danger); }

/* ── «Disponible»: el total de todos los fondos ──────────────────────
   Corona la cabecera del inicio y comparte tarjeta con ella: se pega por
   arriba (sin redondear abajo, sin borde inferior) y la cabecera renuncia a
   sus esquinas superiores. Las dos cifras responden a preguntas distintas y
   por eso van juntas y en este orden: arriba lo que QUEDA, debajo lo que se
   ha ido este mes. */
.cash-disponible {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .5rem 1rem;
    background: linear-gradient(to bottom, #f0fdf4, var(--cash-primary-wash));
    border: 1px solid var(--cash-line);
    border-bottom: 0;
    border-radius: var(--cash-radius) var(--cash-radius) 0 0;
    box-shadow: var(--cash-shadow);
}
/* Al ir pegadas, la de abajo pierde sus esquinas de arriba. */
.cash-disponible + .cash-resumen {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}
.cash-compacto .cash-disponible { padding: .4375rem .875rem; }

.cash-disponible-label {
    display: flex;
    align-items: center;
    gap: .375rem;
    min-width: 0;
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--cash-ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cash-disponible-label i { flex: none; font-size: .75rem; color: var(--cash-success); }

.cash-disponible-cifra {
    flex: none;
    font-size: 1.0625rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.01em;
    color: var(--cash-success);
    line-height: 1.2;
}
.cash-disponible-cifra.is-negativo { color: var(--cash-danger); }

@media (max-width: 380px) {
    /* En lo más estrecho, la cifra tiene que caber entera. */
    .cash-disponible-cifra { font-size: .9375rem; }
}

/* ── Tira de fondos del explorador (escritorio) ─────────────────────── */
.cash-fondos-tira {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: .625rem;
}
.cash-fondo-card {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .5rem .75rem .5rem .5rem;
    border: 1px solid var(--cash-line);
    border-radius: .75rem;
    background: var(--cash-surface);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.cash-fondo-card:hover {
    border-color: var(--cash-primary);
    box-shadow: var(--cash-shadow);
}
.cash-fondo-card-nombre {
    display: block;
    font-size: .75rem;
    color: var(--cash-ink-faint);
    line-height: 1.2;
    white-space: nowrap;
}
.cash-fondo-card-saldo {
    display: block;
    font-size: .9375rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--cash-success);
    line-height: 1.25;
    white-space: nowrap;
}
.cash-fondo-card-saldo.is-negativo { color: var(--cash-danger); }

/* =====================================================================
 * FICHA DE UN FONDO
 * ===================================================================== */

/* Las cuatro casillas se leen como una frase: venías con X, entró Y,
   sacaste Z y los gastos se llevaron W. Cuatro columnas fijas para que
   el orden de la frase no cambie al cambiar el ancho. */
.cash-flujo {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: .375rem;
    margin-bottom: .625rem;
}
.cash-flujo-card {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    padding: .5rem .5rem .5625rem;
    border: 1px solid var(--cash-line);
    border-radius: .625rem;
    background: var(--cash-surface);
    min-width: 0;
}
.cash-flujo-card.is-vacio { opacity: .45; }
.cash-flujo-label {
    display: flex;
    align-items: center;
    gap: .25rem;
    font-size: .625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--cash-ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cash-flujo-label i { font-size: .625rem; flex: none; }
.cash-flujo-card.is-entrada .cash-flujo-label i { color: var(--cash-success); }
.cash-flujo-card.is-salida  .cash-flujo-label i { color: #b45309; }
.cash-flujo-card.is-gasto   .cash-flujo-label i { color: var(--cash-importe); }
.cash-flujo-total {
    font-size: .875rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--cash-ink);
    line-height: 1.15;
}
.cash-flujo-total.is-negativo { color: var(--cash-danger); }

@media (max-width: 420px) {
    /* En pantallas estrechas cuatro columnas dejan los importes ilegibles:
       pasan a dos filas de dos y se sigue leyendo en el mismo orden. */
    .cash-flujo { grid-template-columns: repeat(2, 1fr); }
}

/* Cierre de la frase: cuánto se movió el fondo en todo el mes. */
.cash-neto {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: .625rem;
    padding: 0 .25rem;
    font-size: .75rem;
    color: var(--cash-ink-faint);
}
.cash-neto strong {
    font-size: .9375rem;
    font-variant-numeric: tabular-nums;
    color: var(--cash-ink);
}
.cash-neto strong.is-positivo { color: var(--cash-success); }
.cash-neto strong.is-negativo { color: var(--cash-danger); }

/* Iconos de los movimientos manuales, en la lista del fondo. */
.cash-mov-entrada { background: #ecfdf5; color: #047857; }
.cash-mov-salida  { background: #fff7ed; color: #b45309; }

/* Un importe que ENTRA no puede pintarse del rojo de un gasto. */
.cash-expense-amount.is-entrada { color: var(--cash-success); }
.cash-day-sep-total.is-negativo { color: var(--cash-danger); }

/* =====================================================================
 * GASTOS DIFERIDOS
 * Van encima de la lista del mes y fuera de ella: no son gasto de este
 * mes, son un compromiso que sigue vivo. Lo que entra en la lista son
 * sus pagos.
 * ===================================================================== */
.cash-difs { margin-bottom: .75rem; }
.cash-difs-ver {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    margin-top: .375rem;
    padding: .25rem .25rem;
    font-size: .75rem;
    font-weight: 500;
    color: var(--cash-primary-dark);
}
.cash-difs-ver:hover { color: var(--cash-primary-deep); }

.cash-diferido {
    padding: .75rem .875rem .875rem;
    margin-bottom: .375rem;
    border: 1px solid var(--cash-line);
    border-radius: var(--cash-radius);
    background: var(--cash-surface);
    box-shadow: var(--cash-shadow);
}
.cash-diferido.is-cerrado { opacity: .6; }
.cash-diferido.is-exceso { border-color: #fecdd3; }

.cash-diferido-cab {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: .75rem;
}
.cash-diferido-desc {
    display: flex;
    align-items: center;
    gap: .375rem;
    font-size: .875rem;
    font-weight: 600;
    color: var(--cash-ink);
    line-height: 1.3;
}
.cash-diferido-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem;
    margin-top: .125rem;
    font-size: .75rem;
    color: var(--cash-ink-faint);
}
.cash-diferido-acciones {
    display: flex;
    align-items: center;
    gap: .25rem;
    flex: none;
}
.cash-diferido-acciones .cash-btn { padding: .375rem .625rem; font-size: .75rem; }

/* Total, pagado y pendiente, en ese orden y siempre en tres columnas: se
   leen como una frase y cambiar su sitio obligaría a releerlas. */
.cash-diferido-cifras {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: .5rem;
    margin: .625rem 0 .5rem;
}
.cash-diferido-cifras > div { min-width: 0; }
.cash-diferido-label {
    display: block;
    font-size: .625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--cash-ink-faint);
}
.cash-diferido-valor {
    display: block;
    margin-top: .0625rem;
    font-size: .875rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--cash-ink);
    line-height: 1.2;
}
.cash-diferido-valor.is-pagado    { color: var(--cash-success); }
.cash-diferido-valor.is-pendiente { color: var(--cash-importe); }
.cash-diferido-valor.is-exceso    { color: var(--cash-danger); }

.cash-progreso {
    height: .375rem;
    border-radius: 999px;
    background: #f1f5f9;
    overflow: hidden;
}
.cash-progreso-barra {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--cash-primary), var(--cash-primary-dark));
    transition: width .3s ease;
}
.cash-diferido.is-exceso .cash-progreso-barra {
    background: linear-gradient(90deg, #fb7185, var(--cash-danger));
}

/* Marca de «esto es un plazo» en la fila de un gasto. */
.cash-chip-dif {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .0625rem .375rem;
    border-radius: 999px;
    background: var(--cash-primary-wash);
    border: 1px solid var(--cash-primary-soft);
    font-size: .625rem;
    font-weight: 600;
    color: var(--cash-primary-deep);
    white-space: nowrap;
    flex: none;
}
.cash-chip-dif i { font-size: .5625rem; }

/* =====================================================================
 * MENÚS FLOTANTES
 * Los coloca el JS con position:fixed (window.utils.abrirMenu), porque
 * viven dentro de cajas que recortan: el cuerpo de un modal tiene scroll
 * propio y las tarjetas, overflow oculto. Aquí solo va su aspecto; el
 * sitio lo decide quien lo abre.
 * ===================================================================== */
.cash-menu-flotante {
    position: fixed;
    /* Por encima de todo, el modal incluido (70): el selector de forma de pago
       se despliega desde dentro de uno. */
    z-index: 90;
    min-width: 12rem;
    padding: .3125rem;
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: .875rem;
    box-shadow: var(--cash-shadow-lg);
}
.cash-menu-flotante .cash-menu-item {
    width: 100%;
    align-items: flex-start;
    border-radius: .625rem;
}
.cash-menu-item-nombre { display: block; font-size: .8125rem; font-weight: 600; }
.cash-menu-item-sub {
    display: block;
    font-size: .6875rem;
    font-weight: 400;
    color: var(--cash-ink-faint);
    line-height: 1.35;
}
.cash-menu-flotante .cash-menu-item:hover .cash-menu-item-sub { color: inherit; opacity: .75; }

/* ── Selector de forma de pago (solo icono) ──────────────────────────
   Tres opciones que se reconocen de un vistazo: enseñar sus nombres
   costaba una fila entera del formulario. El texto sigue ahí para los
   lectores de pantalla (sr-only + aria-label) y al desplegarlo. */
.cash-fila-pago { display: flex; align-items: flex-end; gap: .625rem; }
.cash-campo-forma { flex: none; }
.cash-campo-fondo { flex: 1 1 auto; min-width: 0; }

.cash-picker { position: relative; }
.cash-picker-btn {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    height: 2.75rem;                 /* la misma altura que .cash-input */
    padding: 0 .625rem;
    border: 1px solid var(--cash-line);
    border-radius: .75rem;
    background: var(--cash-surface);
    color: var(--cash-ink);
    font-size: 1rem;
    transition: border-color .15s ease, background .15s ease;
}
.cash-picker-btn:hover { border-color: #cbd5e1; background: #f8fafc; }
.cash-picker-btn[aria-expanded="true"] {
    border-color: var(--cash-primary);
    background: var(--cash-primary-wash);
}
.cash-picker-flecha { font-size: .5625rem; color: var(--cash-ink-faint); }

/* El icono lleva su color en el `style` que pinta el JS al elegir, copiado de
   la opción. Las formas de pago no traen color propio, así que se les da aquí
   —el mismo del resto de la app— por el valor que llevan. */
.cash-picker-op[data-valor="efectivo"]      > i:first-child,
.js-picker:has([data-valor="efectivo"][aria-selected="true"]) .cash-picker-btn > i:first-child { color: #047857; }
.cash-picker-op[data-valor="tarjeta"]       > i:first-child,
.js-picker:has([data-valor="tarjeta"][aria-selected="true"]) .cash-picker-btn > i:first-child { color: #1d4ed8; }
.cash-picker-op[data-valor="transferencia"] > i:first-child,
.js-picker:has([data-valor="transferencia"][aria-selected="true"]) .cash-picker-btn > i:first-child { color: #6d28d9; }

.cash-picker-menu {
    position: fixed;
    /* Por encima del modal (70) desde el que se abre. */
    z-index: 90;
    min-width: 11.5rem;
    max-width: calc(100vw - 1rem);
    max-height: 60vh;
    overflow-y: auto;
    padding: .3125rem;
    background: var(--cash-surface);
    border: 1px solid var(--cash-line);
    border-radius: .875rem;
    box-shadow: var(--cash-shadow-lg);
}
/* El de «pagado desde» ocupa la fila entera y enseña el nombre elegido. */
.cash-picker-btn-ancho {
    display: flex;
    width: 100%;
    justify-content: flex-start;
    font-size: .875rem;
}
/* Con el texto en sr-only, el botón se queda en el ancho del icono. */
.cash-picker-valor.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

.cash-picker-valor {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: left;
}
/* Sin fondo elegido, en tenue: es opcional y no debe parecer que falta algo. */
.cash-picker-valor.is-vacio { color: var(--cash-ink-faint); }
.cash-picker-icono { width: 1.125rem; text-align: center; font-size: .875rem; flex: none; }

.cash-picker-op {
    display: flex;
    align-items: center;
    gap: .625rem;
    width: 100%;
    padding: .5rem .625rem;
    border-radius: .625rem;
    font-size: .8125rem;
    color: var(--cash-ink-soft);
    text-align: left;
}
.cash-picker-op > i:first-child { width: 1.125rem; text-align: center; font-size: .875rem; }
/* El nombre se queda el hueco y NO se parte: el saldo va a su derecha, en una
   sola línea. Es justo lo que el desplegable nativo no podía garantizar. */
.cash-picker-op > span:first-of-type {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cash-picker-saldo {
    flex: none;
    font-size: .75rem;
    font-variant-numeric: tabular-nums;
    color: var(--cash-ink-faint);
    white-space: nowrap;
}
.cash-picker-op.is-elegida .cash-picker-saldo { color: inherit; opacity: .75; }
.cash-picker-op:hover { background: var(--cash-primary-wash); color: var(--cash-primary-deep); }
.cash-picker-check { font-size: .6875rem; color: var(--cash-primary); opacity: 0; }
.cash-picker-op.is-elegida { background: var(--cash-primary-wash); color: var(--cash-primary-deep); }
.cash-picker-op.is-elegida .cash-picker-check { opacity: 1; }

/* ── Barra de filtros de Buscar ──────────────────────────────────────
   DOS por línea en el móvil: con uno por línea, la barra se comía media
   pantalla antes de enseñar el primer gasto. En escritorio caben los
   cuatro de una vez. */
.cash-filtros {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    margin-bottom: 1rem;
}
.cash-filtros-busca { display: flex; align-items: stretch; gap: .5rem; }
.cash-filtros-busca .cash-btn { flex: none; }

.cash-filtros-rejilla {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .5rem;
}
@media (min-width: 1024px) {
    .cash-filtros-rejilla { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    /* Las fechas no se estiran a un cuarto de pantalla cada una: son campos
       cortos y estirarlos solo aleja el día del mes. */
    .cash-filtros-fechas { grid-template-columns: repeat(2, minmax(0, 13rem)); }
}

/* Campo de fecha con su rótulo dentro: «Desde» y «Hasta» necesitan decir
   cuál es cuál, y una etiqueta encima les robaría una línea a los filtros. */
.cash-campo-fecha { display: flex; flex-direction: column; gap: .1875rem; min-width: 0; }
.cash-campo-fecha > span {
    font-size: .625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--cash-ink-faint);
    padding-left: .125rem;
}
.cash-campo-fecha .cash-input { padding-top: .375rem; padding-bottom: .375rem; }

/* ── Pistas bajo un campo ───────────────────────────────────────────── */
.cash-hint {
    margin-top: .375rem;
    font-size: .75rem;
    line-height: 1.4;
    color: var(--cash-ink-faint);
}
.cash-hint.is-peligro { color: var(--cash-danger); }

/* Aviso en rojo: el saldo negativo y el exceso de un diferido. Avisan, no
   bloquean — si el dinero salió, salió. */
.cash-aviso.is-peligro {
    border-color: #fecdd3;
    background: #fff1f2;
    color: #9f1239;
}
.cash-aviso.is-peligro i { color: var(--cash-danger); }
.cash-aviso strong.is-negativo { color: var(--cash-danger); }

/* ── Transiciones reutilizables (Alpine) ─────────────────────────────── */
.cash-fade-enter-active, .cash-fade-leave-active { transition: opacity .18s ease; }
.cash-fade-enter-from, .cash-fade-leave-to { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        transition-duration: .01ms !important;
    }
}

/* ── Impresión ───────────────────────────────────────────────────────── */
@media print {
    .cash-header, .cash-fab, .cash-menuf { display: none !important; }
    .cash-main { width: 100% !important; max-width: none !important; min-width: 0 !important; padding: 0 !important; }
    .cash-card, .cash-local-card { box-shadow: none; border-color: #cbd5e1; }
}
