/* ============================================================================
   DESIGN SYSTEM — FIDELIZACIÓN ADMIN
   ----------------------------------------------------------------------------
   Estilo:      Data-Dense Dashboard (densidad 8/10, movimiento 3/10)
   Tipografía:  Inter (auto-hospedada en /fonts)
   Iconos:      Phosphor outline, SVG inline vía <Icon />. Nunca emojis.

   ARQUITECTURA DE TOKENS — tres capas, en este orden:
     1. Paleta cruda      --gray-*, --indigo-*   (valores literales)
     2. Capa semántica    --bg-*, --text-*, ...  (única capa que cambia con el tema)
     3. Componentes       .btn, .card, ...       (consumen SOLO la capa semántica)

   Los componentes nunca leen la paleta cruda. Esa indirección es lo que hace
   que el modo oscuro funcione redefiniendo ~30 variables en vez de cada regla.
   ========================================================================= */

/* ===== 0. FUENTE ======================================================== */
/* Auto-hospedada: el panel puede correr como Windows Service sin salida a
   internet, y evita la petición a fonts.gstatic.com en cada carga. */
/* Fuente variable (un archivo cubre los pesos 300-800), partida en dos subsets.
   `latin` ya incluye todo el español —acentos, ñ, ¿, ¡, €— así que en la
   práctica solo se descargan 48 KB; `latin-ext` queda como respaldo y el
   navegador solo lo pide si aparece un carácter de ese rango. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url('fonts/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url('fonts/inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                   U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ===== 1. RESET ========================================================= */
*, *::before, *::after { box-sizing: border-box; }

/* ===== 2. PALETA CRUDA ================================================== */
:root {
    --indigo-50:  #eef2ff;
    --indigo-100: #e0e7ff;
    --indigo-300: #a5b4fc;
    --indigo-400: #818cf8;
    --indigo-500: #6366f1;
    --indigo-600: #4f46e5;
    --indigo-700: #4338ca;

    --gray-50:  #f8fafc;
    --gray-100: #f1f5f9;
    --gray-200: #e2e8f0;
    --gray-300: #cbd5e1;
    --gray-400: #94a3b8;
    --gray-500: #64748b;
    --gray-600: #475569;
    --gray-700: #334155;
    --gray-800: #1e293b;
    --gray-900: #0f172a;
    --gray-950: #020617;

    /* --- Escala de espaciado (densidad 8/10 — panel operativo, no marketing) */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    --space-6: 24px;
    --space-7: 28px;
    --space-8: 32px;

    /* --- Métricas de layout */
    --sidebar-w: 248px;
    --header-h:  56px;
    --row-h:     36px;
    --content-max: 1440px;

    --radius-sm: 6px;
    --radius:    10px;
    --radius-lg: 14px;
    --radius-xl: 20px;

    /* --- Movimiento (subtle) */
    --dur-fast: 120ms;
    --dur:      180ms;
    --dur-slow: 240ms;
    --ease:     cubic-bezier(0.4, 0, 0.2, 1);

    --z-sidebar: 100;
    --z-overlay: 150;
    --z-modal:   200;
    --z-toast:   300;
}

/* ===== 3. CAPA SEMÁNTICA — TEMA CLARO =================================== */
:root {
    color-scheme: light;

    --bg-page:     var(--gray-100);
    --bg-surface:  #ffffff;
    --bg-elevated: #ffffff;
    --bg-subtle:   var(--gray-50);
    --bg-inset:    var(--gray-100);
    --bg-hover:    var(--gray-50);

    --text-primary:   var(--gray-900);
    --text-secondary: var(--gray-700);
    /* gray-600 y no gray-500: #64748b sobre --bg-page da 4.34:1, por debajo del
       4.5:1 de AA. Afectaba a subtítulos, pestañas y textos de ayuda. */
    --text-muted:     var(--gray-600);
    --text-faint:     var(--gray-400);
    --text-on-accent: #ffffff;

    --border:        var(--gray-200);
    --border-subtle: var(--gray-100);
    --border-strong: var(--gray-300);

    /* Relleno de las superficies neutras que deben SEPARARSE del fondo: chips
       grises, círculo del estado vacío. No puede ser --bg-inset, que en oscuro
       es más oscuro que la tarjeta y hace desaparecer el elemento. */
    /* gray-200 y no gray-100: gray-100 es exactamente --bg-page, así que el
       círculo del estado vacío desaparecía al quedar sobre el fondo. */
    --neutral-soft: var(--gray-200);

    /* El índigo se parte en tres papeles porque cada uno tiene una exigencia de
       contraste distinta, y usar un solo valor incumple AA en alguno:
         --primary      decorativo (bordes, anillo de foco, barra de activo).
                        No lleva texto encima, así que no tiene mínimo.
         --primary-text índigo sobre fondo claro. #6366f1 da 4.08:1 sobre
                        --bg-page: insuficiente. Se oscurece a indigo-600.
         --primary-fill fondo de botón con --text-on-accent encima. Blanco sobre
                        #6366f1 da 4.47:1, también insuficiente por poco. */
    --primary:       var(--indigo-500);
    --primary-text:  var(--indigo-600);
    --primary-fill:  var(--indigo-600);
    --primary-hover: var(--indigo-700);
    --primary-soft:  var(--indigo-100);
    --primary-on-soft: #3730a3;
    --primary-ring:  rgba(99, 102, 241, 0.35);

    --success:      #10b981;
    --success-soft: #d1fae5;
    --success-on-soft: #065f46;
    --warning:      #f59e0b;
    --warning-soft: #fef3c7;
    --warning-on-soft: #92400e;
    --danger:       #ef4444;
    --danger-soft:  #fee2e2;
    --danger-on-soft: #991b1b;
    --info:         #3b82f6;
    --info-soft:    #dbeafe;
    --info-on-soft: #1e40af;

    /* Chrome de la barra lateral: neutro y oscuro en ambos temas, para que el
       panel se lea igual cambie o no el tema. */
    --sidebar-bg:            var(--gray-900);
    --sidebar-text:          var(--gray-300);
    --sidebar-text-active:   #ffffff;
    --sidebar-hover:         rgba(255, 255, 255, 0.07);
    --sidebar-active:        rgba(99, 102, 241, 0.22);
    /* gray-400: gray-500 sobre el fondo de la barra daba 3.75:1 */
    --sidebar-section:       var(--gray-400);
    --sidebar-border:        rgba(255, 255, 255, 0.08);

    /* Acento del tenant. Se sobreescribe por empresa desde MainLayout.
       Uso restringido a badge/avatar de identificación: un color arbitrario
       de la base de datos no tiene contraste garantizado sobre texto. */
    --tenant-accent: var(--indigo-400);

    --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.08);
    --shadow:    0 4px 12px rgba(15, 23, 42, 0.08);
    --shadow-lg: 0 8px 24px rgba(15, 23, 42, 0.12);
    --overlay:   rgba(15, 23, 42, 0.5);
}

/* ===== 4. CAPA SEMÁNTICA — TEMA OSCURO ================================== */
/* Se declara dos veces a propósito:
     - @media  = respeta la preferencia del sistema cuando el usuario no eligió
     - [data-theme] = la elección explícita gana, en AMBAS direcciones
   El atributo lo estampa el script inline de App.razor antes del primer pintado. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --bg-page:     var(--gray-950);
        --bg-surface:  #0e1425;
        --bg-elevated: #161d31;
        --bg-subtle:   #131a2b;
        --bg-inset:    #0b1120;
        --bg-hover:    rgba(255, 255, 255, 0.04);

        --text-primary:   #f1f5f9;
        --text-secondary: #cbd5e1;
        --text-muted:     #94a3b8;
        --text-faint:     #64748b;

        --border:        #253049;
        --border-subtle: #1a2337;
        --border-strong: #354564;
        --neutral-soft:  rgba(255, 255, 255, 0.09);

        --primary:       var(--indigo-400);
        --primary-text:  var(--indigo-300);
        /* En oscuro el botón se rellena claro y el texto va oscuro: blanco
           sobre indigo-400 da 2.98:1. Con #0f172a encima sube a 6.0:1. */
        --primary-fill:  var(--indigo-400);
        --primary-hover: var(--indigo-300);
        --text-on-accent: var(--gray-900);
        --primary-soft:  rgba(129, 140, 248, 0.16);
        --primary-on-soft: #c7d2fe;
        --primary-ring:  rgba(129, 140, 248, 0.45);

        --success:      #34d399;
        --success-soft: rgba(52, 211, 153, 0.15);
        --success-on-soft: #6ee7b7;
        --warning:      #fbbf24;
        --warning-soft: rgba(251, 191, 36, 0.15);
        --warning-on-soft: #fcd34d;
        --danger:       #f87171;
        --danger-soft:  rgba(248, 113, 113, 0.15);
        --danger-on-soft: #fca5a5;
        --info:         #60a5fa;
        --info-soft:    rgba(96, 165, 250, 0.15);
        --info-on-soft: #93c5fd;

        --sidebar-bg:     #0b1120;
        --sidebar-border: rgba(255, 255, 255, 0.06);

        --tenant-accent: var(--indigo-300);

        --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
        --shadow:    0 4px 12px rgba(0, 0, 0, 0.45);
        --shadow-lg: 0 8px 28px rgba(0, 0, 0, 0.55);
        --overlay:   rgba(2, 6, 23, 0.7);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --bg-page:     var(--gray-950);
    --bg-surface:  #0e1425;
    --bg-elevated: #161d31;
    --bg-subtle:   #131a2b;
    --bg-inset:    #0b1120;
    --bg-hover:    rgba(255, 255, 255, 0.04);

    --text-primary:   #f1f5f9;
    --text-secondary: #cbd5e1;
    --text-muted:     #94a3b8;
    --text-faint:     #64748b;

    --border:        #253049;
    --border-subtle: #1a2337;
    --border-strong: #354564;
    --neutral-soft:  rgba(255, 255, 255, 0.09);

    --primary:       var(--indigo-400);
    --primary-text:  var(--indigo-300);
    --primary-fill:  var(--indigo-400);
    --primary-hover: var(--indigo-300);
    --text-on-accent: var(--gray-900);
    --primary-soft:  rgba(129, 140, 248, 0.16);
    --primary-on-soft: #c7d2fe;
    --primary-ring:  rgba(129, 140, 248, 0.45);

    --success:      #34d399;
    --success-soft: rgba(52, 211, 153, 0.15);
    --success-on-soft: #6ee7b7;
    --warning:      #fbbf24;
    --warning-soft: rgba(251, 191, 36, 0.15);
    --warning-on-soft: #fcd34d;
    --danger:       #f87171;
    --danger-soft:  rgba(248, 113, 113, 0.15);
    --danger-on-soft: #fca5a5;
    --info:         #60a5fa;
    --info-soft:    rgba(96, 165, 250, 0.15);
    --info-on-soft: #93c5fd;

    --sidebar-bg:     #0b1120;
    --sidebar-border: rgba(255, 255, 255, 0.06);

    --tenant-accent: var(--indigo-300);

    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
    --shadow:    0 4px 12px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 8px 28px rgba(0, 0, 0, 0.55);
    --overlay:   rgba(2, 6, 23, 0.7);
}

/* --- Alias de compatibilidad ------------------------------------------------
   Las 14 páginas aún no migradas referencian estos nombres. Se mantienen para
   que sigan funcionando y hereden el tema. Código nuevo: usar los semánticos. */
:root {
    --primary-dark:  var(--primary-hover);
    --primary-light: var(--primary-soft);
    --success-light: var(--success-soft);
    --warning-light: var(--warning-soft);
    --danger-light:  var(--danger-soft);
    --info-light:    var(--info-soft);
}

/* ===== 5. BASE ========================================================== */
html { height: 100%; }

body {
    font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
    font-size: 15px;
    line-height: 1.5;
    color: var(--text-secondary);
    background: var(--bg-page);
    margin: 0;
    padding: 0;
    min-height: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    font-variant-numeric: tabular-nums;   /* columnas de cifras alineadas */
}

/* Un solo anillo de foco para todo el panel. Nunca `outline: none` sin
   reemplazo: el panel se opera con teclado. */
:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

::selection { background: var(--primary-soft); color: var(--primary-on-soft); }

/* Salto al contenido: primer tabulador de la página. */
.skip-link {
    position: absolute;
    left: var(--space-2);
    top: -100px;
    z-index: 999;
    padding: var(--space-2) var(--space-4);
    background: var(--primary-fill);
    color: var(--text-on-accent);
    border-radius: var(--radius-sm);
    font-weight: 600;
    font-size: 0.875rem;
    text-decoration: none;
    transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: var(--space-2); }

/* ===== 6. TIPOGRAFÍA ==================================================== */
h1, h2, h3, h4, h5 {
    font-weight: 700;
    color: var(--text-primary);
    margin: 0 0 var(--space-2);
    letter-spacing: -0.011em;
}
h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.0625rem; }
h4 { font-size: 0.9375rem; }

a { color: var(--primary-text); text-decoration: none; }
a:hover { text-decoration: underline; }

.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-6);
}
.page-title {
    font-size: 1.375rem;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    letter-spacing: -0.015em;
}
.page-title svg { color: var(--primary); flex-shrink: 0; }
.page-subtitle {
    font-size: 0.875rem;
    color: var(--text-muted);
    margin: var(--space-1) 0 0;
    max-width: 68ch;
}
.page-header-actions { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }

/* ===== 7. APP SHELL ===================================================== */
.app-shell { display: flex; min-height: 100vh; background: var(--bg-page); }

.app-sidebar {
    width: var(--sidebar-w);
    flex-shrink: 0;
    background: var(--sidebar-bg);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    z-index: var(--z-sidebar);
}

.app-main {
    flex: 1;
    min-width: 0;              /* sin esto las tablas anchas estiran el flex item */
    display: flex;
    flex-direction: column;
}

.app-content {
    flex: 1;
    padding: var(--space-6);
    max-width: var(--content-max);
    width: 100%;
}

/* --- Barra superior */
.app-bar {
    height: var(--header-h);
    flex-shrink: 0;
    background: var(--bg-surface);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-6);
    position: sticky;
    top: 0;
    z-index: 90;
}
.app-bar-title {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;   /* sin esto el ellipsis no actúa dentro de un contenedor flex */
}
.app-bar-spacer { flex: 1; }

.icon-btn {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.icon-btn:hover { background: var(--bg-hover); color: var(--text-primary); }

/* --- Interruptor de tema
   Qué icono se ve lo decide el CSS, no JavaScript: el botón lleva los dos y
   cada tema oculta el que no corresponde. Así el icono ya es correcto en el
   primer pintado, sin esperar a que corra ningún script.
   Se muestra la ACCIÓN, no el estado: en claro se ve la luna ("ir a oscuro"). */
.theme-to-light { display: none; }
.theme-to-dark  { display: block; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .theme-to-dark  { display: none; }
    :root:not([data-theme="light"]) .theme-to-light { display: block; }
}
:root[data-theme="dark"]  .theme-to-dark  { display: none; }
:root[data-theme="dark"]  .theme-to-light { display: block; }
:root[data-theme="light"] .theme-to-dark  { display: block; }
:root[data-theme="light"] .theme-to-light { display: none; }

/* Disparador del menú de usuario. 36px de alto visual, pero el área táctil
   completa cumple el mínimo junto al padding de la barra. */
.user-menu { position: relative; }
.user-trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    min-height: 36px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    cursor: pointer;
    color: var(--text-secondary);
    font: inherit;
    font-size: 0.8125rem;
    transition: background var(--dur) var(--ease);
}
.user-trigger:hover { background: var(--bg-hover); }
.user-avatar {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border-radius: 50%;
    /* Las iniciales van sobre --primary-fill, cuyo contraste está garantizado.
       El color del tenant queda como aro exterior: identifica la empresa sin
       ponerse nunca detrás de un texto. */
    background: var(--primary-fill);
    color: var(--text-on-accent);
    box-shadow: 0 0 0 2px var(--tenant-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    font-weight: 700;
}
.user-meta { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.2; }
.user-name { font-weight: 600; color: var(--text-primary); }
.user-role { font-size: 0.6875rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

/* Abierto/cerrado lo controla ui.js poniendo .open en el contenedor [data-menu].
   `display:none` (y no opacidad) para que el contenido cerrado quede fuera del
   orden de tabulación. */
.dropdown { display: none; }
[data-menu].open > .dropdown { display: block; }

.dropdown {
    position: absolute;
    right: 0;
    top: calc(100% + var(--space-2));
    min-width: 200px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--space-1);
    z-index: var(--z-modal);
    animation: dropIn var(--dur) var(--ease);
}
.dropdown-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: none;
    background: none;
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: 0.8125rem;
    color: var(--text-secondary);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease);
}
.dropdown-item:hover { background: var(--bg-hover); color: var(--text-primary); text-decoration: none; }
.dropdown-item.danger { color: var(--danger); }
.dropdown-divider { height: 1px; background: var(--border-subtle); margin: var(--space-1) 0; }
.dropdown-label {
    padding: var(--space-2) var(--space-3) var(--space-1);
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-faint);
}

/* --- Barra superior en pantallas estrechas
   A 375px la barra tiene que albergar hamburguesa + título + tema + usuario.
   Se ocultan el título y el nombre; queda el avatar, que abre el mismo menú, y
   dentro del desplegable se repiten nombre, correo y rol, así que no se pierde
   información.

   Esta regla va DESPUÉS de `.user-meta { display: flex }` a propósito: ambas
   tienen la misma especificidad (0,1,0) y una media query no la aumenta, así
   que la que gana es la última del archivo. Colocada antes, no hacía nada. */
@media (max-width: 640px) {
    .app-bar-title { display: none; }
    .user-meta     { display: none; }
    .user-trigger  { padding: var(--space-1); }
    .app-bar       { gap: var(--space-2); }
}

/* ===== 8. NAVEGACIÓN LATERAL ============================================ */
.nav-brand {
    height: var(--header-h);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0 var(--space-4);
    border-bottom: 1px solid var(--sidebar-border);
    color: #fff;
    font-weight: 700;
    font-size: 0.9375rem;
    text-decoration: none;
    letter-spacing: -0.01em;
}
.nav-brand:hover { text-decoration: none; color: #fff; }
.nav-brand svg { color: var(--tenant-accent); flex-shrink: 0; }

.nav-tenant {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--sidebar-border);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}
.nav-tenant-dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--tenant-accent);
    flex-shrink: 0;
}
.nav-tenant-name {
    font-size: 0.8125rem;
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.nav-scroll { flex: 1; overflow-y: auto; padding: var(--space-3) var(--space-2) var(--space-6); }
.nav-scroll::-webkit-scrollbar { width: 6px; }
.nav-scroll::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.12); border-radius: 3px; }

.nav-section { margin-bottom: var(--space-5); }
.nav-section-label {
    padding: 0 var(--space-3) var(--space-2);
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--sidebar-section);
}

.app-sidebar .nav-link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    min-height: 38px;
    border-radius: var(--radius-sm);
    color: var(--sidebar-text);
    font-size: 0.8438rem;
    font-weight: 500;
    text-decoration: none;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.app-sidebar .nav-link svg { flex-shrink: 0; opacity: 0.75; }
.app-sidebar .nav-link:hover {
    background: var(--sidebar-hover);
    color: var(--sidebar-text-active);
    text-decoration: none;
}
.app-sidebar .nav-link:hover svg { opacity: 1; }
.app-sidebar .nav-link.active {
    background: var(--sidebar-active);
    color: var(--sidebar-text-active);
    font-weight: 600;
    /* La barra izquierda duplica la señal de "estás aquí" sin depender del
       color: sigue siendo visible en escala de grises. */
    box-shadow: inset 3px 0 0 var(--primary);
}
.app-sidebar .nav-link.active svg { opacity: 1; color: var(--indigo-300); }
.app-sidebar .nav-link:focus-visible { outline-offset: -2px; }

.nav-badge {
    margin-left: auto;
    min-width: 20px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--danger);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 700;
    text-align: center;
}

/* --- Off-canvas (móvil/tablet) */
.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--overlay);
    z-index: var(--z-overlay);
    animation: fadeIn var(--dur) var(--ease);
}

@media (max-width: 900px) {
    .app-sidebar {
        position: fixed;
        left: 0; top: 0; bottom: 0;
        height: 100dvh;
        transform: translateX(-100%);
        transition: transform var(--dur-slow) var(--ease);
        z-index: var(--z-overlay);
        box-shadow: var(--shadow-lg);
    }
    .app-shell.nav-open .app-sidebar { transform: translateX(0); }
    .app-shell.nav-open .sidebar-overlay { display: block; }
    .app-content { padding: var(--space-4); }
    .app-bar { padding: 0 var(--space-4); }
}
@media (min-width: 901px) {
    .nav-toggle { display: none; }
}

/* ===== 9. TARJETAS ====================================================== */
.card {
    background: var(--bg-surface);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    color: var(--text-secondary);
}
.card-header {
    padding: var(--space-3) var(--space-5);
    border-bottom: 1px solid var(--border-subtle);
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--text-primary);
    background: var(--bg-subtle);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}
.card-body { padding: var(--space-5); }
.card-footer {
    padding: var(--space-3) var(--space-5);
    border-top: 1px solid var(--border-subtle);
    background: var(--bg-subtle);
}

/* ===== 10. STAT CARDS =================================================== */
.stat-card {
    background: var(--bg-surface);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    padding: var(--space-5);
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.stat-card:hover { box-shadow: var(--shadow); transform: translateY(-1px); }
a.stat-card { text-decoration: none; }
a.stat-card:hover { text-decoration: none; border-color: var(--primary); }

.stat-icon {
    width: 44px;
    height: 44px;
    border-radius: var(--radius);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.stat-icon.green  { background: var(--success-soft); color: var(--success-on-soft); }
.stat-icon.blue   { background: var(--info-soft);    color: var(--info-on-soft); }
.stat-icon.yellow { background: var(--warning-soft); color: var(--warning-on-soft); }
.stat-icon.purple { background: var(--primary-soft); color: var(--primary-on-soft); }
.stat-icon.red    { background: var(--danger-soft);  color: var(--danger-on-soft); }

.stat-body  { flex: 1; min-width: 0; }
.stat-value { font-size: 1.5rem; font-weight: 700; color: var(--text-primary); line-height: 1.15; letter-spacing: -0.02em; }
.stat-label { font-size: 0.8125rem; color: var(--text-muted); font-weight: 500; margin-top: 2px; }
.stat-delta { display: inline-flex; align-items: center; gap: 3px; font-size: 0.75rem; font-weight: 600; margin-top: var(--space-2); }
.stat-delta.up   { color: var(--success); }
.stat-delta.down { color: var(--danger); }
.stat-delta.flat { color: var(--text-muted); }

/* ===== 11. BOTONES ====================================================== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    min-height: 36px;
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
    font-weight: 600;
    font-family: inherit;
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
    white-space: nowrap;
    line-height: 1.4;
}
.btn:hover { text-decoration: none; }
.btn svg { flex-shrink: 0; }

.btn-primary { background: var(--primary-fill); border-color: var(--primary-fill); color: var(--text-on-accent); }
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: var(--text-on-accent); }
.btn-success { background: var(--success); border-color: var(--success); color: #fff; }
.btn-success:hover { filter: brightness(0.93); color: #fff; }
.btn-warning { background: var(--warning); border-color: var(--warning); color: #422006; }
.btn-warning:hover { filter: brightness(0.93); color: #422006; }
.btn-danger  { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { filter: brightness(0.93); color: #fff; }
.btn-outline { background: transparent; border-color: var(--border-strong); color: var(--text-secondary); }
.btn-outline:hover { background: var(--bg-hover); border-color: var(--text-faint); color: var(--text-primary); }
.btn-ghost   { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn-ghost:hover { background: var(--bg-hover); color: var(--text-primary); }

.btn-sm { padding: var(--space-1) var(--space-3); min-height: 30px; font-size: 0.8125rem; }
.btn-lg { padding: var(--space-3) var(--space-6); min-height: 44px; font-size: 0.9375rem; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; }

/* En pantallas táctiles todo control interactivo sube al mínimo de 44px.
   No se aplica en escritorio: haría el panel innecesariamente disperso. */
@media (pointer: coarse) {
    .btn, .icon-btn, .form-control, .form-select { min-height: 44px; }
    .btn-sm { min-height: 40px; }
    .table-actions { gap: var(--space-2); }
}

/* ===== 12. BADGES ======================================================= */
.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px var(--space-2);
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    white-space: nowrap;
}
.badge-success { background: var(--success-soft); color: var(--success-on-soft); }
.badge-warning { background: var(--warning-soft); color: var(--warning-on-soft); }
.badge-danger  { background: var(--danger-soft);  color: var(--danger-on-soft); }
.badge-info    { background: var(--info-soft);    color: var(--info-on-soft); }
.badge-primary { background: var(--primary-soft); color: var(--primary-on-soft); }
.badge-gray    { background: var(--neutral-soft); color: var(--text-secondary); }

/* --- Tarjeta de un registro desactivado ---------------------------------
   Atenúa sin llegar a esconder: el registro sigue siendo legible y accionable
   (hay que poder reactivarlo). No se baja de 0.65 para no incumplir contraste. */
.card.inactivo { opacity: 0.65; }
.card.inactivo:hover, .card.inactivo:focus-within { opacity: 1; }

/* ===== 13. FORMULARIOS ================================================== */
.form-group { margin-bottom: var(--space-4); }
.form-label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: var(--space-1);
}
.form-label .required { color: var(--danger); margin-left: 2px; }

.form-control, .form-select {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    min-height: 36px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
    font-family: inherit;
    color: var(--text-primary);
    background: var(--bg-surface);
    transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
    outline: none;
}
.form-control:focus, .form-select:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-ring);
}
.form-control::placeholder { color: var(--text-faint); }
.form-control:disabled, .form-select:disabled { background: var(--bg-inset); color: var(--text-muted); cursor: not-allowed; }
textarea.form-control { min-height: 80px; resize: vertical; }

.form-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-3) center;
    padding-right: var(--space-8);
}

.form-check { display: flex; align-items: center; gap: var(--space-2); min-height: 28px; }
.form-check-input {
    width: 16px; height: 16px;
    flex-shrink: 0;
    border: 1px solid var(--border-strong);
    border-radius: 4px;
    cursor: pointer;
    accent-color: var(--primary);
}
.form-check-label { font-size: 0.875rem; color: var(--text-secondary); cursor: pointer; }
.form-text { font-size: 0.78rem; color: var(--text-muted); margin-top: var(--space-1); }

/* --- Color de marca de una empresa --------------------------------------
   La muestra NUNCA lleva texto encima: el valor hexadecimal va siempre al lado
   o en el `title`. Un cuadrado de color, por sí solo, no comunica nada a quien
   no distingue ese tono. */
.color-chip {
    width: 16px;
    height: 16px;
    border-radius: 4px;
    border: 1px solid var(--border-strong);
    flex-shrink: 0;
    display: inline-block;
}

/* El selector nativo de color deforma la muestra si hereda el relleno de
   .form-control, así que se dimensiona aparte. */
.color-swatch {
    width: 44px;
    height: 36px;
    flex-shrink: 0;
    padding: 2px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--bg-surface);
    cursor: pointer;
}

.input-group { display: flex; }
.input-group .form-control { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.input-group .btn { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

/* Complemento fijo de un campo: el «$» o el «%» que acompaña a un importe.
   Antes cada página lo montaba con estilos en línea distintos. */
.input-addon {
    flex: 0 0 auto;
    width: auto;
    min-width: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-inset);
    color: var(--text-muted);
    font-weight: 600;
}
/* El complemento va al final: redondea por la derecha y el campo, por la izquierda */
.input-group > .input-addon:last-child {
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    border-left: none;
}
/* …y al revés cuando abre el grupo */
.input-group > .input-addon:first-child {
    border-radius: var(--radius-sm) 0 0 var(--radius-sm);
    border-right: none;
}
.input-group > .input-addon:first-child + .form-control {
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* Divulgación progresiva: agrupa opciones avanzadas para no abrumar de entrada */
.disclosure { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.disclosure > summary {
    padding: var(--space-3) var(--space-4);
    background: var(--bg-subtle);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    list-style: none;
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before {
    content: '';
    width: 0; height: 0;
    border-left: 5px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    transition: transform var(--dur) var(--ease);
}
.disclosure[open] > summary::before { transform: rotate(90deg); }
.disclosure > summary:hover { background: var(--bg-hover); }
.disclosure-body { padding: var(--space-4); border-top: 1px solid var(--border-subtle); }

/* --- Credenciales recién generadas --------------------------------------
   Se muestran una sola vez: la contraseña se guarda con hash y no se puede
   volver a consultar. */
.cred-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-2) var(--space-4);
    margin: 0 0 var(--space-3);
    align-items: baseline;
}
.cred-list dt {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}
.cred-list dd { margin: 0; font-size: 0.875rem; color: var(--text-primary); }

/* user-select: all — un doble clic selecciona la contraseña entera. */
.cred-password {
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    user-select: all;
    background: var(--bg-inset);
    padding: 2px var(--space-2);
    border-radius: var(--radius-sm);
    display: inline-block;
}

@media (max-width: 520px) {
    .cred-list { grid-template-columns: 1fr; gap: var(--space-1); }
    .cred-list dd { margin-bottom: var(--space-3); }
}

/* ===== 14. TABLAS ======================================================= */
.table-wrapper {
    background: var(--bg-surface);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    overflow-x: auto;          /* la tabla scrollea dentro, la página nunca */
    box-shadow: var(--shadow-sm);
    -webkit-overflow-scrolling: touch;
}
.table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
}
.table thead tr { background: var(--bg-subtle); }
.table th {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    background: var(--bg-subtle);
    z-index: 1;
}
.table td {
    padding: var(--space-3) var(--space-4);
    height: var(--row-h);
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
    color: var(--text-secondary);
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover td { background: var(--bg-hover); }
.table-actions { display: flex; gap: var(--space-1); align-items: center; }
.table-num { text-align: right; font-variant-numeric: tabular-nums; }

/* Colapso a tarjetas por debajo de 768px. Cada <td> necesita data-label:
   <td data-label="Puntos">1,240</td>. Es lo que hace usable el panel en móvil
   sin mantener una segunda plantilla. */
@media (max-width: 768px) {
    .table-cards thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
    .table-cards, .table-cards tbody, .table-cards tr, .table-cards td { display: block; width: 100%; }
    .table-cards tr {
        border: 1px solid var(--border);
        border-radius: var(--radius);
        margin-bottom: var(--space-3);
        padding: var(--space-2);
        background: var(--bg-surface);
    }
    .table-cards td {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: var(--space-4);
        padding: var(--space-2);
        height: auto;
        border-bottom: 1px solid var(--border-subtle);
        text-align: right;
    }
    .table-cards td:last-child { border-bottom: none; }
    .table-cards td::before {
        content: attr(data-label);
        font-size: 0.6875rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        color: var(--text-muted);
        text-align: left;
        flex-shrink: 0;
    }
    .table-cards td:empty { display: none; }
    .table-cards .table-actions { justify-content: flex-end; }
}

/* Barra de acciones masivas — aparece al seleccionar filas */
.bulk-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
    background: var(--primary-soft);
    border: 1px solid var(--primary);
    border-radius: var(--radius);
    margin-bottom: var(--space-3);
    font-size: 0.8125rem;
    color: var(--primary-on-soft);
    font-weight: 600;
}

/* ===== 13b. CHIPS SELECCIONABLES ======================================== */
/* Valor que se activa o desactiva con un clic (líneas, marcas, SKU…).
   Es un <button> con aria-pressed, no un <span> con onclick: un span no recibe
   foco, no responde a Enter ni a la barra espaciadora, y el lector de pantalla
   no anuncia que se pueda pulsar ni si está activo. */
.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    min-height: 28px;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--bg-surface);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.chip:hover { border-color: var(--primary); color: var(--primary-text); }

/* El estado activo no depende solo del color de fondo: también cambia el borde
   y se marca con aria-pressed, que es lo que anuncia el lector de pantalla. */
.chip[aria-pressed="true"] {
    background: var(--primary-soft);
    border-color: var(--primary);
    color: var(--primary-on-soft);
    font-weight: 600;
}
.chip[aria-pressed="true"]::before {
    content: '';
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--primary);
    flex-shrink: 0;
}

.chip-group { display: flex; flex-wrap: wrap; gap: var(--space-2); }

@media (pointer: coarse) { .chip { min-height: 36px; } }

/* ===== 14b. BARRA DE PROGRESO =========================================== */
/* Para tasas y proporciones (apertura de notificaciones, avance de un plan).
   Siempre acompañada del número: la barra sola obliga a estimar a ojo, y a
   cierto tamaño la diferencia entre 18 % y 25 % no se aprecia. */
.progress {
    flex: 1;
    height: 6px;
    min-width: 48px;
    background: var(--neutral-soft);
    border-radius: 999px;
    overflow: hidden;
}
.progress-bar {
    height: 100%;
    border-radius: 999px;
    background: var(--primary);
    transition: width var(--dur-slow) var(--ease);
}
.progress-bar.good { background: var(--success); }
.progress-bar.mid  { background: var(--warning); }
.progress-bar.low  { background: var(--danger); }

.progress-row { display: flex; align-items: center; gap: var(--space-2); }
.progress-value { font-size: 0.75rem; color: var(--text-muted); font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; }

/* ===== 15. ALERTAS ====================================================== */
.alert {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    font-size: 0.875rem;
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    border: 1px solid transparent;
}
.alert svg { flex-shrink: 0; margin-top: 1px; }
.alert-success { background: var(--success-soft); color: var(--success-on-soft); border-color: var(--success); }
.alert-danger  { background: var(--danger-soft);  color: var(--danger-on-soft);  border-color: var(--danger); }
.alert-warning { background: var(--warning-soft); color: var(--warning-on-soft); border-color: var(--warning); }
.alert-info    { background: var(--info-soft);    color: var(--info-on-soft);    border-color: var(--info); }

/* ===== 16. MODALES ====================================================== */
.modal-overlay {
    position: fixed; inset: 0;
    background: var(--overlay);
    z-index: var(--z-modal);
    display: flex; align-items: center; justify-content: center;
    padding: var(--space-4);
    backdrop-filter: blur(2px);
    animation: fadeIn var(--dur) var(--ease);
}
.modal-box {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    width: 100%;
    max-width: 520px;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: var(--shadow-lg);
    animation: slideUp var(--dur-slow) var(--ease);
}
.modal-box.wide { max-width: 760px; }
.modal-header {
    padding: var(--space-5) var(--space-6);
    border-bottom: 1px solid var(--border-subtle);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    font-weight: 700;
    font-size: 1rem;
    color: var(--text-primary);
}
.modal-body   { padding: var(--space-6); }
.modal-footer {
    padding: var(--space-4) var(--space-6);
    border-top: 1px solid var(--border-subtle);
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
    background: var(--bg-subtle);
    flex-wrap: wrap;
}
.modal-close {
    background: none; border: none; cursor: pointer;
    color: var(--text-faint);
    width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.modal-close:hover { background: var(--bg-hover); color: var(--text-primary); }

@media (max-width: 640px) {
    .modal-overlay { align-items: flex-end; padding: 0; }
    .modal-box { max-width: 100%; border-radius: var(--radius-xl) var(--radius-xl) 0 0; max-height: 92dvh; }
    .modal-footer { flex-direction: column-reverse; }
    .modal-footer .btn { width: 100%; }
}

/* ===== 17. PESTAÑAS ===================================================== */
.nav-tabs {
    display: flex;
    gap: var(--space-1);
    border-bottom: 1px solid var(--border);
    margin-bottom: var(--space-6);
    overflow-x: auto;
    overflow-y: hidden; /* el margin-bottom: -1px de .nav-tab provocaba una barra vertical */
}
.nav-tab {
    padding: var(--space-3) var(--space-4);
    font-size: 0.875rem;
    font-weight: 600;
    font-family: inherit;
    color: var(--text-muted);
    cursor: pointer;
    border: none;
    background: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    white-space: nowrap;
}
.nav-tab:hover  { color: var(--text-primary); text-decoration: none; }
.nav-tab.active { color: var(--primary-text); border-bottom-color: var(--primary); }

/* ===== 18. ACCIONES RÁPIDAS ============================================= */
.quick-action {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-5) var(--space-4);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    text-decoration: none;
    color: var(--text-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
    text-align: center;
}
.quick-action:hover {
    border-color: var(--primary);
    color: var(--primary-text);
    box-shadow: var(--shadow);
    transform: translateY(-2px);
    text-decoration: none;
}
.quick-action-icon {
    width: 40px; height: 40px;
    border-radius: var(--radius);
    display: flex; align-items: center; justify-content: center;
    background: var(--primary-soft);
    color: var(--primary-on-soft);
}

/* ===== 19. CARGA Y ESTADOS VACÍOS ======================================= */
.spinner {
    width: 32px; height: 32px;
    border: 3px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}
.spinner-sm { width: 16px; height: 16px; border-width: 2px; }
.loading-center {
    display: flex; align-items: center; justify-content: center;
    padding: var(--space-8); color: var(--text-muted);
    flex-direction: column; gap: var(--space-4);
    font-size: 0.875rem;
}

/* Skeleton: reserva el espacio final para que no haya salto de layout (CLS) */
.skeleton {
    background: linear-gradient(90deg, var(--bg-inset) 25%, var(--bg-hover) 50%, var(--bg-inset) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.4s infinite linear;
    border-radius: var(--radius-sm);
}
.skeleton-text { height: 12px; margin-bottom: var(--space-2); }
.skeleton-row  { height: var(--row-h); margin-bottom: var(--space-1); border-radius: var(--radius-sm); }

.empty-state {
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    padding: var(--space-8) var(--space-4);
    text-align: center;
    color: var(--text-muted);
}
.empty-state-icon {
    width: 48px; height: 48px;
    border-radius: 50%;
    background: var(--neutral-soft);
    color: var(--text-muted);
    display: flex; align-items: center; justify-content: center;
    margin-bottom: var(--space-4);
}
.empty-state-title { font-weight: 600; color: var(--text-primary); font-size: 0.9375rem; margin-bottom: var(--space-1); }
.empty-state-text  { font-size: 0.875rem; max-width: 44ch; margin-bottom: var(--space-4); }

/* ===== 20. TOAST DE ERROR DE BLAZOR ===================================== */
/* Sustituye el `background: lightyellow` de la plantilla por defecto. */
#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: var(--space-5);
    left: 50%;
    transform: translateX(-50%);
    z-index: var(--z-toast);
    max-width: min(560px, calc(100vw - var(--space-8)));
    padding: var(--space-4) var(--space-5);
    background: var(--bg-elevated);
    border: 1px solid var(--danger);
    border-left: 4px solid var(--danger);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    color: var(--text-primary);
    font-size: 0.875rem;
}
#blazor-error-ui .error-actions { display: flex; gap: var(--space-4); margin-top: var(--space-2); }
#blazor-error-ui a { color: var(--primary); font-weight: 600; cursor: pointer; }

/* ===== 21. UTILIDADES ===================================================
   Bootstrap ya no está cargado (retirado al terminar la migración de las 18
   páginas), así que estas clases ya no necesitan !important para ganarle.
   ===================================================================== */

.d-flex      { display: flex; }
.flex-wrap   { flex-wrap: wrap; }
.flex-column { flex-direction: column; }
.mt-auto     { margin-top: auto; }
.w-100       { width: 100%; }
.fw-bold     { font-weight: 700; }

.gap-1 { gap: var(--space-1); }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }
.gap-5 { gap: var(--space-5); }
.gap-6 { gap: var(--space-6); }

.mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-5 { margin-bottom: var(--space-5); }
.mb-6 { margin-bottom: var(--space-6); }

.text-muted   { color: var(--text-muted); }
.text-success { color: var(--success); }
.text-danger  { color: var(--danger); }
.text-warning { color: var(--warning); }
.text-primary { color: var(--primary-text); }

.align-center    { align-items: center; }
.align-start     { align-items: flex-start; }
.justify-between { justify-content: space-between; }
.justify-end     { justify-content: flex-end; }
.flex-1          { flex: 1; min-width: 0; }

.text-sm  { font-size: 0.8125rem; }
.text-xs  { font-size: 0.75rem; }
.fw-600   { font-weight: 600; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
/* Grids de KPI/tarjetas: se reajustan sin media queries y sin dejar huérfanas */
.grid-auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--space-4); }

/* Solo para lectores de pantalla */
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ===== 22. VALIDACIÓN =================================================== */
.valid.modified:not([type=checkbox]) { border-color: var(--success) !important; }
.invalid { border-color: var(--danger) !important; }
.validation-message {
    color: var(--danger);
    font-size: 0.78rem;
    margin-top: var(--space-1);
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

/* ===== 23. ANIMACIONES ================================================== */
@keyframes spin    { to { transform: rotate(360deg); } }
@keyframes fadeIn  { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
@keyframes dropIn  { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* ===== 24. GRIDS RESPONSIVOS ============================================ */
@media (max-width: 1100px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px) {
    .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
    h1 { font-size: 1.25rem; }
    .page-title { font-size: 1.125rem; }
}

/* ===== 25. MOVIMIENTO REDUCIDO ========================================== */
/* Última regla del archivo: gana sobre todo lo anterior sin necesitar !important
   en cada transición. Se conserva una duración mínima para que los callbacks
   de `transitionend` sigan disparándose. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ===== 26. IMPRESIÓN ==================================================== */
@media print {
    .app-sidebar, .app-bar, .page-header-actions, .table-actions, .btn { display: none !important; }
    .app-content { padding: 0; }
    .card, .table-wrapper { box-shadow: none; border-color: #ccc; }
}

/* ==========================================================================
   Acceso (login, alta del autenticador, error): fuera del armazón del panel.
   Copiado de Login.razor.css de fidelización; aquí global porque lo usan varias páginas.
   ========================================================================== */
.login-page {
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-6);
    background: var(--bg-page);
    background-image: radial-gradient(ellipse 80% 60% at 50% -10%, var(--primary-soft), transparent 70%);
}

.login-card {
    width: 100%;
    max-width: 420px;
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    padding: var(--space-8);
}

.login-brand { text-align: center; margin-bottom: var(--space-7); }

.login-logo {
    width: 52px;
    height: 52px;
    margin: 0 auto var(--space-4);
    border-radius: var(--radius-lg);
    background: var(--primary-fill);
    color: var(--text-on-accent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.login-brand h1 { font-size: 1.375rem; margin: 0; letter-spacing: -0.02em; }
.login-brand p { margin: var(--space-1) 0 0; font-size: 0.875rem; color: var(--text-muted); }

/* QR del autenticador: siempre sobre blanco (los lectores de QR no leen bien el invertido del modo oscuro). */
.qr-box {
    width: 200px;
    margin: 0 auto var(--space-4);
    padding: var(--space-3);
    background: #fff;
    border-radius: var(--radius-lg);
}
.qr-box svg { display: block; width: 100%; height: auto; }

.secreto-totp {
    display: block;
    text-align: center;
    font-size: 0.95rem;
    letter-spacing: 0.08em;
    word-break: break-all;
    user-select: all;
}

.codigo-input { font-size: 1.25rem; letter-spacing: 0.3em; text-align: center; font-variant-numeric: tabular-nums; }

@media (max-width: 480px) {
    .login-page { padding: var(--space-4); align-items: flex-start; padding-top: var(--space-8); }
    .login-card { padding: var(--space-6); box-shadow: var(--shadow); }
}
