/* netza-base.css - extracted from base.html L121-1979 (refactor #72 v1.75.0) */
/* ======================================================================
   NETZA · DESIGN TOKENS v2.0
   ====================================================================== */
:root {
    --netza-ink:        #141311;
    --netza-ink-2:      #2a2825;
    --netza-ink-3:      #55514a;
    --netza-ink-4:      #8a857b;

    --netza-paper:      #f4f0e8;
    --netza-stone:      #ebe5d8;
    --netza-stone-2:    #ddd5c4;
    --netza-rule:       #c9c0ab;

    --netza-terracota:  #a84a2a;
    --netza-terracota-2:#92401f;

    /* v2.10.9 rev5 — Verde/rojo OSCUROS en ambos modes (decision Facu).
       Antes split por mode con claros en dark; ahora unificado a oscuros. */
    --netza-positivo:   #3a7d5a;
    --netza-negativo:   #c45a3f;
    --netza-warning:    #b38a2a;
    --netza-info:       #55514a;

    /* v2.10.7 — Unificación tipográfica: Roboto en toda la app (decision
       Facu 2026-05-11). El mono solo se usa donde el rediseño lo pide
       específicamente (etiquetas eyebrow, montos tabulares). */
    --netza-font-sans:  'Roboto', system-ui, -apple-system, sans-serif;
    --netza-font-mono:  'Roboto Mono', ui-monospace, monospace;

    --netza-fs-xs:      11px;
    --netza-fs-sm:      12px;
    --netza-fs-base:    13px;
    --netza-fs-md:      14px;
    --netza-fs-lg:      16px;
    --netza-fs-xl:      18px;
    --netza-fs-2xl:     22px;
    --netza-fs-3xl:     32px;

    --netza-r-sm:       4px;
    --netza-r-md:       6px;
    --netza-r-lg:       10px;
    --netza-r-xl:       12px;

    --nav-h:            48px;
}

/* Splash tilt animation */
@keyframes netzaTilt {
    0%, 100% { transform: rotate(-5deg); }
    50%      { transform: rotate(-2deg); }
}

/* ======================================================================
   RESET & BASE
   ====================================================================== */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: var(--netza-font-sans);
    /* v2.10.49 (Facu 2026-05-13) — Body matches header color (--dm-paper #f4f0e8),
       NOT wrap color (--dm-paper-warm #fbf8f2). Logic: lo que está por encima del
       header debe tener el mismo bg que el header para evitar línea visible. */
    background-color: var(--netza-paper);
    color: var(--netza-ink);
    -webkit-font-smoothing: antialiased;
    font-size: var(--netza-fs-base);
    line-height: 1.5;
    /* v2.10.96 (Facu 2026-05-14) — REVERT del sticky footer flex layout.
       v2.10.93 puso `display:flex column + min-height:100vh + .container
       flex:1` para que el footer quede al bottom. Pero eso creaba espacio
       muerto feo en pantallas con poco contenido (ej. /configuracion
       mobile con 2 cards → 60% del viewport vacío arriba del footer).
       Ahora el footer fluye naturalmente al final del contenido. En
       pantallas con poco contenido, el body bg se propaga al viewport
       (CSS rule estándar) → cremoso uniforme sin "hueco" visible. */
}

/* v2.10.96 (Facu 2026-05-14) — Sticky footer ELIMINADO. Ver comentario
   en regla `body { }` arriba. El footer fluye naturalmente al final del
   contenido en TODAS las pantallas (DT y mobile). */

/* ======================================================================
   TYPOGRAPHY
   ====================================================================== */
/* v2.10.108 (Facu 2026-05-14) — Header del perfil (DT) en flex para que
   el toggle expandir/colapsar todo (`.perfil-toggle-all`) quede al margen
   derecho, alineado con el h2 "Mi Perfil". `!important` porque
   reglas de h2 generales podrían pisar display. */
.perfil-h2 {
    display: flex !important;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
}
.perfil-h2 .perfil-toggle-all {
    margin-left: auto;
}
/* En mobile el wrap es sticky con flex justify-content:space-between → los
   2 botones de la derecha (lamparita + toggle-all) deben quedar juntos. */
body.perfil-mobile-page .pm-header .pm-btn-tut {
    margin-left: auto;
}
body.perfil-mobile-page .pm-header .perfil-toggle-all {
    margin-left: 0;
}
h2 {
    font-size: 18px;
    font-weight: 600;
    color: var(--netza-ink);
    margin-top: 0;
    margin-bottom: 12px;
    letter-spacing: -0.02em;
    line-height: 1.3;
}
/* v1.71.x — Texto explicativo (subtítulo) debajo del título de página.
   Uniforme en todas las pantallas. El margen del h2 ya da el espaciado;
   el page-intro arranca pegado a él (margin-top:0) y deja aire abajo. */
.page-intro {
    color: var(--netza-ink-3);
    font-size: 13px;
    line-height: 1.5;
    margin-top: 0;
    margin-bottom: 18px;
}
@media (max-width: 600px) {
    /* v1.80.0 — Escala tipográfica mobile unificada en toda la app.
       Ver docs/escala_tipografica_comparacion.xlsx para los valores acordados.
       Items: h2, h3, th, td, label, input/select/textarea (este último
       gobernado por el bloque iOS-detection más abajo). */
    h2 { font-size: 15px; font-weight: 500; margin-bottom: 6px; }
    h3 { font-size: 13px; font-weight: 500; }
    th { font-size: 9px; }
    td { font-size: 11px; }
    label { font-size: 9px; }
    .page-intro { font-size: 12px; margin-bottom: 8px; }
}
@media (min-width: 601px) and (max-width: 900px) {
    /* v1.81.0 — Escala tipográfica TABLET (601-900px).
       Diferencia con desktop: h2 17/600 (vs 18), h3 14/600 (vs 15),
       td 12 (vs 13). El resto (th, label, input/select) hereda desktop. */
    h2 { font-size: 17px; }
    h3 { font-size: 14px; }
    td { font-size: 12px; }
}
h3 {
    font-size: 15px;
    font-weight: 600;
    color: var(--netza-ink);
    margin-top: 0;
    margin-bottom: 14px;
    letter-spacing: -0.02em;
    line-height: 1.3;
}
h4 {
    font-size: 13px;
    font-weight: 600;
    color: var(--netza-ink);
    margin-top: 0;
    margin-bottom: 10px;
}
p { margin-top: 0; margin-bottom: 12px; }

/* ======================================================================
   SPLASH
   ====================================================================== */
/* v2.10.28 — Splash invertible según theme (Facu 2026-05-16). Antes era
   siempre dark (bg negro + logo paper), ahora el default es light (bg
   paper + logo ink) para que respete el modo claro del user. Dark mode
   más abajo aplica los colores originales. El SVG inline tiene
   `fill="#f4f0e8"` por defecto en los elementos del logo; el CSS pisa
   ese atributo con `!important` (CSS `fill` tiene mayor especificidad
   que el atributo HTML cuando se declara !important). Triángulo
   terracota (#a84a2a) se mantiene fijo en ambos themes. */
#netza-splash {
    position: fixed;
    inset: 0;
    background: var(--netza-paper);
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 250ms ease-out;
}
#netza-splash .tilt-group rect,
#netza-splash .tilt-group circle {
    fill: var(--netza-ink) !important;
}
#netza-splash.fadeout { opacity: 0; pointer-events: none; }
#netza-splash svg { width: 140px; height: 140px; }
#netza-splash .tilt-group {
    transform-origin: 90px 100px;
    animation: netzaTilt 2.4s ease-in-out infinite;
}
/* Dark mode: bg ink + logo paper (versión original del v2.8.x). */
body.dark-mode #netza-splash {
    background: #141311;
}
body.dark-mode #netza-splash .tilt-group rect,
body.dark-mode #netza-splash .tilt-group circle {
    fill: #f4f0e8 !important;
}

/* ======================================================================
   NAVBAR
   ====================================================================== */
nav {
    /* v2.10.8 — Bg con el mismo gradient que la card "Patrimonio Neto"
       (.hm-hero-pn) para unificar la identidad visual del header en toda la
       app, pre y postlogin. Light: gradient de tonos oscuros (ink-dark → ink).
       Dark override más abajo en el bloque dark-mode. */
    background: linear-gradient(140deg, #141311 0%, #2d2520 70%);
    padding: 0 20px;
    height: var(--nav-h);
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: sticky;
    top: 0;
    z-index: 100;
    border-bottom: 1px solid var(--netza-ink-2);
}
/* Dark mode — mismo gradient que .hm-hero-pn en dark. */
body.dark-mode nav {
    background: linear-gradient(140deg, #2a251f 0%, #1a1611 70%);
    /* v2.10.10 — Sin border-bottom en dark mode. Antes
       rgba(255,255,255,0.08) generaba una línea blanca/clara visible entre
       el navbar y el contenido (sobre todo notable cuando lo que está
       debajo es bg oscuro #141311). En dark el navbar queda seamless. */
    border-bottom: 0;
}
.nav-brand {
    color: var(--netza-paper);
    font-size: 15px;
    font-weight: 500;
    letter-spacing: -0.015em;
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 10px;
}
.nav-brand svg { width: 22px; height: 22px; flex-shrink: 0; }
.nav-brand .sep { color: var(--netza-ink-4); font-weight: 300; margin: 0 2px; }
.nav-brand .tagline { color: var(--netza-ink-4); font-weight: 400; font-size: 13px; }
.nav-brand .version {
    font-family: var(--netza-font-mono);
    font-size: 10px;
    color: var(--netza-ink-4);
    margin-left: 8px;
    letter-spacing: 0.05em;
}
.nav-icons {
    display: flex;
    align-items: center;
    gap: 18px;
}
.nav-icons a {
    color: var(--netza-paper);
    text-decoration: none;
    font-size: 14px;
    display: flex;
    align-items: center;
    gap: 6px;
    transition: opacity 0.2s;
    position: relative;
}
.nav-icons a:hover { opacity: 0.7; }
.nav-badge {
    position: absolute;
    top: -6px;
    right: -8px;
    background-color: var(--netza-terracota);
    color: var(--netza-paper);
    border-radius: 999px;
    min-width: 16px;
    height: 16px;
    padding: 0 5px;
    font-size: 10px;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--netza-font-mono);
}

/* ======================================================================
   NOTIF DROPDOWN
   ====================================================================== */
.notif-nav-wrap {
    position: relative;
    display: flex;
    align-items: center;
}
.notif-nav-btn-trigger {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 14px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    position: relative;
    transition: opacity 0.2s;
    line-height: 1;
}
.notif-nav-btn-trigger:hover { opacity: 0.7; }

/* v2.10.28 — Estado activo del botón notif (dropdown abierto). Mismo
   diseño que `.netza-bottom-tab.active`: scale 1.35 + drop-shadow glow.
   En light mantenemos el color paper (los íconos son blancos sobre el
   fondo oscuro del navbar) y agregamos solo halo blanco — el cambio a
   terracota se veía muy intenso y rompía la paleta del navbar (Facu
   2026-05-16). Override dark-mode más abajo aplica terracota porque
   contrasta mejor sobre el navbar dark gradient. El badge no se toca. */
.notif-nav-btn-trigger.active i {
    transform: scale(1.35) translateY(-1px);
    filter: drop-shadow(0 2px 6px rgba(244, 240, 232, 0.5))
            drop-shadow(0 0 12px rgba(244, 240, 232, 0.45));
    transition: transform 0.18s ease, filter 0.18s ease, color 0.18s ease;
}
.notif-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: 480px;
    /* v2.10.x (Facu 2026-05-13) — Bg paper-warm (#fbf8f2) en lugar de
       --netza-paper (#f4f0e8) para matchear el patrón unificado de modales/
       wraps en la app. */
    background: #fbf8f2;
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-lg);
    box-shadow: 0 6px 24px rgba(20,19,17,0.18);
    z-index: 9999;
    overflow: hidden;
}
.notif-drop-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    border-bottom: 1px solid var(--netza-rule);
    font-size: 13px;
    font-weight: 600;
    color: var(--netza-ink);
    /* v2.10.9 rev7 — bg transparente (hereda paper del dropdown) para
       alinear con el look del menú (#dropdown-nav-cards) que tiene
       header/footer sin bg distinto. Antes era stone (más oscuro). */
    background: transparent;
}
.notif-drop-ver {
    font-size: 11px;
    color: var(--netza-ink-2) !important;
    text-decoration: none;
    font-family: var(--netza-font-mono);
    letter-spacing: 0.04em;
    background: none;
    border: none;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 5px;
}
.notif-drop-ver:hover { color: var(--netza-ink) !important; }
.notif-drop-lista {
    max-height: 280px;
    overflow-y: auto;
    /* v2.10.72 (Facu 2026-05-13) — Área de lista con bg paper plano para
       contrastar con header y footer del dropdown (paper-warm). Mismo
       patrón sandwich que mobile. */
    background: #f4f0e8;
}
.notif-drop-empty {
    padding: 18px 14px;
    text-align: center;
    font-size: 13px;
    color: var(--netza-ink-4);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: #f4f0e8;
}
.notif-drop-empty i { color: var(--netza-positivo); }
.notif-drop-footer {
    padding: 8px 14px;
    border-top: 1px solid var(--netza-rule);
    /* v2.10.9 rev7 — bg transparente, mismo patrón que .notif-drop-header
       y el menú principal. */
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    flex-wrap: nowrap;
    white-space: nowrap;
}
.notif-drop-footer a,
.notif-drop-footer button.notif-drop-link {
    font-size: 11px;
    color: var(--netza-ink-3);
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 5px;
    font-family: var(--netza-font-mono);
    letter-spacing: 0.04em;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
}
.notif-drop-footer a:hover,
.notif-drop-footer button.notif-drop-link:hover { color: var(--netza-ink); }
.notif-drop-footer .notif-drop-sep {
    color: var(--netza-rule);
    font-size: 11px;
}

/* ======================================================================
   CONTAINER
   v2.10.8 — Wrap eliminado globalmente. Antes había bg + border + padding 20px
   creando una "card" alrededor del content de toda la app. Ahora `.container`
   es un wrapper transparente; solo conserva un padding horizontal igual al
   del home mercado (18px) para que el contenido respire en mobile. El home
   y los auth pages tienen sus propios :has overrides con !important que
   pisan este padding (ya manejan su propio interno).
   ====================================================================== */
.container {
    max-width: none;
    margin: 0;
    padding: 16px 18px;
    background: transparent;
    border: none;
    border-radius: 0;
}

/* ======================================================================
   FLASH MESSAGES
   ====================================================================== */
.flash-container { margin-bottom: 16px; }
.flash {
    padding: 10px 14px;
    border-radius: var(--netza-r-md);
    margin-bottom: 8px;
    font-size: var(--netza-fs-sm);
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid transparent;
}
.flash.success {
    background: rgba(90, 98, 52, 0.1);
    color: var(--netza-positivo);
    border-color: rgba(90, 98, 52, 0.25);
}
.flash.error, .flash.danger {
    background: rgba(168, 74, 42, 0.1);
    color: var(--netza-terracota);
    border-color: rgba(168, 74, 42, 0.25);
}
.flash.warning {
    background: rgba(179, 138, 42, 0.1);
    color: var(--netza-warning);
    border-color: rgba(179, 138, 42, 0.25);
}
.flash.info {
    background: rgba(85, 81, 74, 0.08);
    color: var(--netza-ink-3);
    border-color: var(--netza-rule);
}

/* ======================================================================
   BUTTONS
   ====================================================================== */
.btn, button.btn {
    padding: 7px 12px;
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-md);
    background: var(--netza-paper);
    color: var(--netza-ink);
    font-size: var(--netza-fs-sm);
    font-family: var(--netza-font-sans);
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: all 0.15s;
    text-decoration: none;
    line-height: 1.4;
    vertical-align: middle;
}
.btn:hover, button.btn:hover {
    border-color: var(--netza-ink);
    background: var(--netza-stone);
    color: var(--netza-ink);
}
.btn-primary, button.btn-primary {
    background: var(--netza-ink);
    color: var(--netza-paper);
    border-color: var(--netza-ink);
}
.btn-primary:hover, button.btn-primary:hover {
    background: var(--netza-ink-2);
    border-color: var(--netza-ink-2);
    color: var(--netza-paper);
}
.btn-accent, button.btn-accent {
    background: var(--netza-terracota);
    color: var(--netza-paper);
    border-color: var(--netza-terracota);
}
.btn-accent:hover, button.btn-accent:hover {
    background: var(--netza-terracota-2);
    border-color: var(--netza-terracota-2);
    color: var(--netza-paper);
}
.btn-sm { padding: 4px 8px; font-size: var(--netza-fs-xs); }

/* Icon-only action buttons (confirm ✓ / cancel ✗) */
.btn-icon-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    cursor: pointer;
    transition: opacity .15s, transform .1s;
    flex-shrink: 0;
    text-decoration: none;
    vertical-align: middle;
}
.btn-icon-action:hover { opacity: .8; transform: scale(1.05); }
.btn-icon-action:active { transform: scale(.95); }
.btn-icon-action.confirm { background: var(--netza-ink); color: var(--netza-paper); }
.btn-icon-action.cancel  { background: var(--netza-stone); color: var(--netza-ink-3); }

/* Form action bar for standalone edit pages */
.form-actions {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-top: 28px;
    padding-top: 20px;
    border-top: 1px solid var(--netza-rule);
}

/* Page-level button row: aligns CTA + lightbulb at same height */
.page-btns {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
    margin-bottom: 20px;
}

/* v2.10.80 (Facu 2026-05-13) — Header row: h2 + lamparita + toggle moneda
   en una sola línea. Toggle alineado a la derecha con margin-left:auto.
   Usado en /registros, /proyecciones y demás pantallas tras la migración. */
.page-title-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.page-title-row h2 {
    margin: 0;
    line-height: 1.2;
}
.page-title-row .btn-ayuda {
    /* La lamparita queda inmediatamente al lado del h2; sin margin-left. */
    margin-left: 0;
}
.page-title-row .dm-curr-toggle,
.page-title-row .vr-curr-toggle-desktop {
    margin-left: auto;
}

/* En DT (≥601px) con sidebar (body.has-bottom-tabs), ocultar la fila
   .page-btns que tenga la clase marcadora .page-btns--fab-replace
   (registros, proyecciones): los botones de "Nuevo X" de esas pantallas
   se reemplazan por el FAB "+" del sidebar. Otras pantallas (Categorías,
   Canales, etc.) mantienen sus botones de "Nuevo X" porque NO están en
   el FAB. En mobile la mobile-page class oculta todo por su cuenta. */
@media (min-width: 601px) {
    body.has-bottom-tabs .page-btns--fab-replace {
        display: none !important;
    }

    /* v2.10.81 (Facu 2026-05-13) — Anti-flash en PJAX swap.
       Las tablas inicializadas por TablaManager (id^="tabla") se ven
       brevemente "crudas" (sin filtros/sticky/sort) entre que PJAX
       inserta el HTML nuevo y el script inline init corre. Resultado:
       flash visible al navegar entre /registros y /proyecciones.
       Solución: ocultar la tabla via opacity:0 hasta que TablaManager
       marque data-tm-ready=1 al finalizar su _init(). El reveal es con
       fade-in suave (.10s) para que no se note. */
    .table-wrapper > table[id^="tabla"]:not([data-tm-ready]) {
        opacity: 0;
    }
    .table-wrapper > table[id^="tabla"][data-tm-ready] {
        opacity: 1;
        transition: opacity 0.10s ease-in;
    }
}
.btn-danger {
    background: rgba(168, 74, 42, 0.1);
    color: var(--netza-terracota);
    border-color: rgba(168, 74, 42, 0.3);
}
.btn-danger:hover {
    background: var(--netza-terracota);
    color: var(--netza-paper);
    border-color: var(--netza-terracota);
}
.btn-warning {
    background: rgba(179, 138, 42, 0.1);
    color: var(--netza-warning);
    border-color: rgba(179, 138, 42, 0.3);
}
.btn-warning:hover {
    background: var(--netza-warning);
    color: var(--netza-paper);
    border-color: var(--netza-warning);
}

/* ======================================================================
   EXPORT BUTTONS (CSV / Excel)
   ====================================================================== */
/* Contenedor de edición inline en tablas */
.inline-edit-form {
    display: none;
    position: fixed;
    z-index: 1000;
    min-width: 220px;
    max-width: calc(100vw - 16px);
    background: var(--netza-stone);
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-md);
    padding: 12px 14px;
    box-shadow: 0 4px 16px rgba(20,19,17,.12);
}
.inline-edit-form .form-row-inline {
    display: flex;
    gap: 12px;
    align-items: flex-end;
    flex-wrap: wrap;
}
.inline-edit-form .form-row-inline > div {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* Fila de botones bulk (Eliminar sel., Limpiar filtros, Limpiar orden.) */
.action-btns {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}
.action-btns > * { margin: 0 !important; }

/* Exportar: siempre en su propia línea */
.btn-export-group {
    display: flex;
    gap: 6px;
    margin-bottom: 10px;
}
.btn-export {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    font-size: 12px;
    font-family: var(--netza-font-sans);
    font-weight: 500;
    border-radius: var(--netza-r-md);
    border: 1px solid var(--netza-rule);
    background: var(--netza-paper);
    color: var(--netza-ink-3);
    cursor: pointer;
    transition: all 0.15s;
    text-decoration: none;
}
.btn-export:hover {
    border-color: var(--netza-ink-3);
    color: var(--netza-ink);
    background: var(--netza-stone);
}
.btn-export-csv  i { color: #3a7a47; }
.btn-export-xlsx i { color: #1f6b2e; }

/* ======================================================================
   TABLES (global)
   ====================================================================== */
table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--netza-fs-base);
}
th {
    background: var(--netza-paper);
    color: var(--netza-ink-3);
    padding: 10px 14px;
    text-align: left;
    font-family: var(--netza-font-mono);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    border-bottom: 1px solid var(--netza-rule);
    white-space: nowrap;
}
td {
    padding: 10px 14px;
    border-bottom: 1px solid var(--netza-stone);
    color: var(--netza-ink-2);
    vertical-align: middle;
    font-family: var(--netza-font-sans);
    font-size: var(--netza-fs-base);
}
tr:last-child td { border-bottom: 0; }
tr:hover td { background: rgba(235, 229, 216, 0.4); }


.t-num {
    font-family: var(--netza-font-mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--netza-ink-3);
    font-weight: 500;
}
.t-num.positivo { color: var(--netza-positivo); }
.t-num.negativo { color: var(--netza-negativo); }
.t-cat {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--netza-r-sm);
    background: var(--netza-stone);
    font-family: var(--netza-font-sans);
    font-size: var(--netza-fs-xs);
    font-weight: 500;
    color: var(--netza-ink-2);
}
.t-date {
    font-family: var(--netza-font-mono);
    font-size: var(--netza-fs-xs);
    color: var(--netza-ink-3);
}
.t-action {
    color: var(--netza-ink-3);
    font-size: var(--netza-fs-base);
    margin-left: 8px;
    text-decoration: none;
}
.t-action:hover { color: var(--netza-ink); }
.t-action.danger:hover { color: var(--netza-terracota); }

/* Table wrapper (for tables with header) */
.table-wrapper {
    background: var(--netza-paper);
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-lg);
    overflow-x: auto;
    overflow-y: visible;
    -webkit-overflow-scrolling: touch;
}

/* v1.53.0 / v1.71.x — Aire entre la última columna y la scrollbar vertical en
   todas las tablas. Aplica a todas las versiones (monitor, tablet, mobile).
   :last-child sobre th/td para no depender del nombre de la columna ni del
   orden. !important es necesario para vencer reglas locales que usan padding
   shorthand (ej: #tablaX td { padding: 5px 6px }). */
.table-wrapper > table > thead > tr > th:last-child,
.table-wrapper > table > tbody > tr > td:last-child {
    padding-right: 14px !important;
}

/* v1.53.0 — Alineación uniforme de tablas en TODAS las versiones:
   - Por default: izquierda + centrado vertical en th y td.
   - Excepción 1: columnas con `style="text-align:right;"` inline (ej: col-monto)
     prevalecen porque inline > regla CSS — montos siguen alineados a la derecha.
   - Excepción 2: col-acciones SIEMPRE centrada (regla aparte con !important
     para vencer el inline `style="text-align:right;"` que tienen esos cells
     en varios templates). */
.table-wrapper > table > thead > tr > th,
.table-wrapper > table > tbody > tr > td,
.table-wrapper > table > thead > tr > td {
    text-align: left;
    vertical-align: middle;
}
.table-wrapper > table > thead > tr > th.col-acciones,
.table-wrapper > table > tbody > tr > td.col-acciones,
.table-wrapper > table > thead > tr > td.col-acciones {
    text-align: center !important;
    vertical-align: middle;
}

/* v1.58.0 — moneda-prefix: solo visible en monitor/tablet (mobile ya tiene
   moneda en .amount-compact). Y ocultar col-moneda en desktop/tablet (la moneda
   se muestra ahora dentro del col-monto). Mobile mantiene su comportamiento. */
.moneda-prefix { display: none; }
@media (min-width: 601px) {
    .moneda-prefix { display: inline; }
    .table-wrapper .col-moneda { display: none !important; }
}

/* v1.53.0 — Headers de columnas de monto/presupuesto alineados a la izquierda.
   Aplica solo en monitor/tablet (>=601px) y excluye `.ultimos-table` (dashboard
   últimos 10) por pedido explícito de Facu. En mobile y en dashboard.ultimos-table
   el header sigue alineado a la derecha (mantiene su inline style). El TD
   (contenido) mantiene su alineación inline a la derecha sin cambios. */
@media (min-width: 601px) {
    .table-wrapper > table:not(.ultimos-table) > thead > tr > th.col-monto {
        text-align: left !important;
    }
}

/* v1.53.0 — col-concepto especial (Movimiento/Ajuste): mostrar texto distinto
   solo en mobile, sin tocar desktop/tablet. Aplicado por la dual-element pattern:
   .mi-title (default, siempre presente) + .mi-title-mobile (solo en filas Movimiento/Ajuste).
   En mobile se oculta el .mi-title default y se muestra .mi-title-mobile.
   Aplica a registros + últimos 10 (ambas usan la clase col-concepto-special). */
.mi-title-mobile { display: none; }
@media (max-width: 600px) {
    .col-concepto-special .mi-title:not(.mi-title-mobile) { display: none; }
    .col-concepto-special .mi-title-mobile { display: block; }
}

/* v1.80.0 — Escala mobile unificada para inputs/selects/textareas.
   Lógica iOS-aware: en Safari iOS el browser hace zoom automático al focus
   si el font-size es <16px. El flag is-ios se setea en <html> via JS al
   cargar (ver <head>). Por eso:
     - No-iOS  → 11px (compacto, alineado con la escala mobile general).
     - iOS     → 16px (anti-zoom).
   Cubre tanto inputs sueltos como dentro de .form-group (mantengo selectores
   con html:(not).is-ios para tener mayor especificidad que el bloque
   .form-group input definido más abajo en este archivo). */
@media (max-width: 600px) {
    html:not(.is-ios) input[type="text"],
    html:not(.is-ios) input[type="email"],
    html:not(.is-ios) input[type="number"],
    html:not(.is-ios) input[type="password"],
    html:not(.is-ios) input[type="search"],
    html:not(.is-ios) input[type="tel"],
    html:not(.is-ios) input[type="url"],
    html:not(.is-ios) input[type="date"],
    html:not(.is-ios) input:not([type]),
    html:not(.is-ios) select,
    html:not(.is-ios) textarea {
        font-size: 11px;
    }
    html.is-ios input[type="text"],
    html.is-ios input[type="email"],
    html.is-ios input[type="number"],
    html.is-ios input[type="password"],
    html.is-ios input[type="search"],
    html.is-ios input[type="tel"],
    html.is-ios input[type="url"],
    html.is-ios input[type="date"],
    html.is-ios input:not([type]),
    html.is-ios select,
    html.is-ios textarea {
        font-size: 16px;
    }
}

.table-header {
    padding: 12px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--netza-rule);
    background: var(--netza-stone);
}
.table-header h3 {
    font-size: var(--netza-fs-md);
    font-weight: 500;
    letter-spacing: -0.01em;
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--netza-ink);
}
.table-header .table-actions { display: flex; gap: 8px; }

/* ======================================================================
   FORMS
   ====================================================================== */
label {
    font-family: var(--netza-font-mono);
    font-size: 9px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--netza-ink-3);
    display: block;
    margin-bottom: 4px;
}
input[type="text"], input[type="password"], input[type="email"],
input[type="number"], input[type="date"], select, textarea {
    width: 100%;
    padding: 5px 9px;
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-md);
    /* v1.91.0 - fondo blanco en TODOS los campos rellenables. */
    background: #ffffff;
    /* v1.81.0 — Desktop input/select/textarea = 13px (var --netza-fs-base).
       En tablet (601-900) hereda 13px. En mobile aplica el bloque iOS-aware
       (11px no-iOS / 16px iOS) más abajo. */
    font-size: var(--netza-fs-base);
    font-family: var(--netza-font-sans);
    color: var(--netza-ink);
    transition: border-color 0.15s;
    appearance: none;
    -webkit-appearance: none;
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--netza-ink);
}
input::placeholder, textarea::placeholder { color: var(--netza-ink-4); }
select {
    /* v2.11.16 (Facu 2026-05-17) — Flecha del select con mejor contraste.
       Antes: fill #55514a (gris suave) — sobre fondos paper #f4f0e8 /
       #fbf8f2 quedaba casi invisible. Ahora: #2d2520 (ink-2, mismo color
       que ya usaba el fix puntual del dashboard v2.10.118). Aplica a
       TODOS los selects de la app en light mode. Dark mode tiene su
       propio fill claro más abajo. */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M6 8L1 3h10z' fill='%232d2520'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
    padding-right: 28px;
    cursor: pointer;
}
.form-group {
    margin-bottom: 14px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.form-group label,
form label {
    font-family: var(--netza-font-mono);
    /* v1.81.0 — Desktop label en form = 9px (alineado a label global y a la
       escala unificada). Tablet hereda. Mobile lo gobierna el bloque mobile. */
    font-size: 9px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--netza-ink-4);
    line-height: 1;
    display: block;
}
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 14px; }
.form-row > .form-group { margin-bottom: 0; }

/* Radio group */
.radio-group {
    display: flex;
    gap: 20px;
    align-items: center;
    flex-wrap: wrap;
    padding-top: 2px;
}
/* label.radio-option: especificidad (0,1,1) — gana a .form-group label (0,1,1) por orden en CSS
   v1.74.0 #68 — tamaño compacto unificado en todos los radio groups. */
label.radio-option {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 5px;
    cursor: pointer;
    font-family: var(--netza-font-sans);
    font-size: 12px;
    color: var(--netza-ink);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    line-height: 1;
    margin-bottom: 0;
}
label.radio-option input[type="radio"] {
    /* v2.10.9 rev3 — Light mode usa el color del navbar/bottom tab bar
       (ink dark = #2d2520), coherente con la regla general "terracota →
       ink en light, terracota en dark" (item 8 v2.10.9). El override dark
       sigue siendo terracota (más abajo). */
    accent-color: var(--netza-ink);
    width: 14px !important;
    height: 14px !important;
    flex-shrink: 0;
    cursor: pointer;
    margin: 0;
}
label.radio-option span {
    line-height: 1;
}

/* ======================================================================
   BACK BUTTON
   ====================================================================== */
.back-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}
.back-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--netza-ink-3);
    text-decoration: none;
    transition: color 0.15s;
    font-family: var(--netza-font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-size: 10px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
}
.back-btn:hover { color: var(--netza-ink); }

/* ======================================================================
   HEADINGS & PAGE TITLES
   ====================================================================== */
h1, h2, h3, h4 {
    font-weight: 500;
    letter-spacing: -0.015em;
    color: var(--netza-ink);
    line-height: 1.25;
}
.page-title {
    font-size: var(--netza-fs-xl);
    margin-bottom: 4px;
    display: flex;
    align-items: center;
    gap: 10px;
}
.page-subtitle {
    font-family: var(--netza-font-mono);
    font-size: var(--netza-fs-xs);
    color: var(--netza-ink-3);
    letter-spacing: 0.08em;
}

/* Section dividers */
/* v1.79.10 #92 - margin reducido (era 24/14) para aprovechar mejor el
   viewport vertical en desktop/tablet del dashboard. Mobile tiene su
   propio override en dashboard.css (10/8). */
.section-divider {
    display: flex;
    align-items: center;
    margin: 14px 0 10px;
    gap: 12px;
}
.section-divider::before, .section-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--netza-rule);
}
.section-divider .label {
    font-family: var(--netza-font-mono);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--netza-ink-3);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* ======================================================================
   MODALS
   ====================================================================== */
.modal-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(20, 19, 17, 0.55);
    /* v2.11.7 (Facu 2026-05-16) — Subido de 9700 a 10025 para que los
       modales secundarios (nueva-categoria / nuevo-concepto / nuevo-canal /
       nueva-tarjeta / nuevo-vto-tarjeta) abiertos DESDE el flow OCR
       (modal preview con z-index 10002) queden por ENCIMA y sean visibles.
       En el flow tradicional (formularios fuera de OCR) no hay regresion:
       igual era el modal "topmost" del stack. */
    z-index: 10025;
    align-items: center;
    justify-content: center;
}
.modal-backdrop.open { display: flex; }

/* v2.10.10 — Animación fade + scale-in para el modal de contacto. Override
   scoped a #modal-contacto para no afectar el resto de los modales que usan
   .modal-backdrop con display:none/flex. Usamos visibility+opacity (animables)
   en lugar de display, y un keyframe scale-in para la card. */
#modal-contacto.modal-backdrop {
    display: flex;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease,
                visibility 0s linear 0.22s,
                background-color 0.22s ease;
}
#modal-contacto.modal-backdrop.open {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    transition: opacity 0.22s ease,
                visibility 0s linear 0s,
                background-color 0.22s ease;
}
#modal-contacto .modal {
    transform: translateY(-14px) scale(0.96);
    opacity: 0;
    transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1),
                opacity 0.22s ease;
    will-change: transform, opacity;
}
#modal-contacto.modal-backdrop.open .modal {
    transform: translateY(0) scale(1);
    opacity: 1;
}

/* v2.10.28 — Modal Contacto en mobile: ocupar todo el alto disponible entre
   la top navbar (~64px) y la bottom tab bar (76px). Antes el modal quedaba
   chico verticalmente (max-height:90vh + height:auto centrado), ahora con
   align-items:stretch + padding en el backdrop el modal se estira full-bleed
   verticalmente entre los chromes (Facu 2026-05-16). */
@media (max-width: 600px) {
    #modal-contacto.modal-backdrop {
        align-items: stretch !important;
        padding: 64px 0 76px !important;
        box-sizing: border-box;
    }
    #modal-contacto .modal {
        max-height: none !important;
        height: auto !important;
        display: flex;
        flex-direction: column;
    }
    /* El form ocupa todo el alto disponible debajo del header/tip. */
    #modal-contacto #form-contacto {
        display: flex;
        flex-direction: column;
        flex: 1 1 auto;
        min-height: 0;
    }
    /* La form-group del mensaje crece para llenar el espacio sobrante. */
    #modal-contacto .form-group-mensaje {
        flex: 1 1 auto;
        display: flex;
        flex-direction: column;
        min-height: 0;
    }
    #modal-contacto .form-group-mensaje textarea {
        flex: 1 1 auto;
        min-height: 80px;
        resize: none !important; /* full-bleed: deshabilitar resize manual */
    }
    /* Botones Cancelar/Enviar más grandes para mejor tap-target en mobile.
       `justify-content: center` para centrar el texto cuando `min-width: 96px`
       deja espacio extra (la regla `.btn` base usa `inline-flex` con
       `justify-content: flex-start` por defecto → texto pegado a la izquierda).
       `line-height: 1.2` para que el ascender/descender de la fuente no
       desplace el texto verticalmente dentro del padding 11px×11px. */
    #modal-contacto .modal-footer .btn {
        padding: 11px 22px;
        font-size: 14px;
        font-weight: 600;
        min-width: 96px;
        line-height: 1.2;
        justify-content: center;
        text-align: center;
    }
}
.modal {
    background: var(--netza-paper);
    border-radius: var(--netza-r-xl);
    border: 1px solid var(--netza-rule);
    padding: 24px;
    max-width: 480px;
    width: calc(100% - 40px);
    max-height: 90vh;
    overflow-y: auto;
}
.modal-title {
    font-size: var(--netza-fs-lg);
    font-weight: 500;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--netza-rule);
    display: flex;
    align-items: center;
    gap: 10px;
}
.modal-footer {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 20px;
    padding-top: 14px;
    border-top: 1px solid var(--netza-rule);
}

/* ======================================================================
   POPOVERS
   ====================================================================== */
.popover-container {
    position: relative;
    display: inline-block;
}
.popover {
    display: none;
    position: absolute;
    background: var(--netza-ink);
    color: var(--netza-paper);
    padding: 10px 14px;
    border-radius: var(--netza-r-md);
    font-size: var(--netza-fs-xs);
    white-space: nowrap;
    z-index: 200;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    pointer-events: none;
    box-shadow: 0 4px 16px rgba(20, 19, 17, 0.18);
}
.popover::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--netza-ink);
}
.popover.open { display: block; }

/* ======================================================================
   CHIPS (tarjeta filter chips)
   ====================================================================== */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: var(--netza-fs-xs);
    font-weight: 500;
    border: 1px solid var(--netza-rule);
    background: var(--netza-paper);
    color: var(--netza-ink-3);
    cursor: pointer;
    transition: all 0.15s;
    font-family: var(--netza-font-mono);
    letter-spacing: 0.04em;
}
.chip:hover { border-color: var(--netza-ink-3); color: var(--netza-ink); }
.chip.active {
    background: var(--netza-ink);
    border-color: var(--netza-ink);
    color: var(--netza-paper);
}

/* ======================================================================
   MISC UTILITIES
   ====================================================================== */
.text-mono { font-family: var(--netza-font-mono); }
.text-muted { color: var(--netza-ink-3); }
.text-sm { font-size: var(--netza-fs-sm); }
.text-xs { font-size: var(--netza-fs-xs); }
.text-positivo { color: var(--netza-positivo); }
.text-negativo { color: var(--netza-negativo); }
.text-warning  { color: var(--netza-warning); }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }

/* ======================================================================
   RESPONSIVE — tablet
   ====================================================================== */
@media (max-width: 900px) {
    .container { margin: 12px; max-width: none; }
    nav { padding: 0 14px; }
    /* v1.61.0 — version visible en tablet; solo ocultar tagline+sep */
    .nav-brand .tagline, .nav-brand .sep { display: none; }
}

/* ======================================================================
   RESPONSIVE — mobile
   ====================================================================== */
/* ======================================================================
   CARDS-GRID / CARD (compatibilidad con templates existentes)
   ====================================================================== */
.cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 10px;
    margin-top: 4px;
}
.card {
    background: var(--netza-paper);
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-lg);
    padding: 20px 14px;
    text-align: center;
    text-decoration: none;
    color: var(--netza-ink);
    transition: border-color 0.15s, background 0.15s;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    /* v1.71.x — alto mínimo igual para todas las cards, independientemente de
       si el texto del span ocupa 1 o 2 líneas. Sin esto, el grid igualaba alto
       por fila y las cards de texto corto quedaban sin contenido centrado. */
    min-height: 100px;
}
.card:hover { border-color: var(--netza-ink-3); background: var(--netza-stone); color: var(--netza-ink); }
.card i { font-size: 22px; color: var(--netza-ink-3); }
.card span { font-size: 12px; font-weight: 500; }

@media (max-width: 600px) {
    /* v1.71.x — En mobile todas las cards (Configuración, Tutoriales, Index)
       tienen la misma altura fija y compacta para que el footer se vea sin
       scroll en pantallas chicas. Las cards de 2 líneas siguen entrando.
       !important para vencer el min-height local de index.html (.nav-card). */
    .card { height: 78px !important; min-height: 78px !important; padding: 8px 8px; gap: 4px; }
    .card i { font-size: 18px; }
    .card span { font-size: 10px; line-height: 1.15; }
    .cards-grid { gap: 6px; }
    .nav-card { height: 78px !important; min-height: 78px !important; padding: 8px 8px !important; gap: 4px !important; }
    .nav-card i { font-size: 18px !important; }
    .nav-card span { font-size: 10px !important; line-height: 1.15 !important; }
    .nav-cards { gap: 6px !important; }

    /* v1.61.0 — version sutil debajo de "Netza" en mobile, casi pegado */
    .nav-brand { flex-wrap: wrap; align-items: flex-start; line-height: 1; }
    .nav-brand .version {
        display: block;
        flex-basis: 100%;
        margin: -10px 0 0 32px;
        font-size: 9px;
        line-height: 1;
    }
    /* #84 — container mobile más compacto: menos margin/padding para reducir aire muerto */
    .container { margin: 6px; padding: 10px; border-radius: var(--netza-r-lg); }
    nav { padding: 0 10px; }
    /* v1.77.0 — ocultar nombre del usuario en mobile (revierte v1.37.11): el FAB
       y el espacio reducido del nav hacen que el username (folaiz, etc.) sume
       ruido innecesario. El ícono de perfil sigue clickeable y lleva a /perfil. */
    .nav-icons a span { display: none; }
    .btn { padding: 6px 9px; font-size: var(--netza-fs-xs); }

    /* Notification dropdown: fixed position, full-width with margins */
    .notif-dropdown {
        position: fixed;
        top: calc(var(--nav-h) + 4px);
        left: 12px;
        right: 12px;
        width: auto;
    }

    /* Tables: min-width so table + header scroll together on mobile */
    .table-wrapper table,
    .table-wrapper .table-header {
        min-width: 480px;
    }
    /* Tablas compactas (1-2 cols): no necesitan min-width, se ajustan a contenido */
    .table-wrapper table.table-compact {
        min-width: 0;
        width: auto;
    }

    /* v1.83.0 — Modales de confirmación (eliminar registros, pago tarjeta).
       Mobile: padding más compacto + botones en una sola línea.
       v2.10.22 rev3 — Centrados (antes right-aligned). Funciona para 2 y 3
       botones (lamparita /proyecciones usa 3). */
    .netza-modal-confirm-card {
        padding: 22px 20px !important;
    }
    .netza-modal-confirm-actions {
        flex-wrap: nowrap !important;
        justify-content: center !important;
        gap: 8px !important;
    }
    .netza-modal-confirm-actions .btn {
        padding: 7px 14px !important;
        font-size: var(--netza-fs-xs) !important;
        white-space: nowrap;
    }

}

/* ======================================================================
   PAGE FOOTER
   ====================================================================== */
.netza-footer {
    margin-top: 32px;
    padding: 16px 24px;
    /* v2.11.18 (Facu 2026-05-18) — Bg transparent en DT + mobile, light +
       dark. Antes tenía paper-warm #fbf8f2 (light) / #1a1611 (dark) que
       creaba una banda de color sobre el wrap. Ahora hereda del body. */
    background: transparent;
    text-align: center;
}

/* v2.10.105 (Facu 2026-05-14) — STICKY FOOTER DT.
   En desktop (≥601px), el footer SIEMPRE debe quedar pegado al fondo
   del viewport, sin importar el contenido. Lo logramos con flex column
   en el body: navbar arriba, .container con flex:1 (crece a ocupar
   todo el espacio sobrante), footer queda al final con margin-top:auto.

   Aplicado solo a `body.has-bottom-tabs` (= users autenticados con
   sidebar DT) para NO afectar auth pages (que tienen su propio
   centering layout) ni mobile (donde el revert de v2.10.96 explicaba
   por qué dejarlo libre en mobile: contenido corto = espacio muerto).

   En mobile el footer fluye naturalmente al final del contenido como
   siempre — el bg paper-warm del body se propaga al viewport en
   pantallas con poco contenido (sin "hueco" visible). */
@media (min-width: 601px) {
    body.has-bottom-tabs {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
    }
    body.has-bottom-tabs > .container {
        flex: 1 0 auto;
    }
    body.has-bottom-tabs > .netza-footer {
        margin-top: auto;
    }
}
.netza-footer-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 11px;
    color: var(--netza-ink-4);
    font-family: var(--netza-font-mono);
    letter-spacing: 0.04em;
}
.netza-footer-brand { font-weight: 600; color: var(--netza-ink-3); }
.netza-footer-dot { color: var(--netza-rule); }
.netza-refresh-fab:active { transform: scale(0.95); }
@media (max-width: 600px) {
    .netza-refresh-fab { display: flex; }
    /* v2.11.18 (Facu 2026-05-18) — Mobile sticky footer + transparent bg.
       Antes: el footer fluía después del contenido con bg paper-warm
       (#fbf8f2 light / #1a1611 dark), creando una banda de color visible
       en pantallas con poco contenido (ej. /grupo-familiar). Ahora:
       1) Body flex column con min-height:100vh → footer al fondo.
       2) bg transparent → toma el color de la página, sin banda. */
    body.has-bottom-tabs {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
    }
    body.has-bottom-tabs > .container,
    body.has-bottom-tabs > main {
        flex: 1 0 auto;
    }
    body.has-bottom-tabs > .netza-footer {
        margin-top: auto;
    }
    /* v1.71.x — En mobile compactar el footer pegándolo a las cards/contenido. */
    .netza-footer {
        margin-top: 8px;
        padding: 8px 16px;
        background: transparent;
    }
    .netza-footer-inner { font-size: 10px; gap: 6px; }
}

/* ======================================================================
   NAVBAR CARDS DROPDOWN
   ====================================================================== */
.nav-cards-wrap {
    position: relative;
    display: flex;
    align-items: center;
}
.nav-cards-btn {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 14px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    position: relative;
    transition: opacity 0.2s;
    line-height: 1;
}
.nav-cards-btn:hover { opacity: 0.7; }
.nav-cards-drop {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: max-content;
    min-width: 0;
    /* v2.10.55 (Facu 2026-05-13) — Bg paper-warm (#fbf8f2) para unificar
       todos los elementos del menú "Ir a..." en el mismo tono. */
    background: #fbf8f2;
    border: 1px solid var(--netza-rule);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(20,19,17,.18);
    z-index: 9500;
    overflow: hidden;
}
.nav-cards-drop.activo { display: block; }
.nav-cards-drop-header {
    padding: 10px 14px 6px;
    font-size: 10px;
    font-family: var(--netza-font-mono);
    color: var(--netza-ink-4);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-bottom: 1px solid var(--netza-rule);
}
/* v2.10.38 (Facu 2026-05-13) — Tipografía y padding del menú "Ir a…"
   alineados al estilo de los botones del FAB (`.netza-bottom-fab-opt`):
   - font-size texto 13px (antes era 17px padres / 14px hijos).
   - font-size ícono 15px (antes 17px / 13px).
   - padding 11px 14px uniforme para padres + hijos (antes 9px / 7px).
   - gap 12px (mismo que FAB).
   - ícono width 22px (mismo slot que FAB).
   Así los 2 menús (FAB + Ir a…) se ven consistentes. */
.nav-cards-drop .nav-cards-item {
    display: flex;
    align-items: center;
    gap: 12px;
    /* v2.10.38 rev3 (Facu 2026-05-13) — Padding vertical 10px (bajado de 14px,
       quedó demasiado espacioso). `line-height: 1.2` explícito en ambos
       (item y item-expand) para garantizar uniformidad — sin esto el
       `<button>` (.nav-cards-item-expand) heredaba un line-height distinto
       al `<a>` (.nav-cards-item) por default del browser, generando saltos
       desiguales entre Registros↔Proyecciones (a-a) vs Proyecciones↔Tutoriales
       (a-button). */
    padding: 10px 14px;
    font-size: 13px;
    line-height: 1.2;
    color: var(--netza-ink-3);
    text-decoration: none;
    transition: background 0.15s;
}
.nav-cards-drop .nav-cards-item:hover { background: var(--netza-stone); color: var(--netza-ink-3); }
.nav-cards-drop .nav-cards-item i { width: 22px; text-align: center; font-size: 15px; }
/* v2.11.21 — Item locked (free user sin acceso a la feature). Mismo
   layout pero opacity sutil + cursor pointer (click abre modal upgrade).
   El ícono fa-lock va al final con width:auto para alinear a la derecha. */
.nav-cards-drop .nav-cards-item-locked { opacity: 0.55; }
.nav-cards-drop .nav-cards-item-locked:hover { opacity: 0.85; }
.nav-cards-drop .nav-cards-item-locked .fa-lock { width: auto !important; }
/* v1.59.0 — Sub-menú expandible para Tutoriales y Configuración */
.nav-cards-drop .nav-cards-item-expand {
    background: none;
    border: none;
    cursor: pointer;
    width: 100%;
    text-align: left;
    font-family: inherit;
    color: var(--netza-ink-3);
    padding: 10px 14px;
    font-size: 13px;
    line-height: 1.2;
    display: flex;
    align-items: center;
    gap: 12px;
}
.nav-cards-drop .nav-cards-item-expand:hover { background: var(--netza-stone); }
.nav-cards-drop .nav-cards-item-expand > i { width: 22px; text-align: center; font-size: 15px; }
.nav-cards-drop .nav-cards-item-expand .nav-caret {
    margin-left: auto;
    font-size: 11px;
    transition: transform 0.18s;
}
.nav-cards-drop .nav-cards-item-expand.activo .nav-caret { transform: rotate(180deg); }
.nav-cards-drop .nav-cards-submenu {
    display: none;
    /* v2.10.38 — Mismo padding-left que padres (14px) en lugar de 18px para
       que el ícono del subitem alinee visualmente con el del padre. */
    padding: 0;
    /* v2.10.55 (Facu 2026-05-13) — Bg paper-warm (#fbf8f2) en lugar de --netza-stone
       (#ebe5d8) para unificar todos los bg del menú "Ir a..." en el mismo tono. */
    background: #fbf8f2;
    border-top: 1px solid var(--netza-rule);
    border-bottom: 1px solid var(--netza-rule);
}
.nav-cards-drop .nav-cards-submenu.activo { display: block; }
.nav-cards-drop .nav-cards-subitem {
    display: flex;
    align-items: center;
    gap: 12px;
    /* v2.10.38 rev3 — Padding uniforme con padres (10px vertical).
       Padding-left extra (22px) para indentar el sub-item bajo su padre. */
    padding: 10px 14px 10px 22px;
    font-size: 13px;
    line-height: 1.2;
    color: var(--netza-ink-3);
    text-decoration: none;
    transition: background 0.15s;
}
.nav-cards-drop .nav-cards-subitem:hover { background: var(--netza-paper); color: var(--netza-ink); }
.nav-cards-drop .nav-cards-subitem i { width: 22px; text-align: center; font-size: 15px; }
@media (max-width: 600px) {
    .nav-cards-drop {
        /* v1.74.0 #70 — ancho ajustado al contenido + alineado a la derecha. */
        position: fixed;
        top: calc(var(--nav-h) + 4px);
        right: 12px;
        left: auto;
        width: max-content;
        max-width: calc(100vw - 24px);
        /* v2.10.38 (Facu 2026-05-13) — Si el dropdown se expande a su altura
           total (Tutoriales/Configuración abiertos), el último ítem quedaba
           pegado al bottom tab bar (64px) sin gap. Limitamos la altura para
           que termine antes del tab bar y agregamos scroll interno si el
           contenido no cabe. El `--bottom-tabs-h` no está como var global,
           usamos el valor literal 64 + 12px de gap = 76px. */
        max-height: calc(100vh - var(--nav-h) - 76px);
        overflow-y: auto;
        padding-bottom: 6px;
    }
}

/* ======================================================================
   CONTACTO NAV BUTTON
   ====================================================================== */
.nav-contacto-btn {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 14px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    position: relative;
    transition: opacity 0.2s;
    line-height: 1;
}
.nav-contacto-btn:hover { opacity: 0.7; }

/* v2.10.28 — Estado activo del botón contacto (modal abierto). Mismo
   tratamiento que `.notif-nav-btn-trigger.active`: en light solo glow
   blanco (sin cambio de color), dark override aplica terracota. */
.nav-contacto-btn.active i {
    transform: scale(1.35) translateY(-1px);
    filter: drop-shadow(0 2px 6px rgba(244, 240, 232, 0.5))
            drop-shadow(0 0 12px rgba(244, 240, 232, 0.45));
    transition: transform 0.18s ease, filter 0.18s ease, color 0.18s ease;
}
/* v2.10.28 — Dark mode: el navbar tiene gradient #2a251f → #1a1611 (más
   profundo que el light). Sobre ese fondo la terracota contrasta mejor
   que el glow blanco, así que volvemos al patrón del bottom-tab dark. */
body.dark-mode .notif-nav-btn-trigger.active i,
body.dark-mode .nav-contacto-btn.active i {
    color: #c0593c;
    filter: drop-shadow(0 2px 6px rgba(192, 89, 60, 0.5))
            drop-shadow(0 0 10px rgba(192, 89, 60, 0.35));
}

/* v2.10.0 — Toggle ojito visible/oculto montos.
   Misma estructura que .nav-contacto-btn (ghost button del navbar).
   Cuando data-on="1" baja la opacidad para indicar estado activo (montos
   ocultos), igual a la convencion visual de "alerta encendida" en la app. */
.nav-ojito-btn {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 14px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    position: relative;
    transition: opacity 0.2s;
    line-height: 1;
}
.nav-ojito-btn:hover { opacity: 0.7; }
.nav-ojito-btn[data-on="1"] { opacity: 0.55; }
.nav-ojito-btn[data-on="1"]:hover { opacity: 0.85; }

/* v2.11.18 rev5 — Toggle Personal/Familia. Mismo patrón ojito:
   data-vista="personal" → dimmed + fa-slash overlay (Familia OFF);
   data-vista="familia"  → full opacity, sin slash (Familia ON).
   Color blanco (netza-paper) en AMBOS modos (light + dark), igual ojito. */
.nav-gf-vista-btn {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 14px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    position: relative;
    transition: opacity 0.2s;
    line-height: 1;
}
.nav-gf-vista-btn:hover { opacity: 0.85; }
.nav-gf-vista-btn[data-vista="personal"] { opacity: 0.55; }
.nav-gf-vista-btn[data-vista="personal"]:hover { opacity: 0.85; }
.nav-gf-vista-btn[data-vista="familia"] { opacity: 1; }
.nav-gf-vista-btn[data-vista="familia"]:hover { opacity: 0.85; }
.nav-gf-icon-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.nav-gf-icon-slash {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 18px;
    color: inherit;
    pointer-events: none;
    display: none;
}
.nav-gf-vista-btn[data-vista="personal"] .nav-gf-icon-slash {
    display: inline-block;
}

/* v2.10.7 — Toggle modo claro/oscuro. Mismo estilo ghost button que ojito
   y contacto. */
.nav-theme-btn {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 14px;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    position: relative;
    transition: opacity 0.2s;
    line-height: 1;
}
.nav-theme-btn:hover { opacity: 0.7; }

/* v2.10.71 (Facu 2026-05-13) — Dark mode SOLO en mobile (rollback temporal
   de v2.10.68: el sprint DT se enfoca en light primero). Botón toggle
   oculto en DT (>600px). */
@media (min-width: 601px) {
    .nav-theme-btn {
        display: none !important;
    }
}

/* ======================================================================
   MODAL DE VALIDACIÓN (global, oculto por defecto)
   ====================================================================== */
#modal-validacion {
    display: none;
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    background: rgba(20,19,17,0.55);
    z-index: 9999;
    align-items: center;
    justify-content: center;
}
#modal-validacion.activo { display: flex; }
.modal-validacion-box {
    background: var(--netza-paper);
    border-radius: var(--netza-r-xl);
    padding: 24px 28px;
    max-width: 400px;
    width: 90%;
    border: 1px solid var(--netza-rule);
    box-shadow: 0 8px 30px rgba(20,19,17,0.2);
}
.modal-validacion-box h3 {
    color: var(--netza-terracota);
    margin-bottom: 10px;
    font-size: 15px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.modal-validacion-box p {
    font-size: 13px;
    color: var(--netza-ink-3);
    margin-bottom: 10px;
}
.modal-validacion-box ul {
    margin: 0 0 18px 18px;
    font-size: 13px;
    color: var(--netza-ink-2);
}
.modal-validacion-box ul li { margin-bottom: 4px; }

/* v2.11.36 — Variante "info" del modal-validacion. Cuando el caller
   pasa opts.tipo='info' a _netzaMostrarModalErrores, se agrega esta
   clase al modal. El icono se cambia a fa-circle-info (JS) y el color
   del titulo deja de ser terracota de alarma para ser ink neutro.
   Usado por _netzaAvisoCanalIol cuando se intenta resetear un canal
   linkeado a IOL — no es un error, solo informacion. */
.modal-validacion--info .modal-validacion-box h3 {
    color: var(--netza-ink);
}
.modal-validacion--info .modal-validacion-box h3 i {
    color: var(--netza-ink-3);
}

/* v2.11.16 — Botón "Entendido" alineado a la derecha en todos los
   modales de validación. `display:block + margin-left:auto` alinea sin
   alterar el layout del resto del contenido (h3/p/ul siguen alineados
   a la izquierda como antes). */
.modal-validacion-box .btn-primary {
    display: block;
    margin-left: auto;
}

/* v2.11.16 — Dark mode del modal-validacion. Antes estaba en
   ocr-comprobante.css que no se carga en todas las páginas. Movido acá
   para coverage global (modal ahora se usa también para montos inválidos
   en cualquier form de la app, no solo OCR). */
body.dark-mode .modal-validacion-box {
    background: #231f1a;
    border-color: rgba(255, 255, 255, 0.08);
    color: #f4f0e8;
}
body.dark-mode .modal-validacion-box p,
body.dark-mode .modal-validacion-box ul {
    color: rgba(244, 240, 232, 0.75);
}
body.dark-mode .modal-validacion-box h3 {
    /* Mantener terracota — buen contraste en ambos modes. */
    color: var(--netza-terracota);
}

/* v2.11.16 — Botón "Entendido" dark mode: terracota Netza estándar
   (#a84a2a, mismo de send-btn del chat / boton primario en dark). Hover
   más claro para feedback visual. */
body.dark-mode .modal-validacion-box .btn-primary {
    background: #a84a2a;
    border-color: #a84a2a;
    color: #fff;
}
body.dark-mode .modal-validacion-box .btn-primary:hover {
    background: #c0593c;
    border-color: #c0593c;
}

/* ======================================================================
   POPOVER DE AYUDA (global, oculto por defecto)
   ====================================================================== */
/* v2.10.95 (Facu 2026-05-14) — UNIFICACIÓN DE LAMPARITAS.
   Antes había varias clases con estilos distintos:
   - .btn-ayuda (rectángulo, color warning) ← canónico
   - .btn-tutorial-dash (circular, color ink-4)
   - .cm-btn-tut / .pm-btn-tut / .dm-btn-tut / etc. (variantes mobile)

   Ahora TODAS usan el mismo look (igual al de splitza): rectángulo,
   color warning (amarillo Netza), opacity 0.75 → 1 hover, bg amarillo
   translúcido cuando "encendida"/"activo". Mismo fa-lightbulb icon
   globalmente. */
.btn-ayuda,
.btn-tutorial-dash,
.cm-btn-tut,
.pm-btn-tut,
.dm-btn-tut,
.vr-btn-tut,
.fc-btn-tut,
.hist-btn-tut,
.notif-btn-tut,
.sm-btn-tut,
.hm-btn-tutorial,
.tutorial-btn-help,
button.btn-lamparita {
    background: none;
    border: 1px solid transparent;
    /* v2.10.106 (Facu 2026-05-14) — Lamparitas APAGADAS por default: color
       gris semi-transparente (igual percepción que la del home). Antes
       todas iban con color warning (amarillo Netza) + opacity 0.75, lo
       que se veía como "encendidas" en cualquier pantalla. Hover / activo
       las prenden a warning + bg amarillo translúcido (rules más abajo). */
    color: rgba(45, 37, 32, 0.45);
    cursor: pointer;
    font-size: 14px;
    padding: 7px 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--netza-r-md);
    opacity: 1;
    transition: opacity 0.2s, border-color 0.15s, background 0.15s, color 0.15s;
    line-height: 1;
    vertical-align: middle;
    /* Resetear width/height para variantes que eran circulares (btn-tutorial-dash). */
    width: auto;
    height: auto;
}
/* Dark mode: lamparita apagada con gris claro semi-transparente. */
body.dark-mode .btn-ayuda,
body.dark-mode .btn-tutorial-dash,
body.dark-mode .cm-btn-tut,
body.dark-mode .pm-btn-tut,
body.dark-mode .dm-btn-tut,
body.dark-mode .vr-btn-tut,
body.dark-mode .fc-btn-tut,
body.dark-mode .hist-btn-tut,
body.dark-mode .notif-btn-tut,
body.dark-mode .sm-btn-tut,
body.dark-mode .hm-btn-tutorial,
body.dark-mode .tutorial-btn-help,
body.dark-mode button.btn-lamparita {
    color: rgba(244, 240, 232, 0.40);
}
/* v2.10.106 — Hover: prende la lamparita (color warning amarillo Netza).
   Wrapped en `@media (hover: hover)` para que NO se aplique en touch devices
   (mobile): ahí el :hover queda "pegajoso" tras el tap y la lamparita
   parecía quedar encendida después de cerrar el modal. */
@media (hover: hover) {
    .btn-ayuda:hover,
    .btn-tutorial-dash:hover,
    .cm-btn-tut:hover,
    .pm-btn-tut:hover,
    .dm-btn-tut:hover,
    .vr-btn-tut:hover,
    .fc-btn-tut:hover,
    .hist-btn-tut:hover,
    .notif-btn-tut:hover,
    .sm-btn-tut:hover,
    .hm-btn-tutorial:hover,
    .tutorial-btn-help:hover,
    button.btn-lamparita:hover {
        color: var(--netza-warning);
        transform: none;  /* Reset transform que algunos mobile variants tenían en hover. */
    }
}
/* On state: encendida (popover-ayuda) o activa (toggle tutorials). */
.btn-ayuda.encendida,
.btn-tutorial-dash.activo,
.btn-tutorial-dash.encendida,
.cm-btn-tut.encendida, .cm-btn-tut.activo,
.pm-btn-tut.encendida, .pm-btn-tut.activo,
.dm-btn-tut.encendida, .dm-btn-tut.activo,
.vr-btn-tut.encendida, .vr-btn-tut.activo,
.fc-btn-tut.encendida, .fc-btn-tut.activo,
.hist-btn-tut.encendida, .hist-btn-tut.activo,
.notif-btn-tut.encendida, .notif-btn-tut.activo,
.sm-btn-tut.encendida, .sm-btn-tut.activo,
.hm-btn-tutorial.encendida, .hm-btn-tutorial.activo,
body.home-tutorial-activo .hm-btn-tutorial,
.tutorial-btn-help.encendida,
button.btn-lamparita.encendida {
    opacity: 1;
    background: rgba(193, 145, 33, 0.18);
    border-color: var(--netza-warning);
    color: var(--netza-warning);
}

/* v2.10.97 (Facu 2026-05-14) — Forzar que los iconos `<i>` dentro de
   las lamparitas hereden el color del botón. Algunos templates tienen
   reglas como `body.X-mobile-page h2 i { color: ... }` que pintan
   TODOS los <i> dentro del h2 (incluido el lightbulb dentro del
   `.btn-ayuda` que vive en el h2 de splitza), pisando el color del
   botón unificado. Con `color: inherit !important` el icono toma el
   color del botón (warning yellow off, warning yellow encendida). */
.btn-ayuda i,
.btn-tutorial-dash i,
.cm-btn-tut i,
.pm-btn-tut i,
.dm-btn-tut i,
.vr-btn-tut i,
.fc-btn-tut i,
.hist-btn-tut i,
.notif-btn-tut i,
.sm-btn-tut i,
.hm-btn-tutorial i,
.tutorial-btn-help i,
button.btn-lamparita i {
    color: inherit !important;
}
.popover-ayuda {
    position: fixed;
    background: var(--netza-paper);
    border-radius: var(--netza-r-xl);
    box-shadow: 0 6px 24px rgba(20,19,17,0.18);
    width: 300px;
    /* v2.10.7 — z-index subido a 10003 para que el popover de la lamparita
       quede ENCIMA del modal-form-global (z-index 8500) y otros modales
       cuando se invoca desde dentro de uno de ellos (Nuevo Registro,
       Forecast Ingreso/Egreso, etc.). */
    z-index: 10003;
    border: 1px solid var(--netza-rule);
    display: none;
}
.popover-ayuda.activo { display: block; }
.popover-ayuda-header {
    background: var(--netza-ink);
    color: var(--netza-paper);
    padding: 10px 14px;
    border-radius: var(--netza-r-xl) var(--netza-r-xl) 0 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 13px;
    font-weight: 500;
}
.popover-ayuda-header button {
    background: none;
    border: none;
    color: var(--netza-paper);
    font-size: 18px;
    cursor: pointer;
    line-height: 1;
    padding: 0;
    opacity: 0.7;
}
.popover-ayuda-header button:hover { opacity: 1; }
.popover-ayuda-body {
    padding: 18px 16px 12px;
    text-align: center;
}
.popover-ayuda-body .p-icono {
    font-size: 28px;
    color: var(--netza-ink);
    margin-bottom: 10px;
    display: block;
}
.popover-ayuda-body h4 {
    font-size: 14px;
    margin-bottom: 8px;
    color: var(--netza-ink);
}
.popover-ayuda-body p {
    font-size: 13px;
    color: var(--netza-ink-3);
    line-height: 1.5;
    margin: 0;
}
.popover-ayuda-tip {
    background: rgba(179,138,42,0.1);
    border: 1px solid rgba(179,138,42,0.3);
    border-radius: var(--netza-r-sm);
    padding: 7px 10px;
    margin-top: 10px;
    font-size: 12px;
    color: var(--netza-warning);
    text-align: left;
}
.popover-ayuda-footer {
    padding: 9px 14px;
    border-top: 1px solid var(--netza-rule);
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.popover-ayuda-footer span {
    font-size: 11px;
    color: var(--netza-ink-4);
    font-family: var(--netza-font-mono);
}
.popover-ayuda-footer button {
    background: none;
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-sm);
    padding: 4px 10px;
    cursor: pointer;
    font-size: 12px;
    color: var(--netza-ink-2);
    font-family: var(--netza-font-sans);
}
.popover-ayuda-footer button:hover:not(:disabled) { background: var(--netza-stone); }
.popover-ayuda-footer button:disabled { opacity: 0.3; cursor: default; }

/* ======================================================================
   MODAL FORM GLOBAL (formularios flotantes)
   ====================================================================== */
#modal-form-global {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(20,19,17,.55);
    z-index: 8500;
    align-items: flex-start;
    justify-content: center;
    padding: 60px 16px 24px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}
#modal-form-global.activo { display: flex; }
.modal-form-box {
    background: var(--netza-paper);
    border-radius: var(--netza-r-xl);
    width: 100%;
    max-width: 520px;
    border: 1px solid var(--netza-rule);
    box-shadow: 0 8px 40px rgba(20,19,17,.28);
    display: flex;
    flex-direction: column;
    margin: 0 auto;
    flex-shrink: 0;
}
.modal-form-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 20px 12px;
    border-bottom: 1px solid var(--netza-rule);
    flex-shrink: 0;
    background: var(--netza-stone);
    border-radius: var(--netza-r-xl) var(--netza-r-xl) 0 0;
}
.modal-form-title {
    font-size: 11px;
    font-weight: 500;
    color: var(--netza-ink-3);
    font-family: var(--netza-font-mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.modal-form-close {
    width: 28px;
    height: 28px;
    border: none;
    background: var(--netza-paper);
    border-radius: 50%;
    cursor: pointer;
    font-size: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--netza-ink-3);
    flex-shrink: 0;
    line-height: 1;
    transition: background 0.15s, color 0.15s;
}
.modal-form-close:hover { background: var(--netza-stone-2); color: var(--netza-ink); }
.modal-form-body {
    padding: 20px;
}
/* Ocultar h2 de páginas de edición cuando se renderizan dentro del modal */
#modal-form-body h2 { display: none !important; }
@media (max-width: 600px) {
    #modal-form-global { padding: 48px 8px 20px; }
}

/* ======================================================================
   TOAST NOTIFICATIONS
   ====================================================================== */
#netza-toast-container {
    position: fixed;
    /* v2.4.x - Reservar espacio para el FAB "+" (FAB: right 24 + width 54 + 18 sep = 96px). */
    bottom: 24px;
    right: 96px;
    z-index: 9600;
    display: flex;
    flex-direction: column-reverse;
    gap: 10px;
    align-items: flex-end;
    pointer-events: none;
}
.netza-toast {
    background: var(--netza-ink);
    border-radius: 10px;
    padding: 11px 12px 11px 11px;
    min-width: 0;
    max-width: 380px;
    display: flex;
    align-items: flex-start;
    gap: 9px;
    box-shadow: 0 4px 22px rgba(20,19,17,.40);
    pointer-events: all;
    transform: translateX(calc(100% + 32px));
    transition: transform 0.3s cubic-bezier(0.34,1.4,0.64,1);
    border: 1px solid rgba(255,255,255,.06);
}
.netza-toast.visible { transform: translateX(0); }
.netza-toast.hiding  { transform: translateX(calc(100% + 32px)); transition: transform 0.2s ease-in; }
.netza-toast-icon {
    width: 22px; height: 22px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 10px;
    flex-shrink: 0;
    margin-top: 1px;
    color: #fff;
}
/* v2.10.9 rev13 — Toast con formato condicional unificado (decision Facu):
   verde #3a7d5a / rojo #c45a3f (mismos códigos que toda la app). Antes el
   negativo usaba terracota #a84a2a, ahora usa el rojo canónico. */
.netza-toast-icon.positivo { background: var(--netza-positivo); }
.netza-toast-icon.negativo { background: var(--netza-negativo); }
.netza-toast-icon.warning  { background: var(--netza-warning); }
.netza-toast-icon.neutro   { background: var(--netza-ink-3); }
/* v1.79.10 - toast rojo fuerte para suscripcion vencida (mas alarmante que terracota) */
.netza-toast-icon.suscripcion-vencida { background: #c0392b; }

/* v1.79.10 - Botones de creacion disabled cuando suscripcion vencida.
   Marca el body con data-susc-vencida="true" desde base.html. Los botones
   se marcan con clase .btn-create-bloqueable. JS handler global intercepta
   clicks y muestra toast (en lugar de pointer-events:none que mata events). */
[data-susc-vencida="true"] .btn-create-bloqueable {
    opacity: 0.5 !important;
    background: var(--netza-ink-3) !important;
    color: var(--netza-paper) !important;
    border-color: var(--netza-ink-3) !important;
    cursor: not-allowed !important;
}
[data-susc-vencida="true"] .btn-create-bloqueable:hover {
    background: var(--netza-ink-3) !important;
    border-color: var(--netza-ink-3) !important;
}

/* v1.79.10 - Empty state generico (forecasts sin cargar, etc).
   Tipografia alineada con la app: 13px desktop / 12px mobile. */
.empty-state {
    color: var(--netza-ink-3);
    font-size: 13px;
    line-height: 1.5;
    padding: 12px 0;
    margin: 0;
}
@media (max-width: 600px) {
    .empty-state { font-size: 12px; padding: 8px 0; }
}
.netza-toast-content { flex: 1; min-width: 0; }
.netza-toast-titulo {
    font-size: 11px;
    font-weight: 600;
    color: var(--netza-paper);
    line-height: 1.3;
    margin-bottom: 2px;
    font-family: var(--netza-font-mono);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.netza-toast-sub {
    font-size: 12px;
    font-family: var(--netza-font-sans);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--netza-ink-4);
}
/* v2.10.9 rev13 — Monto del toast con paleta unificada (Facu): verde
   #3a7d5a / rojo #c45a3f, mismos que el resto de la app. Antes había
   tonos custom (#8fd15e / #e8826a). */
.netza-toast-monto { font-weight: 600; font-family: var(--netza-font-mono); }
.netza-toast-monto.positivo { color: #3a7d5a; }
.netza-toast-monto.negativo { color: #c45a3f; }
.netza-toast-monto.warning  { color: #b38a2a; }
.netza-toast-monto.neutro   { color: var(--netza-ink-4); }
.netza-toast-close {
    background: none; border: none;
    color: rgba(255,255,255,.35);
    cursor: pointer; font-size: 15px; line-height: 1;
    padding: 0; flex-shrink: 0; margin-left: 2px;
    transition: color 0.15s;
}
.netza-toast-close:hover { color: rgba(255,255,255,.8); }
@media (max-width: 600px) {
    /* v2.10.10 — Toasts del FAB action alineados a la derecha y ajustados
       al contenido (no full-width). Antes left:12px + right:12px hacía que
       el toast ocupara todo el ancho del viewport — quedaba demasiado pesado
       visualmente para mensajes cortos como "Registro creado". */
    #netza-toast-container { bottom: 76px; right: 12px; left: auto; }
    .netza-toast {
        max-width: calc(100vw - 24px);
        width: max-content;
        box-sizing: border-box;
    }
    /* v1.53.0 — Permitir wrap del subtítulo en mobile (antes tenía nowrap+ellipsis,
       cortaba mensajes largos como "Movimiento eliminado: Caja $ → ICBC $"). */
    .netza-toast-sub {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
        word-wrap: break-word;
    }
    /* v2.10.10 — Texto alineado a la izquierda dentro del toast (el toast
       en sí está a la derecha de la pantalla). Antes text-align:center
       quedaba raro cuando el contenido es corto y el toast es chico. */
    .netza-toast-titulo { font-size: 10px; text-align: left; }
    .netza-toast-sub    { font-size: 11px; text-align: left; }
}

/* ===== Toast in-app de notificaciones (v1.88.x) =====
   Aparece arriba a la derecha cuando llega una notif nueva. Sirve en mobile
   (donde la Notification del SO puede no funcionar) y como complemento en
   desktop. Auto-fade en 5s. */
.netza-notif-toast {
    position: fixed;
    /* v2.4.x - debajo del nav sticky (var(--nav-h)) para no pisar el menu principal */
    top: calc(var(--nav-h) + 12px);
    right: 16px;
    z-index: 99999;
    background: var(--netza-ink);
    color: var(--netza-paper);
    padding: 12px 16px;
    border-radius: 10px;
    box-shadow: 0 8px 28px rgba(20, 19, 17, 0.35);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.4;
    /* v2.10.10 — Ancho ajustado al contenido (no fijo) con cap del 90% del
       viewport para que mensajes largos no se desborden. Antes en mobile
       tenía left:12px + right:12px → ocupaba todo el ancho. Ahora siempre
       alineado a la derecha. */
    width: max-content;
    max-width: min(360px, calc(100vw - 32px));
    display: flex;
    align-items: center;
    gap: 10px;
    opacity: 0;
    transform: translateY(-12px);
    transition: opacity .25s ease, transform .25s ease;
    pointer-events: none;
}
.netza-notif-toast.visible {
    opacity: 1;
    transform: translateY(0);
}
.netza-notif-toast i {
    color: var(--netza-terracota);
    font-size: 14px;
    flex-shrink: 0;
}
@media (max-width: 600px) {
    .netza-notif-toast {
        top: calc(var(--nav-h) + 8px);
        right: 12px;
        max-width: calc(100vw - 24px);
        font-size: 12px;
        padding: 10px 14px;
    }
}

/* ===== TUTORIALES FORMALES (shared across all tutorial_*.html) ===== */
.tutorial-layout {
    display: flex;
    gap: 25px;
    align-items: flex-start;
}
.tutorial-sidebar {
    width: 260px;
    flex-shrink: 0;
    background-color: var(--netza-paper);
    border-radius: 10px;
    border: 1px solid var(--netza-stone);
    overflow: hidden;
}
.tutorial-sidebar h3 {
    padding: 15px;
    margin: 0;
    font-size: 14px;
    border-bottom: 1px solid var(--netza-stone);
}
.sidebar-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 15px;
    text-decoration: none;
    color: var(--netza-ink);
    font-size: 13px;
    border-bottom: 1px solid var(--netza-stone);
    cursor: pointer;
    transition: background-color 0.2s;
}
.sidebar-item:last-child {
    border-bottom: none;
}
.sidebar-item:hover {
    background-color: #eef1f3;
}
.sidebar-item.active {
    background-color: var(--netza-ink);
    color: white;
}
.sidebar-item i {
    width: 18px;
    text-align: center;
}
.tutorial-main {
    flex: 1;
    min-width: 0;
}
.tutorial-nav-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
    /* v1.88.x — Alinear con tutorial-content (al lado del sidebar 260px + gap 25px). */
    padding-left: 285px;
    box-sizing: border-box;
}
.tutorial-nav-top .btn {
    min-width: 110px;
    justify-content: center;
}
.step-counter-top {
    font-size: 13px;
    color: #999;
}
.tutorial-progress {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-bottom: 20px;
    flex-wrap: wrap;
    /* v1.88.x — Alinear las pelotitas con el centro del .tutorial-content
       (que esta al lado del sidebar). Sidebar 260px + gap 25px = 285px de
       offset. En mobile el sidebar pasa arriba (flex-direction: column) y
       las pelotitas se ocultan. */
    padding-left: 285px;
    box-sizing: border-box;
}
.tutorial-progress .step-dot {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--netza-rule);
    color: #999;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: bold;
    transition: all 0.3s;
    cursor: pointer;
}
.tutorial-progress .step-dot.active {
    background-color: var(--netza-ink);
    color: white;
}
.tutorial-progress .step-dot.completed {
    background-color: var(--netza-positivo);
    color: white;
}
.tutorial-content {
    background-color: var(--netza-paper);
    border-radius: 10px;
    padding: 30px;
    border: 1px solid var(--netza-stone);
    min-height: 280px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
}
/* v1.74.0 #69 — fonts compactas para unificar con el resto de la app. */
.tutorial-content i.main-icon {
    font-size: 36px;
    color: var(--netza-ink);
    margin-bottom: 16px;
}
.tutorial-content h3 {
    font-size: 16px;
    margin-bottom: 10px;
}
.tutorial-content p {
    color: var(--netza-ink-3);
    font-size: 13px;
    line-height: 1.55;
    max-width: 800px;
    width: 100%;
}
.tutorial-content .tip {
    background-color: #fff3cd;
    border: 1px solid #ffc107;
    border-radius: 6px;
    padding: 10px 14px;
    margin-top: 12px;
    font-size: 11px;
    color: #856404;
    max-width: 800px;
    width: 100%;
}
.tutorial-content .tip i {
    margin-right: 6px;
}
@media (max-width: 768px) {
    .tutorial-layout {
        flex-direction: column;
    }
    .tutorial-sidebar {
        width: 100%;
    }
    /* v1.88.x — Eliminar pelotitas en mobile: con sidebar arriba ocupan
       espacio sin aportar. El step-counter del header ya muestra "X de N". */
    .tutorial-progress {
        display: none;
    }
    .tutorial-content {
        padding: 18px 14px;
        min-height: 200px;
    }
    .tutorial-content i.main-icon {
        font-size: 28px;
    }
    .tutorial-content h3 {
        font-size: 14px;
    }
    .tutorial-content p {
        font-size: 12px;
    }
    .tutorial-content .tip { font-size: 10px; }
    /* v1.74.0 #69 — sidebar de Contenido más compacto en mobile. */
    .tutorial-sidebar h3 { font-size: 12px; padding: 10px 12px; }
    .sidebar-item { font-size: 11px; padding: 8px 12px; gap: 8px; }
    .sidebar-item i { width: 14px; font-size: 12px; }
    .tutorial-nav-top .btn {
        min-width: 90px;
        font-size: 12px;
    }
    /* v1.88.x — En mobile el sidebar pasa arriba, sin offset al nav-top */
    .tutorial-nav-top {
        padding-left: 0;
    }
}
.tutorial-nav-bottom {
    display: none;
}
@media (max-width: 768px) {
    .tutorial-nav-bottom {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-top: 20px;
        padding-top: 16px;
        border-top: 1px solid var(--netza-rule);
    }
    .tutorial-nav-bottom .btn {
        min-width: 90px;
        font-size: 12px;
        justify-content: center;
        flex-shrink: 0;
    }
    .tutorial-nav-bottom .step-counter-top {
        flex: 1;
        text-align: center;
        font-size: 13px;
        color: var(--netza-ink-3);
    }
}

/* ======================================================================
   FORMULARIOS — compactos en mobile (v1.50.0)
   Aplica a TODOS los form-group de la app: modales, forms inline de Nuevo,
   edición, login, signup, reset password, etc. Objetivo: entrar sin scroll.
   ====================================================================== */
@media (max-width: 600px) {
    /* Modal container */
    .modal-backdrop .modal {
        padding: 10px 12px;
        max-width: calc(100% - 16px);
        width: calc(100% - 16px);
        max-height: 96vh;
    }
    .modal-backdrop .modal-title {
        font-size: 12px;
        margin-bottom: 6px;
        padding-bottom: 6px;
        gap: 6px;
    }
    .modal-backdrop .modal-title i { font-size: 12px; }
    .modal-backdrop .modal p { font-size: 10px; margin: 4px 0; }
    .modal-backdrop .modal-footer {
        margin-top: 8px;
        padding-top: 8px;
        gap: 6px;
    }

    /* Form-group universal — compacto para que entre sin scroll vertical */
    .form-group { margin-bottom: 5px; }
    .form-group label {
        font-size: 9px; /* v1.80.0 — escala mobile unificada (era 11px) */
        margin-bottom: 2px;
        letter-spacing: 0.06em;
        line-height: 1.1;
        display: block;
    }
    /* v1.80.0 — font-size de los inputs DENTRO de form-group queda gobernado
       por el bloque iOS-detection (líneas ~668+). No declaramos font-size acá
       para que cascadee 11px (no-iOS) o 16px (iOS). Mantenemos padding/altura. */
    .form-group input[type="text"],
    .form-group input[type="password"],
    .form-group input[type="email"],
    .form-group input[type="number"],
    .form-group input[type="date"],
    .form-group input[type="tel"],
    .form-group select,
    .form-group textarea {
        padding: 5px 9px;
        min-height: 30px;
        height: auto;
        box-sizing: border-box;
    }
    /* Radios en mobile: mismo tamaño compacto en TODOS los forms (pantalla
       directa o dentro del modal). v1.74.0 #68. */
    .radio-group { gap: 14px !important; padding-top: 0 !important; }
    .radio-group label.radio-option,
    label.radio-option {
        font-size: 12px !important;
        gap: 5px !important;
    }
    label.radio-option input[type="radio"] { width: 13px !important; height: 13px !important; }
    label.radio-option span { font-size: 12px !important; }
    .form-group textarea { height: auto; min-height: 36px; }
    .form-row { gap: 6px; margin-bottom: 5px; }
    /* v1.89.2 — Año + Mes en paralelo en mobile (en lugar de apilados) para
       reducir altura del form. Mes recibe mas ancho (3fr) que Año (2fr) porque
       los meses ("septiembre") son mas largos que los años ("2026"). Aplica a
       carga simple, edicion y carga masiva (anio-ini/mes-ini, anio-fin/mes-fin). */
    .form-row.form-row-anio-mes { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
    .form-actions { gap: 6px; margin-top: 6px; }
    .btn-icon-action { width: 26px; height: 26px; }
    .btn-icon-action svg { width: 12px !important; height: 12px !important; }

    /* Botones dentro de modales */
    .modal-backdrop .btn,
    .modal-backdrop .btn-primary {
        font-size: 10px; padding: 4px 8px; height: auto;
    }

    /* Toggle "Carga simple / Carga masiva" en los forecasts */
    #form_nuevo > form > div[style*="border-bottom"],
    .modal-backdrop .modal > div[style*="border-bottom"] {
        padding: 4px 0 8px !important;
        margin-bottom: 8px !important;
        gap: 14px !important;
    }
    #form_nuevo > form > div[style*="border-bottom"] label,
    .modal-backdrop .modal > div[style*="border-bottom"] label {
        font-size: 10px !important;
        text-transform: none !important;
        letter-spacing: 0 !important;
        margin: 0 !important;
    }
    #form_nuevo > form > div[style*="border-bottom"] input[type="radio"],
    .modal-backdrop .modal > div[style*="border-bottom"] input[type="radio"] {
        width: 12px;
        height: 12px;
        margin-right: 4px;
    }

    /* Botón calculadora al lado del monto */
    .btn-calc-open { width: 26px; height: 24px; font-size: 12px; }
}

/* ======================================================================
   v1.75.1 #77 — Override global para `body.page-scroll-footer`.
   El pattern del template fija `height: 100vh` para tener footer sticky abajo
   y la tabla con scroll interno. En mobile `100vh` incluye la URL bar dinámica
   del browser → el footer queda fuera de la pantalla visible.
   Solución: `100dvh` (dynamic viewport height) que excluye la URL bar.
   Usamos !important porque la regla local de cada template (en su <style>
   inline) viene después del CSS global y la pisaría sin él.
   Aplica a las 11 pantallas: anios, categorias, conceptos, canales, vto_tarjeta,
   usd_historico, ver_registros, historial, notificaciones, forecast_egresos,
   forecast_ingresos.
   ====================================================================== */
body.page-scroll-footer {
    height: 100dvh !important;
}


/* ======================================================================
   v1.84.0 #6 — Card "Total canales" + modal selector de canal.
   Estilos compartidos entre home (index.html) y dashboard (dashboard.html).
   Antes vivian inline en el <style> del home; movidos aca para reutilizar.
   ====================================================================== */

/* Card combinada de canales (home + dashboard) */
.home-card {
    background: var(--netza-paper);
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-lg);
    padding: 12px 14px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}
.home-card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 4px;
    width: 100%;
}
.home-card-fc {
    min-height: 2.6em;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    font-family: var(--netza-font-mono);
    font-size: 10px;
    color: var(--netza-ink-4);
    line-height: 1.3;
}
.home-card-fc .num { font-weight: 500; color: var(--netza-ink-3); }
/* === home-card shared styles (home + dashboard) === */
.home-card-label {
    font-family: var(--netza-font-mono);
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--netza-ink-4);
}

.home-card-value {
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.2;
    word-break: break-word;
}
.home-card-value .cents {
    font-size: 11px;
    font-weight: 400;
    color: var(--netza-ink-3);
    margin-left: 2px;
    letter-spacing: 0.05em;
}
.home-card.full-width { grid-column: 1 / -1; }
.home-val-pos { color: var(--netza-positivo); }
.home-val-neg { color: var(--netza-terracota); }
/* v2.10.118 — Monto de "Saldo Total Canales" en color ink-3 (#55514a) cuando
   está en neutro (=0), unificando con DT/mob. pos/neg ganan por specificity. */
.home-card.home-card-total-canales .home-card-value:not(.home-val-pos):not(.home-val-neg) {
    color: #55514a;
}
/* v2.10.124 — Total canales home: pos (>=0) verde #3a7d5a, neg (<0) rojo
   #c45a3f. Override scoped (no terracota global) en light + dark mode. */
.home-card.home-card-total-canales .home-card-value.home-val-pos { color: #3a7d5a; }
.home-card.home-card-total-canales .home-card-value.home-val-neg { color: #c45a3f; }

/* Botón reset por canal (home + dashboard). Requiere position:relative en el padre. */
.home-card.home-curr,
.home-card.home-card-total-canales { position: relative; }
.home-card-reset {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 24px; height: 24px;
    border: 1px solid var(--netza-rule);
    background: var(--netza-paper);
    border-radius: 50%;
    color: var(--netza-ink-3);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    font-size: 10px;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
    z-index: 1;
}
.home-card-reset:hover {
    background: var(--netza-ink);
    color: var(--netza-paper);
    border-color: var(--netza-ink);
}

/* Items del selector de canal (home + dashboard) */
.home-canal-select-item {
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 12px;
    border: 1px solid var(--netza-rule);
    border-radius: var(--netza-r-md);
    background: var(--netza-paper);
    cursor: pointer;
    font-family: var(--netza-font-sans);
    text-align: left;
    transition: border-color 0.15s, background 0.15s;
}
.home-canal-select-item:hover {
    border-color: var(--netza-ink-3);
    background: var(--netza-stone);
}
.home-canal-select-nombre { font-size: 13px; color: var(--netza-ink); font-weight: 500; }
.home-canal-select-saldo {
    font-family: var(--netza-font-mono); font-variant-numeric: tabular-nums;
    font-size: 12px;
}
.home-canal-select-saldo.home-val-pos { color: var(--netza-positivo); }
.home-canal-select-saldo.home-val-neg { color: var(--netza-terracota); }

/* Patrimonio Neto card — fondo oscuro, tipografía clara (v1.86.0) */
.home-card.home-card-pn {
    background: var(--netza-ink);
    border-color: var(--netza-ink-2);
    color: var(--netza-paper);
    position: relative;
    overflow: hidden;
}
.home-card.home-card-pn::before {
    content: '';
    position: absolute;
    top: 6px;
    right: 6px;
    width: 64px;
    height: 64px;
    opacity: 0.07;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 180 180'><g transform='rotate(-5 90 90)'><rect x='22' y='88.25' width='136' height='3' fill='%23f4f0e8'/><circle cx='46' cy='78' r='9' fill='%23f4f0e8'/><circle cx='138' cy='66' r='22' fill='%23f4f0e8'/></g><path d='M 90 100 L 74 126 L 106 126 Z' fill='%23f4f0e8'/></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    pointer-events: none;
}
.home-card.home-card-pn .home-card-label { color: var(--netza-ink-4); }
.home-card.home-card-pn .home-card-fc { color: var(--netza-ink-4); }
.home-card.home-card-pn .home-card-fc .num { color: var(--netza-paper); }
.home-card.home-card-pn .home-card-value .cents { color: var(--netza-ink-4); }
.home-card.home-card-pn .home-val-pos { color: #3a7d5a; }
.home-card.home-card-pn .home-val-neg { color: var(--netza-terracota); }

/* ======================================================================
   DARK MODE GLOBAL (v2.10.7)
   Aplica cuando body.dark-mode. Tokens locales para componentes globales:
   navbar dropdown, notif dropdown, footer, modales (.modal-backdrop > .modal),
   modal contacto, etc.
   ====================================================================== */
body.dark-mode {
    background: #141311;
    color: #f4f0e8;
    /* v2.10.9 rev5 — Decision Facu: verde/rojo OSCUROS en ambos modos
       (#3a7d5a / #c45a3f). Antes en dark se cambiaba a los claros del
       hero PN; ahora unificamos todo a los oscuros. Las vars se mantienen
       como en :root (no se redefinen acá). */
}
/* v2.10.9 rev19 — Modal de inactividad ("¿Seguís ahí?") en dark mode.
   El modal usa inline styles con vars --netza-paper / --netza-ink que NO
   se redefinen en dark. Override directo de los estilos inline acá. */
body.dark-mode #modal-inactividad > div {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
}
body.dark-mode #modal-inactividad > div > div:first-child {
    background: rgba(217, 164, 65, 0.15) !important;
}
body.dark-mode #modal-inactividad h3 { color: #f4f0e8; }
body.dark-mode #modal-inactividad p {
    color: rgba(244, 240, 232, 0.65) !important;
}
body.dark-mode #modal-inactividad p strong {
    color: #c0593c !important;
}
body.dark-mode #modal-inactividad button.btn:not(.btn-primary) {
    color: rgba(244, 240, 232, 0.78) !important;
    border-color: rgba(255, 255, 255, 0.15) !important;
}
body.dark-mode #modal-inactividad button.btn:not(.btn-primary):hover {
    background: rgba(255, 255, 255, 0.05) !important;
}

/* v2.10.9 rev25 — Modal "¿En qué periodo lo cargamos?" en dark mode.
   Igual que el modal de inactividad, usa estilos inline con var(--netza-paper)
   que no se redefine en dark. Override directo de los inline styles acá.
   Aplica a ambos prefixes: nr (nuevo registro) y mr (modificar registro). */
body.dark-mode .netza-modal-confirm .netza-modal-confirm-card {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6) !important;
}
body.dark-mode .netza-modal-confirm .netza-modal-confirm-card > div:first-child > div:first-child {
    background: rgba(168, 74, 42, 0.18) !important;
}
body.dark-mode .netza-modal-confirm .netza-modal-confirm-card h3 {
    color: #f4f0e8 !important;
}
body.dark-mode .netza-modal-confirm .netza-modal-confirm-card p {
    color: rgba(244, 240, 232, 0.65) !important;
}
/* Opciones de periodo (botones MAYO 2026 / JUNIO 2026) */
body.dark-mode .netza-modal-confirm [id*="opcion-periodo-"] {
    background: rgba(255, 255, 255, 0.04) !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
}
body.dark-mode .netza-modal-confirm [id*="opcion-periodo-"]:hover {
    background: rgba(168, 74, 42, 0.10) !important;
    border-color: #c0593c !important;
}
body.dark-mode .netza-modal-confirm [id*="opcion-periodo-"] [data-role^="opcion-titulo-"] {
    color: #f4f0e8 !important;
}
body.dark-mode .netza-modal-confirm [id*="opcion-periodo-"] [data-role^="opcion-sub-"] {
    color: rgba(244, 240, 232, 0.55) !important;
}
/* Botón Cancelar */
body.dark-mode .netza-modal-confirm .netza-modal-confirm-actions button.btn {
    color: rgba(244, 240, 232, 0.78) !important;
    border-color: rgba(255, 255, 255, 0.15) !important;
}
body.dark-mode .netza-modal-confirm .netza-modal-confirm-actions button.btn:hover {
    background: rgba(255, 255, 255, 0.05) !important;
}
body.dark-mode footer.netza-footer {
    background: transparent;
    border-top-color: rgba(255, 255, 255, 0.06);
    color: rgba(244, 240, 232, 0.45);
}
body.dark-mode .netza-footer-brand { color: rgba(244, 240, 232, 0.65); }
body.dark-mode .netza-footer-dot { color: rgba(255, 255, 255, 0.10); }

/* Menú dropdown (navbar burger) */
body.dark-mode .nav-cards-drop {
    background: #231f1a;
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
body.dark-mode .nav-cards-drop-header { color: rgba(244, 240, 232, 0.55); border-bottom-color: rgba(255, 255, 255, 0.06); }
body.dark-mode .nav-cards-item,
body.dark-mode .nav-cards-subitem { color: #f4f0e8; }
body.dark-mode .nav-cards-item:hover,
body.dark-mode .nav-cards-subitem:hover {
    background: rgba(255, 255, 255, 0.06);
    color: #f4f0e8;
}
/* v2.10.x (Facu 2026-05-13) — Submenú con el mismo bg que el padre (dropdown)
   para que los items hijos de Tutoriales y Configuración no se vean como un
   "rectángulo aparte" dentro del menú. */
body.dark-mode .nav-cards-submenu { background: #231f1a; border-top-color: transparent; border-bottom-color: transparent; }

/* Notif dropdown */
body.dark-mode .notif-dropdown {
    background: #231f1a;
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
body.dark-mode .notif-drop-header,
body.dark-mode .notif-drop-footer {
    background: #1a1611;
    border-color: rgba(255, 255, 255, 0.06);
    color: rgba(244, 240, 232, 0.65);
}
/* v2.10.90 (Facu 2026-05-14) — .notif-drop-lista + .notif-drop-empty
   tienen `background: #f4f0e8` hardcoded en su base (línea ~340) sin
   override dark → en dark mode el área de lista se veía como un panel
   beige claro fuera de paleta entre header y footer dark. Override
   ahora al tono card-bg (#231f1a) para que mantenga el look sandwich
   con header/footer #1a1611 (más oscuros). */
body.dark-mode .notif-drop-lista,
body.dark-mode .notif-drop-empty {
    background: #231f1a;
}
body.dark-mode .notif-drop-empty { color: rgba(244, 240, 232, 0.55); }
body.dark-mode .notif-drop-ver,
body.dark-mode .notif-drop-footer a,
body.dark-mode .notif-drop-link { color: #f4f0e8 !important; }
body.dark-mode .notif-drop-ver:hover,
body.dark-mode .notif-drop-footer a:hover,
body.dark-mode .notif-drop-link:hover { color: #ffd9c4 !important; }
/* v2.10.7 — items de notif renderizados por JS con color inline `--netza-ink`.
   En dark forzamos texto claro para que sean legibles. */
body.dark-mode .notif-dropdown [data-notif-item] a {
    color: #f4f0e8 !important;
}
body.dark-mode .notif-dropdown [data-notif-item] {
    border-bottom-color: rgba(255, 255, 255, 0.06) !important;
}

/* Modal "Sin vencimiento registrado" — inline-styled del form_registro.
   Selector amplio que matchea id "modal-sin-vto" y "mr-modal-sin-vto". */
body.dark-mode [id$="modal-sin-vto"] > div {
    background: #231f1a !important;
    border: 1px solid rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode [id$="modal-sin-vto"] h3 { color: #f4f0e8 !important; }
body.dark-mode [id$="modal-sin-vto"] p { color: #b8aea0 !important; }

/* v2.10.28 — Overlay global (#overlay-global) ahora muestra el splash
   Netza (no el viejo modal "Procesando..."). Mismo tratamiento que
   #netza-splash: light = bg paper + logo ink, dark = bg ink + logo
   paper. El triángulo terracota se mantiene. Las reglas viejas que
   afectaban `> div`, `-msg`, `-sub`, `.fa-spinner` quedaron obsoletas
   con el rediseño v2.10.25. */
#overlay-global {
    background: var(--netza-paper);
}
#overlay-global .tilt-group rect,
#overlay-global .tilt-group circle {
    fill: var(--netza-ink) !important;
}
body.dark-mode #overlay-global {
    background: #141311;
}
body.dark-mode #overlay-global .tilt-group rect,
body.dark-mode #overlay-global .tilt-group circle {
    fill: #f4f0e8 !important;
}

/* v2.10.8 — Modal "Bienvenido al trial/plan" (_modal_plan_actual.html).
   Inline styles con `var(--netza-paper)` no se cambian en dark; override. */
body.dark-mode #modal-plan-actual > div {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #modal-plan-actual #mpa-titulo { color: #f4f0e8 !important; }
body.dark-mode #modal-plan-actual #mpa-subtitulo { color: #b8aea0 !important; }
body.dark-mode #modal-plan-actual #mpa-features li { color: #f4f0e8 !important; }
body.dark-mode #modal-plan-actual #mpa-secundario {
    background: transparent !important;
    border-color: rgba(255, 255, 255, 0.12) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #modal-plan-actual #mpa-empezar {
    background: #a84a2a !important;
    color: #fff !important;
}

/* v2.10.8 — Pantalla /upgrade (.upg-wrap, .upg-card, .upg-card-free) y
   modal "Funcionalidades — Plan X" (.netza-modal-features). */
body.dark-mode .upg-wrap { color: #f4f0e8 !important; }
body.dark-mode .upg-wrap h1,
body.dark-mode .upg-wrap h2,
body.dark-mode .upg-wrap h3 { color: #f4f0e8 !important; }
body.dark-mode .upg-wrap .page-intro,
body.dark-mode .upg-wrap p { color: rgba(244, 240, 232, 0.65) !important; }
body.dark-mode .upg-card {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode .upg-card .precio { color: #f4f0e8 !important; }
body.dark-mode .upg-card .desc,
body.dark-mode .upg-card .desc-extra,
body.dark-mode .upg-card .label-tarjeta,
body.dark-mode .upg-card .info-line,
body.dark-mode .upg-card .info-line strong { color: rgba(244, 240, 232, 0.75) !important; }
body.dark-mode .upg-card .info-discount { color: #74c89f !important; }
body.dark-mode .upg-card .off-badge { color: #74c89f !important; }
body.dark-mode .upg-card .upg-feats {
    color: rgba(244, 240, 232, 0.65) !important;
}
body.dark-mode .upg-card .upg-feats li { color: rgba(244, 240, 232, 0.75) !important; }
body.dark-mode .upg-card .upg-ver-todo {
    background: transparent !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
    color: rgba(244, 240, 232, 0.65) !important;
}
body.dark-mode .upg-card .upg-ver-todo:hover {
    background: rgba(255, 255, 255, 0.04) !important;
    border-color: rgba(255, 255, 255, 0.30) !important;
    color: #f4f0e8 !important;
}
body.dark-mode .upg-card .upg-btn-primary {
    background: #a84a2a !important;
    border-color: #a84a2a !important;
    color: #fff !important;
}
body.dark-mode .upg-card .upg-btn-secondary {
    background: transparent !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
    color: #f4f0e8 !important;
}
body.dark-mode .upg-card .upg-btn-secondary:hover {
    background: rgba(255, 255, 255, 0.05) !important;
    border-color: #a84a2a !important;
}
body.dark-mode .upg-card-free { background: rgba(255, 255, 255, 0.02) !important; }
body.dark-mode .upg-card .ribbon { color: #fff !important; }
/* v2.10.8 — .upg-card-info tiene `background: var(--netza-stone)` (beige)
   que en dark mode quedaba CLARO sobre la card oscura → texto adentro
   ilegible. Forzamos bg oscuro acá. */
body.dark-mode .upg-card .upg-card-info {
    background: rgba(255, 255, 255, 0.04) !important;
    color: rgba(244, 240, 232, 0.85) !important;
}
body.dark-mode .upg-card .upg-card-info .info-line strong { color: #f4f0e8 !important; }
body.dark-mode .upg-card .upg-card-info .info-line span { color: rgba(244, 240, 232, 0.80) !important; }

/* Modal "Funcionalidades — Plan X" (.netza-modal-features) — los overrides
   originales en upgrade.html ponen paleta clara con !important. Aquí los
   pisamos en dark con specificity mayor (body.dark-mode + clase + !important). */
body.dark-mode .netza-modal-features .netza-mfc-card {
    background: #231f1a !important;
    color: #f4f0e8 !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}
body.dark-mode .netza-modal-features .netza-mfc-titulo { color: #f4f0e8 !important; }
body.dark-mode .netza-modal-features .netza-mfc-sub { color: rgba(244, 240, 232, 0.65) !important; }
body.dark-mode .netza-modal-features .netza-mfc-close { color: rgba(244, 240, 232, 0.65) !important; }
body.dark-mode .netza-modal-features .netza-mfc-close:hover { color: #f4f0e8 !important; }
body.dark-mode .netza-modal-features .netza-mfc-lista li { color: rgba(244, 240, 232, 0.85) !important; }
body.dark-mode .netza-modal-features .netza-mfc-btn-ok {
    background: #a84a2a !important;
    color: #fff !important;
    border-color: #a84a2a !important;
}
body.dark-mode .netza-modal-features .netza-mfc-btn-ok:hover {
    background: #c0593c !important;
    border-color: #c0593c !important;
}

/* v2.10.8 — Cloudflare Turnstile widget: el iframe del captcha es 300×65
   fijo. En mobile lo escalamos con transform-origin: center top (no center
   center) para que se mantenga centrado horizontalmente respecto al
   contenedor del form. */
.cf-turnstile {
    max-width: 100%;
    overflow: visible;
    display: inline-block;
    transform-origin: center top;
}
.auth-form .cf-turnstile-wrap,
.auth-form .form-group:has(.cf-turnstile) {
    display: flex !important;
    justify-content: center;
    align-items: center;
    text-align: center;
}
@media (max-width: 400px) {
    /* v2.10.8 — Shift de -10px para centrar visualmente (el widget reserva
       más espacio del lado del texto "Verifique que es un ser humano"). */
    .cf-turnstile { transform: translateX(-10px) scale(0.86); margin-bottom: -8px; }
}
@media (max-width: 340px) {
    .cf-turnstile { transform: translateX(-10px) scale(0.75); margin-bottom: -16px; }
}

/* Modales globales (.modal-backdrop > .modal) */
body.dark-mode .modal-backdrop > .modal {
    background: #231f1a;
    border-color: rgba(255, 255, 255, 0.08);
    color: #f4f0e8;
}
body.dark-mode .modal-title { color: #f4f0e8; }
body.dark-mode .modal-title i { color: #a84a2a; }
body.dark-mode .modal-footer { border-top-color: rgba(255, 255, 255, 0.06); }
body.dark-mode .modal label { color: rgba(244, 240, 232, 0.55); }
body.dark-mode .modal .form-group input,
body.dark-mode .modal .form-group select,
body.dark-mode .modal .form-group textarea,
body.dark-mode .modal input[type="text"],
body.dark-mode .modal input[type="number"],
body.dark-mode .modal input[type="email"],
body.dark-mode .modal input[type="date"],
body.dark-mode .modal select,
body.dark-mode .modal textarea {
    background: #1a1611 !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
    color: #f4f0e8 !important;
}
body.dark-mode .modal .btn {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.12);
    color: #f4f0e8;
}
body.dark-mode .modal .btn:hover {
    background: rgba(255, 255, 255, 0.06);
}
body.dark-mode .modal .btn-primary {
    background: #a84a2a;
    border-color: #a84a2a;
    color: #fff;
}
body.dark-mode .modal .btn-primary:hover {
    background: #c0593c;
    border-color: #c0593c;
}

/* v2.10.16 — Modal global de confirmacion (#modal-confirmar-netza). Usa
   .netza-modal-confirm (NO .modal), por eso la regla de arriba no aplica.
   Cuando tonoConfirmar='primary' el btn queda .btn .btn-primary con
   --netza-ink que en dark se invierte a color claro -> botón blanco/gris
   ilegible. Forzamos terracota igual que en el resto de modales dark. */
body.dark-mode #modal-confirmar-netza .btn-primary {
    background: #a84a2a !important;
    border-color: #a84a2a !important;
    color: #fff !important;
}
body.dark-mode #modal-confirmar-netza .btn-primary:hover {
    background: #c0593c !important;
    border-color: #c0593c !important;
    color: #fff !important;
}
/* v2.10.20 — Modal confirmar en dark mode: card, icono y texto.
   El card usa var(--netza-paper) (ya dark-aware globally). El icono wrap
   y texto títulos/mensaje necesitan overrides explícitos. */
body.dark-mode #modal-confirmar-netza .netza-modal-confirm-card {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}
body.dark-mode #modal-confirmar-netza #mcn-icon-wrap {
    background: rgba(192, 89, 60, 0.20) !important;
}
body.dark-mode #modal-confirmar-netza #mcn-icon {
    color: #c0593c !important;
}
body.dark-mode #modal-confirmar-netza #mcn-titulo {
    color: #f4f0e8 !important;
}
body.dark-mode #modal-confirmar-netza #mcn-mensaje {
    color: rgba(244, 240, 232, 0.78) !important;
}
body.dark-mode #modal-confirmar-netza #mcn-btn-cancel {
    background: transparent !important;
    color: rgba(244, 240, 232, 0.78) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
}
body.dark-mode #modal-confirmar-netza #mcn-btn-cancel:hover {
    background: rgba(255, 255, 255, 0.05) !important;
}

/* v2.10.112 (Facu 2026-05-15) — Modal "Posible duplicado" del Splitza
   (#div-mov-split-duplicados, abierto via abrirModalFormConElemento).
   El HTML inline + el JS de split-form.js usan vars `--netza-paper` /
   `--netza-stone` / `--netza-ink-3` / `--netza-rule` que no se redefinen
   en dark → cards quedaban casi invisibles. Override directo. */
body.dark-mode #div-mov-split-duplicados {
    color: #f4f0e8;
}
body.dark-mode #div-mov-split-duplicados p {
    color: rgba(244, 240, 232, 0.65) !important;
}
body.dark-mode #div-mov-split-duplicados p strong {
    color: #c0593c !important;
}
/* Criterio info box (background:var(--netza-stone)) — primer <div style> tras el <p>. */
body.dark-mode #div-mov-split-duplicados > div > div[style*="background:var(--netza-stone)"]:not(#sf-dup-target) {
    background: rgba(255, 255, 255, 0.04) !important;
    color: rgba(244, 240, 232, 0.55) !important;
}
/* Card "Estás por cargar" target */
body.dark-mode #sf-dup-target {
    background: rgba(255, 255, 255, 0.04) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #sf-dup-target strong {
    color: #c0593c !important;
}
/* Cards de duplicados encontrados (renderizadas por _sfRenderDupList).
   Los spans/divs internos tienen `color:var(--netza-ink-3)` inline — los
   pisamos con selectores de atributo para no tener que enumerar c/u. */
body.dark-mode #sf-dup-list li {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #sf-dup-list li [style*="color:var(--netza-ink-3)"] {
    color: rgba(244, 240, 232, 0.65) !important;
}
body.dark-mode #sf-dup-list li strong {
    color: #c0593c !important;
}
/* Pill "Tarjeta" (es_tarjeta badge) */
body.dark-mode #sf-dup-list li [style*="background:var(--netza-stone-2)"] {
    background: rgba(255, 255, 255, 0.08) !important;
    color: rgba(244, 240, 232, 0.65) !important;
}
/* Separador hr del footer */
body.dark-mode #div-mov-split-duplicados > div > div[style*="border-top"] {
    border-top-color: rgba(255, 255, 255, 0.08) !important;
}
/* Botón Cancelar (background:#fff hardcoded) */
body.dark-mode #div-mov-split-duplicados button[onclick="cerrarModalForm()"] {
    background: rgba(255, 255, 255, 0.05) !important;
    color: rgba(244, 240, 232, 0.85) !important;
    border-color: rgba(255, 255, 255, 0.15) !important;
}
body.dark-mode #div-mov-split-duplicados button[onclick="cerrarModalForm()"]:hover {
    background: rgba(255, 255, 255, 0.10) !important;
}
/* Botón "Crear nuevo igual" (background:var(--netza-ink) + color paper) — en dark
   el ink-on-ink desaparece. Usamos terracota oscura para hacerlo legible. */
body.dark-mode #div-mov-split-duplicados button[onclick="_sfCrearNuevoIgual()"] {
    background: #a84a2a !important;
    color: #fff !important;
}
body.dark-mode #div-mov-split-duplicados button[onclick="_sfCrearNuevoIgual()"]:hover {
    background: #c0593c !important;
}
/* Botón "Vincular este" (background:var(--netza-ink) inline en el JS) */
body.dark-mode #sf-dup-list li button {
    background: #a84a2a !important;
    color: #fff !important;
}
body.dark-mode #sf-dup-list li button:hover {
    background: #c0593c !important;
}

/* Modal global form (#modal-form-global): los forms de Nuevo Registro,
   Forecast Ingreso/Egreso usan este wrapper. */
body.dark-mode #modal-form-global {
    background: rgba(20, 19, 17, 0.75);
}
body.dark-mode #modal-form-global .modal-form-content,
body.dark-mode #modal-form-global .modal-form-body,
body.dark-mode #modal-form-global > div {
    background: #231f1a;
    color: #f4f0e8;
    border-color: rgba(255, 255, 255, 0.08);
}
body.dark-mode #modal-form-global input,
body.dark-mode #modal-form-global select,
body.dark-mode #modal-form-global textarea {
    background: #1a1611 !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #modal-form-global label {
    color: rgba(244, 240, 232, 0.55);
}
/* Botones embebidos dentro de los forms modales (calc trigger, clear "x",
   submit ✓, cancel ✕). En dark deben quedar oscuros para no chillar. */
body.dark-mode #modal-form-global .btn-calc-open,
body.dark-mode #modal-form-global .btn-icon-action {
    background: rgba(255, 255, 255, 0.06) !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #modal-form-global .btn-calc-open:hover,
body.dark-mode #modal-form-global .btn-icon-action:hover {
    background: rgba(255, 255, 255, 0.12) !important;
}
body.dark-mode #modal-form-global .btn-icon-action.confirm {
    background: #a84a2a !important;
    border-color: #a84a2a !important;
    color: #fff !important;
}
body.dark-mode #modal-form-global .btn-icon-action.confirm:hover {
    background: #c0593c !important;
}
/* Radio group dentro del modal form: solo unificamos flex/gap. El padding
   queda con el default por form (revertimos la pelea por el spacing entre
   "Pagado con" y los radios — ver feedback de v2.10.7). */
#modal-form-global .radio-group {
    gap: 16px !important;
    display: flex !important;
    flex-wrap: wrap !important;
}
#modal-form-global .radio-option {
    display: inline-flex !important;
    align-items: center !important;
    gap: 6px !important;
}

/* v2.10.9 — Radio inputs en dark mode (modales de carga). color-scheme dark
   hace que Chrome/Edge renderee el círculo del radio con bg oscuro y borde
   claro (sin esto sale white sobre fondo oscuro, ilegible). accent-color
   ya está terracota globalmente (ver label.radio-option). */
body.dark-mode label.radio-option input[type="radio"],
body.dark-mode .modal input[type="radio"],
body.dark-mode #modal-form-global input[type="radio"] {
    color-scheme: dark;
    accent-color: #a84a2a;
}
/* Label del radio option en dark mode con buen contraste */
body.dark-mode label.radio-option { color: #f4f0e8; }

/* Inputs type=date — color-scheme dark para que el ícono del calendario
   nativo del browser se renderee blanco/claro sobre fondo oscuro. */
body.dark-mode input[type="date"],
body.dark-mode input[type="datetime-local"],
body.dark-mode input[type="time"],
body.dark-mode input[type="month"],
body.dark-mode input[type="week"] {
    color-scheme: dark;
}
/* Calendar picker popup del browser nativo: color-scheme: dark hace que
   Chrome/Edge muestren el calendario en tema oscuro. Safari iOS usa su
   propio picker oscuro automáticamente. */
body.dark-mode {
    color-scheme: dark;
}

/* Modal Contacto — tip box con look unificado y dark mode. */
.modal-contacto-tip {
    /* v2.10.x (Facu 2026-05-13) — Bg paper (#f4f0e8) en lugar de stone para
       contrastar con el modal en #fbf8f2 (patrón unificado). */
    background: #f4f0e8;
    border: 1px solid var(--netza-rule);
    border-radius: 10px;
    padding: 10px 12px;
    margin-bottom: 16px;
    font-size: 12px;
    color: var(--netza-ink-3);
    display: flex;
    gap: 8px;
    align-items: flex-start;
    line-height: 1.45;
}
.modal-contacto-tip i {
    color: var(--netza-warning);
    margin-top: 2px;
    flex-shrink: 0;
}
body.dark-mode .modal-contacto-tip {
    background: #1a1611;
    border-color: rgba(255, 255, 255, 0.10);
    color: #f4f0e8;
}
body.dark-mode .modal-contacto-tip i { color: #ffc04d; }
/* Email readonly del modal contacto en dark mode (tenía bg stone inline). */
body.dark-mode #contacto-email {
    background: rgba(255, 255, 255, 0.04) !important;
    color: rgba(244, 240, 232, 0.65) !important;
}

/* v2.10.20 — A2HS modal (_modal_pwa_install.html) dark mode.
   El modal tiene inline styles con bg:var(--netza-paper) + step boxes
   con bg:var(--netza-stone) que no responden a dark. Override forzado. */
body.dark-mode #pwa-install-modal .pwa-install-card {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
}
body.dark-mode #pwa-install-modal h3 { color: #f4f0e8 !important; }
body.dark-mode #pwa-install-modal p { color: rgba(244, 240, 232, 0.75) !important; }
body.dark-mode #pwa-install-modal strong { color: #f4f0e8; }
/* Cada step box (Tocá los 3 puntos / Elegí "Instalar app" / Confirmá) */
body.dark-mode #pwa-install-modal [style*="background:var(--netza-stone)"] {
    background: #1a1611 !important;
    color: rgba(244, 240, 232, 0.85) !important;
}
/* Step 3 (gradient warm) → en dark queda como rojo terracota soft */
body.dark-mode #pwa-install-modal [style*="linear-gradient(135deg,#fff5e6"] {
    background: rgba(192, 89, 60, 0.16) !important;
    border-color: rgba(192, 89, 60, 0.40) !important;
}
/* Texto dentro de los steps */
body.dark-mode #pwa-install-modal [style*="background:var(--netza-stone)"] > div,
body.dark-mode #pwa-install-modal [style*="linear-gradient(135deg,#fff5e6"] > div {
    color: rgba(244, 240, 232, 0.85) !important;
}
/* Botones */
body.dark-mode #pwa-install-modal #pwa-install-btn-ahora-no {
    background: transparent !important;
    color: rgba(244, 240, 232, 0.78) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
}
body.dark-mode #pwa-install-modal #pwa-install-btn-nunca-mas {
    color: rgba(244, 240, 232, 0.55) !important;
}
body.dark-mode #pwa-install-modal #pwa-install-btn-instalar {
    background: #c0593c !important;
    border-color: #c0593c !important;
    color: #fff !important;
}

/* v2.10.20 — Splitza pantallas con dark mode global (no scoped a mobile).
   .unirse-card (split_unirse.html): card de invitación con bg:#fff hardcoded
   inline en el template → se ve blanco sobre fondo dark. Override forzado. */
body.dark-mode .splitza-page .unirse-card {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.10) !important;
    color: #f4f0e8;
}
body.dark-mode .splitza-page .unirse-card h2 { color: #f4f0e8; }
body.dark-mode .splitza-page .unirse-card p {
    color: rgba(244, 240, 232, 0.75) !important;
}
body.dark-mode .splitza-page .unirse-card .grupo-nombre {
    color: #c0593c !important;
}
body.dark-mode .splitza-page .unirse-card.ok .icon-big { color: #c0593c !important; }
body.dark-mode .splitza-page .unirse-card.upgrade .icon-big { color: #d8a878 !important; }
body.dark-mode .splitza-page .unirse-card.error .icon-big { color: #d6663f !important; }
body.dark-mode .splitza-page .btn-aceptar {
    background: #c0593c !important;
    color: #fff !important;
    border-color: #c0593c !important;
}
body.dark-mode .splitza-page .btn-rechazar {
    background: #1a1611 !important;
    color: rgba(244, 240, 232, 0.85) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
}

/* .solicitudes-wrap: el modal donde está clonada NO está bajo .splitza-page,
   por eso scope sin ese ancestor. */
body.dark-mode .solicitudes-wrap {
    background: rgba(192, 89, 60, 0.12) !important;
    border-color: rgba(192, 89, 60, 0.40) !important;
}
body.dark-mode .solicitudes-titulo {
    color: #c0593c !important;
}
body.dark-mode .solicitudes-wrap .miembros-list li {
    color: rgba(244, 240, 232, 0.85) !important;
    border-color: rgba(192, 89, 60, 0.18) !important;
}

/* Botones invite (Copiar, Nuevo link) en dark globalmente */
body.dark-mode .splitza-page .invite-btn {
    background: #1a1611 !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
    color: rgba(244, 240, 232, 0.85) !important;
}
body.dark-mode .splitza-page .invite-btn:hover {
    background: rgba(255, 255, 255, 0.06) !important;
    border-color: rgba(255, 255, 255, 0.30) !important;
    color: #f4f0e8 !important;
}
/* v2.10.20 rev11 — Estado "Copiado" en dark: subir contraste del check
   verde (antes #6fc28e sobre rgba(46,139,87,0.18) era poco visible).
   Ahora bg más sólido + verde más brillante. */
body.dark-mode .splitza-page .invite-btn.invite-btn-ok {
    background: rgba(74, 153, 104, 0.30) !important;
    border-color: #6fc28e !important;
    color: #9ed8a8 !important;
}
body.dark-mode .splitza-page .invite-btn.invite-btn-ok i {
    color: #9ed8a8 !important;
}

/* v2.10.20 rev15 — Header "Miembros" del modal: ICONO en terracota,
   TEXTO en color contrastado (blanco en dark / ink en light).
   BUG FIX: antes el selector tenía `.splitza-page` como ancestor pero
   #modal-miembros-mobile está al nivel del body (SIBLING de .splitza-page,
   no descendant). Por eso el selector nunca matcheaba. Ahora sin
   ancestor: targets los IDs/clases directos. */
.panel-miembros h3,
#modal-mm-body h3,
.modal-mm-content h3 {
    color: var(--netza-ink, #141311) !important;
}
.panel-miembros h3 i,
#modal-mm-body h3 i,
.modal-mm-content h3 i {
    color: var(--netza-terracota, #a84a2a) !important;
}
body.dark-mode .panel-miembros h3,
body.dark-mode #modal-mm-body h3,
body.dark-mode .modal-mm-content h3 {
    color: #f4f0e8 !important;
}
body.dark-mode .panel-miembros h3 i,
body.dark-mode #modal-mm-body h3 i,
body.dark-mode .modal-mm-content h3 i {
    color: #c0593c !important;
}

/* v2.10.20 rev15 — Modal Miembros y solicitudes pendientes: los nombres
   se ven muy tenues en dark. Selectors sin `.splitza-page` porque el
   modal está fuera de ese wrap. */
body.dark-mode .panel-miembros .miembros-list li,
body.dark-mode .modal-mm-content .miembros-list li,
body.dark-mode #modal-mm-body .miembros-list li {
    color: #f4f0e8 !important;
}
body.dark-mode .panel-miembros .miembros-list li strong,
body.dark-mode .modal-mm-content .miembros-list li strong,
body.dark-mode #modal-mm-body .miembros-list li strong {
    color: #f4f0e8;
}
/* Solicitud nombre — el `<span class="solicitud-nombre">` (era inline style) */
.solicitud-nombre {
    color: var(--netza-ink-2);
    font-weight: 500;
}
body.dark-mode .solicitud-nombre {
    color: #f4f0e8 !important;
}
/* rol-tag NO admin (Miembro / Co-admin) en dark — sin .splitza-page
   ancestor (las tags se ven dentro del modal Miembros fuera del wrap). */
body.dark-mode .rol-tag {
    background: rgba(255, 255, 255, 0.08) !important;
    color: rgba(244, 240, 232, 0.85) !important;
}
body.dark-mode .rol-tag.admin {
    background: #c0593c !important;
    color: #fff !important;
}
body.dark-mode .rol-tag.coadmin {
    background: rgba(255, 255, 255, 0.10) !important;
    color: rgba(244, 240, 232, 0.85) !important;
}

/* Container global (.container) — sin override dark; el wrap ya es transparente
   (ver regla base línea 330). Solo el color de texto heredado del body cubre
   el contenido interno. */

/* Popover de ayuda (lamparita) — dark mode + radius más amplio. */
.popover-ayuda { border-radius: 16px !important; }

/* v2.10.11 rev30 — Popover responsive en mobile: width adaptable al viewport
   (antes 300px fijo podía quedar pegado a un borde y mal posicionado). */
@media (max-width: 600px) {
    .popover-ayuda {
        width: calc(100vw - 24px) !important;
        max-width: 360px !important;
        left: 12px !important;
    }
}
body.dark-mode .popover-ayuda {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5) !important;
}
body.dark-mode .popover-ayuda-header {
    background: #1a1611 !important;
    border-bottom-color: rgba(255, 255, 255, 0.06) !important;
    color: #f4f0e8 !important;
}
body.dark-mode .popover-ayuda-body h4 { color: #f4f0e8 !important; }
body.dark-mode .popover-ayuda-body p,
body.dark-mode .popover-ayuda-body .p-icono { color: #b8aea0 !important; }
body.dark-mode .popover-ayuda-tip {
    background: rgba(193, 145, 33, 0.10) !important;
    color: rgba(244, 240, 232, 0.75) !important;
}
body.dark-mode .popover-ayuda-footer {
    border-top-color: rgba(255, 255, 255, 0.06) !important;
    color: #b8aea0 !important;
}
body.dark-mode .popover-ayuda-footer button {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.12);
    color: #f4f0e8;
}
body.dark-mode .popover-ayuda-footer button:disabled { opacity: 0.35; }
body.dark-mode .btn-ayuda.encendida {
    background: rgba(193, 145, 33, 0.22);
}

/* Botones del popover-ayuda en dark con background visible (no transparente
   gris claro que no contrasta). */
body.dark-mode .popover-ayuda-footer button {
    background: rgba(255, 255, 255, 0.06) !important;
    border-color: rgba(255, 255, 255, 0.12) !important;
    color: #f4f0e8 !important;
}
body.dark-mode .popover-ayuda-footer button:hover {
    background: rgba(255, 255, 255, 0.12) !important;
}

/* Modal Form Global — header oscuro en dark mode (cubre los 4 forms:
   Nuevo Registro, Nuevo Forecast Ingreso/Egreso, Editar Registro). */
body.dark-mode .modal-form-box {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
}
body.dark-mode .modal-form-header {
    background: #1a1611 !important;
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
}
body.dark-mode .modal-form-title { color: rgba(244, 240, 232, 0.55) !important; }
body.dark-mode .modal-form-close {
    background: rgba(255, 255, 255, 0.06) !important;
    color: rgba(244, 240, 232, 0.75) !important;
}
body.dark-mode .modal-form-close:hover {
    background: rgba(255, 255, 255, 0.14) !important;
    color: #f4f0e8 !important;
}

/* Calculadora (calc-modal-bg / calc-box) — dark mode. Las clases reales
   del HTML son .ck-fn (AC/⌫/%), .ck-op (÷×−+), .ck-pair (( ) / 0 / .),
   .ck-eq (=) — los selectores ".calc-op" / ".calc-eq" no existen. */
body.dark-mode #calc-modal-bg .calc-box {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #calc-modal-bg .calc-header {
    background: #1a1611 !important;
    border-bottom-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode #calc-modal-bg .calc-header span { color: #f4f0e8 !important; }
body.dark-mode #calc-modal-bg .calc-display {
    background: #2a251f !important;
    color: #f4f0e8 !important;
}
/* Teclas numéricas: bg gris oscuro + texto claro */
body.dark-mode #calc-modal-bg .calc-keys button {
    background: #2a251f !important;
    color: #f4f0e8 !important;
}
body.dark-mode #calc-modal-bg .calc-keys button:active {
    background: rgba(255, 255, 255, 0.12) !important;
}
/* Función (AC, ⌫, %) */
body.dark-mode #calc-modal-bg .calc-keys .ck-fn {
    background: #1a1611 !important;
    color: #b8aea0 !important;
}
body.dark-mode #calc-modal-bg .calc-keys .ck-fn:active {
    background: rgba(255, 255, 255, 0.10) !important;
}
/* Operadores ÷ × − + : color naranja sobre bg oscuro */
body.dark-mode #calc-modal-bg .calc-keys .ck-op {
    background: #1a1611 !important;
    color: #e06c00 !important;
}
/* Par (( ) y 0 / . ) — bg menos contraste */
body.dark-mode #calc-modal-bg .calc-keys .ck-pair {
    background: #1a1611 !important;
}
body.dark-mode #calc-modal-bg .calc-keys .ck-pair button {
    background: transparent !important;
    color: #b8aea0 !important;
}
body.dark-mode #calc-modal-bg .calc-keys .ck-pair button:active {
    background: rgba(255, 255, 255, 0.10) !important;
}
/* Igual = : accent terracota */
body.dark-mode #calc-modal-bg .calc-keys .ck-eq {
    background: #a84a2a !important;
    color: #fff !important;
}
body.dark-mode #calc-modal-bg .calc-keys .ck-eq:active {
    background: #7d3318 !important;
}
body.dark-mode #calc-modal-bg .calc-header-close {
    color: rgba(244, 240, 232, 0.75) !important;
}
body.dark-mode #calc-modal-bg .calc-header-close:hover {
    color: #f4f0e8 !important;
}
body.dark-mode #calc-modal-bg .calc-load-btn {
    background: #3a7d5a !important;
    color: #fff !important;
}

/* Modal "Conflictos detectados" — rediseño + dark mode (selector amplio
   para cubrir forecast_ingresos y forecast_egresos).
   v2.11.16 rev10 (Facu 2026-05-17) — box-shadow desactivado en ambos
   modes por pedido. */
[id^="modal-conflictos-"] > div {
    border-color: #ede4d2 !important;
    padding: 22px 20px 18px !important;
    box-shadow: none !important;
}
[id^="modal-conflictos-"] h3 {
    font-family: 'Roboto Mono', ui-monospace, monospace !important;
    font-size: 10.5px !important;
    font-weight: 500 !important;
    letter-spacing: 0.16em !important;
    text-transform: uppercase !important;
    color: #6b6157 !important;
}
body.dark-mode [id^="modal-conflictos-"] > div {
    background: #231f1a !important;
    border-color: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
}
body.dark-mode [id^="modal-conflictos-"] h3 { color: rgba(244, 240, 232, 0.55) !important; }
body.dark-mode [id^="modal-conflictos-"] p { color: #b8aea0 !important; }
body.dark-mode [id^="lista-conflictos-"] {
    border-color: rgba(255, 255, 255, 0.06) !important;
    background: transparent !important;
}
body.dark-mode [id^="modal-conflictos-"] .btn {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.12);
    color: #f4f0e8;
}
body.dark-mode [id^="modal-conflictos-"] .btn-primary {
    background: #a84a2a !important;
    border-color: #a84a2a !important;
    color: #fff !important;
}

/* v2.10.9 rev13 — Dark mode completo del modal de conflictos. Los inline
   styles del partial usan vars (--netza-stone, --netza-rule, --netza-ink,
   --netza-ink-4) que no se redefinen en body.dark-mode. Override acá
   con !important para pisarlas. */
body.dark-mode [id^="modal-conflictos-"] [id$="-applyall"] {
    background: #1a1611 !important;
    border-radius: 8px !important;
    color: #f4f0e8 !important;
}
/* v2.11.16 rev13 — Forzar `.fc-applyall-buttons` (wrapper interno de los
   3 botones del toolbar) a background transparent. Sin esto, en algunos
   layouts (mobile column) podía heredar/mostrar un bg distinto al del
   bloque applyall que lo contiene. */
body.dark-mode [id^="modal-conflictos-"] .fc-applyall-buttons {
    background: transparent !important;
}
body.dark-mode [id^="modal-conflictos-"] [id$="-applyall"] span {
    color: rgba(244, 240, 232, 0.62) !important;
}
/* v2.11.16 rev15 (Facu 2026-05-17) — Contenedor `lista` sin styling
   propio (cada fila se vuelve su propia card vía .conflicto-fila). */

/* Cada fila del modal de conflictos como card individual, mismo look
   que el bloque "Aplicar a todos" (bg + border-radius + margin separador).
   v2.11.16 rev16 — Light mode usa `#ebe5d8` (stone) para diferenciarse
   del modal exterior `#f4f0e8` (paper). Dark mode con `#1a1611`. */
[id^="modal-conflictos-"] .conflicto-fila {
    background: #ebe5d8;
    border-radius: 8px;
    margin-bottom: 8px;
}
body.dark-mode [id^="modal-conflictos-"] .conflicto-fila {
    background: #1a1611 !important;
}
/* v2.11.16 rev10 — `.conflicto-fila` ya no tiene border-bottom (removido
   del inline style por pedido), por lo que este override dark mode no
   aplica. Se mantiene la regla vacía como comentario por trazabilidad. */
body.dark-mode [id^="modal-conflictos-"] .conflicto-fila > div > div:first-child {
    color: #f4f0e8 !important;
}
body.dark-mode [id^="modal-conflictos-"] .conflicto-fila > div > div:nth-child(2) {
    color: rgba(244, 240, 232, 0.55) !important;
}
/* Botones del modal de conflictos en dark mode. v2.11.16 rev14 — Color
   sólido #231f1a (un tono más claro que el bg del bloque applyall #1a1611
   para que los botones se distingan visualmente). Aplica a Duplicar y
   Omitir, en toolbar (data-applyall) y filas (data-action). Reemplazar
   mantiene terracota. */
body.dark-mode [id^="modal-conflictos-"] [data-applyall="omitir"],
body.dark-mode [id^="modal-conflictos-"] [data-action="omitir"] {
    background: #a89d8a !important;
}
body.dark-mode [id^="modal-conflictos-"] [data-applyall="duplicar"],
body.dark-mode [id^="modal-conflictos-"] [data-action="duplicar"] {
    background: #2a2825 !important;
}
/* Botón "Cancelar" en dark — usa la regla .btn de más arriba (transparente
   con borde claro). El "Aplicar" usa la regla .btn-primary terracota. */

/* v2.10.8 — Dark mode para #modal-sin-vto-global (warning "Sin vencimiento
   registrado"). El modal usa inline styles con `var(--netza-paper)` y
   `var(--netza-ink)`, pero las CSS vars no se redefinen en body.dark-mode,
   así que las override acá específicamente. El botón verde "Agregar
   Vencimiento" lo dejamos igual (#msvg-confirmar = positivo); solo cambia
   el bg de la card, los textos, y el botón cancelar. */
body.dark-mode #modal-sin-vto-global > div {
    background: #231f1a !important;
    border: 1px solid rgba(255, 255, 255, 0.08) !important;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5) !important;
}
body.dark-mode #modal-sin-vto-global h3 { color: #f4f0e8 !important; }
body.dark-mode #modal-sin-vto-global p { color: rgba(244, 240, 232, 0.65) !important; }
body.dark-mode #msvg-cancelar {
    background: rgba(255, 255, 255, 0.08) !important;
    color: #f4f0e8 !important;
    border: 1px solid rgba(255, 255, 255, 0.14) !important;
}
body.dark-mode #msvg-cancelar:hover {
    background: rgba(255, 255, 255, 0.14) !important;
}

/* Flecha del <select> en dark mode. La flecha del light es un SVG inline con
   fill #55514a (gris oscuro), invisible sobre bg #1a1611. Re-aplicamos con
   fill #b8aea0 (gris claro) para que sea visible. Se declara DESPUÉS de los
   shorthand `background: #1a1611 !important` de las reglas dark del modal
   para que el longhand `background-image` gane (misma o mayor specificity). */
body.dark-mode select,
body.dark-mode .modal select,
body.dark-mode .modal .form-group select,
body.dark-mode #modal-form-global select {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M6 8L1 3h10z' fill='%23b8aea0'/></svg>") !important;
    background-repeat: no-repeat !important;
    background-position: right 10px center !important;
}

/* ======================================================================
   v2.10.40 (Facu 2026-05-13) — View Transitions API: animación tipo "cubo
   giratorio 3D" para navegaciones same-document (vía PJAX en
   `page-transitions.js`) + fallback cross-document.

   La pantalla saliente rota -90° en Y mientras se desvanece; la entrante
   viene desde +90° → efecto "card flip" que se percibe como cubo girando.

   - `@view-transition { navigation: auto }` también activa cross-document
     (back/forward, fallback cuando PJAX no aplica o el browser no soporta
     `document.startViewTransition`).
   - Aplicado a `root` (todo el documento). `perspective(1200px)` da un
     look cinemático sin distorsión exagerada.
   - 380ms cubic-bezier(0.65, 0, 0.35, 1) — arranque firme + decelera suave.
   - `prefers-reduced-motion`: skip total (accesibilidad).
   ====================================================================== */
/* v2.10.41 — `navigation: auto` REMOVIDO. Solo PJAX same-document (vía
   `document.startViewTransition()` en page-transitions.js) usa estas
   reglas. Cross-document causaba flash del splash en login→home. */
::view-transition-old(root) {
    animation: cube-out 380ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
    transform-origin: center center;
    /* v2.10.91 (Facu 2026-05-14) — bg explícito en cada snapshot del
       view-transition para evitar el flash blanco entre frames del cubo
       (especialmente notorio en dark mode al navegar a /splitza). El
       browser por default usa transparente, que muestra el bg del viewport
       (blanco) durante el roto-flip. */
    background: var(--netza-paper-warm, #fbf8f2);
}
::view-transition-new(root) {
    animation: cube-in 380ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
    transform-origin: center center;
    background: var(--netza-paper-warm, #fbf8f2);
}
/* View-transition pseudo elements viven en el top layer del browser
   (fuera del subtree del body), por lo que `body.dark-mode` no llega
   con descendant selector. Usamos `html:has(body.dark-mode)` para que
   el match sea desde root. */
html:has(body.dark-mode) ::view-transition-old(root),
html:has(body.dark-mode) ::view-transition-new(root) {
    background: #141311;
}
@keyframes cube-out {
    from { transform: perspective(1200px) rotateY(0deg);   opacity: 1; }
    to   { transform: perspective(1200px) rotateY(-90deg); opacity: 0; }
}
@keyframes cube-in {
    from { transform: perspective(1200px) rotateY(90deg);  opacity: 0; }
    to   { transform: perspective(1200px) rotateY(0deg);   opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) {
        animation: none !important;
    }
}

/* v2.10.45 rev2 (Facu 2026-05-13) - main#netza-main wrapper REMOVIDO de base.html (display:contents no afectaba selectores CSS). .container ahora marcado con data-pjax-target=1 para page-transitions.js. */

/* ======================================================================
   v2.10.49 (Facu 2026-05-13) — Body bg en dark unificado a #1a1611 para
   TODAS las pantallas mobile. Logic: header/banner/footer usan --dm-paper
   (#1a1611 dark). El body, que está por encima del header y por debajo
   del footer, debe matchear ese mismo color para evitar líneas visibles.

   El wrap mobile usa --dm-paper-warm (#141311) que es ligeramente más
   oscuro — eso es intencional, marca el área de contenido. Pero todo lo
   que está FUERA del wrap (body, banner-wrap, footer) usa --dm-paper.
   ====================================================================== */
@media (max-width: 600px) {
    body.dark-mode.vr-mobile-page,
    body.dark-mode.fi-mobile-page,
    body.dark-mode.fe-mobile-page,
    body.dark-mode.notif-mobile-page,
    body.dark-mode.hist-mobile-page,
    body.dark-mode.canales-mobile-page,
    body.dark-mode.categorias-mobile-page,
    body.dark-mode.conceptos-mobile-page,
    body.dark-mode.calendario-mobile-page,
    body.dark-mode.usd-historico-mobile-page,
    body.dark-mode.vto-tarjeta-mobile-page,
    body.dark-mode.configuracion-mobile-page,
    body.dark-mode.tutoriales-menu-mobile-page,
    body.dark-mode.tutorial-mobile-page,
    body.dark-mode.splitza-mobile-page,
    body.dark-mode.perfil-mobile-page {
        background: #1a1611;
    }
}

/* ======================================================================
   v2.10.46 rev2 (Facu 2026-05-13) — Fusión visual del header con el wrap.
   Los headers de pantalla (vr-header, fc-header, hist-header, notif-header,
   cm-header, pm-header) usaban `var(--dm-paper-warm)` que es ligeramente
   distinto al wrap (`var(--dm-paper)`). Resultado: línea visible de
   transición entre header y wrap. Lo igualamos a `--dm-paper` para que
   se fusionen visualmente. Cubre light + dark (la var se redefine en cada
   modo dentro del scope de los wraps mobile).
   ====================================================================== */
@media (max-width: 600px) {
    .vr-mobile-wrap .vr-header,
    .fc-mobile-wrap .fc-header,
    .hist-mobile-wrap .hist-header,
    .notif-mobile-wrap .notif-header,
    .cm-wrap .cm-header,
    .pm-wrap .pm-header {
        background: var(--dm-paper) !important;
    }
}

/* ======================================================================
   v2.10.49 rev2 (Facu 2026-05-13) — Override por pantalla: HOME MERCADO
   + DASHBOARD. Ambos wraps usan --*-paper-warm (#fbf8f2 light / #141311
   dark) como bg principal. Por ende body, banner y footer en estas
   pantallas deben matchear paper-warm para evitar líneas visibles.
   ====================================================================== */
@media (max-width: 600px) {
    /* Light */
    body.home-mercado-mobile-page,
    body.home-mercado-page,
    body.dashboard-mobile-page {
        background: #fbf8f2;
    }
    body.home-mercado-mobile-page .susc-banner-wrap,
    body.home-mercado-page .susc-banner-wrap,
    body.dashboard-mobile-page .susc-banner-wrap {
        background: #fbf8f2 !important;
    }
    body.home-mercado-mobile-page .netza-footer,
    body.home-mercado-page .netza-footer,
    body.dashboard-mobile-page .netza-footer {
        background: #fbf8f2 !important;
    }
    /* Dark */
    body.dark-mode.home-mercado-mobile-page,
    body.dark-mode.home-mercado-page,
    body.dark-mode.dashboard-mobile-page {
        background: #141311;
    }
    body.dark-mode.home-mercado-mobile-page .susc-banner-wrap,
    body.dark-mode.home-mercado-page .susc-banner-wrap,
    body.dark-mode.dashboard-mobile-page .susc-banner-wrap {
        background: #141311 !important;
    }
    body.dark-mode.home-mercado-mobile-page .netza-footer,
    body.dark-mode.home-mercado-page .netza-footer,
    body.dark-mode.dashboard-mobile-page .netza-footer {
        background: #141311 !important;
    }
}

/* ======================================================================
   v2.10.x (Facu 2026-05-13) — Contraste en modales y dropdowns LIGHT.
   Patrón unificado: contenedor #fbf8f2 (paper-warm), items adentro
   #f4f0e8 (paper). Solo light mode (:not(.dark-mode)).
   ====================================================================== */
/* Modal contacto: card grande + inputs/textarea/select adentro */
body:not(.dark-mode) #modal-contacto .modal {
    background: #fbf8f2;
}
body:not(.dark-mode) #modal-contacto input[type="text"],
body:not(.dark-mode) #modal-contacto input[type="email"],
body:not(.dark-mode) #modal-contacto select,
body:not(.dark-mode) #modal-contacto textarea {
    background: #f4f0e8 !important;
}
body:not(.dark-mode) #modal-contacto .btn:not(.btn-primary) {
    background: #f4f0e8;
}

/* Dropdown notificaciones: cada item de notificación en #f4f0e8 para
   contrastar con el dropdown que ahora es #fbf8f2. */
body:not(.dark-mode) .notif-dropdown [data-notif-item] {
    background: #f4f0e8;
}

/* Modal-form-global (forms del FAB: Nuevo Registro, Editar Registro,
   Nueva Proyección Ingreso/Egreso, Editar Proyección, etc.):
   - .modal-form-box → #fbf8f2 (paper-warm, "modal grande")
   - .modal-form-header → #f4f0e8 (paper, "card header")
   - inputs/select/textarea → #f4f0e8 (paper, "campos")
   - Botones secundarios (cancelar) → #f4f0e8 */
body:not(.dark-mode) #modal-form-global .modal-form-box {
    background: #fbf8f2;
}
body:not(.dark-mode) #modal-form-global .modal-form-header {
    background: #f4f0e8;
}
body:not(.dark-mode) #modal-form-global input[type="text"],
body:not(.dark-mode) #modal-form-global input[type="password"],
body:not(.dark-mode) #modal-form-global input[type="email"],
body:not(.dark-mode) #modal-form-global input[type="number"],
body:not(.dark-mode) #modal-form-global input[type="date"],
body:not(.dark-mode) #modal-form-global textarea {
    background: #f4f0e8 !important;
}
/* v2.11.16 (Facu 2026-05-17) — `background-color` en lugar de `background`
   shorthand para que la flechita SVG del select (definida en netza-base.css
   línea ~931 como background-image) no se pierda. Mismo patrón v2.10.118
   ya aplicado en dashboard. Antes los selects del modal-form-global
   light mode quedaban sin flechita. */
body:not(.dark-mode) #modal-form-global select {
    background-color: #f4f0e8 !important;
}
body:not(.dark-mode) #modal-form-global .btn:not(.btn-primary):not(.btn-danger):not(.btn-success) {
    background: #f4f0e8;
}

/* ======================================================================
   v2.10.69 (Facu 2026-05-13) — Paleta unificada DESKTOP/TABLET (≥601px)
   trasladando el patrón mobile a todas las pantallas autenticadas.

   Patrón (mismo de mobile):
   - Light: body/wrap → #fbf8f2 (paper-warm). Cards/panels → #f4f0e8.
     Header sticky, banner, footer → #f4f0e8 (matchea cards).
     Inputs/selects/textareas → #f4f0e8.
   - Dark: body/wrap → #141311. Cards/panels → #1a1611.
     Header, banner, footer → #1a1611. Inputs → #1a1611.

   Scope: por body class de cada pantalla logueada + @media min-width 601px
   para NO afectar mobile (que mantiene su CSS scoped en dashboard-mobile.css
   y home-mercado.css con media max-width 600px).
   ====================================================================== */
@media (min-width: 601px) {
    /* ── LIGHT MODE ── body bg + banner + footer para todas las pantallas
       autenticadas. Excluyo auth (login/registro/etc.) y landing que
       tienen su propia paleta. */
    body.home-mercado-mobile-page:not(.dark-mode),
    body.dashboard-mobile-page:not(.dark-mode),
    body.vr-mobile-page:not(.dark-mode),
    body.fi-mobile-page:not(.dark-mode),
    body.fe-mobile-page:not(.dark-mode),
    body.notif-mobile-page:not(.dark-mode),
    body.hist-mobile-page:not(.dark-mode),
    body.canales-mobile-page:not(.dark-mode),
    body.categorias-mobile-page:not(.dark-mode),
    body.conceptos-mobile-page:not(.dark-mode),
    body.calendario-mobile-page:not(.dark-mode),
    body.usd-historico-mobile-page:not(.dark-mode),
    body.vto-tarjeta-mobile-page:not(.dark-mode),
    body.configuracion-mobile-page:not(.dark-mode),
    body.tutoriales-menu-mobile-page:not(.dark-mode),
    body.tutorial-mobile-page:not(.dark-mode),
    body.splitza-mobile-page:not(.dark-mode),
    body.perfil-mobile-page:not(.dark-mode) {
        background: #fbf8f2;
    }
    /* Banner suscripción y footer en todas las pantallas autenticadas */
    body.home-mercado-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.dashboard-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.vr-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.fi-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.fe-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.notif-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.hist-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.canales-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.categorias-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.conceptos-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.calendario-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.usd-historico-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.vto-tarjeta-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.configuracion-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.tutoriales-menu-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.tutorial-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.splitza-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.perfil-mobile-page:not(.dark-mode) .susc-banner-wrap,
    body.home-mercado-mobile-page:not(.dark-mode) .netza-footer,
    body.dashboard-mobile-page:not(.dark-mode) .netza-footer,
    body.vr-mobile-page:not(.dark-mode) .netza-footer,
    body.fi-mobile-page:not(.dark-mode) .netza-footer,
    body.fe-mobile-page:not(.dark-mode) .netza-footer,
    body.notif-mobile-page:not(.dark-mode) .netza-footer,
    body.hist-mobile-page:not(.dark-mode) .netza-footer,
    body.canales-mobile-page:not(.dark-mode) .netza-footer,
    body.categorias-mobile-page:not(.dark-mode) .netza-footer,
    body.conceptos-mobile-page:not(.dark-mode) .netza-footer,
    body.calendario-mobile-page:not(.dark-mode) .netza-footer,
    body.usd-historico-mobile-page:not(.dark-mode) .netza-footer,
    body.vto-tarjeta-mobile-page:not(.dark-mode) .netza-footer,
    body.configuracion-mobile-page:not(.dark-mode) .netza-footer,
    body.tutoriales-menu-mobile-page:not(.dark-mode) .netza-footer,
    body.tutorial-mobile-page:not(.dark-mode) .netza-footer,
    body.splitza-mobile-page:not(.dark-mode) .netza-footer,
    body.perfil-mobile-page:not(.dark-mode) .netza-footer {
        /* v2.10.86 (Facu 2026-05-14) — Paper-warm #fbf8f2 unificado en
           todos los pie de página. Antes era #f4f0e8 paper. */
        background: #fbf8f2;
    }
    /* Container global (la mayoría de templates desktop lo usa como wrap
       principal). Excluyo home-mercado y auth que ya tienen :has() override. */
    body.dashboard-mobile-page:not(.dark-mode) > .container,
    body.vr-mobile-page:not(.dark-mode) > .container,
    body.fi-mobile-page:not(.dark-mode) > .container,
    body.fe-mobile-page:not(.dark-mode) > .container,
    body.notif-mobile-page:not(.dark-mode) > .container,
    body.hist-mobile-page:not(.dark-mode) > .container,
    body.canales-mobile-page:not(.dark-mode) > .container,
    body.categorias-mobile-page:not(.dark-mode) > .container,
    body.conceptos-mobile-page:not(.dark-mode) > .container,
    body.calendario-mobile-page:not(.dark-mode) > .container,
    body.usd-historico-mobile-page:not(.dark-mode) > .container,
    body.vto-tarjeta-mobile-page:not(.dark-mode) > .container,
    body.configuracion-mobile-page:not(.dark-mode) > .container,
    body.tutoriales-menu-mobile-page:not(.dark-mode) > .container,
    body.tutorial-mobile-page:not(.dark-mode) > .container,
    body.splitza-mobile-page:not(.dark-mode) > .container,
    body.perfil-mobile-page:not(.dark-mode) > .container {
        background: #fbf8f2;
    }
    /* Inputs/selects/textareas: paper plano. Excluyo el navbar dark
       (que tiene un input no-paper) y los chats. */
    body.home-mercado-mobile-page:not(.dark-mode) input[type="text"],
    body.dashboard-mobile-page:not(.dark-mode) input[type="text"],
    body.vr-mobile-page:not(.dark-mode) input[type="text"],
    body.fi-mobile-page:not(.dark-mode) input[type="text"],
    body.fe-mobile-page:not(.dark-mode) input[type="text"],
    body.notif-mobile-page:not(.dark-mode) input[type="text"],
    body.hist-mobile-page:not(.dark-mode) input[type="text"],
    body.canales-mobile-page:not(.dark-mode) input[type="text"],
    body.categorias-mobile-page:not(.dark-mode) input[type="text"],
    body.conceptos-mobile-page:not(.dark-mode) input[type="text"],
    body.calendario-mobile-page:not(.dark-mode) input[type="text"],
    body.usd-historico-mobile-page:not(.dark-mode) input[type="text"],
    body.vto-tarjeta-mobile-page:not(.dark-mode) input[type="text"],
    body.configuracion-mobile-page:not(.dark-mode) input[type="text"],
    body.splitza-mobile-page:not(.dark-mode) input[type="text"],
    body.perfil-mobile-page:not(.dark-mode) input[type="text"],
    body:not(.dark-mode) input[type="email"]:not(.netzia-input):not(.chat-input),
    body:not(.dark-mode) input[type="password"]:not(.netzia-input):not(.chat-input),
    body:not(.dark-mode) input[type="number"]:not(.netzia-input):not(.chat-input),
    body:not(.dark-mode) input[type="date"]:not(.netzia-input):not(.chat-input),
    body:not(.dark-mode) input[type="search"]:not(.netzia-input):not(.chat-input),
    body:not(.dark-mode) select:not(.netzia-input):not(.chat-input),
    body:not(.dark-mode) textarea:not(.netzia-input):not(.chat-input) {
        background: #f4f0e8;
    }

    /* ── DARK MODE ── espejo de light con #141311 (wrap) / #1a1611 (cards) */
    body.dark-mode.home-mercado-mobile-page,
    body.dark-mode.dashboard-mobile-page,
    body.dark-mode.vr-mobile-page,
    body.dark-mode.fi-mobile-page,
    body.dark-mode.fe-mobile-page,
    body.dark-mode.notif-mobile-page,
    body.dark-mode.hist-mobile-page,
    body.dark-mode.canales-mobile-page,
    body.dark-mode.categorias-mobile-page,
    body.dark-mode.conceptos-mobile-page,
    body.dark-mode.calendario-mobile-page,
    body.dark-mode.usd-historico-mobile-page,
    body.dark-mode.vto-tarjeta-mobile-page,
    body.dark-mode.configuracion-mobile-page,
    body.dark-mode.tutoriales-menu-mobile-page,
    body.dark-mode.tutorial-mobile-page,
    body.dark-mode.splitza-mobile-page,
    body.dark-mode.perfil-mobile-page {
        background: #141311;
        color: #f4f0e8;
    }
    body.dark-mode.home-mercado-mobile-page .susc-banner-wrap,
    body.dark-mode.dashboard-mobile-page .susc-banner-wrap,
    body.dark-mode.vr-mobile-page .susc-banner-wrap,
    body.dark-mode.fi-mobile-page .susc-banner-wrap,
    body.dark-mode.fe-mobile-page .susc-banner-wrap,
    body.dark-mode.notif-mobile-page .susc-banner-wrap,
    body.dark-mode.hist-mobile-page .susc-banner-wrap,
    body.dark-mode.canales-mobile-page .susc-banner-wrap,
    body.dark-mode.categorias-mobile-page .susc-banner-wrap,
    body.dark-mode.conceptos-mobile-page .susc-banner-wrap,
    body.dark-mode.calendario-mobile-page .susc-banner-wrap,
    body.dark-mode.usd-historico-mobile-page .susc-banner-wrap,
    body.dark-mode.vto-tarjeta-mobile-page .susc-banner-wrap,
    body.dark-mode.configuracion-mobile-page .susc-banner-wrap,
    body.dark-mode.tutoriales-menu-mobile-page .susc-banner-wrap,
    body.dark-mode.tutorial-mobile-page .susc-banner-wrap,
    body.dark-mode.splitza-mobile-page .susc-banner-wrap,
    body.dark-mode.perfil-mobile-page .susc-banner-wrap,
    body.dark-mode.home-mercado-mobile-page .netza-footer,
    body.dark-mode.dashboard-mobile-page .netza-footer,
    body.dark-mode.vr-mobile-page .netza-footer,
    body.dark-mode.fi-mobile-page .netza-footer,
    body.dark-mode.fe-mobile-page .netza-footer,
    body.dark-mode.notif-mobile-page .netza-footer,
    body.dark-mode.hist-mobile-page .netza-footer,
    body.dark-mode.canales-mobile-page .netza-footer,
    body.dark-mode.categorias-mobile-page .netza-footer,
    body.dark-mode.conceptos-mobile-page .netza-footer,
    body.dark-mode.calendario-mobile-page .netza-footer,
    body.dark-mode.usd-historico-mobile-page .netza-footer,
    body.dark-mode.vto-tarjeta-mobile-page .netza-footer,
    body.dark-mode.configuracion-mobile-page .netza-footer,
    body.dark-mode.tutoriales-menu-mobile-page .netza-footer,
    body.dark-mode.tutorial-mobile-page .netza-footer,
    body.dark-mode.splitza-mobile-page .netza-footer,
    body.dark-mode.perfil-mobile-page .netza-footer {
        background: #1a1611;
        color: rgba(244, 240, 232, 0.62);
    }
    body.dark-mode.dashboard-mobile-page > .container,
    body.dark-mode.vr-mobile-page > .container,
    body.dark-mode.fi-mobile-page > .container,
    body.dark-mode.fe-mobile-page > .container,
    body.dark-mode.notif-mobile-page > .container,
    body.dark-mode.hist-mobile-page > .container,
    body.dark-mode.canales-mobile-page > .container,
    body.dark-mode.categorias-mobile-page > .container,
    body.dark-mode.conceptos-mobile-page > .container,
    body.dark-mode.calendario-mobile-page > .container,
    body.dark-mode.usd-historico-mobile-page > .container,
    body.dark-mode.vto-tarjeta-mobile-page > .container,
    body.dark-mode.configuracion-mobile-page > .container,
    body.dark-mode.tutoriales-menu-mobile-page > .container,
    body.dark-mode.tutorial-mobile-page > .container,
    body.dark-mode.splitza-mobile-page > .container,
    body.dark-mode.perfil-mobile-page > .container {
        background: #141311;
        color: #f4f0e8;
    }
    /* Inputs en dark: bg paper-card #1a1611 con texto claro */
    body.dark-mode input[type="text"]:not(.netzia-input):not(.chat-input),
    body.dark-mode input[type="email"]:not(.netzia-input):not(.chat-input),
    body.dark-mode input[type="password"]:not(.netzia-input):not(.chat-input),
    body.dark-mode input[type="number"]:not(.netzia-input):not(.chat-input),
    body.dark-mode input[type="date"]:not(.netzia-input):not(.chat-input),
    body.dark-mode input[type="search"]:not(.netzia-input):not(.chat-input),
    body.dark-mode select:not(.netzia-input):not(.chat-input),
    body.dark-mode textarea:not(.netzia-input):not(.chat-input) {
        background: #1a1611;
        color: #f4f0e8;
        border-color: rgba(255, 255, 255, 0.10);
    }
    /* Cards/panels genéricos en dark: bg #1a1611 con borde sutil. */
    body.dark-mode .card,
    body.dark-mode .panel,
    body.dark-mode .perfil-section,
    body.dark-mode .tarjeta-info-card,
    body.dark-mode .grupo-card,
    body.dark-mode .liq-card,
    body.dark-mode .auth-card,
    body.dark-mode table {
        background: #1a1611;
        color: #f4f0e8;
        border-color: rgba(255, 255, 255, 0.08);
    }
    body.dark-mode th, body.dark-mode td {
        border-color: rgba(255, 255, 255, 0.06);
        color: #f4f0e8;
    }
    body.dark-mode h1, body.dark-mode h2, body.dark-mode h3, body.dark-mode h4 { color: #f4f0e8; }
    body.dark-mode p, body.dark-mode label { color: rgba(244, 240, 232, 0.85); }
}

