/* ═══════════════════════════════════════════════════════════
   7Days ERP — Tema Corporativo Minimalista (Tailwind-inspired)
   Bootstrap 5.3 overrides + custom design system
   ═══════════════════════════════════════════════════════════ */

/* ── Design Tokens ── */
:root {
    /* Colors */
    --color-bg:          #f8fafc;
    --color-surface:     #ffffff;
    --color-border:      #e2e8f0;
    --color-border-light:#f1f5f9;

    --color-primary:     #4f46e5;
    --color-primary-hover:#4338ca;
    --color-primary-light:#eef2ff;
    --color-primary-text: #312e81;

    --color-success:     #059669;
    --color-success-light:#ecfdf5;
    --color-warning:     #d97706;
    --color-warning-light:#fffbeb;
    --color-danger:      #dc2626;
    --color-danger-light: #fef2f2;
    --color-info:        #0891b2;
    --color-info-light:  #ecfeff;

    --color-text:        #1e293b;
    --color-text-secondary:#64748b;
    --color-text-muted:  #94a3b8;

    /* Texto sobre los fondos `-light` de avisos y etiquetas. Estaba escrito a mano en cada regla,
       y por eso el tema oscuro lo destapó: allí esos fondos pasan a ser MUY oscuros, así que un
       color de texto fijo y oscuro deja el aviso ilegible justo cuando dice que algo ha fallado. */
    --color-success-fuerte: #047857;
    --color-danger-fuerte:  #b91c1c;
    --color-warning-fuerte: #92400e;
    --color-info-fuerte:    #0e7490;
    --color-success-borde:  #a7f3d0;
    --color-danger-borde:   #fecaca;

    /* Texto sobre un relleno de color de marca: botones sólidos, insignias, el logotipo.
       En claro es blanco; en oscuro los rellenos se ACLARAN, así que el blanco deja de leerse y
       este token pasa a ser oscuro. Es el motivo de que exista en vez de escribir `white`. */
    --color-sobre-relleno: #ffffff;

    /* Barra lateral.
       El fondo lo define ESTE token, no la clase `bg-dark` de Bootstrap: aquella pinta #212529, un
       gris más apagado, así que el tema decía un color y la pantalla enseñaba otro.
       Los tonos de texto están elegidos para cumplir AA sobre el fondo, no por parecido:
       #e2e8f0 da ~12:1 y #94a3b8 ~5,3:1. El anterior #64748b se quedaba en ~2,8:1, por debajo del
       mínimo, y los rótulos de sección casi no se leían. */
    --color-sidebar:        #1e293b;
    --color-sidebar-hover:  #334155;
    --color-sidebar-active: #4f46e5;
    --color-sidebar-text:   #e2e8f0;
    --color-sidebar-muted:  #94a3b8;
    --color-sidebar-border: rgba(255, 255, 255, 0.08);
    --color-sidebar-raised: #334155;
    /* Índigo claro para el icono del módulo actual: el primario a secas se pierde sobre el fondo
       oscuro, y el blanco no lo distingue del resto. */
    --color-sidebar-accent: #a5b4fc;

    /* Spacing */
    --radius-sm: 0.375rem;
    --radius:    0.5rem;
    --radius-lg: 0.75rem;
    --radius-xl: 1rem;

    /* Shadows */
    --shadow-sm:  0 1px 2px 0 rgba(0,0,0,0.05);
    --shadow:     0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1);
    --shadow-md:  0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);
    --shadow-lg:  0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1);

    /* Transitions */
    --transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);

    /* Typography */
    --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
    --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
}

/* ── Base ── */
body {
    font-family: var(--font-sans);
    background: var(--color-bg);
    color: var(--color-text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-size: 0.9375rem;
    line-height: 1.6;
}

/* ── Typography ── */
h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    letter-spacing: -0.025em;
    color: var(--color-text);
}
h1 { font-size: 1.875rem; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.25rem; }
h4 { font-size: 1.125rem; }
h5, h6 { font-size: 1rem; }

.text-muted { color: var(--color-text-secondary) !important; }
.small, small { font-size: 0.8125rem; }

/* ── Links ── */
a {
    color: var(--color-primary);
    text-decoration: none;
    transition: color var(--transition);
}
a:hover { color: var(--color-primary-hover); }

/* ── Buttons ── */
.btn {
    font-weight: 500;
    border-radius: var(--radius);
    padding: 0.5rem 1rem;
    font-size: 0.875rem;
    transition: all var(--transition);
    letter-spacing: 0.01em;
    border: 1px solid transparent;
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.btn:active { transform: translateY(0); }
.btn-sm { padding: 0.375rem 0.75rem; font-size: 0.8125rem; border-radius: var(--radius-sm); }
.btn-lg { padding: 0.625rem 1.25rem; font-size: 1rem; }

.btn-primary {
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.btn-primary:hover { background: var(--color-primary-hover); border-color: var(--color-primary-hover); }
.btn-outline-primary {
    color: var(--color-primary);
    border-color: var(--color-primary);
}
.btn-outline-primary:hover { background: var(--color-primary); color: var(--color-sobre-relleno); }

.btn-success { background: var(--color-success); border-color: var(--color-success); }
.btn-outline-success { color: var(--color-success); border-color: var(--color-success); }
.btn-outline-success:hover { background: var(--color-success); color: var(--color-sobre-relleno); }

.btn-danger { background: var(--color-danger); border-color: var(--color-danger); }
.btn-outline-danger { color: var(--color-danger); border-color: var(--color-danger); }
.btn-outline-danger:hover { background: var(--color-danger); color: var(--color-sobre-relleno); }

.btn-warning { background: var(--color-warning); border-color: var(--color-warning); color: var(--color-sobre-relleno); }
.btn-outline-warning { color: var(--color-warning); border-color: var(--color-warning); }
.btn-outline-warning:hover { background: var(--color-warning); color: var(--color-sobre-relleno); }

.btn-info { background: var(--color-info); border-color: var(--color-info); color: var(--color-sobre-relleno); }
.btn-outline-info { color: var(--color-info); border-color: var(--color-info); }
.btn-outline-info:hover { background: var(--color-info); color: var(--color-sobre-relleno); }

.btn-outline-secondary {
    color: var(--color-text-secondary);
    border-color: var(--color-border);
    background: var(--color-surface);
}
.btn-outline-secondary:hover {
    background: var(--color-bg);
    border-color: var(--color-text-muted);
}
.btn-link { color: var(--color-primary); }
.btn-link:hover { color: var(--color-primary-hover); }

/* ── Cards ── */
.card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--transition);
    background: var(--color-surface);
}
.card:hover { box-shadow: var(--shadow); }
.card-header {
    background: transparent;
    border-bottom: 1px solid var(--color-border);
    font-weight: 600;
    padding: 1rem 1.25rem;
}
.card-body { padding: 1.25rem; }
.card-title { color: var(--color-text); }
.card-title.h5, .card-title.h6 { font-weight: 600; }
.shadow-sm { box-shadow: var(--shadow-sm) !important; }

/* ── Forms ── */
.form-control, .form-select {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.5rem 0.75rem;
    font-size: 0.875rem;
    transition: all var(--transition);
    background: var(--color-surface);
    color: var(--color-text);
}
.form-control:focus, .form-select:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(79,70,229,0.15);
    outline: none;
}
.form-control-sm, .form-select-sm {
    padding: 0.375rem 0.625rem;
    font-size: 0.8125rem;
    border-radius: var(--radius-sm);
}
.form-label {
    font-weight: 500;
    font-size: 0.875rem;
    color: var(--color-text-secondary);
    margin-bottom: 0.375rem;
}
.form-text {
    color: var(--color-text-muted);
    font-size: 0.8125rem;
}

/* ── Input Groups ── */
.input-group .form-control {
    border-right: 0;
}
.input-group .btn {
    border-left: 0;
}

/* ── Alerts ── */
.alert {
    border: none;
    border-radius: var(--radius);
    font-size: 0.875rem;
    padding: 0.875rem 1rem;
}
.alert-info    { background: var(--color-info-light);    color: var(--color-info-fuerte); }
.alert-success { background: var(--color-success-light); color: var(--color-success-fuerte); }
.alert-warning { background: var(--color-warning-light); color: var(--color-warning-fuerte); }
.alert-danger  { background: var(--color-danger-light);  color: var(--color-danger-fuerte); }

/* ── Badges ── */
.badge {
    font-weight: 500;
    font-size: 0.75rem;
    padding: 0.25rem 0.625rem;
    border-radius: var(--radius-sm);
    letter-spacing: 0.02em;
}
.bg-success { background: var(--color-success) !important; }
.bg-warning { background: var(--color-warning) !important; }
.bg-danger  { background: var(--color-danger) !important; }
.bg-info    { background: var(--color-info) !important; }
.bg-primary { background: var(--color-primary) !important; }
.text-bg-light { background: var(--color-bg) !important; color: var(--color-text) !important; border: 1px solid var(--color-border); }

/* ── Tables ── */
.table {
    font-size: 0.875rem;
    border-color: var(--color-border);
}
.table thead th {
    font-weight: 600;
    color: var(--color-text-secondary);
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 2px solid var(--color-border);
    background: var(--color-bg);
    padding: 0.75rem 1rem;
}
.table tbody td {
    padding: 0.75rem 1rem;
    border-color: var(--color-border-light);
    vertical-align: middle;
}
.table tbody tr:hover {
    background: var(--color-bg);
}

/* ── Nav Tabs / Pills ── */
.nav-pills .nav-link {
    border-radius: var(--radius);
    color: var(--color-text-secondary);
    font-weight: 500;
    padding: 0.5rem 0.875rem;
    transition: all var(--transition);
}
.nav-pills .nav-link:hover {
    background: var(--color-bg);
    color: var(--color-text);
}
.nav-pills .nav-link.active {
    background: var(--color-primary);
    color: var(--color-sobre-relleno);
}

/* ── Modals ── */
.modal-content {
    border: none;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}
.modal-header {
    border-bottom: 1px solid var(--color-border);
    padding: 1.25rem 1.5rem;
}
.modal-body { padding: 1.5rem; }
.modal-footer {
    border-top: 1px solid var(--color-border);
    padding: 1rem 1.5rem;
}

/* ── Spinners ── */
.spinner-border {
    color: var(--color-primary);
    width: 1.5rem;
    height: 1.5rem;
    border-width: 0.15em;
}

/* ── Dropdowns ── */
.dropdown-menu {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: 0.375rem;
}
.dropdown-item {
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
    padding: 0.5rem 0.75rem;
    transition: all var(--transition);
}
.dropdown-item:hover { background: var(--color-bg); }
.dropdown-divider { border-color: var(--color-border); margin: 0.375rem 0; }

/* ── Page Title ── */
h4.fw-bold + .text-muted {
    font-weight: 400;
}

/* ── Utility ── */
.border { border-color: var(--color-border) !important; }
.border-top { border-color: var(--color-border) !important; }
.border-bottom { border-color: var(--color-border) !important; }
.rounded { border-radius: var(--radius) !important; }
.rounded-lg { border-radius: var(--radius-lg) !important; }

/* ── Container spacing ── */
.container-fluid {
    max-width: 1440px;
}

/* ── Scrollbar ── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--color-text-muted); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--color-text-secondary); }

/* ── Responsive ── */
@media (max-width: 768px) {
    body { font-size: 0.875rem; }
    .card-body { padding: 1rem; }
    h1 { font-size: 1.5rem; }
    h2 { font-size: 1.25rem; }
}


/* ═══════════════════════════════════════════════════════════
   PAGE HEADERS
   ═══════════════════════════════════════════════════════════ */
.page-header {
    margin-bottom: 1.5rem;
}
.page-header h4 {
    font-weight: 700;
    letter-spacing: -0.03em;
}
.page-header .text-muted {
    font-size: 0.875rem;
}

/* ═══════════════════════════════════════════════════════════
   STATUSBAR / STATUS ALERTS
   ═══════════════════════════════════════════════════════════ */
.status-message {
    font-size: 0.875rem;
    padding: 0.75rem 1rem;
    border-radius: var(--radius);
    margin-bottom: 1rem;
    font-weight: 500;
}
.status-message.success {
    background: var(--color-success-light);
    color: var(--color-success-fuerte);
    border: 1px solid var(--color-success-borde);
}
.status-message.error {
    background: var(--color-danger-light);
    color: var(--color-danger-fuerte);
    border: 1px solid var(--color-danger-borde);
}

/* ═══════════════════════════════════════════════════════════
   GRID CUSTOM
   ═══════════════════════════════════════════════════════════ */

.auto-fit-column {
    width: max-content !important;
    min-width: 100px; 
    white-space: nowrap; 
}

.rz-datagrid-table {
    width: auto !important;
    min-width: 100%;
}

/* ═══════════════════════════════════════════════════════════
   ACCESO (/login, /register) — marco común de `AuthShell.razor`
   ───────────────────────────────────────────────────────────
   Sustituye al bloque `.login-*`, que solo servía a /login mientras /register
   usaba una tarjeta de Bootstrap suelta: dos pantallas seguidas del mismo flujo
   con distinto ancho, distinto título y distinto pie.
   ═══════════════════════════════════════════════════════════ */
.auth-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(60rem 40rem at 15% -10%, var(--color-primary-light) 0%, transparent 60%),
        radial-gradient(45rem 35rem at 100% 100%, var(--color-primary-light) 0%, transparent 55%),
        var(--color-bg);
    padding: 2rem 1rem;
}

.auth-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 27.5rem;
    overflow: hidden;
}

/* Para formularios con varios campos por fila. Una tarjeta estrecha con dos
   campos se lee mejor que una ancha medio vacía, así que es opcional. */
.auth-card--wide { max-width: 40rem; }

.auth-header {
    padding: 2.5rem 2rem 1.5rem;
    text-align: center;
}

.auth-logo {
    width: 3rem;
    height: 3rem;
    background: var(--color-primary);
    border-radius: var(--radius-lg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 1rem;
    box-shadow: var(--shadow-md);
}
.auth-logo i {
    font-size: 1.5rem;
    color: var(--color-sobre-relleno);
    line-height: 1;
}

.auth-title {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    margin-bottom: 0.375rem;
}

.auth-subtitle {
    color: var(--color-text-secondary);
    font-size: 0.875rem;
    margin-bottom: 0;
}

.auth-body { padding: 0 2rem 2rem; }

.auth-body .form-control,
.auth-body .form-select {
    padding: 0.625rem 0.875rem;
    font-size: 0.9375rem;
}

.auth-body .btn {
    padding: 0.625rem 1rem;
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}

/* Separador de secciones dentro del formulario: `/register` agrupa datos
   personales y datos fiscales, y sin esto son quince campos seguidos. */
.auth-section {
    margin: 1.75rem 0 1rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--color-border-light);
}
.auth-section:first-of-type { margin-top: 1.25rem; }
.auth-section-title {
    font-size: 0.8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
    margin-bottom: 0.25rem;
}
.auth-section-help {
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    margin-bottom: 0;
}

.auth-busy {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
    padding: 2.5rem 0;
    color: var(--color-text-secondary);
    font-size: 0.875rem;
}

.auth-footer {
    padding: 1.25rem 2rem;
    background: var(--color-bg);
    border-top: 1px solid var(--color-border);
    text-align: center;
    font-size: 0.875rem;
    color: var(--color-text-secondary);
}
.auth-footer a { font-weight: 600; }

@media (max-width: 576px) {
    .auth-shell { padding: 0; align-items: stretch; }
    .auth-card {
        border: 0;
        border-radius: 0;
        box-shadow: none;
        min-height: 100vh;
        display: flex;
        flex-direction: column;
    }
    .auth-body { flex-grow: 1; }
    .auth-header { padding: 2rem 1.25rem 1.25rem; }
    .auth-body   { padding: 0 1.25rem 1.5rem; }
    .auth-footer { padding: 1rem 1.25rem; }
}

/* ═══════════════════════════════════════════════════════════
   PORTADA (/) — estaba en un <style> dentro de Index.razor
   ───────────────────────────────────────────────────────────
   Aquel bloque repetía en hexadecimal colores que ya existen como tokens
   (#eef2ff era --color-primary-light), así que cambiar el color corporativo
   dejaba la portada con el anterior.
   ═══════════════════════════════════════════════════════════ */
.home-shell { display: flex; flex-direction: column; min-height: 100%; }

/* Accesos rápidos del usuario autenticado */
.home-tile {
    display: block;
    height: 100%;
    text-decoration: none;
    color: inherit;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 1.25rem;
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.home-tile:hover,
.home-tile:focus-visible {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--color-primary);
}
.home-tile-icon {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--radius);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    margin-bottom: 0.875rem;
}
.home-tile-title { font-weight: 600; font-size: 0.9375rem; margin-bottom: 0.125rem; }
.home-tile-text  { font-size: 0.8125rem; color: var(--color-text-secondary); }

/* Tintes de los iconos, derivados de los tokens del tema */
.tint-primary { background: var(--color-primary-light); color: var(--color-primary); }
.tint-success { background: var(--color-success-light); color: var(--color-success); }
.tint-info    { background: var(--color-info-light);    color: var(--color-info); }
.tint-warning { background: var(--color-warning-light); color: var(--color-warning); }

/* Presentación para visitantes */
.home-hero {
    background:
        radial-gradient(55rem 35rem at 20% -20%, var(--color-primary-light) 0%, transparent 60%),
        var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 4.5rem 0 3.5rem;
}
.home-badge {
    display: inline-block;
    background: var(--color-primary-light);
    color: var(--color-primary-text);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 0.375rem 0.875rem;
    border-radius: 2rem;
}
.home-hero-title {
    font-size: clamp(1.875rem, 5vw, 3rem);
    font-weight: 800;
    letter-spacing: -0.035em;
    line-height: 1.1;
    margin: 1rem 0;
}
.home-hero-text {
    font-size: 1.0625rem;
    color: var(--color-text-secondary);
    max-width: 38rem;
    margin: 0 auto 2rem;
}
.home-feature-icon {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--radius);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    margin-bottom: 1rem;
}
.home-footer {
    padding: 1.5rem 0;
    border-top: 1px solid var(--color-border);
    margin-top: auto;
}

/* ── SweetAlert2: animación corta ────────────────────────────────────────────────
   Sus animaciones por defecto duran ~300 ms al entrar y otros tantos al salir. No
   parece mucho, pero se paga en CADA aviso, y en este back office se encadenan:
   bloquear cinco carritos, cobrar cuatro pagos. Ese cuarto de segundo repetido es
   lo que hace que una aplicación rápida se sienta pesada.

   Se acorta, no se quita: sin animación el aviso aparece de golpe y cuesta más
   localizarlo con la vista.

   `prefers-reduced-motion` la desactiva del todo, que es lo que pide quien tiene
   esa preferencia puesta. */
.swal2-popup.swal-rapido {
    animation-duration: 0.14s !important;
}

@media (prefers-reduced-motion: reduce) {
    .swal2-popup.swal-rapido {
        animation: none !important;
    }
}

/* ── Cabecera de página ──────────────────────────────────────────────────────────
   Un solo formato para las 16 vistas. Antes había 19 variantes de encabezado —cinco
   niveles semánticos para el mismo papel visual, y el margen saltando entre mb-0 y
   mb-3 sin criterio—, que es lo que hacía que la aplicación se viera hecha a trozos.

   El tamaño se define aquí y no con clases de Bootstrap en cada página: así cambiarlo
   es tocar un sitio, y el `h1` conserva su significado para los lectores de pantalla
   sin arrastrar el tamaño enorme que trae por defecto. */
.erp-pagina-cabecera {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

.erp-pagina-titulo {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--color-text);
    margin: 0;
}

.erp-pagina-subtitulo {
    font-size: 0.875rem;
    color: var(--color-text-secondary);
    margin: 0.25rem 0 0;
    max-width: 68ch; /* Una línea larga de texto es difícil de seguir con la vista. */
}

.erp-pagina-acciones {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* En pantalla estrecha las acciones bajan y ocupan el ancho, en lugar de apretarse
   contra el título hasta partir sus palabras. */
@media (max-width: 575.98px) {
    .erp-pagina-acciones {
        width: 100%;
    }

    .erp-pagina-acciones > * {
        flex: 1 1 auto;
    }
}

/* ── Esqueleto de carga ──────────────────────────────────────────────────────────
   Sustituye a los trece spinners centrados. Un spinner colapsa la página: el alto se
   reduce y al llegar los datos todo salta de golpe. El esqueleto mantiene la
   estructura, así que la carga se percibe más corta aunque dure lo mismo.

   El brillo se mueve de izquierda a derecha, en la dirección de la lectura. */
.erp-cargando { width: 100%; }

.erp-skeleton-fila,
.erp-skeleton-tarjeta,
.erp-skeleton-etiqueta,
.erp-skeleton-control {
    background: linear-gradient(
        90deg,
        var(--color-border-light) 25%,
        var(--color-border) 37%,
        var(--color-border-light) 63%);
    background-size: 400% 100%;
    animation: erp-skeleton 1.4s ease-in-out infinite;
    border-radius: var(--radius-sm);
}

@keyframes erp-skeleton {
    from { background-position: 100% 50%; }
    to   { background-position: 0 50%; }
}

/* Sin animación para quien la ha desactivado en su sistema: se queda el bloque gris,
   que sigue comunicando la forma y la espera. */
@media (prefers-reduced-motion: reduce) {
    .erp-skeleton-fila,
    .erp-skeleton-tarjeta,
    .erp-skeleton-etiqueta,
    .erp-skeleton-control {
        animation: none;
    }
}

.erp-skeleton-tabla { display: flex; flex-direction: column; gap: 0.5rem; }
.erp-skeleton-fila { height: 2.5rem; }
.erp-skeleton-cabecera { height: 2rem; opacity: 0.75; }

.erp-skeleton-formulario { display: flex; flex-direction: column; gap: 1rem; }
.erp-skeleton-campo { display: flex; flex-direction: column; gap: 0.375rem; }
.erp-skeleton-etiqueta { height: 0.875rem; width: 32%; }
.erp-skeleton-control { height: 2.375rem; }

.erp-skeleton-tarjetas {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
}
.erp-skeleton-tarjeta { height: 6rem; }

/* ── Estado vacío ────────────────────────────────────────────────────────────────
   Sustituye a los `alert alert-info`. No haber datos todavía NO es un aviso: usar el
   mismo componente para «no hay nada» y para «algo ha fallado» hace que el operador
   deje de distinguirlos de un vistazo. */
.erp-vacio {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 2.5rem 1rem;
    color: var(--color-text-secondary);
}

.erp-vacio-icono {
    font-size: 2.5rem;
    color: var(--color-text-muted);
    margin-bottom: 0.75rem;
    line-height: 1;
}

.erp-vacio-titulo {
    font-weight: 600;
    color: var(--color-text);
    margin: 0;
}

.erp-vacio-detalle {
    margin: 0.375rem 0 0;
    font-size: 0.875rem;
    max-width: 46ch; /* Una línea larga centrada es especialmente difícil de leer. */
}

.erp-vacio-accion { margin-top: 1rem; }

/* ── Tema oscuro ─────────────────────────────────────────────────────────────────
   El operador trabaja de noche: los directos son a esas horas. Una pantalla blanca
   a las dos de la mañana es una queja que llega sola.

   Se define REDEFINIENDO los tokens, no duplicando reglas. Todo lo que ya usa
   `var(--color-*)` cambia solo; lo que tenga un color escrito a mano no, y eso es
   justamente lo que este bloque destapó — ver `--color-sobre-relleno` y los
   `--color-*-fuerte` de arriba, que existen porque el tema oscuro los sacó a la luz.

   ── Por qué un atributo `data-tema-efectivo` y no `prefers-color-scheme` ────────

   Hay TRES estados: sin elegir (manda el sistema), claro forzado y oscuro forzado.
   Escrito en CSS puro serían dos bloques idénticos —uno dentro de
   `@media (prefers-color-scheme: dark)` y otro para `[data-tema="oscuro"]`— porque
   una regla de medios no se puede unir con una de atributo en la misma lista de
   selectores.

   Y esa duplicación es exactamente el defecto que este proyecto arrastra en todas
   partes: **el día que alguien retoque un color en un bloque y no en el otro, el
   tema del sistema y el forzado dejarán de decir lo mismo**, y nadie lo verá porque
   hay que tener el equipo en oscuro para notarlo.

   Así que el estado EFECTIVO lo resuelve el guion —que ya hace falta para recordar
   la elección— y aquí hay **una sola definición**. El guion escucha además los
   cambios del sistema, así que en modo automático la página cambia sola sin
   recargar, cosa que la regla de medios daba gratis y no se quería perder.

   `color-scheme` va con ella: hace que el navegador pinte en oscuro lo que NO
   controlamos —barras de desplazamiento, selectores de fecha, autocompletado—.
   Sin eso quedan blancos sobre una página oscura y cantan. */

:root[data-tema-efectivo="oscuro"] {
    color-scheme: dark;

    --color-bg:           #0f172a;
    --color-surface:      #1e293b;
    --color-border:       #334155;
    --color-border-light: #263449;

    /* El primario se ACLARA. #4f46e5 sobre #0f172a da ~3:1, por debajo del mínimo para
       texto; #818cf8 sube a ~7:1. Un color de marca que no se lee no es de marca, es
       un adorno. */
    --color-primary:      #818cf8;
    --color-primary-hover:#a5b4fc;
    --color-primary-light:#1e1b4b;
    --color-primary-text: #c7d2fe;

    --color-success:      #34d399;
    --color-success-light:#052e1f;
    --color-warning:      #fbbf24;
    --color-warning-light:#2c1a02;
    --color-danger:       #f87171;
    --color-danger-light: #2d0b0b;
    --color-info:         #22d3ee;
    --color-info-light:   #062c33;

    --color-text:          #e2e8f0;
    --color-text-secondary:#94a3b8;
    --color-text-muted:    #64748b;

    /* Los fondos `-light` de arriba son oscuros aquí, así que el texto fuerte se
       invierte: claro sobre oscuro. Con los valores del tema claro, un aviso de error
       quedaría en granate sobre granate. */
    --color-success-fuerte: #6ee7b7;
    --color-danger-fuerte:  #fca5a5;
    --color-warning-fuerte: #fcd34d;
    --color-info-fuerte:    #67e8f9;
    --color-success-borde:  #065f46;
    --color-danger-borde:   #7f1d1d;

    /* Los rellenos de color son claros aquí, así que lo que va encima tiene que ser
       oscuro. Es la razón de que este token exista. */
    --color-sobre-relleno: #0f172a;

    /* La barra lateral casi no cambia: ya era oscura. Solo se separa del fondo, que
       ahora también lo es, para que no se fundan en una sola mancha. */
    --color-sidebar:        #111c33;
    --color-sidebar-hover:  #1e293b;
    --color-sidebar-raised: #1e293b;

    /* Sombras más marcadas: sobre fondo oscuro una sombra suave no se ve, y las
       tarjetas pierden el relieve que las separa del fondo. */
    --shadow-sm:  0 1px 2px 0 rgba(0,0,0,0.4);
    --shadow:     0 1px 3px 0 rgba(0,0,0,0.5), 0 1px 2px -1px rgba(0,0,0,0.4);
    --shadow-md:  0 4px 6px -1px rgba(0,0,0,0.5), 0 2px 4px -2px rgba(0,0,0,0.4);
    --shadow-lg:  0 10px 15px -3px rgba(0,0,0,0.6), 0 4px 6px -4px rgba(0,0,0,0.5);
}

/* ── Radzen en oscuro ────────────────────────────────────────────────────────────
   Las tablas, los desplegables y los diálogos los pinta Radzen, y su hoja de estilos
   trae **1.646 variables propias**. No hace falta tocarlas: todas derivan de una
   escala de grises y un puñado de colores raíz, así que basta con invertir la
   escala. Comprobado sobre `material-base.css` 10.3.2, no supuesto.

   Se remapean a los tokens de AQUÍ y no a la hoja oscura que Radzen distribuye
   (`material-dark-base.css`) por dos razones: cambiarla obliga a intercambiar el
   `<link>` en caliente —con su parpadeo— y, sobre todo, **su paleta gris no es la
   nuestra**, así que las tablas se verían de otra aplicación distinta al resto. Que
   cada trozo esté bien y el conjunto no case es justo lo que este rediseño corrige. */

:root[data-tema-efectivo="oscuro"] {
    --rz-white: #e2e8f0;
    --rz-black: #0f172a;

    --rz-base-background-color: var(--color-surface);

    /* La escala invertida. No es un espejo exacto: los tres primeros peldaños se
       separan poco a propósito, porque son fondos (tabla, cabecera, agrupación) y
       tienen que distinguirse entre sí sobre un fondo ya oscuro. */
    --rz-base-50:  #223046;
    --rz-base-100: #263449;
    --rz-base-200: #2d3d54;
    --rz-base-300: #3b4a63;
    --rz-base-400: #64748b;
    --rz-base-500: #7c8ba1;
    --rz-base-600: #94a3b8;
    --rz-base-700: #cbd5e1;
    --rz-base-800: #e2e8f0;
    --rz-base-900: #f1f5f9;

    --rz-base:         #2d3d54;
    --rz-base-light:   #263449;
    --rz-base-lighter: #1e293b;
    --rz-base-dark:    #94a3b8;
    --rz-base-darker:  #f1f5f9;

    /* `on-base` es el texto que va SOBRE esos fondos, así que se invierte con ellos:
       dejarlo en el #212121 de serie pinta texto casi negro sobre gris oscuro. */
    --rz-on-base:         #e2e8f0;
    --rz-on-base-light:   #e2e8f0;
    --rz-on-base-lighter: #e2e8f0;

    --rz-text-color:           #e2e8f0;
    --rz-text-secondary-color: #cbd5e1;
    --rz-text-disabled-color:  #64748b;

    --rz-primary: var(--color-primary);
    --rz-on-primary: var(--color-sobre-relleno);
}

/* ── Bootstrap con color fijo ────────────────────────────────────────────────────
   Estas clases traen el color escrito en la hoja de Bootstrap, así que NO siguen a
   los tokens: en oscuro dejarían recuadros blancos sueltos por la pantalla. Son las
   cuatro que de verdad se usan en el marcado —medido, no listadas por si acaso—, y
   `text-bg-light` es con diferencia la más frecuente: las insignias de estado de
   ocho pantallas. */

:root[data-tema-efectivo="oscuro"] .bg-light,
:root[data-tema-efectivo="oscuro"] .text-bg-light {
    background-color: var(--color-border-light) !important;
    color: var(--color-text) !important;
}

:root[data-tema-efectivo="oscuro"] .text-dark { color: var(--color-text) !important; }

/* ── Foco visible ────────────────────────────────────────────────────────────────
   Un contorno que se ve en los dos temas y que NO desplaza el contenido: `outline`
   no ocupa espacio, un `border` sí. `:focus-visible` y no `:focus`, para que no
   aparezca al hacer clic con el ratón — que es la razón por la que tanta gente lo
   desactiva y deja la aplicación sin navegación por teclado. */
:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ── Movimiento reducido, de una vez y para todo ─────────────────────────────────
   Estaba puesto en dos sitios —los diálogos y el esqueleto de carga— y **no en el
   resto**, así que quien tiene esa preferencia del sistema seguía viendo saltar
   todos los botones al pasar por encima y las tarjetas del inicio levantarse.

   La preferencia no la pone nadie por gusto: quien la activa suele hacerlo porque el
   movimiento le provoca mareo o migraña. Respetarla a medias es no respetarla.

   Lo que se anula es el DESPLAZAMIENTO, no el cambio de color: un botón que no
   cambia de aspecto al pasar por encima deja de parecer pulsable. Por eso se apagan
   `transform` y `animation` y se dejan vivas las transiciones de color, que no
   mueven nada. */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
    }

    .btn:hover,
    .btn:active,
    .home-tile:hover,
    .home-tile:focus-visible {
        transform: none !important;
    }
}

/* ── Selector de acceso: roles y permisos ────────────────────────────────────────
   Los roles y los permisos se pintaban como dos listas de casillas, una debajo de
   otra y dentro de una columna estrecha. Quince casillas en fila vertical no son una
   decisión informada: son un muro que se acepta sin leer.

   Aquí el ancho disponible se usa. Dos rejillas `auto-fill`, así que el número de
   columnas lo decide el sitio que haya —tres en un monitor, una en el móvil— sin
   puntos de ruptura escritos a mano. */

.erp-roles-rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
    gap: 0.75rem;
}

/* Cada rol es una tarjeta elegible, no una línea de texto con una casilla delante.
   Se lee de un vistazo qué hace cada uno, que es lo que hacía falta: crear un
   `vendedor` obligaba a saberse de memoria qué permisos tocaban. */
.erp-rol-tarjeta {
    display: flex;
    gap: 0.625rem;
    align-items: flex-start;
    padding: 0.75rem 0.875rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.erp-rol-tarjeta:hover { border-color: var(--color-primary); }

/* El foco va en la TARJETA y no solo en la casilla: el recuadro de 2 px alrededor de
   un cuadradito de 1 em es casi invisible, y quien navega con teclado necesita saber
   en qué rol está. */
.erp-rol-tarjeta:focus-within {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.erp-rol-tarjeta.seleccionado {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
}

.erp-rol-nombre { font-weight: 600; display: block; }
.erp-rol-detalle {
    display: block;
    font-size: 0.8125rem;
    color: var(--color-text-secondary);
    line-height: 1.35;
}

/* Los grupos de permisos van en columnas, no apilados: con tres grupos y quince
   permisos, apilarlos obliga a desplazarse para ver lo que se está concediendo. */
.erp-permisos-rejilla {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
    gap: 1rem;
}

.erp-permisos-grupo {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.875rem 1rem;
    background: var(--color-surface);
}

.erp-permisos-grupo-titulo {
    font-weight: 600;
    font-size: 0.875rem;
    margin: 0;
}
.erp-permisos-grupo-detalle {
    font-size: 0.75rem;
    color: var(--color-text-secondary);
    margin: 0.125rem 0 0.75rem;
    line-height: 1.35;
}

/* El grupo «sin efecto hoy» se apaga visualmente: sigue estando —el sitio está hecho
   para cuando se use— pero no compite por la atención con los que sí conceden algo. */
.erp-permisos-grupo.sin-efecto {
    background: var(--color-bg);
    border-style: dashed;
}

.erp-permiso-detalle {
    display: block;
    font-size: 0.75rem;
    color: var(--color-text-secondary);
    line-height: 1.3;
}

/* Resumen de lo que se está concediendo. Existe porque el estado real de veinte
   casillas no se lee contándolas: se lee en una frase. */
.erp-acceso-resumen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.625rem 0.875rem;
    border-radius: var(--radius);
    background: var(--color-border-light);
    font-size: 0.875rem;
}

/* ── Secciones de un formulario largo ────────────────────────────────────────────
   El alta de usuario mezclaba datos personales, roles, permisos y modo de acceso en
   una sola caída, sin nada que dijera dónde termina un asunto y empieza el
   siguiente. */
.erp-seccion + .erp-seccion {
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--color-border);
}

.erp-seccion-titulo {
    font-size: 0.9375rem;
    font-weight: 600;
    margin: 0 0 0.125rem;
}
.erp-seccion-detalle {
    font-size: 0.8125rem;
    color: var(--color-text-secondary);
    margin: 0 0 1rem;
}

/* ── Cifra destacada de un informe ───────────────────────────────────────────────
   Tres partes, y las tres hacen falta: QUÉ es, CUÁNTO, y de dónde sale. La tercera
   es la que evita el error que más veces ha costado dinero aquí — confundir
   artículos, facturado y cobrado, que son tres cifras distintas del mismo periodo. */
.erp-cifra {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    padding: 0.875rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    height: 100%;
}

.erp-cifra-rotulo {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-secondary);
}

.erp-cifra-valor {
    font-size: 1.375rem;
    font-weight: 600;
    line-height: 1.2;
    /* Cifras de ancho fijo: en una columna de importes, las proporcionales bailan y
       cuesta comparar dos filas de un vistazo. */
    font-variant-numeric: tabular-nums;
}

.erp-cifra-nota {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    line-height: 1.3;
}

/* ═══════════════════════════════════════════════════════════
   IgbCombo — desplegable de búsqueda
   Todo el color sale de tokens: el tema oscuro no necesita ni una regla propia aquí.
   ═══════════════════════════════════════════════════════════ */

.igb-combo {
    position: relative;
}

.igb-combo__campo {
    position: relative;
    display: flex;
    align-items: center;
}

/* Sitio para el botón de quitar, para que no se monte sobre el texto */
.igb-combo__campo > input {
    padding-right: 2rem;
}

.igb-combo__limpiar {
    position: absolute;
    right: .35rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--color-text-muted);
    font-size: .7rem;
    line-height: 1;
    cursor: pointer;
}

.igb-combo__limpiar:hover {
    background: var(--color-border-light);
    color: var(--color-text);
}

.igb-combo__lista {
    position: absolute;
    z-index: 1080; /* por encima del contenido del modal de Bootstrap (1055) */
    top: calc(100% + 2px);
    left: 0;
    right: 0;
    margin: 0;
    padding: .25rem 0;
    max-height: 17rem;
    overflow-y: auto;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: .5rem;
    box-shadow: 0 8px 24px rgb(15 23 42 / .12);
}

.igb-combo__opcion {
    padding: .4rem .75rem;
    font-size: .875rem;
    color: var(--color-text);
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.igb-combo__opcion:hover,
.igb-combo__opcion--activa {
    background: var(--color-primary-light);
    color: var(--color-primary-text);
}

.igb-combo__opcion--elegida {
    font-weight: 600;
}

/* La coincidencia se resalta con peso y color, NO con un fondo amarillo: `mark` trae uno fijo del
   navegador que no pasa por los tokens y en el tema oscuro queda ilegible. */
.igb-combo__coincidencia {
    background: transparent;
    color: inherit;
    font-weight: 700;
    text-decoration: underline;
    text-underline-offset: .15em;
}

.igb-combo__vacio,
.igb-combo__pie {
    padding: .4rem .75rem;
    font-size: .78rem;
    color: var(--color-text-secondary);
}

.igb-combo__pie {
    border-top: 1px solid var(--color-border-light);
    margin-top: .25rem;
    padding-top: .4rem;
}
