/* Fonts loaded via <link> tags in HTML - no @import needed */
@import url('./modules/pdrs-navbar.css');

/* =========================================================================
   SKELETON SHIMMER - sistema de precarga visual reutilizable
   =========================================================================
   Uso: agregar `data-loading="true"` al <body>. Cuando el módulo JS
   termina de renderizar, llama `document.body.removeAttribute('data-loading')`.
   Los bloques `.page-skeleton` se muestran solo durante la carga; el
   contenido real (`.page-content`) se oculta hasta que el loading termina.
   ========================================================================= */
body[data-loading] .page-skeleton { display: flex; flex-direction: column; gap: 1.5rem; }
body:not([data-loading]) .page-skeleton { display: none; }
body[data-loading] .page-content { display: none; }

.sk {
    background: #e5e7eb;
    border-radius: 8px;
    position: relative;
    overflow: hidden;
}
.dark .sk, [data-theme='dark'] .sk {
    background: #2a2a2a;
}
.sk::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.08) 50%, transparent 100%);
    animation: sk-shimmer 1.5s ease-in-out infinite;
}
.dark .sk::after, [data-theme='dark'] .sk::after {
    background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%);
}
@keyframes sk-shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }

.sk-text { height: 14px; margin-bottom: 8px; }
.sk-text-lg { height: 20px; margin-bottom: 10px; }
.sk-text-xl { height: 32px; margin-bottom: 12px; }
.sk-card {
    border-radius: 12px;
    border: 1px solid #e5e7eb;
    padding: 1rem;
}
.dark .sk-card, [data-theme='dark'] .sk-card {
    border-color: #333;
}
.sk-row {
    height: 48px;
    margin-bottom: 4px;
    border-radius: 0;
}
.sk-circle {
    border-radius: 50%;
}
.sk-btn { height: 40px; width: 140px; border-radius: 8px; }
.sk-filter { height: 38px; border-radius: 8px; }
.sk-kpi { height: 100px; border-radius: 12px; }
.sk-chart { height: 250px; border-radius: 12px; }

/* Skeleton específico de attendance: refleja el layout real (scanner card +
   6 KPIs + tabs + filtro + tabla). Cada bloque adopta el mismo shape que
   su contraparte en `.page-content` para que la transición no dispare
   layout shift. */
body[data-loading] .page-skeleton.sk-attendance-layout {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}
.sk-attendance-scanner {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-radius: 16px;
    border: 1px solid var(--color-border, #e5e7eb);
    background: var(--color-surface, #ffffff);
    flex-wrap: wrap;
}
.dark .sk-attendance-scanner, [data-theme='dark'] .sk-attendance-scanner {
    background: #1a1a1a;
    border-color: #2a2a2a;
}
.sk-attendance-kpis {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
}
@media (min-width: 1024px) {
    .sk-attendance-kpis { grid-template-columns: repeat(6, 1fr); }
}

/* Skeleton específico de settings: refleja el layout real (sidebar + cards) */
body[data-loading] .page-skeleton.sk-settings-layout {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 1.5rem;
    align-items: start;
}
.sk-settings-sidebar {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border-radius: 16px;
    background: var(--color-surface, #ffffff);
    border: 1px solid var(--color-border, #e5e5e5);
}
.dark .sk-settings-sidebar, [data-theme='dark'] .sk-settings-sidebar {
    background: #1a1a1a;
    border-color: #2a2a2a;
}
.sk-settings-nav { height: 36px; border-radius: 8px; }
.sk-settings-content {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}
.sk-settings-card { height: 260px; border-radius: 16px; }
@media (max-width: 768px) {
    body[data-loading] .page-skeleton.sk-settings-layout {
        grid-template-columns: 1fr;
    }
    .sk-settings-sidebar { flex-direction: row; overflow-x: auto; }
    .sk-settings-nav { min-width: 100px; flex-shrink: 0; }
}

/* =========================================
   .consent-check - checkbox de consentimiento con texto multi-línea al lado.
   Usado por: DPA en superadmin (Nuevo Club), términos en login y saas-login.
   Centralizado acá para no repetir estilos inline y mantener un solo lugar
   de verdad para el patrón "acepto X".
   ========================================= */
.consent-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 0.85rem;
    line-height: 1.5;
    cursor: pointer;
}
/* label.consent-check para elevar specificity (0,2,2) por sobre
   `.sa-modal input[type="checkbox"]` (0,2,1) que vive en <style> inline
   de superadmin.html. Sin esto, el margen top de 3px se perdía. */
label.consent-check > input[type="checkbox"] {
    margin: 3px 0 0 0;
    padding: 0;
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    cursor: pointer;
    /* --consent-accent puede setearse por página (saas-login usa --sa-accent).
       Fallback a --color-primary del tema activo. */
    accent-color: var(--consent-accent, var(--color-primary));
}
label.consent-check > span { flex: 1; }


/* Hide Material Symbols ligature text until the icon font is loaded.
   theme.js adds `html.fonts-ready` via document.fonts.ready (3s fallback). */
html:not(.fonts-ready) .material-symbols-outlined {
    visibility: hidden;
}

/* =========================================
   PURE CSS SCROLL LOCK
   Bloquea el scroll del body automáticamente si hay algún modal u overlay abierto.
   Esto reemplaza los "parches" en JavaScript (theme.js lockScroll, etc)
   ========================================= */
body:has(
    .modal-overlay.open, 
    .confirm-overlay.show, 
    .inv-modal-overlay.show, 
    .crew-modal-overlay.show, 
    .inv-modal-overlay.active, 
    .report-modal-overlay.show, 
    .backup-modal-overlay.show, 
    .settings-modal-overlay.show, 
    .camera-modal-overlay.show, 
    .overlay.show, 
    .modal.show:not(.inline-modal)
) {
    overflow: hidden !important;
}

/* =========================================
   LAYER: TOKENS
   Design tokens (CSS custom properties)
   ========================================= */
:root {
    /* Tailwind Dynamic Variables */
    --tw-color-primary: 221 0 0;
    --tw-color-primary-text: 255 255 255;

    /* Brand palette - LIGHT mode uses red as the accent color (in DARK mode
       these tokens flip to the system yellow via .dark overrides below).
       Use ONLY for branding: navbar active state, primary CTA buttons, focus
       rings, links. For danger/error signals use --badge-danger-* instead -
       those don't flip with theme and stay red-as-signal in both modes. */
    --color-brand: #dd0000;
    --color-primary: #dd0000;
    --color-accent-red: #dd0000;

    --color-sidebar: #0a0a0a;
    --color-bg: #fafafa;
    --color-surface: #ffffff;
    --color-surface-hover: #f5f5f5;
    --color-surface-recessed: #fafafa;
    --color-text-main: #111111;
    --color-text-muted: #525252;
    --color-border: #e5e5e5;

    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);

    --shadow-glow-red: 0 0 15px rgb(var(--tw-color-primary) / 0.3);

    --font-main: 'Outfit', sans-serif;
    --font-heading: 'Space Grotesk', sans-serif;

    --radius-md: 10px;
    --radius-lg: 16px;

    /* Semantic State Colors solid */
    --color-state-info: #1d4ed8;
    --color-state-info-bg: #dbeafe;
    --color-state-warning-bg: #fee2e2;
    --color-state-warning: var(--color-brand);
    --color-state-warning-border: #fca5a5;
    --color-badge-members: var(--color-brand);
    --color-badge-members-bg: #fee2e2;
    --color-sifen-query: #1d4ed8;
    --color-confirm-icon: #10b981;

    /* Status tokens - semantic single-color palette usada por cards, KPIs,
       indicadores y cualquier acento de estado. Consumido por dashboard.css,
       select-club.css y cards del sistema. Los cuatro estados canónicos. */
    --color-status-success: #10b981;
    --color-status-warning: var(--color-primary);
    --color-status-error: var(--color-brand);
    --color-status-info: var(--color-state-info);

    /* ── BADGE DESIGN TOKENS ── 4-color semantic system.
       Every badge/chip/pill/tooltip/banner/chart in the system resolves through
       these. Non-signal categories (info, primary, accent, muted) collapse to
       neutral by design - differentiation happens via icons + labels, not hue. */
    --badge-success-bg: #059669; --badge-success-fg: #ffffff;  /* emerald-600 - dinero + / OK / al día */
    --badge-danger-bg:  #b91c1c; --badge-danger-fg:  #ffffff;  /* red-700    - dinero - / error / deuda */
    --badge-warning-bg: #facc15; --badge-warning-fg: #111827;  /* brand yellow - atención / VIP / master */
    --badge-neutral-bg: #334155; --badge-neutral-fg: #ffffff;  /* slate-700  - todo lo demás */

    /* Aliases collapsed to neutral - kept for API stability across the codebase.
       If a specific accent color is needed later, only the alias line changes. */
    --badge-info-bg:    #2563eb; --badge-info-fg:    #ffffff;  /* blue-600   - zona agua / info contextual */
    --badge-primary-bg: var(--badge-neutral-bg); --badge-primary-fg: var(--badge-neutral-fg);
    --badge-accent-bg:  var(--badge-neutral-bg); --badge-accent-fg:  var(--badge-neutral-fg);
    --badge-muted-bg:   var(--badge-neutral-bg); --badge-muted-fg:   var(--badge-neutral-fg);

    /* Actividad deportiva: dos hues fijos usados en KPIs, barras, headers y dots
       del análisis de tiempo (salón vs agua). Un solo lugar donde tocar el color. */
    --color-salon: #10b981; /* emerald-500 */
    --color-water: #3b82f6; /* blue-500   */

    /* Semantic single-color tokens (icons, dots, standalone text) reference badge palette. */
    --status-paid: var(--badge-success-bg);
    --status-paid-bg: var(--badge-success-bg);
    --status-paid-border: var(--badge-success-bg);
    --status-paid-text: var(--badge-success-bg);
    --status-debt: var(--badge-danger-bg);
    --status-debt-bg: var(--badge-danger-bg);
    --status-debt-border: var(--badge-danger-bg);
    --status-debt-text: var(--badge-danger-bg);
    --status-plan: var(--badge-neutral-bg);
    --status-attendance: var(--badge-neutral-bg);
    --status-category: var(--badge-warning-bg);
}

/* =========================================
   MODO OSCURO - Paleta basada en negros y grises puros
   Sin azules ni tonos fríos
   ========================================= */
.dark,
[data-theme='dark'] {
    --tw-color-primary: 250 204 21;
    --tw-color-primary-text: 10 10 10;

    /* Tailwind theme variable overrides - swap red → gold */
    --color-primary: #facc15;
    --color-accent-red: #facc15;

    --color-bg: #0a0a0a;
    --color-surface: #141414;
    --color-surface-hover: #1c1c1c;
    --color-surface-recessed: #1c1c1c;
    --color-text-main: #f5f5f5;
    --color-text-muted: #a3a3a3;
    --color-border: #262626;

    --color-brand: #facc15;
    --color-btn-text: #0a0a0a;
    --shadow-glow-red: 0 0 15px rgb(var(--tw-color-primary) / 0.3);
    --shadow-glow-hover: rgb(var(--tw-color-primary) / 0.4);

    /* Semantic State Colors - dark: gold accent for info/members, green for confirm */
    --color-state-info: var(--color-primary);
    --color-state-info-bg: rgba(250, 204, 21, 0.1);
    --color-state-warning-bg: #713f12;
    --color-state-warning: var(--color-primary);
    --color-state-warning-border: #a16207;
    --color-badge-members: var(--color-primary);
    --color-badge-members-bg: rgba(250, 204, 21, 0.1);
    --color-sifen-query: var(--color-primary);
    --color-confirm-icon: #10b981;

    /* Status tokens - dark: warning/error/info colapsan al primary (gold) igual
       que el resto del sistema; success sigue verde porque es señal semántica
       (dinero +, aprobado) que no debe leerse como el color de marca. */
    --color-status-success: #10b981;
    --color-status-warning: var(--color-primary);
    --color-status-error: var(--color-primary);
    --color-status-info: var(--color-primary);

    /* Semantic tokens inherit from :root (which references --badge-* single source). */

    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.5);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
}
/* =========================================
   GLOBAL COMPONENT + UTILITY STYLES
   Unlayered so they override Tailwind's base reset.
   Tailwind utilities (in @layer tw) still win over these
   by class order when intentionally used together.
   ========================================= */

/* Prevent transition animations on page load (FOUC) */
.preload *,
.preload {
    transition: none;
}


body {
    background-color: var(--color-bg);
    color: var(--color-text-main);
    font-family: var(--font-main);
    transition:
        background-color 0.3s ease,
        color 0.3s ease;
}

:is(h1, h2, h3, h4, h5, h6),
.logo-container h1,
#page-title {
    font-family: var(--font-heading);
    letter-spacing: -0.02em;
}

/* Sidebar & Topbar */
.sidebar {
    background-color: var(--color-sidebar);
    border-right: 1px solid var(--color-border);
}
.sidebar .main-nav li a:hover,
.sidebar .main-nav li a.active {
    background-color: #1f1f1f;
    border-left-color: var(--color-brand);
}
.top-bar {
    background-color: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text-main);
}

/* Cards & Contenedores */
:is(.card, .dashboard-card, .data-card, .glass-card, .detail-card, .filter-section) {
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    color: var(--color-text-main);
    transition:
        transform 0.2s ease,
        box-shadow 0.2s ease;
}
:is(.card, .dashboard-card):hover {
    box-shadow: var(--shadow-md);
}

/* Modales */
.modal-content {
    background-color: var(--color-surface);
    color: var(--color-text-main);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    font-family: var(--font-main);
}
.modal-header h2 {
    color: var(--color-text-main);
}
.close-modal {
    color: var(--color-text-muted);
}
.close-modal:hover {
    color: var(--color-brand);
}

/* ==========================================================================
   BASE LAYER: element-level defaults
   -------------------------------------------------------------------------
   Envueltos en @layer base para que utilities Tailwind (pl-*, text-*, etc.)
   puedan ganarles por cascade v4. Sin este layer, la regla element-selector
   gana siempre a la utility clase (aunque tenga más especificidad), porque
   un-layered > cualquier @layer. Ver [[project-pdrs-tailwind-layer-gotcha]].
   ========================================================================= */
@layer base {
    /* Inputs & Formularios */
    :is(input, select, textarea),
    .form-group :is(input, select) {
        background-color: var(--color-bg);
        color: var(--color-text-main);
        border: 1px solid var(--color-border);
        border-radius: var(--radius-md);
        font-family: var(--font-main);
        padding: 10px 14px;
        transition: all 0.2s ease;
    }

    /* Native select: single clean arrow, no double UA-arrow */
    select {
        appearance: none;
        -webkit-appearance: none;
        -moz-appearance: none;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%239ca3af'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
        background-position: right 0.75rem center;
        background-repeat: no-repeat;
        background-size: 1rem 1rem;
        padding-right: 2.5rem;
    }

    /* Dark mode native select arrow color adjustment */
    .dark select {
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23d4d4d4'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
    }

    label {
        color: var(--color-text-main);
        font-weight: 500;
    }
}

/* FOUC prevention se queda un-layered - es contract con selects JS-upgraded */
select:not([data-custom-select]):not(.sr-only) {
    opacity: 0;
    pointer-events: none;
}

/* Force screen-reader-only (sr-only) selects (used as hidden value stores for custom buttons)
   to be completely invisible and have 0px layout footprint, resolving overlapping double-arrows */
select.sr-only,
.sr-only select,
input.sr-only,
textarea.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
    background: none;
    background-image: none;
    opacity: 0;
    pointer-events: none;
}

/* General utility bulletproofing for all sr-only elements */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}
/* Los workarounds .relative input.pl-10 / .pl-11 se eliminaron: con el input
   base ahora en @layer base, la utility Tailwind pl-10/pl-11 gana sola.
   El :focus también se movió al @layer base de arriba. */
@layer base {
    :is(input, select, textarea):focus {
        outline: none;
        border-color: var(--color-brand);
        box-shadow: 0 0 0 3px rgb(var(--tw-color-primary) / 0.15);
    }
}

/* =========================================================================
   BOTONES SISTEMA DE COMPONENTES
   -------------------------------------------------------------------------
   Reemplaza la "sopa de utilidades" (bg-primary + hover:opacity-90 +
   dark:bg-surface-dark + hover:bg-gray-50 + dark:hover:bg-gray-800 + ...)
   por clases semánticas que encapsulan estado base, hover, focus,
   disabled y contraste con la superficie del contenedor.

   Uso en HTML: <button class="btn btn-primary flex-1">Guardar</button>

   Variantes:
     · .btn geometría + tipografía + transición base
     · .btn-primary fondo sólido de marca (rojo/oro)
     · .btn-secondary outline: sin fondo, borde visible, hover con fill
     · .btn-emerald verde (Exportar/Confirmar), definido más abajo
     · .btn-ghost transparente sin borde, definido más abajo
   ========================================================================= */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.625rem 1.25rem;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-family: var(--font-main);
    font-size: 0.875rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition:
        background-color 0.15s ease,
        border-color 0.15s ease,
        color 0.15s ease,
        filter 0.15s ease,
        box-shadow 0.15s ease,
        transform 0.08s ease;
}
.btn:disabled,
.btn[aria-disabled='true'] {
    opacity: 0.5;
    cursor: not-allowed;
    filter: none;
    pointer-events: none;
}
.btn:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 2px;
}

/* Primary fondo sólido de marca. Hover con filter (nunca opacity ni
 * color-mix con transparent) para evitar bleed-through del backdrop.
 *
 * Decisión de diseño: hover = BRIGHTEN (nunca darken). El botón nunca
 * se oscurece al pasarle el cursor. El "press feedback" del :active sí
 * usa brightness<1 porque el click sí debe leerse como "hundido".
 * Válido para light y dark: `filter: brightness(1.08)` sube luminancia
 * de forma uniforme sobre cualquier color base. */
:is(.btn-primary, .btn-action) {
    background-color: var(--color-primary);
    color: var(--color-btn-text, #ffffff);
    border-color: transparent;
    /* Box-shadow compuesto: highlight blanco interno arriba + ring
     * blanco exterior + drop-shadow. Los blancos son SIEMPRE visibles
     * (no dependen del color base) el botón se lee brillante y
     * elevado ante cualquier render, compresión o gamut. */
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.45),
        0 0 0 1px rgba(255, 255, 255, 0.18),
        0 4px 12px -2px rgba(0, 0, 0, 0.5),
        0 2px 4px -1px rgba(0, 0, 0, 0.35);
}
.dark :is(.btn-primary, .btn-action),
[data-theme='dark'] :is(.btn-primary, .btn-action) {
    color: #0a0a0a; /* accent-black para contraste sobre el oro del tema dark */
}
:is(.btn-primary, .btn-action):hover:not(:disabled):not([aria-disabled='true']) {
    /* Feedback SIN tocar `background-color` ni `filter`. Sólo agrega un
     * ring blanco alrededor y sube la elevación del shadow el color
     * del fondo del botón queda idéntico entre base y hover. */
    box-shadow:
        0 0 0 2px rgba(255, 255, 255, 0.35),
        0 8px 20px -2px rgba(0, 0, 0, 0.5),
        0 4px 8px -2px rgba(0, 0, 0, 0.35);
}
:is(.btn-primary, .btn-action):active:not(:disabled):not([aria-disabled='true']) {
    /* Press feedback via encoger, no via brightness nunca oscurece. */
    transform: scale(0.98);
}

/* Secondary superficie sólida propia (nunca `transparent`).
 *
 * ¿Por qué NO `transparent`? En cualquier modal el shell es casi negro
 * (`dark:bg-surface-dark` = #141414). Un botón `background: transparent`
 * hereda esa negrura y visualmente se lee "botón negro" aunque el
 * componente esté correcto. Le damos una superficie propia con Δ
 * suficiente para despegarse del shell tanto en base como en hover.
 *
 * Colores plenos (no rgba/color-mix/alpha) para eliminar cualquier
 * dependencia del fondo del contenedor. */
:is(.btn-secondary, .btn-outline) {
    background-color: #f5f5f5;
    color: var(--color-text-main);
    border: 1px solid var(--color-border);
}
:is(.btn-secondary, .btn-outline):hover:not(:disabled):not([aria-disabled='true']) {
    /* Mismo efecto que .btn-primary y .btn-emerald: ring blanco alrededor
     * + shadow lifted. `background-color` NO se toca el fondo del
     * botón queda idéntico entre base y hover. */
    box-shadow:
        0 0 0 2px rgba(255, 255, 255, 0.35),
        0 8px 20px -2px rgba(0, 0, 0, 0.5),
        0 4px 8px -2px rgba(0, 0, 0, 0.35);
}
.dark :is(.btn-secondary, .btn-outline),
[data-theme='dark'] :is(.btn-secondary, .btn-outline) {
    /* Base #2f2f2f: Δ ≈ 27 sobre el shell #141414 el botón se lee
     * claramente como GRIS, no como "otro negro del modal". */
    background-color: #2f2f2f;
    border-color: #4a4a4a;
    color: #f5f5f5;
}
.dark :is(.btn-secondary, .btn-outline):hover:not(:disabled):not([aria-disabled='true']),
[data-theme='dark'] :is(.btn-secondary, .btn-outline):hover:not(:disabled):not([aria-disabled='true']) {
    /* Feedback en dark mode: sólo borde reforzado. El ring y el shadow
     * lift vienen del selector base de arriba (heredado en dark).
     * `background-color` NO cambia se mantiene la superficie #2f2f2f
     * de la base para que el fondo no se oscurezca ni se aclare. */
    border-color: #6a6a6a;
}
:is(.btn-secondary, .btn-outline):active:not(:disabled):not([aria-disabled='true']) {
    /* Press feedback via encoger, no via brightness nunca oscurece. */
    transform: scale(0.98);
}

/* .btn-submit alias legacy: aplica geometría base del sistema. */
.btn-submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.625rem 1.25rem;
    border-radius: var(--radius-md);
    font-family: var(--font-main);
    font-weight: 700;
    cursor: pointer;
}

/* Modificadores de tamaño se combinan con cualquier variante:
 * <button class="btn btn-primary btn-sm">Agregar</button> */
.btn-sm {
    padding: 0.375rem 0.75rem;
    font-size: 0.8125rem;
    gap: 0.375rem;
}
.btn-lg {
    padding: 0.75rem 1.5rem;
    font-size: 1rem;
    gap: 0.625rem;
}
/* .btn-tight padding mínimo para triggers compactos (avatar de
 * navbar, etc.) donde el contenido ya define su propia altura. */
.btn-tight {
    padding: 0.25rem;
}

/* Tamaño de iconos de Material Symbols dentro de otros componentes * reemplaza los `style="font-size:XXpx"` inline que quedaban en JS.
 * Escala coherente con `.btn-sm`, `.btn`, `.btn-lg`. */
.icon-xs { font-size: 14px; }
.icon-2xs { font-size: 10px; }
.icon-sm { font-size: 16px; }
.icon-md { font-size: 18px; }
.icon-lg { font-size: 20px; }
.icon-xl { font-size: 24px; }

/* Botón flotante circular (FAB) del speed-dial y "back to top". Antes
 * usaba `style="width:3.5rem;height:3.5rem"` inline en HTML. */
.fab {
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 9999px;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-lg);
    transition: box-shadow 0.2s ease, filter 0.15s ease, transform 0.15s ease;
}
.fab:hover:not(:disabled):not([aria-disabled='true']) {
    filter: brightness(1.1);
    box-shadow: 0 8px 20px -2px rgba(0, 0, 0, 0.4), 0 0 0 2px rgba(255, 255, 255, 0.2);
    transform: scale(1.05);
}
.fab:active:not(:disabled):not([aria-disabled='true']) { transform: scale(0.98); }

/* Alineación del contenido (por defecto centrado). `btn-align-start`
 * lo pega a la izquierda útil en pickers/listas donde el texto guía
 * la lectura (ej: "JSON (backup)", "CSV"). */
.btn-align-start {
    justify-content: flex-start;
    text-align: left;
}

/* .btn-icon botón cuadrado sin texto, para controles de icono
 * (limpiar filtro, editar, borrar, etc.). Se combina con variantes de
 * color: `.btn .btn-secondary .btn-icon`, `.btn .btn-ghost .btn-icon`.
 * Sizes: default 2.5rem, `.btn-icon.btn-sm` 2rem, `.btn-icon.btn-lg` 3rem. */
.btn-icon {
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    gap: 0;
    flex-shrink: 0;
}
.btn-icon.btn-sm {
    width: 2rem;
    height: 2rem;
}
.btn-icon.btn-lg {
    width: 3rem;
    height: 3rem;
}

/* .btn-danger variante destructiva.
 * btn-icon (delete): fondo rojo permanente.
 * Sin btn-icon (clear filter): reposo gris, hover rojo. */
.btn-danger.btn-icon {
    background-color: #b91c1c;
    border-color: #b91c1c;
    color: #ffffff;
}
.btn-danger.btn-icon:hover:not(:disabled):not([aria-disabled='true']) {
    background-color: #991b1b;
    border-color: #991b1b;
}
.btn-danger:not(.btn-icon):hover:not(:disabled):not([aria-disabled='true']) {
    color: #ffffff;
    border-color: var(--color-brand);
    background-color: var(--color-brand);
}
.dark .btn-danger:not(.btn-icon):hover:not(:disabled):not([aria-disabled='true']),
[data-theme='dark'] .btn-danger:not(.btn-icon):hover:not(:disabled):not([aria-disabled='true']) {
    color: #ffffff;
    border-color: #b91c1c;
    background-color: #b91c1c;
}

/* Tablas de datos */
:is(table, .data-table) {
    color: var(--color-text-main);
}
:is(th, .data-table th) {
    color: var(--color-text-muted);
    border-bottom: 2px solid var(--color-border);
    font-family: var(--font-heading);
    letter-spacing: 0.05em;
}
:is(td, .data-table td) {
    border-bottom: 1px solid var(--color-border);
}
tr:hover td {
    background-color: var(--color-surface-hover);
}

/* Theme Toggle Button */
.theme-toggle {
    background: none;
    border: 1px solid var(--color-border);
    border-radius: 9999px;
    padding: 8px;
    cursor: pointer;
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
    margin-left: 15px;
}
.theme-toggle:hover {
    background-color: var(--color-surface-hover);
    color: var(--color-brand);
}

/* Scrollbars */
::-webkit-scrollbar-track {
    background: var(--color-bg);
}
::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border: 2px solid var(--color-bg);
}
::-webkit-scrollbar-thumb:hover {
    background: var(--color-brand);
}

/* Dark mode primary text */
.dark .bg-primary {
    color: rgb(var(--tw-color-primary-text));
}

/* =========================================
   GLOBAL UTILITIES
   Migrated from style.css (which no page loaded)
   ========================================= */

/* Accessibility */
:focus-visible {
    outline: 2px solid var(--color-brand);
    outline-offset: 3px;
    border-radius: 4px;
}
:focus:not(:focus-visible) {
    outline: none;
}

[aria-disabled='true'],
button:disabled,
input:disabled,
select:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* =========================================================================
   VARIANTES DE BOTÓN extensiones del sistema `.btn` definido arriba
   -------------------------------------------------------------------------
   `.btn-primary` y `.btn-secondary` viven junto a `.btn` en la sección
   principal del sistema de componentes. Aquí van sólo las variantes de
   color extra (emerald, ghost) que no encajan en primary/secondary.
   ========================================================================= */

/* Emerald acción de confirmación positiva (Exportar XLSX/JSON, Guardar
 * en formularios financieros, Confirmar). Color diferenciado de la marca
 * para señalar "confirmar/completar" cuando conviven con `.btn-primary`.
 * Misma regla que .btn-primary: hover = brighten, nunca darken. */
.btn-emerald {
    background-color: #10b981;
    color: #ffffff;
    border-color: transparent;
    box-shadow: var(--shadow-sm);
    transition: background-color 0.15s ease, filter 0.15s ease, box-shadow 0.15s ease;
}
.btn-emerald:hover:not(:disabled):not([aria-disabled='true']) {
    /* Mismo criterio que .btn-primary: hover NO toca background-color
     * ni filter. Sólo ring + elevación. */
    box-shadow:
        0 0 0 2px rgba(255, 255, 255, 0.35),
        0 8px 20px -2px rgba(0, 0, 0, 0.5),
        0 4px 8px -2px rgba(0, 0, 0, 0.35);
}
.btn-emerald:active:not(:disabled):not([aria-disabled='true']) { transform: scale(0.98); }

/* Ghost transparente sin borde, overlay sutil al hover. Ideal para
 * acciones terciarias (Cancelar en pickers pequeños, "Volver", etc.). */
.btn-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--color-text-main);
    transition: background 0.15s ease;
}
.btn-ghost:hover:not(:disabled):not([aria-disabled='true']) { background: var(--color-surface-hover, rgba(0, 0, 0, 0.05)); }
.dark .btn-ghost:hover:not(:disabled):not([aria-disabled='true']),
[data-theme='dark'] .btn-ghost:hover:not(:disabled):not([aria-disabled='true']) { background: rgba(255, 255, 255, 0.05); }

/* =========================================================================
   COMPONENTES INTERACTIVOS NO-BOTÓN
   -------------------------------------------------------------------------
   Mismo criterio que `.btn-*`: colores sólidos, feedback nítido, sin
   depender de `hover:bg-gray-*` sueltos ni utilidades transparentes.
   ========================================================================= */

/* .menu-item item clickeable dentro de un dropdown / menú desplegable
 * (cambiar de club, cambiar contraseña, seleccionar formato, etc.).
 * Sin borde, con padding cómodo, hover con superficie sólida. */
.menu-item {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    width: 100%;
    padding: 0.625rem 0.875rem;
    font-family: var(--font-main);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-text-main);
    background: transparent;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.menu-item:hover:not(:disabled):not([aria-disabled='true']),
.menu-item:focus-visible {
    background-color: #f0f0f0;
    color: var(--color-text-main);
    outline: none;
}
.dark .menu-item:hover:not(:disabled):not([aria-disabled='true']),
.dark .menu-item:focus-visible,
[data-theme='dark'] .menu-item:hover:not(:disabled):not([aria-disabled='true']),
[data-theme='dark'] .menu-item:focus-visible {
    background-color: #2a2a2a;
    color: #ffffff;
}
.menu-item:disabled,
.menu-item[aria-disabled='true'] {
    opacity: 0.5;
    cursor: not-allowed;
}
.menu-item.is-danger { color: var(--badge-danger-bg); }
.dark .menu-item.is-danger,
[data-theme='dark'] .menu-item.is-danger { color: #ef4444; }
/* .is-info para acciones informativas / superadmin (ej: "volver a
 * impersonar"), en violeta para no confundir con acciones destructivas. */
.menu-item.is-info { color: #9333ea; }
.dark .menu-item.is-info,
[data-theme='dark'] .menu-item.is-info { color: #a855f7; }
/* .is-strong item con peso "semibold" para marcar el default u opción
 * destacada dentro del menú (ej: "Todos" al comienzo de un filtro). */
.menu-item.is-strong { font-weight: 600; }
/* .has-arrow item con submenu: separa el label del arrow con
 * `space-between` para que el icono termine pegado a la derecha. */
.menu-item.has-arrow { justify-content: space-between; }
/* .is-selected item marcado como selección actual (default en filtro,
 * país actual en phone picker, etc.). Reemplaza el patrón anterior de
 * `bg-primary/10 dark:bg-primary/20` inline con alpha. */
.menu-item.is-selected {
    background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
    font-weight: 600;
}
.dark .menu-item.is-selected,
[data-theme='dark'] .menu-item.is-selected {
    background-color: color-mix(in srgb, var(--color-primary) 20%, transparent);
    color: var(--color-primary);
}

/* .row-hover filas de tabla, filas de lista o cards que reaccionan al
 * cursor (drill-down, selección, expandir). Cambia sólo el fondo el
 * layout (borders, grid, flex) lo pone el HTML. Sólido en ambos temas. */
.row-hover {
    transition: background-color 0.12s ease;
}
.row-hover:hover {
    background-color: #f5f5f5;
    cursor: pointer;
}
.dark .row-hover:hover,
[data-theme='dark'] .row-hover:hover {
    background-color: #1f1f1f;
}
.row-hover.is-selected {
    background-color: #ececec;
}
.dark .row-hover.is-selected,
[data-theme='dark'] .row-hover.is-selected {
    background-color: #262626;
}

/* .card-hover tarjeta clickeable con hover más marcado (bg + borde). */
.card-hover {
    transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
    cursor: pointer;
}
.card-hover:hover {
    background-color: #f5f5f5;
    border-color: color-mix(in srgb, var(--color-border) 60%, var(--color-text-main));
}
.dark .card-hover:hover,
[data-theme='dark'] .card-hover:hover {
    background-color: #1f1f1f;
    border-color: #3a3a3a;
}

/* .radio-chip label envolvente de un radio dentro de un segmented
 * control (Permanente / Meses / Fecha en plan-config, Exento / Precio,
 * etc.). Padding compacto, hover con superficie sólida. */
.radio-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem 0.375rem;
    border-radius: 0.375rem;
    cursor: pointer;
    transition: background-color 0.12s ease;
}
.radio-chip:hover { background-color: #f0f0f0; }
.dark .radio-chip:hover,
[data-theme='dark'] .radio-chip:hover { background-color: #2a2a2a; }

/* .th-sortable `<th>` clickeable para ordenar columnas de tabla.
 * Su fondo base viene del thead el hover añade una superficie sólida
 * suficiente para diferenciarse sin depender de alpha sobre el thead. */
.th-sortable {
    cursor: pointer;
    user-select: none;
    transition: background-color 0.12s ease;
}
.th-sortable:hover { background-color: #ececec; }
.dark .th-sortable:hover,
[data-theme='dark'] .th-sortable:hover { background-color: #262626; }

/* Drop zone (import de archivos): borde punteado que cambia a color primario
 * al hover. Antes cada zona repetía el mismo `onmouseover` inline. */
.pdrs-dropzone {
    border: 2px dashed var(--border-color, var(--color-border, #d1d5db));
    border-radius: 0.75rem;
    transition: border-color 0.2s ease;
    cursor: pointer;
}
.pdrs-dropzone:hover { border-color: var(--color-primary, #dd0000); }

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}

/* Skeleton Loaders */
@keyframes skeleton-shimmer {
    0% {
        background-position: -200% 0;
    }
    100% {
        background-position: 200% 0;
    }
}
.skeleton {
    background: linear-gradient(
        90deg,
        rgba(229, 229, 229, 0.8) 25%,
        rgba(245, 245, 245, 0.9) 50%,
        rgba(229, 229, 229, 0.8) 75%
    );
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.5s ease-in-out infinite;
    border-radius: 0.5rem;
}
.dark .skeleton {
    background: linear-gradient(90deg, rgba(20, 20, 20, 0.8) 25%, rgba(28, 28, 28, 0.9) 50%, rgba(20, 20, 20, 0.8) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.5s ease-in-out infinite;
}
.skeleton-text {
    height: 1rem;
    width: 70%;
    border-radius: 0.25rem;
    margin-bottom: 0.5rem;
}
.skeleton-title {
    height: 1.5rem;
    width: 40%;
    border-radius: 0.375rem;
    margin-bottom: 1rem;
}
.skeleton-avatar {
    height: 3rem;
    width: 3rem;
    border-radius: 9999px;
}
.skeleton-badge {
    height: 1.25rem;
    width: 5rem;
    border-radius: 9999px;
}
.skeleton-chart {
    height: 12rem;
    border-radius: 0.75rem;
}
.skeleton-btn {
    height: 2.5rem;
    width: 8rem;
    border-radius: 0.5rem;
}
.skeleton-row {
    height: 3.5rem;
    border-radius: 0.5rem;
    margin-bottom: 0.5rem;
}

/* Status Badges */
.status-badge {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 20px;
    font-size: 0.8rem;
    font-weight: 600;
    text-align: center;
}
.status-badge.status-active { background-color: var(--badge-success-bg); color: var(--badge-success-fg); border: 1px solid var(--badge-success-bg); }
.status-badge.status-inactive { background-color: var(--badge-neutral-bg); color: var(--badge-neutral-fg); border: 1px solid var(--badge-neutral-bg); }
.status-badge.status-completed { background-color: var(--badge-muted-bg); color: var(--badge-muted-fg); border: 1px solid var(--badge-muted-bg); }

/* ── UTILITY CHIP CLASSES ──
   For inline HTML use (e.g. count pills, quick labels). Reference badge tokens.
   Fuera de @layer para que tengan prioridad normal en la cascada. */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.25rem 0.625rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
    border: 1px solid transparent;
}
/* .chip está fuera de @layer utilities y sobreescribiría el `.hidden`
   (display:none) de Tailwind. Reglas defensivas para que hidden gane. */
.chip.hidden, .chip[hidden] { display: none; }
.chip-success { background: var(--badge-success-bg); color: var(--badge-success-fg); border-color: var(--badge-success-bg); }
.chip-danger { background: var(--badge-danger-bg); color: var(--badge-danger-fg); border-color: var(--badge-danger-bg); }
.chip-warning { background: var(--badge-warning-bg); color: var(--badge-warning-fg); border-color: var(--badge-warning-bg); }
.chip-info { background: var(--badge-info-bg); color: var(--badge-info-fg); border-color: var(--badge-info-bg); }
.chip-primary { background: var(--badge-primary-bg); color: var(--badge-primary-fg); border-color: var(--badge-primary-bg); }
.chip-accent { background: var(--badge-accent-bg); color: var(--badge-accent-fg); border-color: var(--badge-accent-bg); }
.chip-neutral { background: var(--badge-neutral-bg); color: var(--badge-neutral-fg); border-color: var(--badge-neutral-bg); }
.chip-muted { background: var(--badge-muted-bg); color: var(--badge-muted-fg); border-color: var(--badge-muted-bg); }

/* ─── Nombre de marca "OarClub Data" ───────────────────────────────────────
   Un solo contrato para el nombre a lo largo del sistema. Uso:
     <span class="brand-name"><span class="brand-name-word">OarClub</span> Data</span>
   - .brand-name          -> wrapper bold, "Data" hereda color del contexto.
   - .brand-name-word     -> "OarClub" en color de marca del modo activo.
   Paginas con identidad propia (superadmin, login hero, facturas-portal,
   consentimiento print) usan variables/clases especificas por decision
   de diseno -- no migrar. */
.brand-name       { font-weight: 700; }
.brand-name-word  { color: var(--color-primary); }
/* Cuando el brand-name vive sobre un fondo del propio color primario
   (ej. header .bg-primary en subir-test.html), el word quedaba invisible
   por color-blending. Heredar el color del contexto para mantener el
   contraste (text-white / dark:text-black del propio header). */
.bg-primary .brand-name-word,
[class*="bg-primary"] .brand-name-word {
    color: currentColor;
}

/* ─── Dropdown search input sticky ────────────────────────────────────────
   Cuando un dropdown scrolleable (max-height + overflow-y:auto) tiene un
   input de busqueda arriba, el input debe quedar sticky al top asi no se
   pierde al scrollear la lista. Uso: <input class="dropdown-search">.

   Bordes propios (4 lados) + margen contra el borde del dropdown: sin esto
   el input queda "pegado" al contenedor y el override global de
   `.dark input:focus` (que pinta border-color primary) pinta solo el
   border-bottom -> se ve como una linea amarilla suelta. Se define un
   focus propio (misma specificity, declarado despues) que gana el desempate. */
.dropdown-search {
    position: sticky;
    top: 0;
    z-index: 2;
    display: block;
    width: calc(100% - 16px);
    margin: 8px;
    padding: 8px 12px;
    font-size: 0.8125rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm, 6px);
    background: var(--color-bg);
    color: var(--color-text-main);
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.dropdown-search:focus,
.dark .dropdown-search:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgb(var(--tw-color-primary) / 0.15);
}

/* Size modifier - bump padding + font size for prominent chips (dashboard counters). */
.chip-lg {
    padding: 0.3rem 0.85rem;
    font-size: 0.8rem;
}

/* Chip children (icons, small text) inherit the chip foreground so nothing
   stays illegible against the solid background. */
.chip .material-symbols-outlined,
.chip small,
.chip p { color: inherit; }

/* KPI card - single source of truth for dashboard summary tiles.
   Uses design tokens for surface, border, muted label and main value. */
.kpi-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 0.75rem;
}
.kpi-card__label {
    color: var(--color-text-muted);
}
.kpi-card__value {
    color: var(--color-text-main);
}

/* Brand icon tile - subtle red tint in light, solid dark surface in dark.
   Layout (size, radius, flex) is handled by callers via Tailwind utilities. */
.icon-tile {
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
}
.dark .icon-tile {
    background: var(--color-bg); /* #0a0a0a en dark, ex-`accent-black` */
}

/* ── BANNER (large informational panel) ──
   Same semantic system as .chip but sized for a full-width alert/notice block. */
.banner {
    padding: 1rem 1.25rem;
    border-radius: 0.75rem;
    border: 1px solid transparent;
}
.banner-success { background: var(--badge-success-bg); color: var(--badge-success-fg); border-color: var(--badge-success-bg); }
.banner-danger { background: var(--badge-danger-bg); color: var(--badge-danger-fg); border-color: var(--badge-danger-bg); }
.banner-warning { background: var(--badge-warning-bg); color: var(--badge-warning-fg); border-color: var(--badge-warning-bg); }
.banner-info { background: var(--badge-info-bg); color: var(--badge-info-fg); border-color: var(--badge-info-bg); }
.banner-primary { background: var(--badge-primary-bg); color: var(--badge-primary-fg); border-color: var(--badge-primary-bg); }
.banner-accent { background: var(--badge-accent-bg); color: var(--badge-accent-fg); border-color: var(--badge-accent-bg); }
.banner-neutral { background: var(--badge-neutral-bg); color: var(--badge-neutral-fg); border-color: var(--badge-neutral-bg); }
/* Nested elements inherit foreground; icons/paragraph subcolors stay legible. */
.banner :is(.material-symbols-outlined, p, small, span, strong, b) { color: inherit; }

/* ── SEMANTIC ICON COLOR CLASSES ──
   For standalone decorator icons that need to signal semantic without a full
   chip background (e.g. leading icons in tooltip rows, list markers). */
.icon-success { color: var(--badge-success-bg); }
.icon-danger  { color: var(--badge-danger-bg); }
.icon-warning { color: var(--badge-warning-bg); }
.icon-neutral { color: var(--badge-neutral-bg); }
.icon-info    { color: var(--badge-info-bg); }
.icon-primary { color: var(--badge-primary-bg); }
.icon-accent  { color: var(--badge-accent-bg); }
.icon-muted   { color: var(--badge-muted-bg); }

/* Semantic text-color utilities (for inline body text, table cells, etc.).
   .text-primary and .text-accent are intentionally omitted - they collide
   with Tailwind's generated utilities of the same name. Use .chip-primary /
   .chip-accent for badge-neutral coloring, or Tailwind's text-primary for
   the brand accent color. */
.text-success      { color: var(--badge-success-bg); }
.text-danger       { color: var(--badge-danger-bg); }
.text-warning      { color: var(--badge-warning-bg); }
.text-neutral      { color: var(--badge-neutral-bg); }
.text-info         { color: var(--badge-info-bg); }
.text-muted-fg     { color: var(--color-text-muted); }
.text-body         { color: var(--color-text-main); }

/* Ghost link-styled button that signals a destructive action. */
.btn-link-danger {
    color: var(--badge-danger-bg);
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
}
.btn-link-danger:hover { text-decoration: underline; }

/* Money-value accent inside .fin-tooltip-detail-item (positive amounts). */
.fin-tooltip-detail-value--money { color: var(--badge-success-bg); font-weight: 600; }

/* ── MEMBER DETAIL - stats semantic variants (token-driven). */
.md-time-kpi--success .md-time-kpi-header,
.md-time-kpi--success .md-time-kpi-value { color: var(--badge-success-bg); }
.md-time-kpi--neutral .md-time-kpi-header,
.md-time-kpi--neutral .md-time-kpi-value { color: var(--badge-neutral-bg); }
.md-time-kpi--warning .md-time-kpi-header,
.md-time-kpi--warning .md-time-kpi-value { color: var(--badge-warning-bg); }
.md-time-kpi--water .md-time-kpi-header,
.md-time-kpi--water .md-time-kpi-value { color: var(--color-water); }

.md-time-comp-row-value--success { color: var(--badge-success-bg); }
.md-time-comp-row-value--neutral { color: var(--badge-neutral-bg); }
.md-time-comp-row-value--warning { color: var(--badge-warning-bg); }

.md-time-total-label {
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    gap: 4px;
}
.md-time-total-label .material-symbols-outlined { font-size: 12px; }

/* Titular indicator "(T)" - bold neutral flag next to name. */
.md-titular-flag {
    color: var(--badge-neutral-bg);
    font-weight: bold;
    margin-left: 4px;
}

/* Action Buttons (used in finance fixed-control) */
.action-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    color: var(--color-text-muted);
    transition: color 0.2s;
}
.edit-btn:hover {
    color: var(--color-text-main);
}
.delete-btn:hover {
    color: var(--color-brand);
}

.btn-icon.btn-edit,
.btn-icon.btn-delete {
    padding: 6px 10px;
    font-size: 0.9rem;
    border-radius: 6px;
}
.btn-icon.btn-edit:hover {
    background-color: #f5f5f5;
    color: var(--color-text-main);
}

/* Fixed Control Header (responsive) */
@media (max-width: 768px) {
    .fixed-control-header {
        display: none !important;
    }
}

/* Smooth theme transition - solo elementos interactivos (evita reflows en tablas masivas) */
body,
.card,
.sidebar,
.main-nav,
.btn,
button,
a,
input,
select,
textarea,
th,
td,
header,
footer,
nav,
.modal-content,
.toast,
.badge,
.chip,
[class*='bg-'],
[class*='surface'],
[class*='border-'] {
    transition-property: background-color, border-color, color;
    transition-duration: 150ms;
    transition-timing-function: ease;
}
.skeleton,
canvas,
[data-no-transition] {
    transition: none;
}

/* Custom Scrollbar */
::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}
* {
    scrollbar-width: thin;
    scrollbar-color: var(--color-text-muted) var(--color-bg);
}

/* =========================================
   EMPTY STATE - Reusable class for empty table rows
   Replaces inline styles with across JS modules
   ========================================= */
.empty-state-cell {
    padding: 40px 20px;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.9375rem;
}
.empty-state-cell.is-italic {
    font-style: italic;
}

/* Icon color override for forced-dark contexts (speed-dial, etc.) */
.icon-forced-dark {
    color: var(--color-brand-black, #0a0a0a);
}
.dark .icon-forced-dark {
    color: var(--color-text-main, #f5f5f5);
}

/* Disabled interactive element (replaces inline style.cursor/style.opacity) */
.is-field-locked {
    cursor: not-allowed;
    opacity: 0.7;
}

/* =========================================
   SPEED DIAL - Fixed action button positioning
   Moved from inline in finance.html
   ========================================= */
.speed-dial {
    position: fixed;
    bottom: 2rem;
    right: 2rem;
    left: auto;
    z-index: 10005;
    display: flex;
    flex-direction: column-reverse;
    align-items: flex-end;
    gap: 12px;
}

/* =========================================
   SPEED DIAL ANIMATIONS
   Staggered entry animation for speed dial options
   ========================================= */
@keyframes speedDialBackdropIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

#speed-dial-backdrop {
    animation: speedDialBackdropIn 0.2s cubic-bezier(0.4, 0, 0.2, 1) both;
}

@keyframes speedDialItemIn {
    0% {
        opacity: 0;
        transform: translateY(12px) scale(0.9);
    }
    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

#speed-dial-options > div {
    opacity: 0;
    transform: translateY(12px) scale(0.9);
    will-change: transform, opacity;
}

body:has(#speed-dial) #speed-dial-options > div {
    animation: speedDialItemIn 0.28s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

body:has(#speed-dial) #speed-dial-options > div:nth-child(1) {
    animation-delay: 0.04s;
}

body:has(#speed-dial) #speed-dial-options > div:nth-child(2) {
    animation-delay: 0.1s;
}

/* =========================================
   AI CHAT FAB & PANEL POSITION OVERRIDES
   Avoids overlap by creating a single vertical stack in the corner
   ========================================= */
body:has(#speed-dial) .ai-chat-fab {
    right: 2rem; /* Align horizontally with the speed-dial column (32px) */
    bottom: 2rem; /* Position at the very bottom of the stack (32px) */
}
body:has(#speed-dial) .speed-dial {
    bottom: 100px; /* Stack speed-dial above the AI FAB (32px bottom + 56px height + 12px gap) */
}
body:has(#speed-dial) .ai-chat-panel {
    right: 100px; /* Aligned horizontally next to the FAB column (32px margin + 56px FAB + 12px gap) */
    bottom: 2rem; /* Position panel at the very bottom of the viewport when open (32px) */
}

/* =========================================
   FINANCE CARD COLORS - replaces .style.color in JS
   ========================================= */
.card-value-income {
    color: #10b981;
}
.card-value-expense {
    color: var(--color-brand);
}
.card-value-neutral {
    color: var(--color-text-main);
}

.card-emoji-income {
    color: rgba(16, 185, 129, 0.6);
}
.card-emoji-expense {
    color: rgb(var(--tw-color-primary) / 0.6);
}
.card-emoji-neutral {
    color: rgba(10, 10, 10, 0.6);
}
.dark .card-emoji-neutral {
    color: rgba(229, 229, 229, 0.6);
}

.card-border-neutral {
    background-color: #0a0a0a;
}
.dark .card-border-neutral {
    background-color: #e5e5e5;
}

/* ── Debt Detection Dialog (profile-groups.js) ── */
.debt-dialog-modal {
    max-width: 460px;
}
.debt-dialog-icon-bg {
    background: var(--color-state-warning-bg);
}

.debt-dialog-icon-color {
    color: var(--color-brand);
}
.debt-dialog-message {
    margin-bottom: 8px;
}
.debt-dialog-list {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 8px 12px;
    margin: 0 0 12px;
    max-height: 150px;
    overflow-y: auto;
}
.dark .debt-dialog-list {
    background: #1c1c1c;
    border-color: #262626;
}
.debt-dialog-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 6px 0;
    border-bottom: 1px solid var(--color-border);
}
.dark .debt-dialog-row {
    border-bottom-color: #262626;
}
.debt-dialog-name {
    font-weight: 500;
}
.debt-dialog-amount {
    color: var(--color-brand);
    font-weight: 600;
}
.debt-dialog-total-row {
    display: flex;
    justify-content: space-between;
    padding: 4px 0 12px;
    font-size: 0.85rem;
}
.debt-dialog-total-label {
    font-weight: 600;
}
.debt-dialog-total-value {
    color: var(--color-brand);
    font-weight: 700;
}
.debt-dialog-sub {
    margin-bottom: 14px;
}
.debt-dialog-actions {
    flex-direction: column;
    gap: 8px;
}
.debt-dialog-btn-full {
    width: 100%;
}
.debt-dialog-btn-icon {
    font-size: 16px;
    vertical-align: middle;
    margin-right: 4px;
}
.debt-dialog-hint {
    font-size: 0.7rem;
    color: var(--color-text-muted);
    margin-top: 10px;
    text-align: center;
}

/* ── Portal Copy Button State (invoicing.js) ── */
.portal-btn-copied {
    color: #059669;
    border-color: #10b981;
}

/* ── Attendance Status Messages (attendance.js) ── */
.att-status-success {
    color: #10b981;
}
.att-status-info {
    color: var(--color-state-info);
}
.att-status-error {
    color: var(--color-brand);
}

/* ── SIFEN Result Banner States (invoicing.js) ── */
.sifen-banner-ok {
    border: 1px solid #6ee7b7;
    background-color: #d1fae5;
}
.dark .sifen-banner-ok,
[data-theme='dark'] .sifen-banner-ok {
    border-color: #047857;
    background-color: #064e3b;
}
.sifen-banner-err {
    border: 1px solid #fca5a5;
    background-color: #fee2e2;
}
.dark .sifen-banner-err,
[data-theme='dark'] .sifen-banner-err {
    border-color: #b91c1c;
    background-color: #7f1d1d;
}
.sifen-banner-warn {
    border: 1px solid #fcd34d;
    background-color: #fef3c7;
}
.dark .sifen-banner-warn,
[data-theme='dark'] .sifen-banner-warn {
    border-color: #a16207;
    background-color: #713f12;
}
.sifen-color-ok {
    color: #10b981;
}
.sifen-color-err {
    color: var(--color-brand);
}
.sifen-color-warn {
    color: var(--color-primary);
}

/* ── Invoicing Environment Badge (invoicing.js) ── */
.inv-badge-prod {
    background: #10b981;
    color: #ffffff;
    border-color: #10b981;
}
.inv-badge-test {
    background: var(--color-state-warning-bg);
    color: var(--color-state-warning);
    border-color: var(--color-state-warning-border);
}

/* ── Invoicing Cert Status (invoicing.js) ── */
.inv-cert-loaded {
    border-color: var(--inv-success, #10b981);
}
.inv-cert-none {
    border-color: var(--inv-border, #e5e5e5);
}

/* ── Invoicing Table Button Colors (invoicing.js) ── */
.inv-btn-sifen-send {
    color: #10b981;
}
.inv-btn-sifen-query {
    color: var(--color-sifen-query);
}
.inv-btn-delete {
    color: var(--color-brand);
}

/* ── Invoicing Confirm Icon (invoicing.js) ── */
.inv-confirm-icon-default {
    color: var(--color-confirm-icon);
}

/* ── Plan Config Tab Active State (plan-config-modal.js) ── */
.plan-tab-active {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

/* ── Finance Card Border States (finance.js) ── */
.card-border-income {
    background-color: #10b981;
}
.card-border-expense {
    background-color: var(--color-brand);
}

/* =========================================
   MOBILE FILTER IMPROVEMENTS
   Filters stack vertically on small screens
   ========================================= */
@media (max-width: 640px) {
    .filters-bar {
        flex-wrap: wrap;
    }
    .filters-bar > div {
        min-width: 100%;
        flex: 1 1 100%;
    }
    .filters-bar > div[style*='width: 40px'],
    .filters-bar > .flex.items-end[style*='width: 40px'] {
        min-width: auto;
        flex: 0 0 40px;
    }
}

/* =========================================
   EMPTY STATE - Enriched version for tables
   ========================================= */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3rem 1.5rem;
    text-align: center;
    color: var(--color-text-muted);
}
.empty-state-icon {
    font-size: 3rem;
    color: var(--color-border);
    margin-bottom: 1rem;
}
.empty-state-title {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--color-text-main);
    margin-bottom: 0.5rem;
}
.empty-state-message {
    font-size: 0.875rem;
    color: var(--color-text-muted);
    max-width: 320px;
    line-height: 1.5;
    margin-bottom: 1rem;
}
.empty-state-action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    font-size: 0.85rem;
    font-weight: 600;
    border-radius: var(--radius-md);
    background-color: var(--color-brand);
    color: var(--color-btn-text, #ffffff);
    border: none;
    cursor: pointer;
    transition: all 0.2s ease;
}
.empty-state-action:hover {
    background-color: var(--color-brand-dark, var(--color-brand-dark));
    transform: translateY(-1px);
}

/* =========================================
   BREADCRUMB - Lightweight navigation aid
   ========================================= */
.breadcrumb {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin-bottom: 0.5rem;
}
.breadcrumb a {
    color: var(--color-text-muted);
    text-decoration: none;
    transition: color 0.15s ease;
}
.breadcrumb a:hover {
    color: var(--color-brand);
}
.breadcrumb-separator {
    font-size: 0.7rem;
    color: var(--color-border);
}
.breadcrumb-current {
    color: var(--color-text-main);
    font-weight: 600;
}

/* =========================================
   KEYBOARD SHORTCUT HINTS
   ========================================= */
.kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.4rem;
    padding: 0 5px;
    font-family: var(--font-main);
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--color-text-muted);
    background: var(--color-surface-hover);
    border: 1px solid var(--color-border);
    border-radius: 4px;
    line-height: 1;
}

/* =========================================
   TAILWIND UTILITY COLOR STANDARDISATION
   Force standard colors on Tailwind utility classes
   ========================================= */

/* Red (Danger / Error / Debt) */
:is(.text-red-400, .text-red-500, .text-red-600, .text-red-700) {
    color: var(--status-debt);
}
:is(.bg-red-400, .bg-red-500, .bg-red-600, .bg-red-700) {
    background-color: var(--status-debt);
}
.hover\:text-red-700:hover {
    color: var(--status-debt);
}
.hover\:bg-red-50:hover {
    background-color: var(--color-state-warning-bg);
}
.dark :is(.dark\:text-red-400, .dark\:text-red-500),
[data-theme='dark'] :is(.dark\:text-red-400, .dark\:text-red-500) {
    color: var(--status-debt);
}
.dark .dark\:hover\:bg-red-900\/20:hover,
[data-theme='dark'] .dark\:hover\:bg-red-900\/20:hover {
    background-color: #7f1d1d;
}

/* Green & Emerald (Success / Paid / Active) */
:is(
    .text-green-400,
    .text-green-500,
    .text-green-600,
    .text-green-700,
    .text-green-800,
    .text-emerald-400,
    .text-emerald-500
) {
    color: var(--status-paid);
}
:is(.bg-green-400, .bg-green-500, .bg-green-600, .bg-green-700, .bg-emerald-500) {
    background-color: var(--status-paid);
}
.bg-green-100 {
    background-color: #d1fae5;
}
.dark .bg-green-100,
[data-theme='dark'] .bg-green-100 {
    background-color: #064e3b;
}
.dark :is(.dark\:text-green-400, .dark\:text-emerald-400),
[data-theme='dark'] :is(.dark\:text-green-400, .dark\:text-emerald-400) {
    color: var(--status-paid);
}

/* Yellow & Amber (Warning / Gold / Pending) */
:is(.text-yellow-600, .text-amber-500, .text-amber-600, .text-amber-700) {
    color: var(--status-category);
}
:is(.bg-yellow-500, .bg-amber-500) {
    background-color: var(--status-category);
}

/* Teal (Special Plans) */
:is(.text-teal-700, .text-teal-600) {
    color: var(--status-plan);
}
.dark :is(.dark\:text-teal-400),
[data-theme='dark'] :is(.dark\:text-teal-400) {
    color: var(--status-plan);
}

/* =========================================
   FINANCIAL TAB PREMIUM REDESIGN
   Impeccable style for Debt Hero and Month cells
   Ensures soft tinted colors and maximum visual quality
   ========================================= */

/* --- 1. HERO BANNER DEUDA (.fin-hero--debt) ---
   The banner is a solid danger surface; every descendant gets the danger
   foreground (white) by inheritance. Nested badges/icons live on a darker
   transparent overlay so they read as distinct chips on the red field. */
.fin-hero--debt {
    background: var(--badge-danger-bg);
    color: var(--badge-danger-fg);
    border: 1px solid var(--badge-danger-bg);
}
.dark .fin-hero--debt,
[data-theme='dark'] .fin-hero--debt {
    box-shadow: 0 4px 25px rgba(0, 0, 0, 0.4);
}

/* Every nested piece inherits the banner foreground automatically. */
.fin-hero--debt :is(.fin-hero__icon .material-symbols-outlined,
                    .fin-hero__balance,
                    .fin-hero__label,
                    .fin-hero__last-payment,
                    .fin-hero__amount-hint) {
    color: inherit;
}

/* Icon container: subtle inset overlay so the icon stands out on the red field. */
.fin-hero--debt .fin-hero__icon {
    background: rgba(0, 0, 0, 0.18);
}

/* Nested badges on the red banner: neutral dark chip with white text. */
.fin-hero--debt .fin-badge,
.fin-hero--debt .fin-badge--debt,
.fin-hero--debt .fin-badge--plan {
    background: var(--badge-neutral-bg);
    color: var(--badge-neutral-fg);
    border: 1px solid var(--badge-neutral-bg);
}

/* --- Mirror variant: HERO BANNER OK (.fin-hero--ok) --- */
.fin-hero--ok {
    background: var(--badge-success-bg);
    color: var(--badge-success-fg);
    border: 1px solid var(--badge-success-bg);
}
.dark .fin-hero--ok,
[data-theme='dark'] .fin-hero--ok {
    box-shadow: 0 4px 25px rgba(0, 0, 0, 0.4);
}

.fin-hero--ok :is(.fin-hero__icon .material-symbols-outlined,
                  .fin-hero__balance,
                  .fin-hero__label,
                  .fin-hero__last-payment,
                  .fin-hero__amount-hint) {
    color: inherit;
}

.fin-hero--ok .fin-hero__icon {
    background: rgba(0, 0, 0, 0.18);
}

.fin-hero--ok .fin-badge,
.fin-hero--ok .fin-badge--ok,
.fin-hero--ok .fin-badge--plan {
    background: var(--badge-neutral-bg);
    color: var(--badge-neutral-fg);
    border: 1px solid var(--badge-neutral-bg);
}

/* Standalone .fin-badge variants (outside the hero) reference tokens. */
.fin-badge--ok   { background: var(--badge-success-bg); color: var(--badge-success-fg); }
.fin-badge--debt { background: var(--badge-danger-bg);  color: var(--badge-danger-fg); }
.fin-badge--plan { background: var(--badge-neutral-bg); color: var(--badge-neutral-fg); }

/* --- 2. CELDAS MENSUALES PENDIENTES (.fin-month-cell--unpaid) ---
   Same solid-surface + inheritance model as .fin-hero--debt: red field,
   every text/icon/amount inside inherits white foreground. */
.fin-month-cell--unpaid {
    background: var(--badge-danger-bg);
    color: var(--badge-danger-fg);
    border: 1px solid var(--badge-danger-bg);
    transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.fin-month-cell--unpaid :is(.fin-month-cell__name,
                            .fin-month-cell__icon,
                            .fin-month-cell__amount,
                            .fin-month-cell__plan,
                            .material-symbols-outlined) {
    color: inherit;
}

/* Pay button inside the red field: neutral dark chip for contrast. */
.fin-month-cell--unpaid .fin-month-cell__pay-btn {
    background: var(--badge-neutral-bg);
    color: var(--badge-neutral-fg);
}

.fin-month-cell--unpaid:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}
.dark .fin-month-cell--unpaid:hover,
[data-theme='dark'] .fin-month-cell--unpaid:hover {
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}

/* --- Mirror variant: PAID cell (.fin-month-cell--paid) --- */
.fin-month-cell--paid {
    background: var(--badge-success-bg);
    color: var(--badge-success-fg);
    border: 1px solid var(--badge-success-bg);
    transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.fin-month-cell--paid :is(.fin-month-cell__name,
                          .fin-month-cell__icon,
                          .fin-month-cell__amount,
                          .fin-month-cell__plan,
                          .material-symbols-outlined) {
    color: inherit;
}

.fin-month-cell--paid:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}
.dark .fin-month-cell--paid:hover,
[data-theme='dark'] .fin-month-cell--paid:hover {
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}

/* =========================================
   MEMBERS LIST - Debt Tooltip on "En deuda" badge
   ========================================= */
.members-debt-tooltip {
    cursor: pointer;
}

/* Tooltip sub-element styles (for the floating tooltip container) */
#members-debt-tooltip-container .fin-tooltip-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-family: var(--font-heading, 'Space Grotesk'), sans-serif;
    font-size: 0.6875rem;
    font-weight: 700;
    color: var(--color-text-muted);
    letter-spacing: 0.5px;
}

#members-debt-tooltip-container .fin-tooltip-divider {
    height: 1px;
    background: #1f1f1f;
    margin: 0.6rem 0;
}

#members-debt-tooltip-container .fin-tooltip-scrollable-months {
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
}

#members-debt-tooltip-container .fin-tooltip-scrollable-months::-webkit-scrollbar {
    width: 4px;
}

#members-debt-tooltip-container .fin-tooltip-scrollable-months::-webkit-scrollbar-track {
    background: transparent;
}

#members-debt-tooltip-container .fin-tooltip-scrollable-months::-webkit-scrollbar-thumb {
    background: #1f1f1f;
    border-radius: 20px;
}

#members-debt-tooltip-container .fin-tooltip-scrollable-months::-webkit-scrollbar-thumb:hover {
    background: #1f1f1f;
}

/* =========================================
   MEMBERS LIST - Rowing Category Badges Styling
   ========================================= */
.category-badge {
    display: inline-flex;
    align-items: center;
    padding: 0.3rem 0.75rem;
    border-radius: 8px;
    font-size: 0.825rem;
    font-weight: 800;
    white-space: nowrap;
    border: 1px solid transparent;
    transition: all 0.2s ease;
}

/* Category badges reference badge design tokens (see :root above). */
.category-badge.infantil { background-color: var(--badge-info-bg); color: var(--badge-info-fg); border-color: var(--badge-info-bg); }
.category-badge.menor-a,
.category-badge.menor-b { background-color: var(--badge-success-bg); color: var(--badge-success-fg); border-color: var(--badge-success-bg); }
.category-badge.juvenil { background-color: var(--badge-primary-bg); color: var(--badge-primary-fg); border-color: var(--badge-primary-bg); }
.category-badge.senior { background-color: var(--badge-accent-bg); color: var(--badge-accent-fg); border-color: var(--badge-accent-bg); }
.category-badge.master { background-color: var(--badge-warning-bg); color: var(--badge-warning-fg); border-color: var(--badge-warning-bg); }
.category-badge.novicio { background-color: var(--badge-neutral-bg); color: var(--badge-neutral-fg); border-color: var(--badge-neutral-bg); }
/* Sized-down variant para uso en headers de tooltip. */
.category-badge--sm { padding: 2px 6px; border-radius: 4px; font-size: 0.65rem; letter-spacing: 0.05em; }

/* ── MEMBER-DETAIL FINANCIAL STATUS BADGE ──
   Single source of truth (previously duplicated in members-profile.css and member-detail.css). */
.md-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.75rem;
    border-radius: 8px;
    font-size: 0.825rem;
    font-weight: 800;
    letter-spacing: 0.01em;
    white-space: nowrap;
    transition: all 0.2s ease;
}
.md-status-badge .material-symbols-outlined {
    font-size: 14px;
    font-weight: 800;
    font-variation-settings: 'FILL' 1;
}
.md-status-badge--ok { background: var(--badge-success-bg); color: var(--badge-success-fg); border: 1px solid var(--badge-success-bg); }
.md-status-badge--debt { background: var(--badge-danger-bg); color: var(--badge-danger-fg); border: 1px solid var(--badge-danger-bg); }
.md-status-badge--near-due { background: var(--badge-warning-bg); color: var(--badge-warning-fg); border: 1px solid var(--badge-warning-bg); }
.md-status-badge--neutral { background: var(--badge-neutral-bg); color: var(--badge-neutral-fg); border: 1px solid var(--badge-neutral-bg); }

/* ── TOOLTIP STATUS PILL ──
   Single source of truth (previously duplicated in members-profile.css, member-detail.css, financial-tooltip.css). */
.fin-tooltip-status {
    padding: 2px 6px;
    border-radius: 4px;
    border: 1px solid;
    font-size: 0.65rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.fin-tooltip-status--paid,
.fin-tooltip-status--success { background: var(--badge-success-bg); color: var(--badge-success-fg); border-color: var(--badge-success-bg); }
.fin-tooltip-status--unpaid,
.fin-tooltip-status--danger  { background: var(--badge-danger-bg); color: var(--badge-danger-fg); border-color: var(--badge-danger-bg); }
.fin-tooltip-status--warning { background: var(--badge-warning-bg); color: var(--badge-warning-fg); border-color: var(--badge-warning-bg); }
.fin-tooltip-status--info    { background: var(--badge-info-bg); color: var(--badge-info-fg); border-color: var(--badge-info-bg); }
.fin-tooltip-status--future,
.fin-tooltip-status--disabled,
.fin-tooltip-status--neutral,
.fin-tooltip-status--muted   { background: var(--badge-muted-bg); color: var(--badge-muted-fg); border-color: var(--badge-muted-bg); }

/* ── Tooltip layout modifiers (token-driven, replace inline style="..."). */
.fin-tooltip-detail-item--row   { justify-content: space-between; width: 100%; display: flex; gap: 8px; }
.fin-tooltip-detail-item--stack { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.fin-tooltip-detail-item--desc  { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 8px; }
.fin-tooltip-detail-value--danger { color: var(--badge-danger-bg); font-weight: 700; }
.fin-tooltip-detail-value--lg     { font-size: 0.85rem; }
.fin-tooltip-empty {
    color: var(--color-text-muted);
    font-size: 0.72rem;
    text-align: center;
    padding: 6px 0;
}
.fin-tooltip-section-label {
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--color-text-muted);
    letter-spacing: 0.05em;
    margin-bottom: 6px;
}
/* Icon-* semantic classes must win over the generic tooltip icon color. */
.fin-tooltip-detail-item .material-symbols-outlined[class*="icon-"] { color: inherit; }
.fin-tooltip-detail-item :is(.icon-success, .icon-danger, .icon-warning, .icon-neutral, .icon-info, .icon-primary, .icon-accent, .icon-muted) {
    color: revert;
}

/* -- CATEGORY DROPDOWN SUBMENU -- */
.cat-submenu-trigger {
    position: relative;
}

/* Submenu portalizado a document.body al abrir para escapar del clip del
   menú padre (overflow-y: auto) y de cualquier ancestor con transform/filter
   que cambie el containing block de position: fixed. Como el submenu ya no
   vive dentro del trigger, la regla NO se puede escopear a
   .cat-submenu-trigger - debe aplicar al .cat-submenu esté donde esté. */
.cat-submenu {
    display: none;
    position: fixed;
    z-index: 9999;
}

/* Estado abierto: JS agrega .open al .cat-submenu al portalizarlo. */
.cat-submenu.open {
    display: block;
}

/* Variante lab-* (mismo comportamiento, selector separado por historia del
   módulo laboratorio; ambos usan wireCategoryDropdown y portal a body). */
.lab-cat-submenu-trigger {
    position: relative;
}
.lab-cat-submenu {
    display: none;
    position: fixed;
    z-index: 9999;
}
.lab-cat-submenu.open {
    display: block;
}

/* -- SCROLL EN DROPDOWNS DE FILTRO --
   Cualquier contenedor de dropdown (por convención: id/clase termina en
   "-menu") o el submenu .cat-submenu/.lab-cat-submenu que contenga ítems
   tipo menu-item debe acotar su alto al viewport y scrollear internamente
   en lugar de desbordarse por debajo del fold. Regla única para no tener
   que añadir max-height ad-hoc en cada HTML. */
[id$="-menu"]:has(> .menu-item),
[class*="-menu"]:has(> .menu-item),
.cat-submenu:has(> .menu-item),
.lab-cat-submenu:has(> .menu-item) {
    max-height: min(50vh, 20rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Firefox: scrollbar siempre visible (no auto-hide) */
    scrollbar-width: thin;
    scrollbar-color: var(--color-text-muted, #888) transparent;
}

/* WebKit (Chrome/Safari/Edge): scrollbar visible dentro del dropdown.
   El default global es 12px pero sobre menús flotantes con esquinas
   redondeadas queda mejor un track angosto y siempre presente. */
[id$="-menu"]:has(> .menu-item)::-webkit-scrollbar,
[class*="-menu"]:has(> .menu-item)::-webkit-scrollbar,
.cat-submenu:has(> .menu-item)::-webkit-scrollbar,
.lab-cat-submenu:has(> .menu-item)::-webkit-scrollbar {
    width: 8px;
}
[id$="-menu"]:has(> .menu-item)::-webkit-scrollbar-thumb,
[class*="-menu"]:has(> .menu-item)::-webkit-scrollbar-thumb,
.cat-submenu:has(> .menu-item)::-webkit-scrollbar-thumb,
.lab-cat-submenu:has(> .menu-item)::-webkit-scrollbar-thumb {
    background: var(--color-text-muted, #888);
    border-radius: 4px;
}
[id$="-menu"]:has(> .menu-item)::-webkit-scrollbar-track,
[class*="-menu"]:has(> .menu-item)::-webkit-scrollbar-track,
.cat-submenu:has(> .menu-item)::-webkit-scrollbar-track,
.lab-cat-submenu:has(> .menu-item)::-webkit-scrollbar-track {
    background: transparent;
}

/* ==========================================================================
   PREMIUM CUSTOM SELECTS - Global Upgraded Dropdowns
   ========================================================================== */

.custom-select-wrapper {
    position: relative;
    width: 100%;
}
.custom-select-wrapper.hidden {
    display: none !important;
}

.custom-select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 14px;
    font-family: var(--font-main), system-ui, sans-serif;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-text-main);
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    text-align: left;
    transition:
        border-color 0.2s ease,
        box-shadow 0.2s ease,
        background-color 0.2s ease;
    outline: none;
    box-sizing: border-box;
}

.custom-select-trigger:hover {
    border-color: var(--color-brand);
    background-color: var(--color-surface-hover);
}

.custom-select-trigger:focus-within,
.custom-select-trigger:focus {
    border-color: var(--color-brand);
    box-shadow: 0 0 0 3px rgb(var(--tw-color-primary) / 0.15);
}

.dark .custom-select-trigger:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgb(var(--tw-color-primary) / 0.15);
}

.custom-select-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding-right: 0.5rem;
}

.custom-select-arrow {
    font-size: 18px;
    color: var(--color-text-muted);
    transition: transform 0.2s ease;
}

.custom-select-wrapper.open .custom-select-arrow {
    transform: rotate(180deg);
}

/* Floating custom dropdown menu */
.custom-select-dropdown {
    position: absolute;
    z-index: 99999;
    margin-top: 6px;
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow:
        var(--shadow-lg),
        0 10px 30px rgba(0, 0, 0, 0.08);
    max-height: 300px;
    /* Layout flex vertical: search fijo arriba, options scrolleable abajo.
       El scroll vive en .custom-select-options-list, NO en el dropdown, para
       que el search-wrap nunca se corte al scrollear (más robusto que sticky
       en dark-mode con backdrop-filter). */
    display: flex;
    flex-direction: column;
    overflow: hidden;
    opacity: 0;
    transform: translateY(8px);
    pointer-events: none;
    transition:
        opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
        transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    box-sizing: border-box;
}

.custom-select-options-list {
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
}

.custom-select-search-wrap {
    padding: 8px;
    flex-shrink: 0;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
}
.dark .custom-select-search-wrap {
    background: rgb(20, 20, 20);
    backdrop-filter: blur(16px);
}
.custom-select-search-input {
    width: 100%;
    padding: 6px 12px;
    font-size: 0.8125rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg);
    color: var(--color-text-main);
    outline: none;
    transition: border-color 0.2s ease;
}
.custom-select-search-input:focus {
    border-color: var(--color-brand);
}

.custom-select-dropdown.open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

/* Custom Scrollbar for Dropdown */
.custom-select-dropdown::-webkit-scrollbar {
    width: 6px;
}
.custom-select-dropdown::-webkit-scrollbar-track {
    background: transparent;
}
.custom-select-dropdown::-webkit-scrollbar-thumb {
    background: #f5f5f5;
    border-radius: 3px;
}
.dark .custom-select-dropdown::-webkit-scrollbar-thumb {
    background: #1f1f1f;
}

/* Glassmorphism for Dark Mode Dropdown */
.dark .custom-select-dropdown {
    background-color: rgb(20, 20, 20);
    backdrop-filter: blur(16px);
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow:
        0 20px 40px rgba(0, 0, 0, 0.5),
        0 0 1px rgba(255, 255, 255, 0.1);
}

/* Custom Option Item */
.custom-select-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-text-main);
    cursor: pointer;
    transition:
        background-color 0.15s ease,
        color 0.15s ease;
}

.custom-select-option:hover {
    background-color: color-mix(in srgb, var(--color-brand) 8%, transparent);
    color: var(--color-text-main);
}

.dark .custom-select-option:hover {
    background-color: color-mix(in srgb, var(--color-brand) 12%, transparent);
    color: #ffffff;
}

.custom-select-option.selected {
    background-color: color-mix(in srgb, var(--color-brand) 12%, transparent);
    color: var(--color-brand);
    font-weight: 600;
}

.dark .custom-select-option.selected {
    background-color: color-mix(in srgb, var(--color-brand) 20%, transparent);
    color: var(--color-primary);
    font-weight: 600;
}

/* ==========================================================================
   AUTOFILL OVERRIDES - Keep mode-appropriate appearance on autofilled fields
   ========================================================================== */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
    -webkit-box-shadow: 0 0 0 30px var(--color-bg) inset;
    -webkit-text-fill-color: var(--color-text-main);
    transition: background-color 5000s ease-in-out 0s;
}

/* ==========================================================================
   PORTAL - Toolbar search field override (fix invisible input)
   ========================================================================== */
#module-tab-portal .search-wrap {
    position: relative;
    flex: 1;
    min-width: 200px;
}
#module-tab-portal .search-wrap svg {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 15px;
    height: 15px;
    color: var(--color-text-muted);
    pointer-events: none;
}
#module-tab-portal .toolbar-input {
    width: 100%;
    padding: 9px 14px 9px 36px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    font-family: inherit;
    font-size: 0.84rem;
    color: var(--color-text-main);
    outline: none;
    transition:
        border-color 0.2s,
        box-shadow 0.2s;
}
#module-tab-portal .toolbar-input:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 15%, transparent);
}
#module-tab-portal .toolbar-input::placeholder {
    color: var(--color-text-muted);
}

/* ==========================================================================
   PORTAL - Create Access Modal (premium design)
   ========================================================================== */

/* Modal shell */
.portal-create-modal {
    max-width: 480px;
    padding: 0;
    overflow: visible;
}

/* ── Header ── */
.portal-create-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 24px 16px;
}
.portal-create-title {
    display: flex;
    align-items: center;
    gap: 10px;
}
.portal-create-title svg {
    width: 20px;
    height: 20px;
    color: var(--color-gold);
}
.portal-create-title h3 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--color-text-main);
}

/* ── Search zone - adapts to light/dark ── */
.portal-search-zone {
    background: var(--color-bg, #fafafa);
    border-top: 1px solid var(--color-border, #e5e5e5);
    border-bottom: 1px solid var(--color-border, #e5e5e5);
    padding: 20px 24px 14px;
}
.dark .portal-search-zone {
    background: #0a0a0a;
    border-color: rgba(255, 255, 255, 0.06);
}
.portal-search-box {
    position: relative;
    display: flex;
    align-items: center;
    background: var(--color-surface, #ffffff);
    border: 1px solid var(--color-border, #e5e5e5);
    border-radius: 10px;
    transition:
        border-color 0.2s,
        box-shadow 0.2s;
}
.dark .portal-search-box {
    background: #161616;
    border-color: rgba(255, 255, 255, 0.1);
}
.portal-search-box:focus-within {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 15%, transparent);
}
.portal-search-icon {
    width: 18px;
    height: 18px;
    margin-left: 14px;
    color: var(--color-text-muted);
    flex-shrink: 0;
    transition: color 0.2s;
}
.dark .portal-search-icon {
    color: rgba(255, 255, 255, 0.3);
}
.portal-search-box:focus-within .portal-search-icon {
    color: var(--color-primary);
}
.portal-search-box > input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    padding: 14px 16px;
    font-size: 0.9rem;
    color: var(--color-text-main, #111);
    font-family: inherit;
}
.dark .portal-search-box > input {
    color: #fff;
}
.portal-search-box > input::placeholder {
    color: var(--color-text-muted);
}
.dark .portal-search-box > input::placeholder {
    color: rgba(255, 255, 255, 0.28);
}
.portal-search-hint {
    display: block;
    margin-top: 8px;
    font-size: 0.72rem;
    color: var(--color-text-muted);
    letter-spacing: 0.02em;
}
.dark .portal-search-hint {
    color: rgba(255, 255, 255, 0.3);
}

/* ── Dropdown results ── */
.member-search-dropdown {
    display: none !important;
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 200;
    max-height: 280px;
    overflow-y: auto;
    background: var(--color-surface, #ffffff);
    border: 1px solid var(--color-border, #e5e5e5);
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}
.dark .member-search-dropdown {
    background: #1a1a1a;
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
    scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
.member-search-item {
    padding: 12px 16px;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 3px;
    border-bottom: 1px solid var(--color-border, #e5e5e5);
    transition:
        background 0.15s,
        padding-left 0.15s;
}
.dark .member-search-item {
    border-bottom-color: rgba(255, 255, 255, 0.05);
}
.member-search-item:last-child {
    border-bottom: none;
}
.member-search-item:hover {
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
    padding-left: 20px;
}
.member-search-item strong {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-main, #111);
}
.dark .member-search-item strong {
    color: #f0f0f0;
}
.member-search-item:hover strong {
    color: var(--color-primary);
}
.member-search-detail {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    letter-spacing: 0.03em;
}
.dark .member-search-detail {
    color: rgba(255, 255, 255, 0.4);
}
.member-search-empty {
    cursor: default;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.82rem;
    padding: 24px 16px;
}
.dark .member-search-empty {
    color: rgba(255, 255, 255, 0.3);
}
.member-search-empty:hover {
    background: transparent;
    padding-left: 16px;
}

/* ── Selected member card ── */
.portal-selected-card {
    display: none !important;
    margin: 0 24px 6px;
    padding: 14px 18px;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
    background: color-mix(in srgb, var(--color-primary) 4%, transparent);
    align-items: center;
    gap: 14px;
    animation: portalCardIn 0.25s ease-out;
}
.portal-selected-card[style*='display: flex'],
.portal-selected-card[style*='display:flex'] {
    display: flex;
}
@keyframes portalCardIn {
    from {
        opacity: 0;
        transform: translateY(-6px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}
.portal-selected-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--color-gold), #e6a800);
    color: #000;
    font-weight: 800;
    font-size: 0.85rem;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    text-transform: uppercase;
}
.portal-selected-info {
    flex: 1;
    min-width: 0;
}
.portal-selected-name {
    font-weight: 700;
    font-size: 0.88rem;
    color: var(--color-text-main);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.portal-selected-detail {
    font-size: 0.74rem;
    color: var(--color-text-muted);
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    margin-top: 1px;
}
.portal-selected-check {
    width: 22px;
    height: 22px;
    color: #22c55e;
    flex-shrink: 0;
}

/* ── Footer ── */
.portal-create-footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 16px 24px 20px;
}


/* ==========================================================================
   PORTAL - Modals & Overlay Style Fixes (prevents layout disassembly)
   ========================================================================== */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(5px);
    z-index: 10000;
    display: none;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.25s ease;
}

.modal-overlay.open {
    display: flex;
    opacity: 1;
}

/* General overlay modal window sizing and shadows */
.modal-overlay .modal {
    background: var(--color-surface, #ffffff);
    border: 1px solid var(--color-border, #e5e5e5);
    border-radius: var(--radius-lg, 16px);
    width: 95%;
    max-width: 480px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    box-shadow: 0 25px 60px rgba(0, 0, 0, 0.25);
    color: var(--color-text-main);
    box-sizing: border-box;
    /* overflow: visible permite que popovers absolute-positioned (dropdowns
       de búsqueda de socio, autocompletes, tooltips) escapen del modal en
       vez de quedar clipeados. Si un modal específico necesita scroll
       interno, el body del modal debe manejarlo con su propio overflow-y:
       auto, no clipear a nivel del contenedor externo. */
    overflow: visible;
    animation: portalModalSlideIn 0.3s ease;
}

.dark .modal-overlay .modal {
    background: #141414;
    color: #e5e5e5;
    border-color: rgba(255, 255, 255, 0.08);
    box-shadow: 0 25px 60px rgba(0, 0, 0, 0.5);
}

@keyframes portalModalSlideIn {
    from {
        transform: translateY(15px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

/* Modal close button styling and SVG constraint */
.modal-close {
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px;
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    transition: all 0.2s ease;
}

.modal-close:hover {
    color: var(--color-brand, var(--color-brand));
    background: var(--color-surface-hover, rgba(0, 0, 0, 0.05));
}

.modal-close svg {
    width: 20px;
    height: 20px;
}

/* Portal token-copy icon button: hereda `.btn .btn-secondary .btn-icon`
 * del sistema de componentes (definidos arriba). Sólo se ajusta el SVG
 * interno para que se vea consistente con Material Symbols. */
.btn-icon svg {
    width: 18px;
    height: 18px;
}

.token-box {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: var(--color-bg, #fafafa);
    border: 1px solid var(--color-border, #e5e5e5);
    border-radius: var(--radius-md, 8px);
    padding: 10px 14px;
    gap: 12px;
}

.dark .token-box {
    background: #0a0a0a;
    border-color: rgba(255, 255, 255, 0.08);
}

.token-url {
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    font-size: 0.8rem;
    color: var(--color-text-main);
    word-break: break-all;
    user-select: all;
}


