/* Generated by npm run build:css; do not edit directly. */

/* source: src/styles/index.css */
/**
 * LM Contable — Design System v3.0 — fuente del bundle core.css.
 * `npm run build:css` resuelve estos imports manteniendo este archivo como
 * fuente mantenible. Orden importa: tokens antes
 * que componentes; temas despues de colors.css (para poder sobreescribir
 * sus variables); brand.css al final (gana sobre light/dark si ambos aplican).
 */

/* source: src/styles/tokens.css */
:root {
  /* Z-index: una sola escala para toda la app, evita guerras de z-index */
  --ds-z-base: 1;
  --ds-z-sidebar: 400;
  --ds-z-header: 500;
  --ds-z-dropdown: 900;
  --ds-z-tooltip: 950;
  --ds-z-modal: 1000;
  --ds-z-toast: 1100;

  /* Breakpoints (referencia — los @media siguen necesitando el literal,
     CSS no permite var() dentro de la condicion de un @media) */
  --ds-bp-mobile: 640px;
  --ds-bp-tablet: 1024px;

  --ds-content-max-width: 1440px;

  --ds-control-xs: 28px;
  --ds-control-sm: var(--ds-space-4);
  --ds-control-md: var(--ds-space-5);
  --ds-control-lg: var(--ds-space-6);

  /* Estandarizacion global de iconos (referencia: Iconos-v2.png) -- 4
     tramos segun el rol del icono en la interfaz, no por libreria/estilo
     (todo sigue siendo Lucide, stroke uniforme ver ui.js/initLucideAutoRefresh):
       - Botones y acciones de tabla:            --ds-icon-action  (16px)
       - Inputs/filtros/navegacion secundaria:    --ds-icon-control (16-18px)
       - Sidebar/topbar:                          --ds-icon-nav     (18-20px)
       - Tarjetas/KPI/encabezados destacados:     --ds-icon-feature (20-24px)
     --ds-icon-xs se mantiene aparte para glifos auxiliares/decorativos
     (cerrar modal, breadcrumb, badges) que no encajan en ninguno de los 4
     tramos de arriba -- forzarlos a 16px+ se ve sobredimensionado en
     contextos muy densos, por eso quedan como excepcion documentada (ver
     auditoria en LM_CONTABLE_DESIGN_SYSTEM.md). */
  --ds-icon-xs: 12px;
  --ds-icon-action: 16px;
  --ds-icon-control: 17px;
  --ds-icon-nav: 19px;
  --ds-icon-feature: 22px;
  /* Alias retrocompatibles (mismo valor, distinto nombre semantico --
     evita romper selectores existentes que ya consumian estos tokens). */
  --ds-icon-sm: var(--ds-icon-control);
  --ds-icon-md: var(--ds-icon-nav);
  --ds-icon-lg: var(--ds-icon-feature);
  --ds-table-row-compact: var(--ds-space-5);
  --ds-table-row-comfortable: var(--ds-space-6);

  --ds-focus-ring-width: 2px;
  --ds-focus-ring-input-width: 4px;
  --ds-focus-offset: 2px;

  --ds-button-padding-y-sm: 7px; --ds-button-padding-x-sm: 14px;
  --ds-button-padding-y-md: 10px; --ds-button-padding-x-md: 18px;
  --ds-button-padding-y-lg: 12px; --ds-button-padding-x-lg: 20px;
  --ds-button-icon-size-sm: var(--ds-icon-action); --ds-button-icon-size-md: var(--ds-icon-action); --ds-button-icon-size-lg: var(--ds-icon-control);
  --ds-button-active-offset: 1px; --ds-button-loading-size: 15px;
  --ds-button-loading-border-width: 2px; --ds-button-border-width: 1px;
  --ds-button-disabled-opacity: 0.55; --ds-button-padding-none: 0px; --ds-button-block-width: 100%;
  --ds-input-height-sm: var(--ds-control-sm); --ds-input-height-md: var(--ds-control-md); --ds-input-height-lg: var(--ds-control-lg);
  --ds-input-legacy-height: var(--ds-control-lg); --ds-input-width: 100%; --ds-input-border-width: 1px;
  --ds-input-padding-x-sm: 12px; --ds-input-padding-x-md: 14px; --ds-input-padding-x-lg: var(--ds-space-2);
  --ds-input-addon-offset: 14px; --ds-input-decorated-padding: var(--ds-control-md); --ds-input-icon-size: var(--ds-icon-sm);
  --ds-badge-padding-y-sm: 2px; --ds-badge-padding-x-sm: 10px;
  --ds-badge-padding-y-md: var(--ds-space-half); --ds-badge-padding-x-md: 12px;
  --ds-badge-font-size-sm: 11px; --ds-badge-font-size-md: var(--ds-fs-caption);
  --ds-badge-border-width: 1px; --ds-badge-disabled-opacity: var(--ds-button-disabled-opacity);
  --ds-modal-width-sm: 400px; --ds-modal-width-md: 480px; --ds-modal-width-lg: 720px;
  --ds-modal-viewport-gap: var(--ds-space-3);
  --ds-toast-width: 384px; --ds-toast-viewport-gap: var(--ds-space-3);
  --ds-toast-enter-duration: 150ms; --ds-toast-exit-duration: 150ms;
}


/* source: src/styles/colors.css */
/**
 * LM Contable — Design System v5.0 — Colores
 * Paleta cruda (escala numerica) + tokens semanticos que la consumen.
 * Ningun componente debe usar un valor hex/rgba literal: siempre var(--ds-*).
 *
 * v5.0: se elimina el dorado por completo. La referencia oficial
 * (C:\Users\lmartinez\Documents\Mejora\portaladmin-cliente.png) define una
 * paleta navy + azul + grises — el acento de marca pasa de
 * --ds-gold-500/-400/-300 a --ds-blue-600/-500/-400, y el rol semantico
 * "--ds-gold*" se renombra a "--ds-accent*" en todo el sistema (no se deja
 * un alias con nombre "gold" apuntando a azul, seria confuso). Se agrega
 * --ds-purple-500 como 5to color de graficas (azul ya es el acento de UI,
 * hacia falta un tono mas para que las 5 series de --ds-chart-* sigan
 * siendo distinguibles entre si). La escala de grises NO cambia: --ds-slate-100
 * (#F1F5F9) y --ds-slate-500 (#64748B) ya coincidian exactamente con la
 * referencia.
 */
:root {
  /* Explicito: controles nativos del navegador (checkbox/radio/select/inputs
     de fecha) en su variante clara por defecto. themes/dark.css sobreescribe
     a "dark" cuando corresponde. */
  color-scheme: light;
  /* ---- Paleta cruda: Primary (navy/slate) ---- */
  --ds-primary-950: #0D1117;
  --ds-primary-900: #111827;
  --ds-primary-800: #1F2937;
  --ds-primary-700: #334155;
  --ds-primary-600: #475569;

  /* ---- Paleta cruda: Azul (acento de marca) ---- */
  --ds-blue-700: #1D4ED8;
  --ds-blue-600: #2563EB;
  --ds-blue-500: #3B82F6;
  --ds-blue-400: #93C5FD;
  --ds-blue-100: #DBEAFE;
  --ds-blue-50: #EFF6FF;

  /* ---- Paleta cruda: Neutrales ---- */
  --ds-slate-50: #F8FAFC;
  --ds-slate-100: #F1F5F9;
  --ds-slate-200: #E2E8F0;
  --ds-slate-300: #CBD5E1;
  --ds-slate-400: #94A3B8;
  --ds-slate-500: #64748B;
  --ds-slate-900: #0F172A;
  --ds-white: #FFFFFF;
  --ds-transparent: transparent;

  /* ---- Paleta cruda: Estado ---- */
  --ds-green-600: #10B981;
  --ds-amber-500: #F59E0B;
  --ds-red-600: #EF4444;
  --ds-purple-500: #8B5CF6;
  /* Variante clara de purple-500 -- misma logica que --ds-blue-400 (pastel
     claro derivado del acento), usada como color de icono brillante sobre
     fondos tonales oscuros (ver --ds-icon-tile-purple-fg en themes/dark.css)
     donde --ds-purple-500 solo no tenia suficiente contraste. */
  --ds-purple-400: #C4B5FD;
  --ds-indigo-500: #6366F1;

  /* ================= TOKENS SEMANTICOS ================= */

  /* Superficies */
  --ds-bg: var(--ds-slate-50);
  --ds-bg-secondary: var(--ds-slate-100);
  --ds-surface: var(--ds-white);
  --ds-card-bg: var(--ds-white);
  --ds-border: var(--ds-slate-200);
  --ds-canvas: var(--ds-bg);
  --ds-surface-subtle: var(--ds-bg-secondary);
  /* Encabezado de tabla / hover de fila: en claro, igual que siempre (--ds-bg
     es mas oscuro que --ds-surface blanco, da el contraste sutil correcto).
     themes/dark.css los sobreescribe -- ver ese archivo para el porque. */
  --ds-table-header-bg: var(--ds-bg);
  --ds-table-row-hover-bg: var(--ds-bg-secondary);
  --ds-table-divider: var(--ds-border);

  /* Texto */
  --ds-text: var(--ds-slate-900);
  /* Sobre las superficies claras, los grises anteriores perdían contraste.
     Se conserva la jerarquía usando tonos ya existentes de la paleta. */
  --ds-text-secondary: var(--ds-primary-600);
  --ds-text-muted: var(--ds-slate-500);
  --ds-text-on-dark: #F8FAFC;
  --ds-text-on-dark-muted: rgba(255, 255, 255, 0.75);
  --ds-icon-on-dark: #94A3B8;
  --ds-text-subtle: var(--ds-text-secondary);
  --ds-text-inverse: var(--ds-text-on-dark);
  /* Alias legados (superficies aun no migradas a v5.0) — mismos valores, otro nombre */
  --ds-text-900: var(--ds-text);
  --ds-text-600: var(--ds-text-secondary);
  --ds-text-400: var(--ds-text-muted);

  /* Marca */
  --ds-navy: var(--ds-primary-900);
  --ds-navy-dark: var(--ds-primary-950);
  --ds-accent: var(--ds-blue-600);
  --ds-accent-dark: var(--ds-blue-500);
  --ds-accent-hover: var(--ds-blue-500);
  --ds-accent-light: var(--ds-blue-400);
  --ds-action: var(--ds-accent);
  --ds-action-hover: var(--ds-accent-hover);

  --ds-focus-ring-color: var(--ds-action);
  --ds-focus-ring-input-color: rgba(37, 99, 235, 0.15);
  --ds-input-border: var(--ds-slate-300);
  --ds-input-hover-border: var(--ds-text-muted);
  --ds-input-focus-border: var(--ds-action);
  --ds-input-focus-ring: var(--ds-focus-ring-input-color);
  --ds-input-error: var(--ds-danger);
  --ds-input-success: var(--ds-success);
  --ds-overlay: rgba(7, 17, 31, 0.6);
  /* Puente de compatibilidad temporal: admin-shell.css/dashboard-shell.css/
     portal-client-shell.css (Fase B, todavia sin migrar) referencian
     --ds-gold* directo. Apuntan a los tonos azules nuevos para que nada se
     vea dorado ni se rompa mientras se completa el renombrado fase a fase.
     Se retiran cuando esos 3 archivos dejen de usar estos nombres. */
  --ds-gold-500: var(--ds-blue-600);
  --ds-gold-400: var(--ds-blue-500);
  --ds-gold-300: var(--ds-blue-400);
  --ds-gold: var(--ds-accent);
  --ds-gold-dark: var(--ds-accent-dark);
  --ds-gold-hover: var(--ds-accent-hover);

  /* Estado (fondo suave derivado del propio color, nunca un hex inventado aparte) */
  --ds-success: var(--ds-green-600);
  --ds-success-bg: rgba(16, 185, 129, 0.12);
  --ds-warning: var(--ds-amber-500);
  --ds-warning-bg: rgba(245, 158, 11, 0.14);
  --ds-danger: var(--ds-red-600);
  --ds-danger-bg: rgba(239, 68, 68, 0.12);
  --ds-danger-hover: #B91C1C;
  --ds-info: var(--ds-blue-600);
  --ds-info-bg: rgba(37, 99, 235, 0.12);
  --ds-neutral: var(--ds-text-secondary);
  --ds-neutral-bg: var(--ds-bg-secondary);
  --ds-primary-badge-bg: var(--ds-action);
  --ds-primary-badge-text: var(--ds-text-inverse);
  --ds-success-badge-text: #065F46;
  --ds-warning-badge-text: #92400E;
  --ds-danger-badge-text: #991B1B;
  --ds-info-badge-text: var(--ds-info);
  --ds-neutral-badge-text: var(--ds-neutral);
  --ds-success-badge-border: rgba(16, 185, 129, 0.24);
  --ds-warning-badge-border: rgba(245, 158, 11, 0.26);
  --ds-danger-badge-border: rgba(239, 68, 68, 0.22);
  --ds-info-badge-border: rgba(37, 99, 235, 0.22);
  --ds-neutral-badge-border: var(--ds-border);
  /* --ds-purple-500 ya existia como 5to color de graficas; le falta su fondo
     suave para poder usarse tambien como acento de icono/badge (ver Reportes). */
  --ds-purple-bg: rgba(139, 92, 246, 0.14);
  --ds-purple-badge-text: #6B21A8;
  --ds-purple-badge-border: rgba(139, 92, 246, 0.26);
  /* Paleta de Estados (ver themes/dark.css para el porque de los 3 estados
     nuevos: Proximo a vencer/En revision/Informativo no tenian variante de
     dsBadge propia, se resolvian pisando 'warning'/'info'/'neutral' sin
     poder distinguirse entre si). Base clara con la misma formula que el
     resto (fondo rgba muy suave del color crudo + texto en su tono oscuro
     de contraste) -- el hex EXACTO de la referencia solo aplica en oscuro,
     ver themes/dark.css. */
  --ds-orange-bg: rgba(234, 88, 12, 0.14);
  --ds-orange-badge-text: #9A3412;
  --ds-orange-badge-border: rgba(234, 88, 12, 0.26);
  --ds-cyan-bg: rgba(8, 145, 178, 0.12);
  --ds-cyan-badge-text: #155E75;
  --ds-cyan-badge-border: rgba(8, 145, 178, 0.22);

  /* Rol "Administrador" (dsRoleBadge): clasificacion, no estado -- un azul
     LM deliberadamente mas tenue que --ds-info-* (que representa el estado
     "En proceso") para que un badge de ROL nunca se lea como un badge de
     ESTADO. Mismo --ds-blue-600 de --ds-info pero con menos de la mitad de
     opacidad de fondo/borde. */
  --ds-role-admin-bg: rgba(37, 99, 235, 0.07);
  --ds-role-admin-badge-text: var(--ds-blue-600);
  --ds-role-admin-badge-border: rgba(37, 99, 235, 0.14);

  /* Navegación (v6.1): un único rol cromático azul para TODO item de sidebar
     (Admin, Portal Cliente y Dashboard Financiero). Antes cada categoria de
     menu (operacion/proceso/finanzas/organizacion/administracion) tenia su
     propio color (verde, ambar, indigo, morado, gris) -- eso dejaba verde/
     ambar/rojo funcionando como simple "etiqueta de modulo" en vez de
     reservarse exclusivamente para estados funcionales (exito/advertencia/
     error). Referencia: mockup "OPCION 1 - AZUL LM". El atributo
     data-nav-category se mantiene en el HTML para agrupar items pero ya no
     selecciona color (ver admin-shell.css/portal-client-shell.css). */
  --ds-nav-icon: var(--ds-blue-600);
  --ds-nav-icon-bg: var(--ds-blue-50);
  --ds-nav-hover-icon: var(--ds-blue-700);
  --ds-nav-hover-bg: var(--ds-blue-100);
  --ds-nav-active-icon: var(--ds-blue-600);
  --ds-nav-active-bg: var(--ds-blue-50);
  --ds-nav-focus: var(--ds-focus-ring-color);

  --ds-success-hover: #15803D; --ds-warning-hover: #D97706;
  --ds-warning-contrast: var(--ds-primary-950);
  --ds-button-loading-track-inverse: rgba(255, 255, 255, 0.4); --ds-button-loading-track: rgba(15, 23, 42, 0.2);

  /* Graficas — unicamente estos 5 colores, nunca aleatorios (ver charts.css).
     Azul ya es el acento de UI, por eso la 3ra serie usa purpura en vez de
     azul otra vez -- si no, 3 de las 5 series compartirian tonalidad. */
  --ds-chart-primary: var(--ds-primary-700);
  --ds-chart-secondary: var(--ds-blue-600);
  --ds-chart-accent: var(--ds-purple-500);
  --ds-chart-success: var(--ds-green-600);
  --ds-chart-danger: var(--ds-red-600);

  /* Sidebar (regla global del sistema, ver layout.css). Se mantiene oscuro;
     el activo pasa de "borde izquierdo dorado" a una pildora azul solida. */
  --ds-sidebar-bg: var(--ds-primary-900);
  --ds-sidebar-text: rgba(255, 255, 255, 0.75);
  --ds-sidebar-icon: #94A3B8;
  --ds-sidebar-hover-bg: rgba(255, 255, 255, 0.06);
  --ds-sidebar-active-bg: var(--ds-blue-600);
  --ds-sidebar-active-border: var(--ds-blue-600);
  --ds-sidebar-active-text: #FFFFFF;
  --ds-sidebar-active-icon: #FFFFFF;

  /* Header (regla global del sistema, ver layout.css). v5.0: el header pasa
     de navy a blanco/claro -- unica superficie oscura que queda es el
     sidebar. */
  --ds-header-bg: var(--ds-white);
  --ds-header-border: var(--ds-slate-200);
  --ds-header-search-bg: var(--ds-slate-100);
  --ds-header-search-placeholder: var(--ds-text-muted);

  /* Header de .ds-modal (ver globals.css): en claro es --ds-navy fijo,
     franja oscura de sobra de contraste sobre el cuerpo blanco del modal
     (--ds-surface). En oscuro ese mismo --ds-navy se vuelve un token
     independiente para que themes/dark.css lo pueda reemplazar por un gris
     neutro -- ver ese archivo para el porque. */
  --ds-modal-header-bg: var(--ds-navy);
}

/* [data-theme="light"] explicito: identico a :root (default), para que un
   toggle futuro pueda alternar sin caso especial. Ver themes/light.css. */


/* source: src/styles/typography.css */
/**
 * LM Contable — Design System v5.0 — Tipografia
 * Unicamente Inter (pesos 300 Light/400/500/600/700 — sin 800), en toda la
 * interfaz incluidos los titulos. La referencia oficial
 * (portaladmin-cliente.png) solo muestra Inter con esa escala de pesos --
 * Satoshi (adoptado en un rebrand anterior) se retira por completo.
 */
:root {
  --ds-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --ds-fs-h1: 32px;
  --ds-fs-h2: 24px;
  --ds-fs-h3: 18px;
  --ds-fs-subtitle: 15px;
  --ds-fs-body: 14px;
  --ds-fs-caption: 12px;
  --ds-fs-button: 13px;
  --ds-fs-table-header: 12px;
  --ds-fs-input: 14px;

  --ds-fw-light: 300;
  --ds-fw-regular: 400;
  --ds-fw-medium: 500;
  --ds-fw-semibold: 600;
  --ds-fw-bold: 700;

  --ds-type-title-lg-size: var(--ds-fs-h1);
  --ds-type-title-size: var(--ds-fs-h2);
  --ds-type-subtitle-size: var(--ds-fs-h3);
  --ds-type-body-size: var(--ds-fs-body);
  --ds-type-label-size: var(--ds-fs-button);
  --ds-type-caption-size: var(--ds-fs-caption);
  --ds-type-control-compact-size: var(--ds-fs-caption);
  --ds-type-financial-size: var(--ds-fs-body);
  --ds-type-table-size: var(--ds-fs-caption);
  --ds-type-table-head-size: var(--ds-fs-table-header);
  --ds-type-kpi-size: 30px;
  --ds-type-financial-variant: tabular-nums;
  --ds-type-button-letter-spacing: 0.01em;
  --ds-type-label-letter-spacing: 0.03em;
}

.ds-scope,
.ds-scope input,
.ds-scope select,
.ds-scope textarea,
.ds-scope button {
  font-family: var(--ds-font);
}

.ds-h1 { font-size: var(--ds-fs-h1); font-weight: var(--ds-fw-bold); color: var(--ds-text); line-height: 1.2; margin: 0; letter-spacing: -0.01em; }
.ds-h2 { font-size: var(--ds-fs-h2); font-weight: var(--ds-fw-bold); color: var(--ds-text); line-height: 1.25; margin: 0; }
.ds-h3 { font-size: var(--ds-fs-h3); font-weight: var(--ds-fw-semibold); color: var(--ds-text); line-height: 1.3; margin: 0; }
.ds-subtitle { font-size: var(--ds-fs-subtitle); font-weight: var(--ds-fw-medium); color: var(--ds-text-secondary); margin: 0; }
.ds-text { font-size: var(--ds-fs-body); font-weight: var(--ds-fw-regular); color: var(--ds-text); }
.ds-caption { font-size: var(--ds-fs-caption); font-weight: var(--ds-fw-regular); color: var(--ds-text-muted); }


/* source: src/styles/spacing.css */
/**
 * LM Contable — Design System v3.0 — Espaciado
 * Escala de 8 puntos (8/16/24/32/40/48) con un unico medio-paso de 4px para
 * micro-espaciado (gap icono-texto, padding de badges) — practica estandar
 * en sistemas de 8pt (Material, etc.), no una excepcion arbitraria.
 */
:root {
  --ds-space-half: 4px;
  --ds-space-1: 8px;
  --ds-space-2: 16px;
  --ds-space-3: 24px;
  --ds-space-4: 32px;
  --ds-space-5: 40px;
  --ds-space-6: 48px;
  /* Pasos adicionales para layout de superficie completa (sidebars/paginas) */
  --ds-space-7: 64px;
  --ds-space-8: 80px;

  --ds-space-control-x: var(--ds-space-2);
  --ds-space-control-y: var(--ds-space-1);
  --ds-space-card-compact: var(--ds-space-2);
  --ds-space-card-comfortable: var(--ds-space-3);
  --ds-space-toolbar-gap: var(--ds-space-2);
  --ds-space-table-cell-compact: var(--ds-space-1);
  --ds-space-table-cell-comfortable: var(--ds-space-2);
  --ds-space-layout-gap: var(--ds-space-3);
}


/* source: src/styles/radius.css */
/**
 * LM Contable — Design System v3.0 — Border radius
 */
:root {
  --ds-radius-btn: 8px;
  --ds-radius-input: 12px;
  --ds-radius-card: 16px;
  --ds-radius-modal: 20px;
  --ds-radius-dropdown: 12px;
  --ds-radius-badge: 999px;

  --ds-radius-button: var(--ds-radius-btn);
  --ds-radius-control: var(--ds-radius-input);
  --ds-radius-pill: var(--ds-radius-badge);
}


/* source: src/styles/shadows.css */
/**
 * LM Contable — Design System v3.0 — Sombras
 * Solo 3 niveles.
 * "sm"/"md" (ambiental, tarjetas/superficies en reposo y su estado
 * elevado/hover) eliminadas -- armonizacion 2026-09-07, direccion
 * "Combinada"/B (Linear): la jerarquia la da el borde + el tono de
 * superficie, no la sombra. Reemplaza la sombra ambiental claramente
 * visible pedida el 2026-08-23 (ver historial), que fue el punto de
 * partida de esta armonizacion pero ya no es la direccion elegida -- se
 * baja el token a un valor "cero" valido (no la palabra `none`: varias
 * reglas componen --ds-shadow-sm en una lista con otra capa, ej.
 * .admin-avatar, .admin-card.is-highlighted -- `none` ahi invalidaria
 * toda la propiedad) en vez de sobreescribir cada selector, asi toda
 * superficie que ya consume --ds-shadow-sm/-md (.ds-card, .admin-card,
 * .card, tabs activos, filter-bar, etc., en los 3 portales) hereda el
 * cambio sin tocar cada regla una por una. dark.css sobreescribe sm/md
 * de la misma forma, sin cambios aca.
 * "lg" (modales/toasts, overlay real sobre el resto de la pagina) sin
 * tocar -- sigue siendo funcionalmente necesaria para separar ese
 * contenido flotante del resto, a diferencia de la sombra decorativa de
 * una tarjeta en reposo.
 */
:root {
  --ds-shadow-sm: 0 0 0 0 rgba(2, 6, 23, 0);
  --ds-shadow-md: 0 0 0 0 rgba(2, 6, 23, 0);
  --ds-shadow-lg: 0 24px 60px rgba(2, 6, 23, 0.14);

  --ds-shadow-rest: var(--ds-shadow-sm);
  --ds-shadow-raised: var(--ds-shadow-md);
  --ds-shadow-overlay: var(--ds-shadow-lg);
  --ds-shadow-input-focus: 0 0 0 var(--ds-focus-ring-input-width) var(--ds-input-focus-ring);
}


/* source: src/styles/animations.css */
/**
 * LM Contable — Design System v3.0 — Animaciones
 * Una sola duracion/easing para toda transicion: 220ms ease. Sin efectos
 * exagerados. Se mantienen 3 nombres (fast/base/slow) para no romper a los
 * consumidores existentes, pero las tres valen lo mismo por diseno.
 */
:root {
  --ds-ease: ease;
  --ds-transition-fast: 0.22s var(--ds-ease);
  --ds-transition-base: 0.22s var(--ds-ease);
  --ds-transition-slow: 0.22s var(--ds-ease);

  --ds-motion-fast: var(--ds-transition-fast);
  --ds-motion-base: var(--ds-transition-base);
  --ds-motion-slow: var(--ds-transition-slow);
  --ds-button-loading-motion: 700ms linear;
}

@keyframes ds-spin { to { transform: rotate(360deg); } }
@keyframes ds-fade-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
@keyframes ds-slide-in { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: translateX(0); } }
@keyframes ds-skeleton-shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }

.ds-fade-in { animation: ds-fade-in var(--ds-transition-base); }

/* Icono "loader-circle" (Lucide) usado como spinner de carga suelto dentro de
   un botón -- `<i data-lucide="loader-circle">Texto…</i>`, sin ningún wrapper
   propio -- en más de 10 lugares de la app (ej. "Conciliar" en
   Conciliaciones, reportado en vivo: el ícono se quedaba estático). Lucide
   conserva el atributo data-lucide en el <svg> que genera, así que este
   selector alcanza el ícono ya hidratado sin tener que tocar cada call site
   por separado. */
[data-lucide="loader-circle"] { animation: ds-spin var(--ds-button-loading-motion) infinite; }

@media (prefers-reduced-motion: reduce) {
  .ds-fade-in,
  .ds-spinner,
  .ds-btn-loading::after,
  .ds-input-control.is-loading::after,
  .ds-switch-loading .ds-switch-track::after,
  .spinner-block::before,
  #eeffAnnexUploadStatus svg,
  .admin-progress-head .label svg,
  [data-lucide="loader-circle"],
  .payroll-view,
  .tab-panel.active {
    animation: none !important;
  }
  .ds-modal-overlay,
  .ds-modal-overlay .ds-modal { transition: none !important; }
}


/* source: src/styles/themes/light.css */
/**
 * LM Contable — Design System v3.0 — Tema claro (default)
 * Identico a los valores de :root en colors.css. Existe como archivo propio
 * para que la arquitectura de temas quede completa (:root / [data-theme=light]
 * / [data-theme=dark]) aunque hoy :root ya sea claro por defecto — un futuro
 * toggle puede setear data-theme="light" explicitamente sin caso especial.
 */
:root[data-theme="light"] {
  color-scheme: light;
  --ds-bg: var(--ds-slate-50);
  --ds-bg-secondary: var(--ds-slate-100);
  --ds-surface: var(--ds-white);
  --ds-card-bg: var(--ds-white);
  --ds-border: var(--ds-slate-200);
  --ds-text: var(--ds-slate-900);
  --ds-text-secondary: var(--ds-slate-500);
  --ds-text-muted: var(--ds-slate-400);
}


/* source: src/styles/themes/dark.css */
/**
 * LM Contable — Design System v3.0 — Tema oscuro
 * Activado por primera vez por el toggle de tema (ver ui.js: toggleTheme/
 * applyStoredTheme). El comentario original de este archivo asumia que
 * "sidebar/header no cambian, ya son oscuros en el tema claro" -- ya no es
 * cierto: v5.0/v6.1 (colors.css/admin-shell.css/dashboard-shell.css/
 * portal-client-shell.css) movieron el sidebar a --ds-bg-secondary (franja
 * clara en tema claro, igual que el resto de la UI) y el header a
 * --ds-header-bg: var(--ds-white) -- ninguno de los dos queda fijo oscuro,
 * los dos necesitan su propia contraparte explicita aca.
 */
:root[data-theme="dark"] {
  /* Controles nativos del navegador (checkbox/radio sin marcar, selects,
     inputs de fecha/hora, scrollbars): sin esto el navegador siempre los
     dibuja con su widget CLARO por defecto sin importar --ds-*, sea cual sea
     el tema -- el checkbox "Estos son los primeros estados financieros..."
     quedaba como cuadrado blanco fijo sobre fondo oscuro (reportado, mismo
     patron para cualquier otro checkbox/radio nativo del sistema). Con
     color-scheme:dark el navegador usa su propia paleta oscura para esos
     widgets nativos -- accent-color (ya seteado en .ds-checkbox/.ds-radio,
     forms.css) sigue controlando el color de "marcado". */
  color-scheme: dark;
  /* Neutro (gris casi negro), no navy -- pedido explicito: "que se pueda
     diferenciar mas facil", tomando como referencia la interfaz oscura de
     claude.ai (gris neutro, no azulado). Antes estos 5 tokens partian de
     --ds-primary-950/-900 (navy) escalados a mano; con tono neutro las
     superficies (sidebar/tarjeta/input) se distinguen por LUMINOSIDAD sola,
     sin que el tinte azul de fondo compita con los acentos azules de UI
     (--ds-accent, nav activo, etc.) ni con los badges de estado. */
  --ds-bg: #171717;
  --ds-bg-secondary: #1E1E1E;
  --ds-surface: #262626;
  --ds-card-bg: #262626;
  --ds-border: #383838;
  --ds-text: #EDEDED;
  --ds-text-secondary: #B0B0B0;
  --ds-text-muted: #828282;

  /* Encabezado de tabla: pedido explicito de "encabezado integrado al
     fondo, sin bloques grises pesados" -- el paso anterior (un token propio
     mas claro que --ds-surface) ya arreglaba el "rectangulo negro" pero
     seguia siendo un bloque de color distinguible. Ahora el header usa
     LITERALMENTE --ds-surface (identico al cuerpo/tarjeta de la tabla): sin
     costura visible, la distincion queda solo en tipografia (mayuscula +
     texto secundario) y el divisor inferior. Opaco a proposito (no
     transparent) porque este mismo token tambien pinta celdas de header
     sticky (#tab-eeffparams, .recon-review-table) que necesitan tapar filas
     desplazandose debajo -- transparent rompia ese enmascarado. */
  --ds-table-header-bg: var(--ds-surface);
  /* Hover de fila: overlay translucido en vez de un color plano -- pedido
     explicito "apenas perceptible". Un overlay se compone igual de sutil
     sobre --ds-surface (tabla) o --ds-card-bg (mismo valor) sin depender de
     acertar un hex exacto un paso mas claro. */
  --ds-table-row-hover-bg: rgba(255, 255, 255, 0.035);
  /* Separadores horizontales de tabla: --ds-border (#383838) es el borde
     ESTRUCTURAL del sistema (tarjetas, inputs, contenedor de la tabla) --
     con suficiente contraste para delimitar superficies. Pedido explicito
     "separadores muy suaves" para las lineas INTERNAS entre filas/header:
     overlay translucido, mucho mas discreto que --ds-border, sin necesidad
     de otro hex fijo. */
  --ds-table-divider: rgba(255, 255, 255, 0.06);

  /* Fondos suaves de icono/badge: en claro son rgba(color, .X) porque el
     compositor siempre mezcla contra blanco/casi-blanco (el fondo real detrás
     no importa demasiado, todo da un pastel claro reconocible). En oscuro esa
     misma rgba mezcla contra lo que sea que haya detrás -- una tarjeta
     (--ds-surface, mas clara) da un chip visible, pero directo sobre
     --ds-bg/--ds-bg-secondary (mas oscuros) el mismo chip queda casi negro y
     el icono/texto encima pierde nitidez (reportado: "los iconos pierden
     detalle"). Antes esto se resolvia con color-mix(30%, --ds-surface) --
     un chip visible pero sin control fino de contraste WCAG. Se reemplaza por
     "Paleta de Estados - Modo Oscuro" (hex exacto, calibrado a mano para
     AA): 8 estados con fondo/texto/borde propios en vez de 4 formulas
     derivadas + grises genericos para "neutral". Completado/Al dia=success,
     En proceso/Activo=info (mismo azul que ya se usaba), Pendiente=warning,
     Vencido/Critico=danger se RECALIBRAN; Proximo a vencer=orange,
     En revision=purple, Informativo=cyan son estados NUEVOS (antes no
     tenian variante de dsBadge propia); Borrador/Inactivo=neutral pasa de
     grises genericos (--ds-bg-secondary/--ds-text-secondary, aun usados en
     mas contextos que solo badges) a su propio trio calibrado. */
  --ds-success-bg: #0D2D25;
  --ds-success-badge-text: #34D399;
  --ds-success-badge-border: #166B55;

  --ds-info-bg: #132A4F;
  --ds-info-badge-text: #60A5FA;
  --ds-info-badge-border: #2457A6;

  --ds-warning-bg: #332A12;
  --ds-warning-badge-text: #FBBF24;
  --ds-warning-badge-border: #725815;

  --ds-orange-bg: #38200F;
  --ds-orange-badge-text: #FB923C;
  --ds-orange-badge-border: #85430F;

  --ds-danger-bg: #351417;
  --ds-danger-badge-text: #F87171;
  --ds-danger-badge-border: #7F2B32;

  --ds-purple-bg: #291A47;
  --ds-purple-badge-text: #C084FC;
  --ds-purple-badge-border: #62359B;

  /* #252A31 original quedaba casi identico a --ds-card-bg/--ds-surface
     (#262626 los dos) -- el relleno del badge no se distinguia de la
     tarjeta/tabla detras (reportado: "Inactivo no tiene color", visible en
     Cliente/Contador via dsRoleBadge, que reusa este mismo trio). Se sube
     la luminosidad del fondo sin salir de gris puro (sin tinte) para que el
     pill se lea como tal contra cualquier superficie oscura del sistema. */
  --ds-neutral-bg: #333A44;
  --ds-neutral-badge-text: #AEB6C2;
  --ds-neutral-badge-border: #4C5461;

  --ds-cyan-bg: #102E38;
  --ds-cyan-badge-text: #67E8F9;
  --ds-cyan-badge-border: #216271;

  /* Rol "Administrador" (dsRoleBadge): mismo criterio que en colors.css --
     azul LM deliberadamente mas apagado que --ds-info-* (estado "En
     proceso"), para que el badge de ROL nunca se confunda con un badge de
     ESTADO. */
  --ds-role-admin-bg: #1B2333;
  --ds-role-admin-badge-text: #8FB4E8;
  --ds-role-admin-badge-border: #33415C;

  /* sm/md aplanadas igual que en claro (ver shadows.css, armonizacion
     2026-09-07) -- valor "cero" valido, no `none`, por las reglas que
     componen --ds-shadow-sm en una lista junto a otra capa. lg (overlay
     real: modales/toasts) se queda igual, mas fuerte que en claro. */
  --ds-shadow-sm: 0 0 0 0 rgba(0, 0, 0, 0);
  --ds-shadow-md: 0 0 0 0 rgba(0, 0, 0, 0);
  --ds-shadow-lg: 0 24px 60px rgba(0, 0, 0, 0.55);

  /* Header: v5.0 lo puso blanco (--ds-header-bg: var(--ds-white)) para el
     tema claro sin agregar contraparte oscura -- sin esto es el "parche
     blanco" mas visible del sistema, la unica franja clara sobre fondo
     oscuro en Admin/Portal Cliente/Dashboard. */
  --ds-header-bg: var(--ds-surface);
  --ds-header-border: var(--ds-border);
  --ds-header-search-bg: var(--ds-bg-secondary);
  --ds-header-search-placeholder: var(--ds-text-muted);

  /* Chips de icono tonales (KPI, Acciones Rapidas, listas de estado, etc. en
     TODOS los portales/modulos -- ver admin-shell.css/portal-client-shell.css/
     dashboard-shell.css/cards.css). v2 -- pedido explicito 2026-08-23 con
     referencia visual adjunta (lmcontable_iconos_dark_neutral.html): "el
     color debe estar principalmente en el icono", no en el contenedor. El
     tratamiento anterior (fondo tonal semitransparente MEZCLADO con el color
     de cada variante, ver comentario que reemplaza este) se cambia por un
     fondo NEUTRO -- --ds-icon-tile-neutral-bg/-border, compartido por las 7
     variantes -- y el color queda solo en el simbolo + un acento inferior
     corto (2px, mismo color del icono) para no perder la identificacion
     rapida por color que ya tenian las tarjetas. Sin glow permanente: el
     token *-shadow queda en `none` (antes era una sombra de color por
     variante). Los 4 tokens por variante (bg/fg/border/shadow) siguen siendo
     el UNICO punto de entrada -- ningun consumidor cambia, todos ya leen
     `background/color/border/box-shadow: var(--ds-icon-tile-X-*)`.
     El acento inferior se logra apilando una segunda capa en `background`
     (un linear-gradient degradado del color del icono a si mismo, recortado
     a 2px de alto y ~46% de ancho, centrado abajo) en vez de un
     pseudo-elemento -- asi no hace falta `position:relative` ni duplicar
     selectores en cada shell para dibujarlo. */
  --ds-icon-tile-neutral-bg: #292929;
  --ds-icon-tile-neutral-border: #3A3A3A;
  --ds-icon-tile-hover-bg: #2E2E2E;
  /* Duracion pedida explicita (~180ms), token propio en vez de reusar
     --ds-transition-fast (220ms, animations.css) porque el pedido fue
     puntual para este componente, no un cambio general de timing. */
  --ds-icon-tile-transition: 180ms ease;

  --ds-icon-tile-info-fg: #60A5FA;
  --ds-icon-tile-info-bg: linear-gradient(var(--ds-icon-tile-info-fg), var(--ds-icon-tile-info-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-info-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-info-shadow: none;
  --ds-icon-tile-info-hover-border: color-mix(in srgb, var(--ds-icon-tile-info-fg) 40%, var(--ds-icon-tile-neutral-border));

  --ds-icon-tile-success-fg: #34D399;
  --ds-icon-tile-success-bg: linear-gradient(var(--ds-icon-tile-success-fg), var(--ds-icon-tile-success-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-success-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-success-shadow: none;
  --ds-icon-tile-success-hover-border: color-mix(in srgb, var(--ds-icon-tile-success-fg) 40%, var(--ds-icon-tile-neutral-border));

  --ds-icon-tile-warning-fg: #FBBF24;
  --ds-icon-tile-warning-bg: linear-gradient(var(--ds-icon-tile-warning-fg), var(--ds-icon-tile-warning-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-warning-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-warning-shadow: none;
  --ds-icon-tile-warning-hover-border: color-mix(in srgb, var(--ds-icon-tile-warning-fg) 40%, var(--ds-icon-tile-neutral-border));

  --ds-icon-tile-danger-fg: #F87171;
  --ds-icon-tile-danger-bg: linear-gradient(var(--ds-icon-tile-danger-fg), var(--ds-icon-tile-danger-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-danger-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-danger-shadow: none;
  --ds-icon-tile-danger-hover-border: color-mix(in srgb, var(--ds-icon-tile-danger-fg) 40%, var(--ds-icon-tile-neutral-border));

  /* Violeta y cyan: la referencia visual pide un tono de ICONO distinto al
     que ya usan los badges de texto (--ds-purple-badge-text/--ds-cyan-
     badge-text, Paleta de Estados de mas arriba) -- se fija hex propio en
     vez de reusar esos tokens, para que los BADGES de estado ("En
     revision"/"Informativo") no cambien de color, solo el ICONO. */
  --ds-icon-tile-purple-fg: #A78BFA;
  --ds-icon-tile-purple-bg: linear-gradient(var(--ds-icon-tile-purple-fg), var(--ds-icon-tile-purple-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-purple-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-purple-shadow: none;
  --ds-icon-tile-purple-hover-border: color-mix(in srgb, var(--ds-icon-tile-purple-fg) 40%, var(--ds-icon-tile-neutral-border));

  --ds-icon-tile-orange-fg: #FB923C;
  --ds-icon-tile-orange-bg: linear-gradient(var(--ds-icon-tile-orange-fg), var(--ds-icon-tile-orange-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-orange-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-orange-shadow: none;
  --ds-icon-tile-orange-hover-border: color-mix(in srgb, var(--ds-icon-tile-orange-fg) 40%, var(--ds-icon-tile-neutral-border));

  --ds-icon-tile-cyan-fg: #22D3EE;
  --ds-icon-tile-cyan-bg: linear-gradient(var(--ds-icon-tile-cyan-fg), var(--ds-icon-tile-cyan-fg)) no-repeat bottom center / 46% 2px, var(--ds-icon-tile-neutral-bg);
  --ds-icon-tile-cyan-border: var(--ds-icon-tile-neutral-border);
  --ds-icon-tile-cyan-shadow: none;
  --ds-icon-tile-cyan-hover-border: color-mix(in srgb, var(--ds-icon-tile-cyan-fg) 40%, var(--ds-icon-tile-neutral-border));

  /* Graficas: --ds-chart-primary (navy oscuro, colors.css) se pensaba como
     "el color mas neutro" sobre fondo claro; sobre fondo oscuro pierde
     contraste frente a --ds-bg. Se aclara solo para este tema; el resto de
     --ds-chart-* (azul/purpura/verde/rojo) ya son suficientemente
     luminosos y se mantienen iguales en ambos temas. */
  --ds-chart-primary: var(--ds-text-secondary);

  /* Navegacion del sidebar (v6.1, colors.css): --ds-nav-icon-bg/-hover-bg/
     -active-bg son azules pastel (blue-50/blue-100) pensados para el sidebar
     claro -- sin overrides quedan como parches casi blancos sobre el sidebar
     oscuro (el item activo/hover es el mas visible: toda la fila queda con
     una pastilla blanquecina). Se reemplazan por el mismo azul translucido
     que ya usan los badges (--ds-info-bg), con mas opacidad para el estado
     activo/hover que para el reposo. */
  --ds-nav-icon-bg: rgba(37, 99, 235, 0.16);
  --ds-nav-hover-bg: rgba(37, 99, 235, 0.24);
  --ds-nav-active-bg: rgba(37, 99, 235, 0.28);

  /* Iconos/texto del sidebar (reposo, hover y activo): en claro son azules
     (--ds-blue-600/-700) sobre una pastilla tambien azul muy palida, con
     contraste de sobra. En oscuro la pastilla es un azul translucido sobre
     el propio sidebar oscuro (arriba) -- un icono/texto TAMBIEN azul se
     mezclaba con su propia pastilla y costaba distinguirlo (reportado). Se
     iguala a --ds-text (blanco casi puro, mismo tono que el resto del texto
     oscuro) para que la pastilla de color siga marcando el estado pero el
     icono/texto quede nitido encima. */
  --ds-nav-icon: var(--ds-text);
  --ds-nav-hover-icon: var(--ds-text);
  --ds-nav-active-icon: var(--ds-text);

  /* Overlay de modal: colors.css lo deja fijo en rgba(7,17,31,.6) (navy),
     pensado para oscurecer un fondo CLARO al abrir un modal. En oscuro ese
     mismo tinte navy se suma al fondo ya oscuro y se veia como si toda la
     pantalla detras del modal "se pusiera navy" (reportado). Se cambia a un
     gris neutro casi negro, consistente con el resto de la paleta oscura de
     arriba. */
  --ds-overlay: rgba(10, 10, 10, 0.7);

  /* Header de .ds-modal: colors.css lo fija en --ds-navy (#111827), pensado
     para dar contraste sobre el cuerpo blanco del modal en tema claro. En
     oscuro ese mismo navy queda pegado como una franja azulada encima del
     gris neutro del resto de la superficie (reportado: "la barra del
     titulo se ve azul navy" en las vistas previas de documentos). Se
     reemplaza por --ds-bg-secondary -- mas oscuro que el cuerpo del modal
     (--ds-surface), asi que el header se sigue distinguiendo del cuerpo
     por LUMINOSIDAD (misma logica que el resto de este archivo), sin
     tinte azul. */
  --ds-modal-header-bg: var(--ds-bg-secondary);
}


/* source: src/styles/themes/brand.css */
/**
 * LM Contable — Design System v5.0 — Multi-tenant (data-brand)
 * Arquitectura lista para clientes adicionales. Cada marca solo puede
 * sobreescribir acento/boton-primario/enlaces-activos/graficas — nunca
 * --ds-primary-* (la identidad navy de LM Contable se mantiene siempre).
 * Nada activa esto hoy: no hay ningun `data-brand` seteado desde la UI.
 * Selectores por atributo (no `:root[data-brand]`) a proposito: heredan igual
 * si se setea en `<html>` (uso real, global) pero tambien permiten previsualizar
 * una marca en un contenedor acotado (ej. la seccion 14 de style-guide.html).
 *
 * v5.0: el acento de marca ya no se deriva de --ds-gold-500/--ds-chart-gold
 * (v4.0, dorado) sino de --ds-accent/--ds-accent-hover/--ds-accent-dark y
 * --ds-chart-secondary directamente (ver colors.css) — por eso cada marca
 * ahora sobreescribe esos tokens en vez de los antiguos. --ds-gold-500/-400/
 * -300/-hover se sobreescriben tambien, solo para que portal-client-shell.css
 * (que aun conserva un puñado de referencias directas a --ds-gold, pendientes
 * de migrar) se mantenga consistente si alguna vez se activa una marca.
 * Convencion de hover heredada del acento base (ver --ds-blue-600/-500): mas
 * claro al hacer hover, no mas oscuro como en la v4.0 dorada.
 *
 * Los valores de serport/multiservicios/cliente son PLACEHOLDERS ilustrativos
 * — reemplazar por la paleta real de cada cliente antes de activarlos.
 */
[data-brand="lm"] {
  /* Explicito: LM Contable = la paleta azul por defecto, sin overrides. */
}

[data-brand="serport"] {
  --ds-accent: #2A9D8F;
  --ds-accent-hover: #3DB3A5;
  --ds-accent-dark: #238176;
  --ds-accent-light: #5FC9BC;
  --ds-gold-500: var(--ds-accent);
  --ds-gold-400: var(--ds-accent-hover);
  --ds-gold-300: var(--ds-accent-light);
  --ds-gold-hover: var(--ds-accent-hover);
  --ds-chart-secondary: var(--ds-accent);
  --ds-sidebar-active-bg: var(--ds-accent);
  --ds-sidebar-active-border: var(--ds-accent);
  --ds-sidebar-active-icon: #FFFFFF;
}

[data-brand="multiservicios"] {
  --ds-accent: #7C5CBF;
  --ds-accent-hover: #9174CE;
  --ds-accent-dark: #664DA3;
  --ds-accent-light: #A996DD;
  --ds-gold-500: var(--ds-accent);
  --ds-gold-400: var(--ds-accent-hover);
  --ds-gold-300: var(--ds-accent-light);
  --ds-gold-hover: var(--ds-accent-hover);
  --ds-chart-secondary: var(--ds-accent);
  --ds-sidebar-active-bg: var(--ds-accent);
  --ds-sidebar-active-border: var(--ds-accent);
  --ds-sidebar-active-icon: #FFFFFF;
}

[data-brand="cliente"] {
  --ds-accent: #64748B;
  --ds-accent-hover: #7C8CA3;
  --ds-accent-dark: #52606F;
  --ds-accent-light: #94A3B8;
  --ds-gold-500: var(--ds-accent);
  --ds-gold-400: var(--ds-accent-hover);
  --ds-gold-300: var(--ds-accent-light);
  --ds-gold-hover: var(--ds-accent-hover);
  --ds-chart-secondary: var(--ds-accent);
  --ds-sidebar-active-bg: var(--ds-accent);
  --ds-sidebar-active-border: var(--ds-accent);
  --ds-sidebar-active-icon: #FFFFFF;
}


/* source: src/styles/globals.css */
/**
 * LM Contable — Design System v3.0 — Globals
 * Reset base, scrollbar, foco accesible, y componentes de overlay
 * (modal/dropdown/toast) que no tienen archivo dedicado propio.
 */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--ds-bg);
  color: var(--ds-text);
  font-family: var(--ds-font);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; }
button, input, select, textarea { font: inherit; }

/* Estandarizacion global de iconos (referencia: Iconos-v2.png) -- stroke
   uniforme para los 428 <i data-lucide> del sistema (Admin + Portal
   Cliente) desde un unico punto. Lucide le agrega la clase "lucide" a
   cada <svg> que genera (ver initLucideAutoRefresh en ui.js); el
   "stroke-width" via CSS le gana al atributo SVG que Lucide escribe
   inline, asi que esta regla cubre las ~40 llamadas a createIcons()
   repartidas por admin.js/portal-client.js sin tener que tocar (ni
   sincronizar) cada una. 1.75 (dentro del rango 1.75-2 pedido) da un
   trazo mas fino/sobrio que el default de Lucide (2), consistente con la
   referencia visual. Los tamanos siguen el tramo de cada contexto (ver
   --ds-icon-action/control/nav/feature en tokens.css); esta regla NO fija
   width/height. */
.lucide { stroke-width: 1.75; }
.ds-sidebar-backdrop { display: none; }

/* Los hijos visuales no interceptan el clic: el área activa es todo el botón. */
.ds-scope button > *,
.ds-scope [role="button"] > * { pointer-events: none; }

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--ds-slate-200); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--ds-text-muted); }

/* Foco accesible: azul, 2px, con offset — nunca se suprime sin reemplazo */
.ds-scope :focus-visible {
  outline: 2px solid var(--ds-accent);
  outline-offset: 2px;
}

/* ============================== MODALES ============================== */
.ds-modal-overlay {
  position: fixed; inset: 0; z-index: var(--ds-z-modal);
  display: flex; align-items: center; justify-content: center;
  /* Antes tambien backdrop-filter: blur(2px) -- se quita: obliga al navegador
     a recomponer/desenfocar TODO lo que hay detras del modal (una tabla
     grande, un formulario con muchos campos) durante la transicion de
     apertura, lo que se sentia como un modal lento de abrir precisamente en
     las pantallas con mas contenido detras (parametros/conceptos de Nomina).
     El fondo semitransparente por si solo ya separa visualmente el modal. */
  background: var(--ds-overlay);
  padding: var(--ds-space-2);
  opacity: 0; pointer-events: none;
  transition: opacity var(--ds-transition-base);
}
.ds-modal-overlay.is-open { opacity: 1; pointer-events: auto; }
/* confirmAction()/openReasonPrompt() pueden abrirse ENCIMA de otro modal ya
   abierto (ej. togglear activo/inactivo desde dentro del modal de edición,
   ver *DesdeEdicion en admin.js) -- todos los .ds-modal-overlay comparten el
   mismo z-index base, así que sin esto el orden de pintado lo decide el
   orden en el DOM (quién se declaró último en el HTML), no cuál se abrió
   último, y el diálogo de confirmación podía quedar oculto detrás del modal
   de edición. */
#modalConfirmAction, #modalReasonPrompt, #modalDocumentAlertConfig { z-index: calc(var(--ds-z-modal) + 10); }
.ds-modal {
  background: var(--ds-surface);
  border-radius: var(--ds-radius-modal);
  box-shadow: var(--ds-shadow-lg);
  width: 100%;
  max-width: var(--ds-modal-width-md);
  max-height: calc(100dvh - var(--ds-modal-viewport-gap));
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transform: translateY(8px) scale(0.98);
  transition: transform var(--ds-transition-base);
}
.ds-modal-overlay.is-open .ds-modal { transform: translateY(0) scale(1); }
.ds-modal-sm { max-width: var(--ds-modal-width-sm); }
.ds-modal-md { max-width: var(--ds-modal-width-md); }
.ds-modal-lg { max-width: var(--ds-modal-width-lg); }
.ds-modal-header {
  display: flex; align-items: center; justify-content: space-between;
  /* Vertical mas chico que el resto de la escala (--ds-space-2 es 16px,
     quedaba en 61-63px de alto total con los botones de accion del header --
     reportado como "muy grande") -- 10px es un valor propio, no hay token de
     espaciado entre 8px y 16px que calce. Los botones (Descargar/cerrar) NO
     cambian de tamano, solo el aire alrededor. La media query de 640px mas
     abajo (touch target de 54px) sigue pisando este valor sin cambios. */
  padding: 10px var(--ds-space-3);
  background: var(--ds-modal-header-bg); color: var(--ds-white);
}
/* --ds-fs-h3 (18px) quedaba grande para una barra ya mas baja -- un escalon
   abajo en la misma escala tipografica (--ds-fs-subtitle, 15px), pedido
   explicito ("reduce tambien un poco el tamaño de la fuente"). */
.ds-modal-header h3 { font-size: var(--ds-fs-subtitle); font-weight: var(--ds-fw-bold); margin: 0; color: var(--ds-white); }
.ds-modal-description { margin: var(--ds-space-half) 0 0; color: var(--ds-text-on-dark-muted); font-size: var(--ds-fs-caption); }
/* Icono "X": cierra el modal -- mismo cierre que ya dispara la tecla Escape
   (ver setupModalDismissal en admin.js/portal-client.js); el icono es solo
   la superficie de mouse/touch, Escape sigue funcionando igual. color:inherit
   + fondo neutro semi-transparente a proposito: este boton vive tanto en
   headers oscuros (--ds-navy, admin) como claros (blanco, portal-client) y
   debe leerse bien en ambos sin necesitar una regla por superficie. */
.ds-modal-close {
  background: rgba(127, 127, 127, 0.16);
  border: 1px solid rgba(127, 127, 127, 0.32);
  color: inherit;
  cursor: pointer;
  padding: 7px;
  border-radius: var(--ds-radius-btn);
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  transition: background var(--ds-transition-fast), border-color var(--ds-transition-fast);
}
.ds-modal-close svg { width: 14px; height: 14px; }
.ds-modal-close:hover { background: rgba(127, 127, 127, 0.3); border-color: rgba(127, 127, 127, 0.45); }
.ds-modal-body { padding: var(--ds-space-3); overflow-y: auto; }
.ds-modal-footer { display: flex; justify-content: flex-end; gap: var(--ds-space-1); padding: var(--ds-space-2) var(--ds-space-3); border-top: 1px solid var(--ds-border); }
.ds-modal[aria-busy="true"] .ds-modal-body { opacity: var(--ds-button-disabled-opacity); }

/* ============================== DRAWER LATERAL ==============================
   Panel de detalle superpuesto desde la derecha (ver openDrawer()/closeDrawer()
   en ui.js). Mismo overlay que .ds-modal-overlay (mismo z-index, mismo fondo)
   pero el panel desliza desde el borde derecho en vez de aparecer centrado --
   calcado del off-canvas .mobile-open que ya usa el sidebar (ver
   .admin-sidebar.mobile-open). Nunca reflowea el layout de fondo: es un
   elemento `position:fixed` fuera del flujo normal del documento. */
.ds-drawer-overlay {
  position: fixed; inset: 0; z-index: var(--ds-z-modal);
  background: var(--ds-overlay);
  display: flex; justify-content: flex-end;
  opacity: 0; pointer-events: none;
  transition: opacity var(--ds-transition-base);
}
.ds-drawer-overlay.is-open { opacity: 1; pointer-events: auto; }
.ds-drawer {
  width: min(460px, 100vw);
  height: 100%;
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-lg);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform var(--ds-transition-base);
}
.ds-drawer-overlay.is-open .ds-drawer { transform: translateX(0); }
.ds-drawer-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px var(--ds-space-3);
  background: var(--ds-modal-header-bg); color: var(--ds-white);
  flex: 0 0 auto;
}
.ds-drawer-header-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ds-drawer-header h3 { font-size: var(--ds-fs-subtitle); font-weight: var(--ds-fw-bold); margin: 0; color: var(--ds-white); }
/* opts.icon (ver openDrawer() en ui.js) -- vacio (sin markup) cuando el
   caller no lo pide, asi que no ocupa espacio ni deja un hueco. */
.ds-drawer-header-icon:empty { display: none; }
.ds-drawer-header-icon {
  display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; flex-shrink: 0;
  border-radius: 8px; background: rgba(255, 255, 255, .12); color: var(--ds-white);
}
.ds-drawer-header-icon svg { width: 16px; height: 16px; }
.ds-drawer-body { padding: var(--ds-space-3); overflow-y: auto; flex: 1; }
/* Variante ancha (~80vw, tope 1200px en pantallas grandes) -- contenido que
   necesita mas aire que el panel de detalle default (ej. un PDF completo),
   ver opts.wide en openDrawer() (ui.js). */
.ds-drawer.ds-drawer-wide { width: min(1200px, 80vw); }
/* Variante mas ancha todavia (~97vw, tope 1800px) -- pedido explicito del
   usuario para la Hoja de vida de Control de Deuda (tabla de Conciliacion
   de ~12 columnas, seguia cortada incluso en 1500px/92vw), ver opts.xwide
   en openDrawer() (ui.js). */
.ds-drawer.ds-drawer-xwide { width: min(1800px, 97vw); }
/* Variante ancha "compacta" -- mismo layout multi-columna de wide pero sin
   necesitar tanto ancho, ver opts.wideCompact en openDrawer() (usada hoy
   solo por "Ver todas" en conclusiones-panel.js; el visor de PDF de
   portal-client.js sigue en wide, sin tocar). Mismo ancho que
   .ds-drawer-medium (774px/92vw, ver "Analisis financiero completo") a
   pedido -- valor propio en vez de compartir la clase porque son dos
   variantes semanticamente distintas (una columna vs. sidebar+contenido)
   que podrian volver a divergir en tamaño mas adelante. */
.ds-drawer.ds-drawer-wide-compact { width: min(774px, 92vw); }
/* Variante intermedia (~774px, 640px + 10% + 10%) -- una sola columna de
   texto/KPIs que se ve apretada en 460px sin necesitar el ancho
   multi-columna de wide, ver opts.medium en openDrawer(). */
.ds-drawer.ds-drawer-medium { width: min(774px, 92vw); }
/* Variante sin padding/scroll propio -- para un <iframe> hijo que debe llenar
   el 100% del alto disponible con SU PROPIO scroll nativo (ver opts.bodyClassName
   en openDrawer()), en vez del padding+overflow-y:auto por defecto pensado
   para texto/KPIs. */
.ds-drawer-body.ds-drawer-body-fill { padding: 0; overflow: hidden; display: flex; flex-direction: column; min-height: 0; }
/* Footer opcional fijo al fondo del drawer, fuera del scroll de
   .ds-drawer-body (ver opts.footerHtml en openDrawer(), ui.js) -- reusa
   .ds-modal-footer para el estilo visual (flex, gap, borde superior) y solo
   agrega el flex-shrink:0 que necesita al vivir dentro del layout de columna
   de .ds-drawer (sin esto, .ds-modal-footer solo -- pensado para .ds-modal,
   que no es flex -- quedaria comprimido/mal ubicado). Oculta con .hidden
   cuando el caller no pasa footerHtml, igual que antes de que existiera. */
.ds-drawer-footer { flex: 0 0 auto; }
body.ds-drawer-open { overflow: hidden; }
@media (max-width: 640px) {
  .ds-drawer, .ds-drawer.ds-drawer-xwide, .ds-drawer.ds-drawer-wide, .ds-drawer.ds-drawer-wide-compact, .ds-drawer.ds-drawer-medium { width: 100vw; }
}

/* Variante "bottom sheet" (opts.sheet en openDrawer(), ver ui.js) -- adaptación
   mobile-first Portal Admin: mismo overlay/mecanismo de apertura-cierre que el
   drawer lateral de siempre, pero desliza desde ABAJO y ocupa solo el alto que
   necesita (no la pantalla completa) -- pensado para paneles cortos invocados
   desde mobile (ej. "Filtros" de una lista, ver openEmpresasFilterSheet en
   admin.js), no para reemplazar el drawer lateral de detalle/edición. Selector
   sobre el overlay (no sobre .ds-drawer solo) porque también hay que voltear
   justify-content de flex-end (derecha) a center + align-items:flex-end
   (abajo). */
.ds-drawer-overlay.ds-drawer-overlay-sheet { align-items: flex-end; justify-content: center; }
.ds-drawer.ds-drawer-sheet {
  /* height:auto pisa el height:100% del .ds-drawer base -- sin esto el panel
     se estira a toda la pantalla aunque el contenido (ej. 2 selects) sea
     corto, dejando un hueco vacío enorme antes del footer (bug real,
     encontrado con playwright-cli al probar el sheet de Filtros). */
  height: auto; width: 100%; max-width: 560px; max-height: min(80vh, 640px);
  border-radius: var(--ds-radius-modal) var(--ds-radius-modal) 0 0;
  transform: translateY(100%);
}
.ds-drawer-overlay-sheet.is-open .ds-drawer.ds-drawer-sheet { transform: translateY(0); }

/* Caja Menor (petty-cash.js, compartido por dashboard.js/portal-dashboard.js
   y portal-client.js) -- drawer combinado de revision: soporte a la
   izquierda + datos/acciones a la derecha, mismo criterio que
   .eeff-preview-frame (portal-client-shell.css) pero en core.css porque este
   modulo corre en las 3 superficies.
   RESTAURADO 2026-08-23: todo este bloque (hasta .pc-history-detail antes de
   DROPDOWNS) vivia hand-added directo en core.css (generado por npm run
   build:css) desde el commit 2764386 -- un `npm run build:css` posterior sin
   relacion (134bb61, refactor de select-picker) lo borro sin querer al
   regenerar core.css desde estos partials, porque nunca se habia migrado
   ACA. Restaurado tal cual estaba, ahora en su fuente correcta para que
   sobreviva la proxima regeneracion (reportado: "Control de Cajas no tiene
   bien aplicado el design system... se perdio la logica de las tarjetas, del
   boton de crear cajas"). */
.pc-movement-detail-grid { display: flex; flex: 1; min-height: 0; }
/* Vista previa mas angosta que el formulario (pedido del usuario -- antes
   1.4fr vs 1fr, la vista previa vacia dominaba el drawer de "Registrar
   gasto" mientras el formulario quedaba apretado a la derecha). */
.pc-movement-preview { flex: 0.85; min-width: 0; display: flex; background: var(--ds-bg-secondary); }
.pc-movement-preview iframe { flex: 1; width: 100%; height: 100%; border: 0; }
.pc-movement-preview img { max-width: 100%; max-height: 100%; margin: auto; object-fit: contain; }
.pc-movement-preview > .spinner-block, .pc-movement-preview > p { margin: auto; }
.pc-movement-side { flex: 1.3; min-width: 320px; max-width: 440px; padding: var(--ds-space-3); overflow-y: auto; border-left: 1px solid var(--ds-border); }
.pc-movement-fields { display: flex; flex-direction: column; gap: 8px; margin: 0 0 14px; }
.pc-movement-fields > div { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
.pc-movement-fields dt { color: var(--ds-text-muted); }
.pc-movement-fields dd { margin: 0; font-weight: 600; text-align: right; }
@media (max-width: 780px) {
  .pc-movement-detail-grid { flex-direction: column; overflow-y: auto; }
  .pc-movement-preview { min-height: 260px; }
  .pc-movement-side { max-width: none; border-left: 0; border-top: 1px solid var(--ds-border); }
}

/* Widgets de reporte (.card/.kpi-grid/.data-table/donut+leyenda) que
   dashboard-shell.css y portal-client-shell.css ya traian (usados por
   reports/pg.js, kpiCard() de ui.js, etc.) pero admin-shell.css nunca
   necesito hasta ahora -- Admin tiene su propio sistema paralelo
   (.admin-card/.admin-table/.admin-kpi-card). Sin esto, petty-cash.js (que
   SI reutiliza kpiCard()/.card/.data-table para ser un solo modulo en las 3
   superficies) se veia sin estilo en el panel Admin (reportado: "no dice
   absolutamente nada"). Solo tokens --ds-* (identicos en las 3 superficies),
   para que actuen como default seguro donde el shell no trae su propia
   version -- admin-shell.css ya sobreescribe .chart-wrap/.donut-center/
   .legend-* con la suya (carga despues de core.css), esto no le cambia nada.
   Version identica a la de dashboard-shell.css. */
.card { background: var(--ds-card-bg); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-card); padding: var(--ds-space-2) var(--ds-space-2) var(--ds-space-1); box-shadow: var(--ds-shadow-sm); transition: box-shadow var(--ds-transition-base); }
.card h3 { font-size: 14.5px; font-weight: var(--ds-fw-semibold); margin: 0 0 var(--ds-space-2); display: flex; align-items: center; justify-content: space-between; color: var(--ds-text); }
.card h3 .tag { font-size: 10px; color: var(--ds-text-muted); font-weight: var(--ds-fw-regular); }
.grid-2 { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--ds-space-2); margin-bottom: var(--ds-space-3); }
.chart-wrap { position: relative; height: 260px; }
.chart-wrap.tall { height: 320px; }
.donut-center { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; pointer-events: none; }
.donut-center .t { font-size: 10.5px; color: var(--ds-text-muted); text-transform: uppercase; letter-spacing: .4px; }
.donut-center .v { font-size: 15px; font-weight: 700; color: var(--ds-text); margin-top: 2px; font-variant-numeric: tabular-nums; }
.legend-list { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.legend-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
.legend-dot { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
.legend-name { flex: 1; color: var(--ds-text-secondary); }
.legend-pct { font-weight: 600; color: var(--ds-text); font-variant-numeric: tabular-nums; }
.legend-extra { color: var(--ds-text-muted); font-variant-numeric: tabular-nums; }
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: var(--ds-space-2); margin-bottom: var(--ds-space-3); }
.kpi-card { background: var(--ds-card-bg); border: 1px solid var(--ds-border); border-top: 3px solid var(--ds-primary-700); border-radius: var(--ds-radius-card); padding: var(--ds-space-2) var(--ds-space-2) var(--ds-space-1); box-shadow: var(--ds-shadow-sm); position: relative; min-width: 0; min-height: 112px; }
.kpi-card.v-green { border-top-color: var(--ds-success); }
.kpi-card.v-blue { border-top-color: var(--ds-info); }
.kpi-card.v-purple { border-top-color: var(--ds-primary-600); }
.kpi-card.v-gold { border-top-color: var(--ds-purple-500); }
.kpi-card.v-rose { border-top-color: var(--ds-danger); }
.kpi-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--ds-space-1); }
.kpi-card .label { font-size: 11px; color: var(--ds-text-secondary); font-weight: var(--ds-fw-semibold); text-transform: uppercase; letter-spacing: .04em; display: flex; align-items: center; gap: 5px; }
.kpi-card-icon { width: 32px; height: 32px; flex: 0 0 32px; display: inline-flex; align-items: center; justify-content: center; border-radius: 9px; color: var(--ds-primary-700); background: color-mix(in srgb, var(--ds-primary-700) 10%, transparent); }
.kpi-card-icon svg { width: var(--ds-icon-feature); height: var(--ds-icon-feature); }
.kpi-card.v-green .kpi-card-icon { color: var(--ds-success); background: color-mix(in srgb, var(--ds-success) 11%, transparent); }
.kpi-card.v-blue .kpi-card-icon { color: var(--ds-info); background: color-mix(in srgb, var(--ds-info) 11%, transparent); }
.kpi-card.v-purple .kpi-card-icon { color: var(--ds-primary-600); background: color-mix(in srgb, var(--ds-primary-600) 11%, transparent); }
.kpi-card.v-gold .kpi-card-icon { color: var(--ds-purple-500); background: color-mix(in srgb, var(--ds-purple-500) 11%, transparent); }
.kpi-card.v-rose .kpi-card-icon { color: var(--ds-danger); background: color-mix(in srgb, var(--ds-danger) 11%, transparent); }
:root[data-theme="dark"] .kpi-card-icon { background: var(--ds-icon-tile-info-bg); color: var(--ds-icon-tile-info-fg); border: 1px solid var(--ds-icon-tile-info-border); box-shadow: var(--ds-icon-tile-info-shadow); }
:root[data-theme="dark"] .kpi-card.v-green .kpi-card-icon { background: var(--ds-icon-tile-success-bg); color: var(--ds-icon-tile-success-fg); border: 1px solid var(--ds-icon-tile-success-border); box-shadow: var(--ds-icon-tile-success-shadow); }
:root[data-theme="dark"] .kpi-card.v-blue .kpi-card-icon { background: var(--ds-icon-tile-info-bg); color: var(--ds-icon-tile-info-fg); border: 1px solid var(--ds-icon-tile-info-border); box-shadow: var(--ds-icon-tile-info-shadow); }
:root[data-theme="dark"] .kpi-card.v-purple .kpi-card-icon { background: var(--ds-icon-tile-info-bg); color: var(--ds-icon-tile-info-fg); border: 1px solid var(--ds-icon-tile-info-border); box-shadow: var(--ds-icon-tile-info-shadow); }
:root[data-theme="dark"] .kpi-card.v-gold .kpi-card-icon { background: var(--ds-icon-tile-purple-bg); color: var(--ds-icon-tile-purple-fg); border: 1px solid var(--ds-icon-tile-purple-border); box-shadow: var(--ds-icon-tile-purple-shadow); }
:root[data-theme="dark"] .kpi-card.v-rose .kpi-card-icon { background: var(--ds-icon-tile-danger-bg); color: var(--ds-icon-tile-danger-fg); border: 1px solid var(--ds-icon-tile-danger-border); box-shadow: var(--ds-icon-tile-danger-shadow); }
.kpi-card .value { font-size: clamp(17px, 1.6vw, 24px); font-weight: var(--ds-fw-bold); margin-top: var(--ds-space-half); letter-spacing: -.025em; line-height: 1.15; color: var(--ds-text); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi-card .delta { font-size: 12px; margin-top: 6px; font-weight: var(--ds-fw-semibold); display: inline-flex; align-items: center; gap: 4px; }
.kpi-card .delta.up { color: var(--ds-success); }
.kpi-card .delta.down { color: var(--ds-danger); }
.kpi-card .delta.flat { color: var(--ds-text-muted); }
table.data-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.data-table th { text-align: left; padding: 10px 12px; font-size: 11px; font-weight: var(--ds-fw-semibold); text-transform: uppercase; letter-spacing: .04em; color: var(--ds-text-secondary); border-bottom: 1px solid var(--ds-border); }
.data-table td { padding: 10px 12px; border-bottom: 1px solid var(--ds-border); color: var(--ds-text); vertical-align: middle; }
.data-table td.num { text-align: left; font-variant-numeric: tabular-nums; }
.data-table tr:hover td { background: var(--ds-bg-secondary); }

/* Caja Menor -- rediseno del lado Cliente (2026-08-21): "Mis cajas" (grilla
   de tarjetas), el overlay grande de "Ver soporte" (Documento/Informacion/
   Historial) y el dropzone del formulario de gasto. El lado Staff sigue
   usando .pc-movement-* de arriba, sin tocar. */
/* auto-fill (no auto-fit): con solo 2-3 cajas reales, auto-fit colapsa las
   columnas vacías a 0 y el 1fr de las tarjetas existentes se reparte todo el
   ancho disponible entre ellas -- se veían enormes (reportado, referencia
   visual: "que en una fila quepan 4 cajas"). auto-fill reserva esas columnas
   vacías (quedan en blanco al final de la fila en vez de estirar las
   tarjetas), y el mínimo baja de 260px a 200px para que 4 quepan en el ancho
   típico del panel de contenido sin necesitar ese estiramiento. */
/* Nombre de empresa (Admin unicamente, ver `companyLabel` en
   mountPettyCashView) -- Modo revision (2026-09-07, pedido explicito): antes
   vivia apilado arriba de esta vista en su propio bloque de admin.js
   (#cajaMenorCompanyHead), ahora comparte fila con "Trasladar fondos" (ver
   renderFundsListView) para quedar a la misma altura. Mismo estilo que el
   <h2> que reemplaza (margin:0, font-size:17px). */
.pc-list-company-label { margin: 0; font-size: 17px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
.pc-fund-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); gap: var(--ds-space-2); margin-bottom: var(--ds-space-3); }
.pc-fund-card { cursor: pointer; transition: box-shadow var(--ds-transition-base), border-color var(--ds-transition-base); padding: 14px 14px 12px; }
.pc-fund-card:hover, .pc-fund-card:focus-visible { box-shadow: var(--ds-shadow-md); border-color: var(--ds-primary-600); }
.pc-fund-card:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.pc-fund-card-head { display: flex; align-items: center; justify-content: space-between; }
.pc-fund-card-icon { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border-radius: 9px; color: var(--ds-primary-700); background: color-mix(in srgb, var(--ds-primary-700) 10%, transparent); }
.pc-fund-card-icon svg { width: var(--ds-icon-feature); height: var(--ds-icon-feature); }
.pc-fund-card-title { margin: 10px 0 8px; font-size: 14px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
.pc-fund-card-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 12px; margin-bottom: 12px; }
.pc-fund-card-stat-full { grid-column: 1 / -1; }
.pc-fund-card-stat span { display: block; font-size: 11px; color: var(--ds-text-muted); margin-bottom: 2px; }
.pc-fund-card-stat strong { font-size: 14px; font-variant-numeric: tabular-nums; color: var(--ds-text); }
.pc-fund-card-progress { margin-bottom: 12px; }
.pc-fund-card-progress-track { height: 5px; border-radius: var(--ds-radius-pill); background: var(--ds-bg-secondary); overflow: hidden; }
.pc-fund-card-progress-fill { height: 100%; background: var(--ds-primary-600); border-radius: var(--ds-radius-pill); transition: width var(--ds-transition-base); }
.pc-fund-card-progress-label { display: block; margin-top: 4px; font-size: 11px; color: var(--ds-text-muted); text-align: right; }
.pc-fund-card-link { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; font-weight: var(--ds-fw-semibold); color: var(--ds-action); }
.pc-fund-card-link svg { width: 13px; height: 13px; }

/* Tile "Agregar nueva caja menor" -- mismo tamaño/posicion que una tarjeta
   real dentro de .pc-fund-grid (reemplaza el boton "Nueva caja" que antes
   vivia arriba junto a "Trasladar fondos", referencia visual del usuario). */
.pc-fund-add-card { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; text-align: center; min-height: 180px; border: 1.5px dashed var(--ds-border); border-radius: var(--ds-radius-card); background: none; padding: 24px 16px; cursor: pointer; color: var(--ds-text-secondary); transition: border-color var(--ds-transition-base), background var(--ds-transition-base); }
.pc-fund-add-card:hover, .pc-fund-add-card:focus-visible { border-color: var(--ds-text-muted); background: var(--ds-bg-secondary); }
.pc-fund-add-card:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.pc-fund-add-icon { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; border: 1.5px solid var(--ds-border); color: var(--ds-text-secondary); }
.pc-fund-add-icon svg { width: 16px; height: 16px; }
.pc-fund-add-card strong { font-size: 13.5px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
.pc-fund-add-card span { font-size: 12px; color: var(--ds-text-muted); }

.pc-back-btn { margin-bottom: 12px; }

/* Punto de estado en los tabs Todos/Pendientes/Aprobados/Devueltos de la
   tabla de movimientos (referencia visual del usuario). */
.pc-tab-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.pc-tab-dot-warning { background: var(--ds-warning); }
.pc-tab-dot-success { background: var(--ds-success); }
.pc-tab-dot-danger { background: var(--ds-danger); }

.pc-soporte-link { display: inline-flex; align-items: center; gap: 4px; color: var(--ds-action); font-size: 12.5px; }
.pc-soporte-link svg { width: 13px; height: 13px; }

.pc-filters-wrap { position: relative; }
.pc-filters-popover { display: none; position: absolute; top: calc(100% + 6px); right: 0; z-index: 20; background: var(--ds-card-bg); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-card); box-shadow: var(--ds-shadow-md); padding: 10px; min-width: 240px; }
.pc-filters-popover.is-open { display: block; }
.pc-filters-popover .ds-search { width: 100%; }

.pc-dropzone { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; text-align: center; border: 1.5px dashed var(--ds-border); border-radius: var(--ds-radius-card); padding: 22px 14px; cursor: pointer; color: var(--ds-text-secondary); transition: border-color var(--ds-transition-base), background var(--ds-transition-base); }
.pc-dropzone:hover, .pc-dropzone.is-dragover { border-color: var(--ds-primary-600); background: color-mix(in srgb, var(--ds-primary-600) 6%, transparent); }
.pc-dropzone svg { width: 22px; height: 22px; color: var(--ds-text-muted); margin-bottom: 2px; }
.pc-dropzone span { font-size: 13px; font-weight: var(--ds-fw-semibold); color: var(--ds-action); }
.pc-dropzone small { font-size: 11px; color: var(--ds-text-muted); }
.ds-hidden-file-input { position: absolute; width: 1px; height: 1px; overflow: hidden; opacity: 0; }

/* Combobox de Categoria (Registrar gasto/movimiento) -- input libre (se
   puede escribir cualquier categoria) + boton de flecha que abre un panel
   de sugerencias con el mismo look que .pc-filters-popover, en vez de la
   flechita nativa sin estilo del <input list> (datalist) de antes. */
.pc-combobox { position: relative; }
.pc-combobox .ds-input { padding-right: 34px; }
.pc-combobox-toggle {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; padding: 0; border-radius: var(--ds-radius-sm, 6px); color: var(--ds-text-muted); cursor: pointer;
}
.pc-combobox-toggle:hover { color: var(--ds-text); background: var(--ds-bg-secondary); }
.pc-combobox-toggle svg { width: 15px; height: 15px; transition: transform var(--ds-transition-fast); }
.pc-combobox.is-open .pc-combobox-toggle svg { transform: rotate(180deg); }
.pc-combobox-panel {
  display: none; position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 30;
  background: var(--ds-card-bg); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-card);
  box-shadow: var(--ds-shadow-md); padding: 6px; max-height: 220px; overflow-y: auto;
}
.pc-combobox.is-open .pc-combobox-panel { display: block; }
.pc-combobox-option { display: block; width: 100%; text-align: left; border: 0; background: none; padding: 8px 10px; border-radius: var(--ds-radius-sm, 6px); font-size: 13px; color: var(--ds-text); cursor: pointer; }
.pc-combobox-option:hover, .pc-combobox-option.is-active { background: var(--ds-bg-secondary); }
.pc-combobox-empty { padding: 8px 10px; font-size: 12.5px; color: var(--ds-text-muted); }

/* Date picker propio (Fecha en Registrar gasto/movimiento) -- reemplaza el
   <input type="date"> nativo (calendario del sistema operativo, sin poder
   aplicarle el design system) por un input de solo lectura + un panel con
   grilla de mes propio, mismo popover que el combobox de arriba. */
.pc-datepicker { position: relative; }
.pc-datepicker-toggle {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; padding: 0; border-radius: var(--ds-radius-sm, 6px); color: var(--ds-text-muted); cursor: pointer;
}
.pc-datepicker-toggle:hover { color: var(--ds-text); background: var(--ds-bg-secondary); }
.pc-datepicker-toggle svg { width: 15px; height: 15px; }
.pc-datepicker-panel {
  display: none; position: absolute; top: calc(100% + 6px); left: 0; z-index: 30; width: 268px;
  background: var(--ds-card-bg); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-card);
  box-shadow: var(--ds-shadow-md); padding: 10px;
}
.pc-datepicker.is-open .pc-datepicker-panel { display: block; }
.pc-datepicker-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.pc-datepicker-head strong { font-size: 13px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); text-transform: capitalize; }
.pc-datepicker-nav { width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; border-radius: var(--ds-radius-sm, 6px); color: var(--ds-text-secondary); cursor: pointer; }
.pc-datepicker-nav:hover { color: var(--ds-text); background: var(--ds-bg-secondary); }
.pc-datepicker-nav svg { width: 15px; height: 15px; }
.pc-datepicker-weekdays, .pc-datepicker-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.pc-datepicker-weekdays span { font-size: 10.5px; font-weight: var(--ds-fw-semibold); color: var(--ds-text-muted); text-transform: uppercase; padding: 4px 0; }
.pc-datepicker-day { border: 0; background: none; padding: 0; height: 30px; border-radius: var(--ds-radius-sm, 6px); font-size: 12.5px; color: var(--ds-text); cursor: pointer; }
.pc-datepicker-day:hover { background: var(--ds-bg-secondary); }
.pc-datepicker-day.is-muted { color: var(--ds-text-muted); }
.pc-datepicker-day.is-selected { background: var(--ds-primary-600); color: var(--ds-text-inverse); font-weight: var(--ds-fw-semibold); }
.pc-datepicker-day.is-today:not(.is-selected) { border: 1px solid var(--ds-primary-600); }
.pc-datepicker-today-btn { margin-top: 8px; width: 100%; }

/* Overlay grande "Ver soporte": area principal (pestanas + documento/
   historial) + columna lateral fija (Informacion del movimiento + acciones),
   dentro del mismo .ds-drawer-wide (80vw) que usa Conclusiones. */
.pc-support-viewer { display: flex; flex: 1; min-height: 0; }
.pc-support-main { flex: 1.6; min-width: 0; padding: var(--ds-space-2) var(--ds-space-3); display: flex; flex-direction: column; min-height: 0; }
.pc-support-main .ds-tabs { margin-bottom: 14px; flex: none; }
/* Documento e Historial se reparten el alto restante de .pc-support-main --
   [hidden] (mas especifico que la regla base de abajo) fuerza display:none
   por encima del display:flex propio, si no el atributo hidden del HTML
   quedaria pisado. Historial mantiene su scroll propio (texto simple);
   Documento pasa su alto completo a .pc-doc-layout para que el visor pueda
   estirarse (ver mas abajo). */
#pcSupportPanelDocumento { flex: 1; min-height: 0; display: flex; }
#pcSupportPanelDocumento[hidden] { display: none; }
#pcSupportPanelHistorial { flex: 1; min-height: 0; overflow-y: auto; }
#pcSupportPanelHistorial[hidden] { display: none; }
.pc-support-side { flex: 1; min-width: 280px; max-width: 340px; padding: var(--ds-space-3); overflow-y: auto; border-left: 1px solid var(--ds-border); }
.pc-support-side-heading { margin: 0 0 14px; font-size: 14px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
#pcMovementActions:not(:empty) { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--ds-border); }
@media (max-width: 860px) {
  .pc-support-viewer { flex-direction: column; overflow-y: auto; }
  .pc-support-main { overflow-y: visible; }
  #pcSupportPanelDocumento { min-height: 480px; }
  .pc-support-side { max-width: none; border-left: 0; border-top: 1px solid var(--ds-border); }
}

.pc-doc-empty { text-align: center; padding: 40px 16px; color: var(--ds-text-muted); margin: auto; }

/* Panel "Documento": miniaturas (izquierda, angosta, scroll propio) + visor
   grande (derecha, ocupa el resto) -- pedido del usuario: aprovechar el alto
   completo del drawer en vez del visor topeado de antes. */
.pc-doc-layout { display: flex; flex: 1; min-height: 0; gap: 12px; width: 100%; }

/* Ancho reducido a la mitad (pedido del usuario, era 176px) -- las
   tarjetas eran demasiado anchas para una simple lista de miniaturas.
   min-width:0 en toda la cadena flex (sidebar/lista/tarjeta) es lo que
   realmente lo fuerza: sin esto, un nombre de archivo largo con
   white-space:nowrap empuja cada nivel a crecer mas alla de su flex-basis
   (el minimo automatico de un flex item es el tamaño de su contenido, no
   0) -- por eso la columna seguia viendose ancha aunque el basis ya
   estuviera en 88px. */
.pc-doc-sidebar { flex: 0 0 88px; min-width: 0; display: flex; flex-direction: column; min-height: 0; }
.pc-doc-sidebar-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; font-size: 10px; font-weight: var(--ds-fw-semibold); text-transform: uppercase; letter-spacing: .03em; color: var(--ds-text-secondary); flex: none; }
.pc-doc-sidebar-head span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-doc-add-btn { flex: none; width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; border-radius: 5px; color: var(--ds-text-muted); cursor: pointer; }
.pc-doc-add-btn:hover { background: var(--ds-bg-secondary); color: var(--ds-text); }
.pc-doc-add-btn svg { width: 12px; height: 12px; }
.pc-doc-sidebar-list { flex: 1; min-width: 0; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding-right: 2px; }

.pc-doc-card { position: relative; display: flex; flex-direction: column; gap: 5px; text-align: left; border: 1.5px solid var(--ds-border); border-radius: var(--ds-radius-card); background: var(--ds-card-bg); padding: 5px; cursor: pointer; flex: none; min-width: 0; max-width: 100%; box-sizing: border-box; }
.pc-doc-card:hover { border-color: var(--ds-primary-600); }
.pc-doc-card.is-active { border-color: var(--ds-primary-600); box-shadow: 0 0 0 1px var(--ds-primary-600); }
.pc-doc-card-badge { position: absolute; top: 4px; right: 4px; z-index: 1; background: var(--ds-primary-600); color: var(--ds-text-inverse); font-size: 8px; font-weight: var(--ds-fw-semibold); text-transform: uppercase; letter-spacing: .02em; padding: 1.5px 4px; border-radius: var(--ds-radius-pill); }
.pc-doc-card-thumb { display: flex; align-items: center; justify-content: center; height: 52px; border-radius: 6px; background: var(--ds-bg-secondary); color: var(--ds-text-muted); overflow: hidden; }
.pc-doc-card-thumb svg { width: 18px; height: 18px; }
.pc-doc-card-thumb img { width: 100%; height: 100%; object-fit: cover; }
.pc-doc-card-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pc-doc-card-name { font-size: 10px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-doc-card-sub { font-size: 8.5px; color: var(--ds-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pc-doc-sidebar-drop { flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; text-align: center; border: 1.5px dashed var(--ds-border); border-radius: var(--ds-radius-card); padding: 8px 4px; cursor: pointer; color: var(--ds-text-secondary); transition: border-color var(--ds-transition-base), background var(--ds-transition-base); }
.pc-doc-sidebar-drop:hover, .pc-doc-sidebar-drop.is-dragover { border-color: var(--ds-primary-600); background: color-mix(in srgb, var(--ds-primary-600) 6%, transparent); }
.pc-doc-sidebar-drop svg { width: 15px; height: 15px; color: var(--ds-text-muted); }
.pc-doc-sidebar-drop span { font-size: 9.5px; font-weight: var(--ds-fw-semibold); color: var(--ds-action); line-height: 1.25; }
.pc-doc-sidebar-drop small { font-size: 8px; color: var(--ds-text-muted); }

.pc-doc-stage { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; position: relative; }
.pc-doc-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; flex: none; }
.pc-doc-filename { font-size: 12.5px; color: var(--ds-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc-doc-toolbar-actions { display: flex; gap: 4px; flex: none; }
/* object-fit:contain sobre un contenedor que SI llena el alto disponible
   (antes max-height:480px fijo) -- un documento vertical ahora usa todo el
   alto del drawer en vez de quedar chico con franjas vacias a los lados. */
.pc-doc-viewer { flex: 1; min-height: 0; background: var(--ds-bg-secondary); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-card); display: flex; align-items: center; justify-content: center; overflow: auto; position: relative; }
.pc-doc-viewer iframe { width: 100%; height: 100%; border: 0; transform-origin: center center; }
.pc-doc-viewer img { max-width: 100%; max-height: 100%; object-fit: contain; transform-origin: center center; }
.pc-doc-viewer > .spinner-block, .pc-doc-viewer > p { margin: auto; }
.pc-doc-stage:fullscreen { background: var(--ds-bg); padding: 16px; }
.pc-doc-stage:fullscreen .pc-doc-viewer { border-radius: 0; }

/* Barra flotante de zoom/rotar/pantalla-completa, centrada al pie del
   visor -- referencia visual del usuario (pill oscuro discreto). */
.pc-doc-zoombar { position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); display: flex; align-items: center; gap: 2px; background: var(--ds-modal-header-bg); border-radius: var(--ds-radius-pill); padding: 5px 8px; box-shadow: var(--ds-shadow-md); }
.pc-doc-zoombar[hidden] { display: none; }
.pc-doc-zoombar-btn { width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; border-radius: 50%; color: var(--ds-white); opacity: .85; cursor: pointer; }
.pc-doc-zoombar-btn:hover { opacity: 1; background: rgba(255, 255, 255, .14); }
.pc-doc-zoombar-btn svg { width: 14px; height: 14px; }
.pc-doc-zoombar-pct { min-width: 38px; text-align: center; font-size: 11px; font-weight: var(--ds-fw-semibold); color: var(--ds-white); font-variant-numeric: tabular-nums; }
.pc-doc-zoombar-sep { width: 1px; height: 16px; background: rgba(255, 255, 255, .2); margin: 0 2px; }

.pc-history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 16px; }
.pc-history-item { display: flex; gap: 10px; }
.pc-history-icon { width: 28px; height: 28px; flex: none; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: color-mix(in srgb, var(--ds-primary-600) 10%, transparent); color: var(--ds-primary-600); }
.pc-history-icon svg { width: 14px; height: 14px; }
.pc-history-label { font-size: 13px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
.pc-history-meta { font-size: 11.5px; color: var(--ds-text-muted); margin-top: 1px; }
.pc-history-detail { font-size: 12px; color: var(--ds-text-secondary); margin-top: 4px; background: var(--ds-bg-secondary); border-radius: 6px; padding: 6px 8px; }

/* ============================== DROPDOWNS ============================== */
/* Revelado "tipo iOS" (notification center / context menu): crece desde la
   esquina superior derecha (junto al icono que lo abre) con opacity+scale en
   vez de solo un translateY. Se mantiene --ds-transition-fast (220ms ease) -
   la misma duracion/easing unica del resto del sistema (ver animations.css) -
   sin overshoot/rebote para no romper esa regla de "sin efectos exagerados". */
.ds-dropdown {
  position: absolute;
  background: var(--ds-surface);
  border-radius: var(--ds-radius-dropdown);
  box-shadow: var(--ds-shadow-lg);
  border: 1px solid var(--ds-border);
  transform-origin: top right;
  opacity: 0; transform: scale(0.92) translateY(-4px); pointer-events: none;
  transition: opacity var(--ds-transition-fast), transform var(--ds-transition-fast);
  z-index: var(--ds-z-dropdown);
}
.ds-dropdown.is-open { opacity: 1; transform: scale(1) translateY(0); pointer-events: auto; }

/* ============================== TOAST ============================== */
.ds-toast-region {
  position: fixed; z-index: var(--ds-z-toast); display: flex; flex-direction: column;
  gap: var(--ds-space-1); width: min(var(--ds-toast-width), calc(100vw - (2 * var(--ds-toast-viewport-gap))));
  pointer-events: none;
}
.ds-toast-region-top-right { top: var(--ds-toast-viewport-gap); right: var(--ds-toast-viewport-gap); }
.ds-toast-region-top-center { top: var(--ds-toast-viewport-gap); left: 50%; transform: translateX(-50%); }
.ds-toast-region-bottom-right { right: var(--ds-toast-viewport-gap); bottom: var(--ds-toast-viewport-gap); }
.ds-toast {
  position: relative; overflow: hidden; display: grid; grid-template-columns: minmax(0, 1fr) auto;
  background: var(--ds-bg-primary); color: var(--ds-text-primary);
  border-radius: var(--ds-radius-card); box-shadow: var(--ds-shadow-lg);
  font-size: var(--ds-fs-body); pointer-events: auto;
  animation: ds-slide-in var(--ds-toast-enter-duration);
}
.ds-toast .ds-toast-alert { min-width: 0; border: 0; box-shadow: none; }
/* Sin icono de estado -- prueba visual pedida explicitamente, solo dentro
   del contexto Toast (dsAlert() se reusa tal cual en banners/alertas
   sueltas fuera de un toast, ahi el icono sigue igual). */
.ds-toast .ds-alert-icon { display: none; }
.ds-toast .ds-toast-alert .ds-card-header { padding-right: var(--ds-control-lg); }
.ds-toast-controls { display: flex; align-items: flex-start; gap: var(--ds-space-half); padding: var(--ds-space-1) var(--ds-space-1) 0 0; }
.ds-toast-action { align-self: center; white-space: nowrap; }
.ds-toast.is-leaving { opacity: 0; transform: translateX(var(--ds-space-2)); transition: opacity var(--ds-toast-exit-duration), transform var(--ds-toast-exit-duration); }
/* Barra de progreso: cuenta regresiva visual del auto-cierre -- mismo
   criterio que .admin-toast-progress/.pcli-toast-progress (currentColor +
   color por tono), pero animation-duration lo fija createDsToast() por JS
   (aca el 3000ms es solo el fallback si por lo que sea no se pisara). Spans
   todas las columnas del grid (alert + controles) via left/right absolutos
   en vez de grid-column, mas simple que participar del grid. */
.ds-toast-progress {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  /* Mismo color solido que el resto de los toasts (sin opacity) -- debe
     leerse identico al acento de la variante, no una version translucida. */
  background: currentColor; color: var(--ds-info);
  transform-origin: left; animation: ds-toast-progress 3000ms linear forwards;
}
.ds-toast-progress[hidden] { display: none; }
.ds-toast.is-leaving .ds-toast-progress { animation-play-state: paused; }
.ds-toast-success .ds-toast-progress { color: var(--ds-success); }
.ds-toast-warning .ds-toast-progress { color: var(--ds-warning); }
.ds-toast-error .ds-toast-progress { color: var(--ds-danger); }
@keyframes ds-toast-progress { to { transform: scaleX(0); } }
@media (prefers-reduced-motion: reduce) {
  .ds-toast { animation: none; }
  .ds-toast.is-leaving { transition: none; }
  .ds-toast-progress { animation: none; opacity: 0; }
}

/* ============================== SPINNER ============================== */
/* Spinner generico independiente de superficie. El .spinner-block especifico
   de dashboard-shell.css ya tenia su propio equivalente aplicado via ::before
   (mismo criterio, no duplicar): este es para cualquier pantalla nueva que
   no cargue ese shell CSS. */
.ds-spinner {
  display: inline-block; width: 20px; height: 20px; flex-shrink: 0;
  border: 2px solid var(--ds-border); border-top-color: var(--ds-accent);
  border-radius: 50%; animation: ds-spin 700ms linear infinite;
}

/* ============================== LOGO ADAPTATIVO (CLARO/OSCURO) ============================== */
/* Compartido por los 3 portales (Admin/Portal Cliente/Contador) -- cualquier
   logo/isotipo que viva sobre una superficie que cambia de claro a oscuro
   con el tema (loader de pantalla completa, loader de módulo, header móvil,
   sidebar lockup) usa este mismo patrón: dos <img> hermanos, uno con la
   variante "claro" (navy, para tema claro) y otro con la variante "dark"
   (blanca, para tema oscuro) -- CSS alterna cuál se ve, nunca JS. Antes vivía
   solo en admin-shell.css con selector .admin-html[data-theme="dark"]
   (rama test/nuevo-logo-admin); se generaliza acá (root[data-theme] en vez
   de exigir la clase de Admin) para que Portal Cliente y Contador -- que no
   tienen esa clase en <html> -- lo reciban gratis sin duplicar la regla.
   NOTA: esta regla se había añadido directamente al core.css generado (commit
   f96cd1a), saltándose `npm run build:css` -- restaurada acá, su fuente
   real, al detectar el desfase durante una limpieza no relacionada. */
.lm-logo-adaptive { display: inline-flex; }
.lm-logo-adaptive .lm-logo-for-dark { display: none; }
.lm-logo-adaptive .lm-logo-for-light { display: block; }
:root[data-theme="dark"] .lm-logo-adaptive .lm-logo-for-dark { display: block; }
:root[data-theme="dark"] .lm-logo-adaptive .lm-logo-for-light { display: none; }

/* ============================== EMPTY / LOADING EXPERIENCE ============================== */
.ds-empty-state { align-items: center; display: flex; flex-direction: column; gap: var(--ds-space-1); padding: var(--ds-space-4); text-align: center; }
.ds-empty-state .ds-card-body { display: contents; }
.ds-empty-state-visual { width: var(--ds-control-lg); height: var(--ds-control-lg); display: inline-flex; align-items: center; justify-content: center; border-radius: var(--ds-radius-pill); background: var(--ds-bg-secondary); color: var(--ds-text-muted); }
.ds-empty-state-visual svg { width: var(--ds-icon-lg); height: var(--ds-icon-lg); }
.ds-empty-state-recoverable-error .ds-empty-state-visual { background: var(--ds-danger-bg); color: var(--ds-danger); }
.ds-empty-state-no-permission .ds-empty-state-visual { background: var(--ds-warning-bg); color: var(--ds-warning-contrast); }
.ds-empty-state-title { margin: 0; color: var(--ds-text); font-size: var(--ds-fs-h3); font-weight: var(--ds-fw-semibold); }
.ds-empty-state-description { max-width: 32rem; margin: 0; color: var(--ds-text-secondary); font-size: var(--ds-fs-body); }
.ds-empty-state .ds-card-footer { justify-content: center; margin-top: var(--ds-space-1); }
.ds-empty-state-compact { padding: var(--ds-space-2); }
.ds-empty-state-compact .ds-empty-state-visual { width: var(--ds-control-md); height: var(--ds-control-md); }
.ds-loading-block { min-height: var(--ds-control-lg); display: flex; align-items: center; justify-content: center; gap: var(--ds-space-1); padding: var(--ds-space-3); color: var(--ds-text-secondary); }
.ds-loading-block .ds-card-body { display: contents; }
.ds-loading-block-compact { min-height: var(--ds-control-md); padding: var(--ds-space-1); }
.ds-loading-label { font-size: var(--ds-fs-body); }
.ds-loading-skeleton { display: grid; gap: var(--ds-space-half); width: 100%; }
.ds-loading-overlay { position: absolute; inset: 0; z-index: var(--ds-z-dropdown); display: grid; place-items: center; padding: var(--ds-space-2); background: var(--ds-overlay); }
.ds-loading-overlay-block { width: min(100%, 20rem); box-shadow: var(--ds-shadow-lg); }

/* ============================== SKELETON ============================== */
.ds-skeleton {
  position: relative; overflow: hidden;
  background: var(--ds-bg-secondary);
  border-radius: var(--ds-radius-input);
}
.ds-skeleton::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
  animation: ds-skeleton-shimmer 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .ds-skeleton::after { animation: none; } }
.ds-skeleton-text { height: 14px; margin-bottom: var(--ds-space-half); }
.ds-skeleton-text:last-child { margin-bottom: 0; width: 70%; }
.ds-skeleton-title { height: 22px; width: 40%; margin-bottom: var(--ds-space-2); }
.ds-skeleton-avatar { width: 40px; height: 40px; border-radius: 50%; }
.ds-skeleton-kpi { height: 88px; border-radius: var(--ds-radius-card); }
.ds-skeleton-row { height: var(--ds-table-row-comfortable); }
.ds-skeleton-card { min-height: 9rem; border-radius: var(--ds-radius-card); }
.ds-skeleton-form { height: var(--ds-input-height-md); border-radius: var(--ds-radius-input); }
.ds-skeleton-table { height: var(--ds-table-row-comfortable); border-radius: 0; }
.ds-skeleton.is-last { width: 70%; }
@media (prefers-reduced-motion: reduce) { .ds-spinner { animation: none; } }

/* .skeleton: placeholder de transición de ruta de Portal Cliente
   (getSkeletonMarkup() en portal-client.js, usado por navigateTo() en las
   14 secciones del router). Antes no tenía NINGÚN CSS en todo el repo --
   quedaba invisible (div vacío) durante los ~250ms de la transición; ya
   reserva alturas correctas via `style="height:...px"` inline en el propio
   markup, así que esto solo lo hace visible (mismo shimmer que .ds-skeleton,
   sin duplicar la animación). */
.skeleton {
  position: relative; overflow: hidden;
  background: var(--ds-surface-subtle);
  border-radius: var(--ds-radius-card);
}
.skeleton::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
  animation: ds-skeleton-shimmer 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .skeleton::after { animation: none; } }

/* ============================== TOOLTIP ============================== */
/* Uso: <button data-tooltip="Texto"> — no requiere JS, funciona con teclado
   via :focus-visible. No usar sobre elementos que ya tengan su propio
   overlay posicionado (ver .ds-dropdown) para evitar conflicto de z-index. */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute; bottom: calc(100% + 8px); left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--ds-primary-950); color: var(--ds-white);
  font-size: 12px; font-weight: var(--ds-fw-medium); white-space: nowrap;
  padding: 6px 10px; border-radius: var(--ds-radius-input);
  box-shadow: var(--ds-shadow-md);
  opacity: 0; pointer-events: none;
  transition: opacity var(--ds-transition-fast), transform var(--ds-transition-fast);
  z-index: var(--ds-z-tooltip);
}
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ============================== RESPONSIVE ============================== */
@media (max-width: 1024px) {
  .ds-h1 { font-size: 26px; }
  .ds-card { padding: var(--ds-space-2); }
}
@media (max-width: 900px) {
  body.sidebar-drawer-open { overflow: hidden; }
  .ds-sidebar-backdrop {
    position: fixed; inset: 0; z-index: 190; display: block; padding: 0;
    border: 0; background: rgba(7, 17, 31, .52); opacity: 0;
    pointer-events: none; transition: opacity var(--ds-transition-base);
  }
  .ds-sidebar-backdrop.is-open { opacity: 1; pointer-events: auto; }
}
@media (max-width: 640px) {
  html { -webkit-text-size-adjust: 100%; }
  button, [role="button"], a, input, select { touch-action: manipulation; }
  .ds-h1 { font-size: 22px; }
  .ds-modal { max-width: 100%; max-height: calc(100dvh - 24px); }
  .ds-modal-overlay { align-items: flex-end; padding: 12px; }
  .ds-modal-body { min-height: 0; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
  .ds-modal-footer { flex-wrap: wrap; }
  .ds-modal-footer .ds-btn { flex: 1 1 auto; min-height: 44px; }
  #modalEmpresa[data-ds-modal-pilot="empresas-create"] .admin-modal-grid-2 { grid-template-columns: minmax(0, 1fr); }
  #modalEmpresa[data-ds-modal-pilot="empresas-create"] .admin-modal-footer-row { align-items: stretch; flex-direction: column-reverse; }
  #modalEmpresa[data-ds-modal-pilot="empresas-create"] .admin-modal-footer-row .ds-btn { width: var(--ds-button-block-width); }
  .ds-card-kpi-value { font-size: 24px; }
  .ds-toast-region { right: var(--ds-toast-viewport-gap); left: var(--ds-toast-viewport-gap); width: auto; transform: none; }
  .ds-toast-region-top-center, .ds-toast-region-top-right { top: var(--ds-toast-viewport-gap); }
  .ds-toast-region-bottom-right { bottom: var(--ds-toast-viewport-gap); }
  .ds-toast { grid-template-columns: minmax(0, 1fr); }
  .ds-toast-controls { justify-content: flex-end; padding: 0 var(--ds-space-1) var(--ds-space-1); }
  .ds-empty-state { padding: var(--ds-space-2); }
  .ds-empty-state .ds-card-footer { align-items: stretch; flex-direction: column-reverse; width: 100%; }
  .ds-empty-state .ds-card-footer .ds-btn { width: 100%; }
  .ds-loading-overlay { padding: var(--ds-space-1); }
}


/* source: src/styles/layout.css */
/**
 * LM Contable — Design System v3.0 — Layout
 * Primitivas de sidebar/header compartidas por las 3 superficies (regla
 * global del sistema, no de un portal en particular). Cada shell
 * (dashboard-shell.css / admin-shell.css / portal-client-shell.css) define
 * su propio ancho de sidebar y grid, pero reusa estas clases base.
 */
:root {
  --ds-header-height: 72px;
}

.ds-container {
  max-width: var(--ds-content-max-width);
  margin-inline: auto;
  padding-inline: var(--ds-space-3);
}

/* ---- Sidebar ---- */
.ds-sidebar {
  background: var(--ds-sidebar-bg);
  color: var(--ds-sidebar-text);
  display: flex;
  flex-direction: column;
  z-index: var(--ds-z-sidebar);
}

/* Encabezado del sidebar (v5.2: fila superior fija del sidebar — logo/wordmark
   + boton de colapsar, ver LM_CONTABLE_DESIGN_SYSTEM.md). Antes el boton de
   colapsar vivia en el header claro de arriba; ahora el sidebar ocupa toda la
   franja izquierda de punta a punta y el boton vive integrado aqui, junto a
   la marca. Mismo fondo que .ds-sidebar (hereda). */
.ds-sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-1);
  padding: var(--ds-space-2);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  flex-shrink: 0;
}
.ds-sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--ds-space-1);
  min-width: 0;
  flex: 1;
  border-radius: var(--ds-radius-btn);
  text-decoration: none;
  transition: background var(--ds-transition-fast);
}
.ds-sidebar-brand:hover { background: var(--ds-sidebar-hover-bg); }
.ds-sidebar-brand img { width: 34px; height: 34px; border-radius: var(--ds-radius-input); flex-shrink: 0; object-fit: cover; }
.ds-sidebar-brand-text { font-size: 15px; font-weight: var(--ds-fw-bold); color: #FFFFFF; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; }
/* El modo icono-solo (.is-collapsed) es un mecanismo de escritorio; en mobil
   (<=900px, ver setupSidebarCollapse en ui.js) el sidebar es un drawer a
   ancho completo y no debe ocultar texto/marca aunque .is-collapsed haya
   quedado activo de una sesion de escritorio previa. Colapsado no hay
   espacio para el logo + el boton de colapsar lado a lado, asi que se oculta
   la marca y solo queda el boton, centrado. */
@media (min-width: 901px) {
  .ds-sidebar.is-collapsed .ds-sidebar-header { justify-content: center; }
  .ds-sidebar.is-collapsed .ds-sidebar-brand { display: none; }
}

.ds-sidebar-nav { padding: var(--ds-space-2) 12px; overflow-y: auto; flex: 1; }

.ds-sidebar-label {
  padding: 8px 12px 6px 12px;
  font-size: 10px;
  font-weight: 700;
  color: var(--ds-sidebar-icon);
  text-transform: uppercase;
  letter-spacing: .08em;
}
.ds-sidebar-label:not(:first-child) { padding-top: 20px; }
@media (min-width: 901px) {
  .ds-sidebar.is-collapsed .ds-sidebar-label { display: none; }
}

.ds-sidebar-item {
  display: flex;
  align-items: center;
  gap: var(--ds-space-1);
  padding: 11px var(--ds-space-2);
  border-radius: var(--ds-radius-btn);
  color: var(--ds-sidebar-text);
  cursor: pointer;
  transition: background var(--ds-transition-fast), color var(--ds-transition-fast);
  text-decoration: none;
  /* Explicito a proposito: sin esto, Admin (que usa <button>) hereda el
     font-size de control nativo del navegador (~13.3px) mientras que Cliente
     (que usa <a>) hereda el del body (16px) -- mismo componente, dos tamaños
     distintos por el tag subyacente. Con font-size fijo aca, ambas superficies
     quedan identicas sin importar si el item es <button> o <a>. */
  font-size: var(--ds-fs-button);
}
.ds-sidebar-item svg, .ds-sidebar-item i { width: 17px; height: 17px; color: var(--ds-sidebar-icon); flex-shrink: 0; }
.ds-sidebar-item:hover { background: var(--ds-sidebar-hover-bg); color: #FFFFFF; }
.ds-sidebar-item.active {
  background: var(--ds-sidebar-active-bg);
  color: var(--ds-sidebar-active-text);
}
.ds-sidebar-item.active svg, .ds-sidebar-item.active i { color: var(--ds-sidebar-active-icon); }

.ds-sidebar-foot { padding: 12px; border-top: 1px solid rgba(255, 255, 255, .08); flex-shrink: 0; }
.ds-sidebar-logout {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--ds-radius-btn);
  background: none;
  border: none;
  cursor: pointer;
  color: #f87171;
  font-size: 13px;
  font-weight: var(--ds-fw-medium);
  text-decoration: none;
  transition: background var(--ds-transition-fast);
}
.ds-sidebar-logout:hover { background: rgba(220, 38, 38, .15); }
.ds-sidebar-logout svg, .ds-sidebar-logout i { width: 15px; height: 15px; flex-shrink: 0; }

/* Boton de colapsar — vive dentro de .ds-sidebar-header (v5.2), por eso usa
   los tokens de icono/hover del sidebar oscuro en vez de los del header
   claro — identico en todas las superficies que comparten este componente. */
.ds-sidebar-toggle {
  padding: 8px;
  color: var(--ds-sidebar-icon);
  border-radius: 8px;
  background: none;
  border: none;
  cursor: pointer;
  display: flex;
  flex-shrink: 0;
  transition: background var(--ds-transition-fast), color var(--ds-transition-fast);
}
.ds-sidebar-toggle:hover { color: #FFFFFF; background: var(--ds-sidebar-hover-bg); }
.ds-sidebar-toggle svg, .ds-sidebar-toggle i { width: 17px; height: 17px; }

/* ---- Buscador del header (v5.2: componente unico, antes duplicado como
   .admin-header-search en Admin y .header-search en Portal Cliente con
   estilos distintos — mismo look/alineacion en las dos superficies). ---- */
.ds-header-search { flex: 1; max-width: 28rem; display: none; }
@media (min-width: 768px) { .ds-header-search { display: block; } }
.ds-header-search-wrap { position: relative; width: 100%; }
.ds-header-search-icon { position: absolute; inset-block: 0; left: 0; display: flex; align-items: center; padding-left: 12px; color: var(--ds-text-muted); pointer-events: none; }
/* Estandarizacion de iconos: buscador del topbar = --ds-icon-control (17px,
   tramo "inputs/filtros/navegacion secundaria") -- antes 13px fijo. */
.ds-header-search-icon svg { width: var(--ds-icon-control); height: var(--ds-icon-control); }
.ds-header-search input {
  width: 100%; padding: 8px 56px 8px 36px; background: var(--ds-header-search-bg); border: 1px solid var(--ds-border);
  border-radius: 8px; font-size: 13px; color: var(--ds-text); font-family: var(--ds-font); height: auto;
}
.ds-header-search input::placeholder { color: var(--ds-text-muted); }
.ds-header-search input:focus { outline: none; background: var(--ds-surface); border-color: var(--ds-accent); box-shadow: 0 0 0 3px rgba(37,99,235,.15); }
.ds-global-search-results {
  position:absolute; top:calc(100% + 8px); left:0; right:0; z-index:var(--ds-z-dropdown);
  max-height:min(440px,70vh); overflow-y:auto; padding:6px;
  border:1px solid var(--ds-border); border-radius:var(--ds-radius-dropdown);
  background:var(--ds-surface); box-shadow:var(--ds-shadow-lg);
}
.ds-global-search-result {
  width:100%; min-height:52px; display:flex; align-items:center; gap:10px; padding:8px 10px;
  border:0; border-radius:8px; background:transparent; color:var(--ds-text); text-align:left;
  font-family:var(--ds-font); cursor:pointer;
}
.ds-global-search-result:hover,.ds-global-search-result.is-active { background:var(--ds-info-bg); }
.ds-global-search-result-icon { width:32px; height:32px; display:grid; place-items:center; flex:0 0 32px; border-radius:8px; color:var(--ds-accent); background:var(--ds-info-bg); }
.ds-global-search-result-icon svg { width:16px; height:16px; }
.ds-global-search-result-copy { min-width:0; flex:1; display:flex; flex-direction:column; gap:2px; }
.ds-global-search-result-copy strong { overflow:hidden; color:var(--ds-text); font-size:13px; text-overflow:ellipsis; white-space:nowrap; }
.ds-global-search-result-copy small { overflow:hidden; color:var(--ds-text-muted); font-size:11px; text-overflow:ellipsis; white-space:nowrap; }
.ds-global-search-result-arrow { width:14px; color:var(--ds-text-muted); }
.ds-global-search-empty { padding:20px 12px; color:var(--ds-text-muted); font-size:13px; text-align:center; }
.ds-header-kbd { position: absolute; inset-block: 0; right: 0; display: flex; align-items: center; padding-right: 12px; pointer-events: none; }
.ds-header-kbd kbd { padding: 2px 6px; background: var(--ds-bg-secondary); color: var(--ds-text-secondary); border-radius: 4px; font-size: 10px; font-family: monospace; border: 1px solid var(--ds-border); }

/* ---- Header ---- */
.ds-header {
  height: var(--ds-header-height);
  background: var(--ds-header-bg);
  border-bottom: 1px solid var(--ds-header-border);
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  padding-inline: var(--ds-space-3);
  z-index: var(--ds-z-header);
}
.ds-header .ds-search .ds-input {
  /* v5.0: el header es claro (ver colors.css), por eso el texto usa
     --ds-text (oscuro) en vez de --ds-text-on-dark. */
  background: var(--ds-header-search-bg);
  border-color: transparent;
  color: var(--ds-text);
}
.ds-header .ds-search .ds-input::placeholder { color: var(--ds-header-search-placeholder); }
.ds-header .ds-search > svg { color: var(--ds-header-search-placeholder); }

/* ModuleHeader compone Card, Badge y Button; los slots no instalan comportamiento. */
.ds-module-header-card { padding: var(--ds-space-3); background: var(--ds-card-bg); }
.ds-module-header-row { display: flex; align-items: center; justify-content: space-between; gap: var(--ds-space-3); }
.ds-module-header-heading { min-width: 0; display: grid; gap: var(--ds-space-half); }
.ds-module-header-breadcrumb { display: flex; align-items: center; flex-wrap: wrap; gap: var(--ds-space-1); color: var(--ds-text-secondary); font-size: var(--ds-fs-caption); }
.ds-module-header-breadcrumb a { color: inherit; text-decoration: none; }
.ds-module-header-breadcrumb a:hover { color: var(--ds-action); }
.ds-module-header-breadcrumb svg { width: var(--ds-icon-xs); height: var(--ds-icon-xs); }
.ds-module-header-breadcrumb [aria-current="page"] { color: var(--ds-text); font-weight: var(--ds-fw-semibold); }
.ds-module-header-title-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--ds-space-1); }
.ds-module-header-title-row h1 { margin: 0; color: var(--ds-text); font-size: var(--ds-fs-h2); font-weight: var(--ds-fw-bold); line-height: 1.25; }
.ds-module-header-description { margin: 0; color: var(--ds-text-secondary); font-size: var(--ds-fs-body); }
.ds-module-header-actions { display: flex; align-items: center; flex-wrap: wrap; gap: var(--ds-space-1); }
.ds-module-header-slots { display: grid; gap: var(--ds-space-2); margin-top: var(--ds-space-2); }
.ds-module-header-filters, .ds-module-header-kpis { min-width: 0; }
@media (max-width: 1024px) { .ds-module-header-row { align-items: stretch; flex-direction: column; } }
@media (max-width: 640px) { .ds-module-header-actions { align-items: stretch; flex-direction: column; } .ds-module-header-actions .ds-btn { width: var(--ds-button-block-width); justify-content: center; } }

/* Adaptador DS-011: efectivo solo cuando Empresas es la sección visible. */
.admin-main:has(#section-empresas:not(.hidden)) > .ds-module-header-surface { display: flex; flex-direction: column; gap: var(--ds-space-2); }
@media (min-width: 640px) { .admin-main:has(#section-empresas:not(.hidden)) > .ds-module-header-surface { flex-direction: row; align-items: center; justify-content: space-between; } }

/* Tabs es presentacional: el modulo consumidor conserva activacion y paneles. */
.ds-tabs { display: flex; align-items: stretch; gap: var(--ds-space-half); min-width: 0; overflow-x: auto; overscroll-behavior-inline: contain; scrollbar-width: thin; }
.ds-tab { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: var(--ds-space-1); border: var(--ds-button-border-width) solid var(--ds-transparent); border-radius: var(--ds-radius-control); background: var(--ds-transparent); color: var(--ds-text-secondary); font-family: var(--ds-font); font-weight: var(--ds-fw-semibold); white-space: nowrap; cursor: pointer; transition: color var(--ds-transition-fast), background-color var(--ds-transition-fast), border-color var(--ds-transition-fast); }
.ds-tabs-sm .ds-tab { min-height: var(--ds-control-sm); padding: 0 var(--ds-space-1); font-size: var(--ds-fs-caption); }
.ds-tabs-md .ds-tab { min-height: var(--ds-control-md); padding: 0 var(--ds-space-2); font-size: var(--ds-fs-body); }
.ds-tab:hover:not(:disabled) { color: var(--ds-text); background: var(--ds-bg-secondary); }
.ds-tab:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.ds-tab.is-active, .ds-tab[aria-selected="true"] { color: var(--ds-action); border-color: var(--ds-border); background: var(--ds-card-bg); box-shadow: var(--ds-shadow-sm); }
/* Tab activa en modo oscuro: texto blanco en vez del azul de --ds-action --
   pedido explicito ("coloca la fuente en blanco en el modo oscuro" para
   cualquier submodulo seleccionado). El azul se conserva para el
   borde/subrayado (.ds-tabs-standard de abajo) -- solo el texto cambia,
   componente compartido por todos los modulos (.ds-tabs/.ds-tab), asi que
   este unico override alcanza a cualquier nav de submodulos de la app.
   RESTAURADO 2026-08-23: ver comentario en globals.css sobre el core.css
   hand-added que un `npm run build:css` posterior borro sin querer. */
:root[data-theme="dark"] .ds-tab.is-active,
:root[data-theme="dark"] .ds-tab[aria-selected="true"] { color: var(--ds-text); }
.ds-tabs-standard { border-bottom: var(--ds-button-border-width) solid var(--ds-border); }
.ds-tabs-standard .ds-tab { border-radius: var(--ds-radius-control) var(--ds-radius-control) 0 0; border-bottom-color: var(--ds-transparent); }
.ds-tabs-standard .ds-tab.is-active, .ds-tabs-standard .ds-tab[aria-selected="true"] { border-bottom-color: var(--ds-action); box-shadow: inset 0 calc(var(--ds-button-border-width) * -1) 0 var(--ds-action); }
.ds-tabs-contained { padding: var(--ds-space-half); border-radius: var(--ds-radius-control); background: var(--ds-bg-secondary); }
.ds-tab:disabled, .ds-tab[aria-disabled="true"] { opacity: var(--ds-button-disabled-opacity); cursor: not-allowed; }
.ds-tab-icon, .ds-tab-icon svg { width: var(--ds-icon-sm); height: var(--ds-icon-sm); flex: none; }
.ds-tab-badge { pointer-events: none; }

/* Adaptador DS-013: solo el grupo General de Configuracion Admin. */
.ds-tabs-config-surface { display: contents; }


/* source: src/styles/buttons.css */
.ds-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-half);
  font-family: var(--ds-font);
  font-size: var(--ds-fs-button);
  font-weight: var(--ds-fw-semibold);
  letter-spacing: var(--ds-type-button-letter-spacing);
  border-radius: var(--ds-radius-button);
  padding: var(--ds-button-padding-y-md) var(--ds-button-padding-x-md);
  border: var(--ds-button-border-width) solid var(--ds-transparent);
  cursor: pointer;
  transition: background var(--ds-transition-fast), color var(--ds-transition-fast),
    border-color var(--ds-transition-fast), transform var(--ds-transition-fast), box-shadow var(--ds-transition-fast);
  white-space: nowrap;
}
.ds-btn:active { transform: translateY(var(--ds-button-active-offset)); }
.ds-btn:focus-visible {
  outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color);
  outline-offset: var(--ds-focus-offset);
}
.ds-btn:disabled,
.ds-btn[aria-disabled="true"] { opacity: var(--ds-button-disabled-opacity); cursor: not-allowed; transform: none; }
.ds-btn svg { width: var(--ds-button-icon-size-md); height: var(--ds-button-icon-size-md); flex-shrink: 0; }

.ds-btn-primary { background: var(--ds-action); color: var(--ds-text-inverse); }
.ds-btn-primary:hover:not(:disabled), .ds-btn-primary:active:not(:disabled) { background: var(--ds-action-hover); }

.ds-btn-secondary { background: var(--ds-surface); color: var(--ds-text); border-color: var(--ds-border); }
.ds-btn-secondary:hover:not(:disabled) { background: var(--ds-bg); }

.ds-btn-outline { background: var(--ds-transparent); color: var(--ds-text); border-color: var(--ds-border); }
.ds-btn-outline:hover:not(:disabled) { background: var(--ds-bg); border-color: var(--ds-text); }

.ds-btn-ghost { background: var(--ds-transparent); color: var(--ds-text-secondary); }
.ds-btn-ghost:hover:not(:disabled) { background: var(--ds-bg); color: var(--ds-text); }

/* Referencia obligatoria (Iconos-v2.png, "Design System - Botones"): salvo
   Primario (ds-btn-primary, azul solido, maximo 1 por vista), las variantes
   semanticas son outline -- fondo blanco, borde y texto del color de la
   accion. Antes rellenas solidas (reportado: "no sigue las instrucciones
   de la foto", extendido a ambos portales ya que Portal Cliente consume
   este mismo sistema via dsButton()/adoptDesignSystemSurface). */
.ds-btn-danger { background: var(--ds-surface); color: var(--ds-danger); border-color: var(--ds-danger); }
.ds-btn-danger:hover:not(:disabled) { background: var(--ds-danger-bg); }

.ds-btn-success { background: var(--ds-surface); color: var(--ds-success); border-color: var(--ds-success); }
.ds-btn-success:hover:not(:disabled) { background: var(--ds-success-bg); }

.ds-btn-warning { background: var(--ds-surface); color: var(--ds-warning-badge-text); border-color: var(--ds-warning); }
.ds-btn-warning:hover:not(:disabled) { background: var(--ds-warning-bg); }

.ds-btn-link { padding-inline: var(--ds-button-padding-none); background: var(--ds-transparent); color: var(--ds-action); }
.ds-btn-link:hover:not(:disabled) { color: var(--ds-action-hover); text-decoration: underline; }

.ds-btn-sm { padding: var(--ds-button-padding-y-sm) var(--ds-button-padding-x-sm); font-size: var(--ds-type-control-compact-size); }
.ds-btn-sm svg { width: var(--ds-button-icon-size-sm); height: var(--ds-button-icon-size-sm); }
.ds-btn-lg { padding: var(--ds-button-padding-y-lg) var(--ds-button-padding-x-lg); font-size: var(--ds-type-body-size); }
.ds-btn-lg svg { width: var(--ds-button-icon-size-lg); height: var(--ds-button-icon-size-lg); }
.ds-btn-icon { width: var(--ds-control-md); height: var(--ds-control-md); padding: var(--ds-button-padding-none); }
.ds-btn-icon.ds-icon-button-xs { width: var(--ds-control-xs); height: var(--ds-control-xs); }
.ds-btn-icon.ds-icon-button-xs svg { width: var(--ds-icon-xs); height: var(--ds-icon-xs); }
.ds-btn-icon.ds-btn-sm { width: var(--ds-control-sm); height: var(--ds-control-sm); }
.ds-btn-icon.ds-btn-lg { width: var(--ds-control-lg); height: var(--ds-control-lg); }
.ds-btn-block { width: var(--ds-button-block-width); margin-top: auto; }
.ds-btn-loading { position: relative; color: var(--ds-transparent) !important; pointer-events: none; }
.ds-btn-loading::after {
  content: '';
  position: absolute;
  width: var(--ds-button-loading-size);
  height: var(--ds-button-loading-size);
  border-radius: var(--ds-radius-pill);
  border: var(--ds-button-loading-border-width) solid var(--ds-button-loading-track-inverse);
  border-top-color: var(--ds-text-inverse);
  animation: ds-spin var(--ds-button-loading-motion) infinite;
}
.ds-btn-outline.ds-btn-loading::after,
.ds-btn-ghost.ds-btn-loading::after,
.ds-btn-secondary.ds-btn-loading::after,
.ds-btn-link.ds-btn-loading::after,
.ds-btn-warning.ds-btn-loading::after { border-color: var(--ds-button-loading-track); border-top-color: var(--ds-text); }


/* source: src/styles/forms.css */
.ds-field { display: flex; flex-direction: column; gap: var(--ds-space-half); }
.ds-label { font-size: var(--ds-fs-caption); font-weight: var(--ds-fw-semibold); color: var(--ds-text-secondary); text-transform: uppercase; letter-spacing: var(--ds-type-label-letter-spacing); }

.ds-input,
.ds-textarea,
.ds-select {
  font-family: var(--ds-font); font-size: var(--ds-fs-input); font-weight: var(--ds-fw-regular); color: var(--ds-text);
  background: var(--ds-surface); border: var(--ds-input-border-width) solid var(--ds-input-border); border-radius: var(--ds-radius-input);
  padding-inline: var(--ds-input-padding-x-md); height: var(--ds-input-legacy-height); width: var(--ds-input-width); box-sizing: border-box;
  transition: border-color var(--ds-transition-fast), box-shadow var(--ds-transition-fast);
}
.ds-input-sm, .ds-select-sm { height: var(--ds-input-height-sm); padding-inline: var(--ds-input-padding-x-sm); }
.ds-input-md, .ds-select-md { height: var(--ds-input-height-md); padding-inline: var(--ds-input-padding-x-md); }
.ds-input-lg, .ds-select-lg { height: var(--ds-input-height-lg); padding-inline: var(--ds-input-padding-x-lg); }
.ds-textarea { height: auto; padding: 12px 14px; resize: vertical; min-height: 96px; }
.ds-input:hover, .ds-textarea:hover, .ds-select:hover { border-color: var(--ds-input-hover-border); }
.ds-input:focus, .ds-textarea:focus, .ds-select:focus {
  outline: none; border-color: var(--ds-input-focus-border); box-shadow: var(--ds-shadow-input-focus);
}
.ds-input:disabled, .ds-textarea:disabled, .ds-select:disabled { background: var(--ds-bg); color: var(--ds-text-muted); cursor: not-allowed; }
.ds-input:read-only { background: var(--ds-bg-secondary); }
.ds-input.is-error, .ds-field-error .ds-input { border-color: var(--ds-input-error); }
.ds-input.is-success, .ds-field-success .ds-input { border-color: var(--ds-input-success); }
.ds-select[aria-invalid="true"], .ds-field-error .ds-select { border-color: var(--ds-input-error); }
.ds-select-density-compact { font-size: var(--ds-type-control-compact-size); }
.ds-select-density-comfortable { font-size: var(--ds-fs-input); }
.ds-select:has(> option:checked[value=""]) { color: var(--ds-text-muted); }
.ds-select option { color: var(--ds-text); }
/* Flecha propia del design system en vez de la del navegador (reportado en
   Categoria de Caja Menor, pero .ds-select es compartido -- corrige el
   selector en toda la app de una sola vez).
   select.ds-select (con el tipo de elemento, no solo la clase) a proposito
   -- muchos selects del panel Admin (Noticias, Asesorias/Servicios, Nomina,
   Auditoria, Empresas, Usuarios, etc.) ya combinan class="admin-select-sm
   ds-select ..." de antes, y .admin-select-sm (admin-shell.css, carga
   DESPUES de este archivo) tambien fija `background`/`padding` en su forma
   corta (shorthand) -- a igual especificidad (0,1,0 ambas), gana la regla
   que carga despues en el documento, asi que .admin-select-sm pisaba (o
   mezclaba mal con) la flecha/el padding de aca, dejando una franja
   repetida en vez de una sola flecha limpia (reportado en Noticias/
   Asesorias/Nomina, pero el mismo combo de clases aparece en varios
   modulos mas). El selector de tipo+clase sube la especificidad a
   (0,1,1), mas que cualquier .clase suelta sin importar el orden de
   carga -- no hace falta !important.
   RESTAURADO 2026-08-23: ver comentario en globals.css sobre el core.css
   hand-added que un `npm run build:css` posterior borro sin querer. Sigue
   siendo el "estado cerrado" valido para cualquier <select> aun no
   convertido a .ds-select-picker (ver CLAUDE.md). */
select.ds-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 34px;
  background-repeat: no-repeat; background-position: right 12px center; background-size: 13px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}
select.ds-select:disabled { background-image: none; }
:root[data-theme="dark"] select.ds-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}
.ds-input::placeholder, .ds-textarea::placeholder { color: var(--ds-text-muted); }

.ds-input-control { position: relative; display: flex; align-items: center; }
.ds-input-control.has-leading .ds-input { padding-left: var(--ds-input-decorated-padding); } .ds-input-control.has-trailing .ds-input { padding-right: var(--ds-input-decorated-padding); }
.ds-input-addon { position: absolute; color: var(--ds-text-muted); pointer-events: none; display: inline-flex; align-items: center; }
.ds-input-addon-leading { left: var(--ds-input-addon-offset); } .ds-input-addon-trailing { right: var(--ds-input-addon-offset); }
.ds-input-addon svg { width: var(--ds-input-icon-size); height: var(--ds-input-icon-size); }
.ds-input-helper { color: var(--ds-text-muted); font-size: var(--ds-fs-caption); }
.ds-field-error .ds-input-helper { color: var(--ds-input-error); }
.ds-field-success .ds-input-helper { color: var(--ds-input-success); }
.ds-input-control.is-loading::after { content: ''; position: absolute; right: var(--ds-input-addon-offset); width: var(--ds-button-loading-size); height: var(--ds-button-loading-size); border-radius: var(--ds-radius-pill); border: var(--ds-button-loading-border-width) solid var(--ds-button-loading-track); border-top-color: var(--ds-input-focus-border); animation: ds-spin var(--ds-button-loading-motion) infinite; }

.ds-search { position: relative; display: flex; align-items: center; }
.ds-search .ds-input { padding-left: var(--ds-input-decorated-padding); }
.ds-search > svg,
.ds-search > i {
  /* top/transform (Modo revisión, petty-cash.js #pcSearchInput): faltaba el
     centrado vertical -- .ds-search es flex+align-items:center, pero un
     hijo position:absolute queda fuera de ese cálculo, así que el ícono
     necesita su propio centrado explícito. petty-cash.js lo resolvía con un
     style="" inline redundante por instancia; se completa acá una sola vez
     para que cualquier .ds-search > svg/i quede bien alineado sin repetirlo. */
  position: absolute; left: var(--ds-input-addon-offset); top: 50%; transform: translateY(-50%); color: var(--ds-text-muted);
  width: var(--ds-input-icon-size); height: var(--ds-input-icon-size); pointer-events: none;
}
.ds-search-has-clear .ds-search-input { appearance: textfield; }
.ds-search-has-clear .ds-search-input::-webkit-search-cancel-button { appearance: none; }
.ds-search-input:not(:placeholder-shown) ~ .ds-search-clear { visibility: visible; opacity: 1; pointer-events: auto; }
.ds-search-clear {
  position: absolute; right: var(--ds-space-half); width: var(--ds-input-height-sm); height: var(--ds-input-height-sm);
  display: inline-flex; align-items: center; justify-content: center; padding: 0; border: 0;
  border-radius: var(--ds-radius-btn); background: transparent; color: var(--ds-text-muted);
  font: inherit; font-size: var(--ds-input-icon-size); cursor: pointer;
  visibility: hidden; opacity: 0; pointer-events: none;
  transition: color var(--ds-transition-fast), background var(--ds-transition-fast), opacity var(--ds-transition-fast);
}
.ds-search-clear:hover { color: var(--ds-text); background: var(--ds-bg-secondary); }
.ds-search-clear:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.ds-search-input:not(:placeholder-shown) { padding-right: var(--ds-input-decorated-padding); }
.ds-search-input:disabled ~ .ds-search-clear,
.ds-search-input:read-only ~ .ds-search-clear { visibility: hidden; opacity: 0; pointer-events: none; }

.ds-choice { display: flex; align-items: flex-start; gap: var(--ds-space-1); color: var(--ds-text); font-family: var(--ds-font); }
.ds-choice-density-compact { gap: var(--ds-space-half); }
.ds-choice-copy { display: flex; flex-direction: column; gap: var(--ds-space-half); }
.ds-choice-label { color: var(--ds-text); font-size: var(--ds-type-label-size); font-weight: var(--ds-fw-semibold); line-height: 1.4; cursor: pointer; }
.ds-choice-helper { color: var(--ds-text-muted); font-size: var(--ds-fs-caption); }
.ds-choice-error .ds-choice-helper { color: var(--ds-danger); }

.ds-checkbox, .ds-radio {
  width: 18px; height: 18px; margin: 0;
  accent-color: var(--ds-accent); cursor: pointer; flex-shrink: 0;
  transition: box-shadow var(--ds-transition-fast);
}
.ds-checkbox-sm { width: var(--ds-input-icon-size); height: var(--ds-input-icon-size); }
.ds-checkbox:hover:not(:disabled) { box-shadow: 0 0 0 var(--ds-focus-ring-width) var(--ds-bg-secondary); }
.ds-checkbox:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.ds-checkbox:disabled { cursor: not-allowed; opacity: var(--ds-button-disabled-opacity); }
.ds-choice-error .ds-checkbox { outline: var(--ds-focus-ring-width) solid var(--ds-danger); outline-offset: var(--ds-focus-offset); }

.ds-switch { --ds-switch-width: var(--ds-input-height-md); --ds-switch-height: 22px; position: relative; display: inline-block; width: var(--ds-switch-width); height: var(--ds-switch-height); flex-shrink: 0; }
.ds-switch-sm { --ds-switch-width: var(--ds-input-height-sm); --ds-switch-height: 18px; }
.ds-switch input { opacity: 0; width: 0; height: 0; }
.ds-switch .ds-switch-track {
  position: absolute; inset: 0; background: var(--ds-border); border-radius: 999px;
  transition: background var(--ds-transition-base), opacity var(--ds-transition-fast); cursor: pointer;
}
.ds-switch .ds-switch-track::before {
  content: ''; position: absolute; height: calc(var(--ds-switch-height) - 6px); width: calc(var(--ds-switch-height) - 6px); left: 3px; top: 3px;
  background: var(--ds-white); border-radius: 50%; transition: transform var(--ds-transition-base);
  box-shadow: var(--ds-shadow-sm);
}
.ds-switch input:checked + .ds-switch-track { background: var(--ds-accent); }
.ds-switch input:checked + .ds-switch-track::before { transform: translateX(calc(var(--ds-switch-width) - var(--ds-switch-height))); }
.ds-switch input:focus-visible + .ds-switch-track { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.ds-switch input:disabled + .ds-switch-track { cursor: not-allowed; opacity: var(--ds-button-disabled-opacity); }
.ds-switch:not(.ds-switch-loading):hover input:not(:disabled) + .ds-switch-track { background: var(--ds-input-hover-border); }
.ds-switch:not(.ds-switch-loading):hover input:checked + .ds-switch-track { background: var(--ds-accent-hover); }
.ds-switch-loading .ds-switch-track::after {
  content: ''; position: absolute; width: var(--ds-button-loading-size); height: var(--ds-button-loading-size); inset: 0; margin: auto;
  border: var(--ds-button-loading-border-width) solid var(--ds-button-loading-track); border-top-color: var(--ds-accent); border-radius: var(--ds-radius-pill);
  animation: ds-spin var(--ds-button-loading-motion) linear infinite;
}

/* FilterBar compone Search, Select, Button y Badge sin lógica propia. */
.ds-filter-bar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--ds-space-2); padding: var(--ds-space-2); background: var(--ds-card-bg); border: var(--ds-button-border-width) solid var(--ds-border); border-radius: var(--ds-radius-card); box-shadow: var(--ds-shadow-sm); }
.ds-filter-bar-controls, .ds-filter-bar-actions { display: flex; align-items: center; flex-wrap: wrap; }
.ds-filter-bar-compact .ds-filter-bar-controls, .ds-filter-bar-compact .ds-filter-bar-actions { gap: var(--ds-space-1); }
.ds-filter-bar-comfortable .ds-filter-bar-controls, .ds-filter-bar-comfortable .ds-filter-bar-actions { gap: var(--ds-space-2); }
.ds-filter-bar-controls { flex: 1 1 auto; }
@media (max-width: 1024px) { .ds-filter-bar { align-items: stretch; } .ds-filter-bar-actions { margin-left: auto; } }
@media (max-width: 640px) { .ds-filter-bar, .ds-filter-bar-controls, .ds-filter-bar-actions { align-items: stretch; flex-direction: column; } .ds-filter-bar .ds-field, .ds-filter-bar .ds-btn { width: var(--ds-button-block-width); } .ds-filter-bar-actions { margin-left: 0; } }

/* Adaptador DS-012: únicamente la toolbar de filtros de Empresas. */
#section-empresas > .admin-toolbar.ds-filter-bar-surface { background: var(--ds-card-bg); padding: var(--ds-space-2); border-radius: var(--ds-radius-card); border: var(--ds-button-border-width) solid var(--ds-border); box-shadow: var(--ds-shadow-sm); gap: var(--ds-space-2); }
#section-empresas > .ds-filter-bar-surface > .ds-filter-bar-surface-controls { gap: var(--ds-input-padding-x-sm); }

/* ---- Select Picker: reemplazo de <select> nativo (design-system.js) ----
   La lista desplegada de un <select> nativo la pinta el navegador/SO, no el
   CSS de la app -- no hay forma de alinearla al design system (reportado
   primero en el selector de empresa de Vacaciones, luego "Ver X por
   página"; ahora estándar para cualquier selector nuevo en cualquiera de
   los 3 entrypoints -- ver CLAUDE.md). El <select> real queda oculto
   (.ds-select-picker-select) y sigue siendo la ÚNICA fuente de verdad:
   todo el código que lee/asigna su .value o escucha su "onchange" sigue
   intacto -- ver syncSelectPicker/toggleSelectPicker/pickSelectOption en
   design-system.js. Vive acá (compartido, no en admin-shell.css) porque
   Admin/Contador, Portal Cliente y Dashboard lo usan los tres. */
.ds-select-picker { position: relative; display: inline-flex; width: 100%; min-width: 0; }
/* El atributo `hidden` nativo aplica `display:none` desde el stylesheet del
   navegador (prioridad más baja que cualquier regla de autor) -- sin esto,
   la regla de arriba (display:inline-flex, regla de autor) siempre gana y
   un `.ds-select-picker` con `hidden` puesto por JS queda IGUAL visible.
   Bug real: control-deuda.js oculta/muestra los pickers de Referencia
   (SOFR/IBR) con `.hidden = true/false` según el tipo de tasa elegido, y
   sin esta regla los dos quedaban apilados y visibles a la vez. */
.ds-select-picker[hidden] { display: none; }
/* Modificador para selectores chicos "en línea" (ej. "Ver 10/20/50/100 por
   página", junto a un <label>) -- a diferencia de un selector de ancho de
   campo de formulario (menú con mínimo de 220px porque el contenido puede
   ser texto largo), acá el trigger y el menú se ajustan al contenido: un
   select de 2-3 dígitos no necesita ni debe abrir un menú de 220px (ver
   positionSelectPickerMenu en design-system.js, que respeta esta clase). */
.ds-select-picker-inline { width: auto; }
.ds-select-picker-inline .ds-select-picker-trigger { width: auto; }
.ds-select-picker-select { position: absolute; opacity: 0; pointer-events: none; width: 1px; height: 1px; overflow: hidden; }
.ds-select-picker-trigger { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; cursor: pointer; text-align: left; }
.ds-select-picker-trigger span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-select-picker-trigger.is-placeholder span { color: var(--ds-text-muted); }
/* "i, svg" a proposito: lucide.createIcons() REEMPLAZA el <i data-lucide>
   original por un <svg> (mismo elemento, tag distinto) -- el selector "i"
   solo deja de matchear apenas corre createIcons(), asi que sin el "svg"
   este chevron nunca tomaba los 14px de aca y quedaba en el tamaño por
   defecto de Lucide (24px, "se ven muy grandes" reportado). Bug pre-
   existente en los ~70 selectores que ya usan este componente en toda la
   app, no solo en el Dashboard Financiero donde se detectó. */
.ds-select-picker-trigger i, .ds-select-picker-trigger svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--ds-text-muted); transition: transform var(--ds-transition-fast); }
.ds-select-picker-trigger:disabled { background: var(--ds-bg); color: var(--ds-text-muted); cursor: not-allowed; }
.ds-select-picker.is-open .ds-select-picker-trigger i, .ds-select-picker.is-open .ds-select-picker-trigger svg { transform: rotate(180deg); }
/* position:fixed (no absolute) a propósito -- el picker suele vivir dentro
   de una tarjeta con overflow:hidden (esquinas redondeadas), que recorta/
   esconde un menú absoluto (reportado: "el selector de empresas queda
   escondido"). Coordenadas (top/left/ancho) se fijan por JS al abrir (ver
   positionSelectPickerMenu, calcula con getBoundingClientRect del
   trigger); acá solo el resto del look, reusando .ds-dropdown. */
/* z-index propio (no solo el z-index:900 heredado de .ds-dropdown, ver
   core.css): al abrirse se reubica en document.body (ver
   positionSelectPickerMenu, design-system.js) para que su position:fixed
   no quede roto por el transform de un modal ancestro -- una vez ahí, es
   hermano de .ds-modal-overlay (z-index:1000) en vez de descendiente, y
   necesita ganarle por z-index para no quedar tapado. Mismo criterio que
   .dsdp-panel en date-picker.css. */
.ds-select-picker-menu { position: fixed; z-index: calc(var(--ds-z-modal, 1000) + 20); max-height: 280px; overflow-y: auto; padding: 6px 0; transform-origin: top left; }
/* Ítem de la lista abierta -- mismo tratamiento visual en los 3
   entrypoints (antes solo existía como .company-switch-item en
   admin-shell.css/portal-client-shell.css, atado al switcher de empresa de
   Contador; acá una versión propia y genérica). */
.ds-select-picker-item {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 10px 16px; background: none; border: none; cursor: pointer;
  font-size: 12.5px; font-weight: 600; color: var(--ds-text-900, var(--ds-text)); text-align: left;
}
.ds-select-picker-item:hover { background: var(--ds-bg-secondary); }
.ds-select-picker-item.is-active { color: var(--ds-text); }
.ds-select-picker-item i { width: 15px; height: 15px; color: var(--ds-accent); }
.ds-select-picker-empty { padding: 24px 16px; text-align: center; color: var(--ds-text-muted); }


/* source: src/styles/tables.css */
/**
 * LM Contable — Design System v3.0 — Tablas
 * Software financiero: la tabla es uno de los componentes mas cuidados.
 * Inspiracion Stripe/QuickBooks/Linear — mucho espacio, cero recargo visual.
 */
.ds-table-wrap { overflow-x: auto; border-radius: var(--ds-radius-card); border: 1px solid var(--ds-border); background: var(--ds-surface); }
.ds-table { width: 100%; border-collapse: collapse; background: var(--ds-surface); }
.ds-data-table-card { padding: 0; overflow: hidden; }
.ds-data-table-card .ds-card-body { min-width: 0; }
.ds-table caption { padding: var(--ds-space-2); color: var(--ds-text); font-weight: var(--ds-fw-semibold); text-align: left; }
.ds-table thead th {
  font-size: var(--ds-fs-table-header);
  font-weight: var(--ds-fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ds-text-secondary);
  background: var(--ds-table-header-bg);
  text-align: left;
  padding: var(--ds-space-1) var(--ds-space-2);
  border-bottom: 1px solid var(--ds-table-divider);
  white-space: nowrap;
}
.ds-table tbody td {
  padding: var(--ds-space-1) var(--ds-space-2);
  font-size: var(--ds-fs-body);
  color: var(--ds-text);
  border-bottom: 1px solid var(--ds-table-divider);
}
.ds-table tbody tr { transition: background var(--ds-transition-fast); }
.ds-table tbody tr:hover { background: var(--ds-table-row-hover-bg); }
.ds-table tbody tr:last-child td { border-bottom: none; }
.ds-table-compact tbody td { height: var(--ds-table-row-compact); }
.ds-table-comfortable tbody td { height: var(--ds-table-row-comfortable); }
.ds-table td.num, .ds-table th.num { text-align: left; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ds-table-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--ds-space-half); }
.ds-table-slot { padding: var(--ds-space-4); text-align: center; color: var(--ds-text-muted); }
.ds-table-pagination { display: flex; align-items: center; justify-content: space-between; padding: var(--ds-space-2); font-size: var(--ds-fs-caption); color: var(--ds-text-secondary); }
.ds-table-pagination-controls { display: flex; align-items: center; gap: var(--ds-space-half); }
.ds-pagination-size { display: flex; align-items: center; flex-direction: row; gap: var(--ds-space-1); }
.ds-pagination-size .ds-label { white-space: nowrap; }
.ds-page-btn {
  width: 28px; height: 28px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--ds-border); background: var(--ds-surface); border-radius: 50%;
  color: var(--ds-text-secondary); font-size: 12px; cursor: pointer; font-family: var(--ds-font);
}
.ds-page-btn:hover:not(:disabled) { background: var(--ds-bg); }
.ds-page-btn:disabled { opacity: .5; cursor: not-allowed; }
.ds-page-btn.is-active { background: var(--ds-accent); color: var(--ds-white); font-weight: var(--ds-fw-bold); border-color: var(--ds-accent); }

/* Acciones dentro de una celda de .ds-table (Portal Cliente: botones .ds-btn
   sueltos en <td>, sin wrapper .ds-table-actions consistente -- ver
   portal-client.js) -- mismo pedido que .admin-table-actions en
   admin-shell.css: "icono + texto sin fondo, fondo sutil solo en hover".
   .ds-btn-outline conserva su borde visible en el resto del sistema (fuera
   de tablas) por diseno; aca se quita para que las acciones de fila lean
   como texto/icono puro, no como chips. */
:root[data-theme="dark"] .ds-table td .ds-btn {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
:root[data-theme="dark"] .ds-table td .ds-btn:hover:not(:disabled) {
  background: var(--ds-table-row-hover-bg);
  border-color: transparent;
}

/* Adaptador DS-016: exclusivamente tabla y paginación de Empresas Admin. */
#section-empresas .ds-data-table-surface { padding: 0; overflow: hidden; }
#empresasTable.ds-table-surface th { color: var(--ds-text-secondary); font-size: var(--ds-fs-table-header); font-weight: var(--ds-fw-semibold); }
#empresasTable.ds-table-surface tbody tr { transition: background var(--ds-transition-fast); }
#empresasTable.ds-table-surface tbody tr:hover { background: var(--ds-table-row-hover-bg); }
#empresasPaginationFooter.ds-table-pagination { gap: var(--ds-space-2); }
#empresasPaginationControls.ds-table-pagination-controls .ds-btn { min-width: var(--ds-control-xs); padding-inline: var(--ds-space-1); }
@media (max-width: 1024px) {
  #empresasPaginationFooter.ds-table-pagination { align-items: flex-start; flex-direction: column; }
  #empresasPaginationControls.ds-table-pagination-controls { max-width: 100%; overflow-x: auto; padding-bottom: var(--ds-space-half); }
}
@media (max-width: 640px) {
  #empresasTable.ds-table-surface { min-width: 760px; }
  #empresasPaginationFooter.ds-table-pagination { padding: var(--ds-space-1); }
}


/* source: src/styles/cards.css */
/**
 * LM Contable — Design System v3.0 — Cards, KPIs, Badges
 */
.ds-card {
  background: var(--ds-card-bg);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-card);
  box-shadow: var(--ds-shadow-sm);
  padding: var(--ds-space-3);
  transition: box-shadow var(--ds-transition-base), transform var(--ds-transition-base);
}
.ds-card-default { background: var(--ds-card-bg); }
.ds-card-elevated { border-color: var(--ds-transparent); box-shadow: var(--ds-shadow-md); }
.ds-card-flat { border-color: var(--ds-transparent); box-shadow: none; }
.ds-card-outline { box-shadow: none; }
.ds-card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--ds-space-2); }
.ds-card-header h2, .ds-card-header h3, .ds-card-header h4, .ds-card-header h5, .ds-card-header h6 { margin: 0; color: var(--ds-text); }
.ds-card-body { color: var(--ds-text); }
.ds-card-footer { display: flex; align-items: center; justify-content: flex-end; gap: var(--ds-space-1); margin-top: var(--ds-space-2); }
.ds-card-actions { display: flex; align-items: center; gap: var(--ds-space-1); }
.ds-card-hover:hover, .ds-card-interactive:hover { box-shadow: var(--ds-shadow-md); transform: scale(1.01); }
.ds-card-interactive { cursor: pointer; }
.ds-card-interactive:focus-visible { outline: var(--ds-focus-ring-width) solid var(--ds-focus-ring-color); outline-offset: var(--ds-focus-offset); }
.ds-card.is-selected, .ds-card[data-selected="true"] { border-color: var(--ds-action); box-shadow: var(--ds-shadow-input-focus); }
.ds-card.is-disabled, .ds-card[aria-disabled="true"] { opacity: var(--ds-button-disabled-opacity); pointer-events: none; transform: none; }

/* KPI: numeros grandes, jerarquia clara, estilo "Power BI" */
.ds-card-kpi { display: flex; flex-direction: column; gap: var(--ds-space-2); }
.ds-card-kpi-head { display: flex; align-items: center; justify-content: space-between; }
.ds-card-kpi-label { font-size: var(--ds-fs-caption); font-weight: var(--ds-fw-semibold); color: var(--ds-text-secondary); text-transform: uppercase; letter-spacing: 0.04em; }
.ds-card-kpi-value { font-size: 30px; font-weight: var(--ds-fw-bold); color: var(--ds-text); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.ds-card-kpi-delta { font-size: 12px; font-weight: var(--ds-fw-semibold); display: inline-flex; align-items: center; gap: 4px; }
.ds-card-kpi-delta.v-up { color: var(--ds-success); }
.ds-card-kpi-delta.v-down { color: var(--ds-danger); }
.ds-card-kpi-delta.v-flat { color: var(--ds-text-muted); }
.ds-card-kpi-icon {
  width: 40px; height: 40px; border-radius: var(--ds-radius-input);
  display: flex; align-items: center; justify-content: center;
  background: var(--ds-info-bg); color: var(--ds-info); font-size: 15px;
}
.ds-card-kpi-icon svg { width: var(--ds-icon-feature); height: var(--ds-icon-feature); }
.ds-card-kpi-icon.v-success { background: var(--ds-success-bg); color: var(--ds-success); }
.ds-card-kpi-icon.v-warning { background: var(--ds-warning-bg); color: var(--ds-warning); }
.ds-card-kpi-icon.v-danger { background: var(--ds-danger-bg); color: var(--ds-danger); }
.ds-card-kpi-icon.v-info { background: var(--ds-info-bg); color: var(--ds-info); }
.ds-card-kpi-icon.v-purple { background: var(--ds-purple-bg); color: var(--ds-purple-500); }

/* KPI Card oficial: composición de Card; nunca calcula ni actualiza valores. */
.ds-kpi-card { min-width: 0; }
.ds-kpi-card .ds-card-body { display: grid; gap: var(--ds-space-1); }
.ds-kpi-head, .ds-kpi-value-row, .ds-kpi-meta { display: flex; align-items: center; }
.ds-kpi-head { justify-content: space-between; gap: var(--ds-space-2); }
.ds-kpi-meta { gap: var(--ds-space-1); }
.ds-kpi-title { margin: 0; color: var(--ds-text-secondary); font-size: var(--ds-fs-caption); font-weight: var(--ds-fw-semibold); letter-spacing: var(--ds-type-label-letter-spacing); text-transform: uppercase; }
.ds-kpi-icon { width: var(--ds-control-md); height: var(--ds-control-md); display: inline-flex; align-items: center; justify-content: center; flex: none; border-radius: var(--ds-radius-input); background: var(--ds-info-bg); color: var(--ds-info); }
.ds-kpi-icon svg { width: var(--ds-icon-md); height: var(--ds-icon-md); }
.ds-kpi-value-row { justify-content: space-between; gap: var(--ds-space-2); }
.ds-kpi-value { color: var(--ds-text); font-size: var(--ds-type-kpi-size); font-weight: var(--ds-fw-bold); font-variant-numeric: var(--ds-type-financial-variant); }
.ds-kpi-subtitle { margin: 0; color: var(--ds-text-muted); font-size: var(--ds-fs-caption); }
.ds-kpi-trend { display: inline-flex; align-items: center; white-space: nowrap; font-size: var(--ds-fs-caption); font-weight: var(--ds-fw-semibold); font-variant-numeric: var(--ds-type-financial-variant); }
.ds-kpi-trend-up { color: var(--ds-success); }
.ds-kpi-trend-down { color: var(--ds-danger); }
.ds-kpi-trend-flat { color: var(--ds-text-muted); }
.ds-kpi-card-compact { padding: var(--ds-space-2); }
.ds-kpi-card-compact .ds-kpi-value { font-size: var(--ds-fs-h2); }
.ds-kpi-card-highlight { border-color: var(--ds-action); }
.ds-kpi-loading-value { display: block; width: 60%; height: var(--ds-type-kpi-size); }
.ds-kpi-loading-label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
@media (max-width: 640px) { .ds-kpi-card { padding: var(--ds-space-2); } .ds-kpi-value { font-size: var(--ds-fs-h2); } }

/* Adaptador DS-017: únicamente cuatro indicadores rápidos de Dashboard Admin. */
#section-dashboard .admin-welcome-stats-row > .admin-kpi-card.ds-kpi-card { color: var(--ds-text); }
#section-dashboard .admin-welcome-stats-row > .ds-kpi-card .admin-kpi-label { color: var(--ds-text-secondary); font-weight: var(--ds-fw-semibold); }
#section-dashboard .admin-welcome-stats-row > .ds-kpi-card .admin-kpi-value { font-variant-numeric: var(--ds-type-financial-variant); }

/* Card de acceso rapido (icono + titulo + descripcion + flecha) */
.ds-card-access {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  width: 100%;
  font-family: inherit;
  text-align: left;
}
.ds-card-access-icon {
  width: 44px; height: 44px; border-radius: var(--ds-radius-input);
  display: flex; align-items: center; justify-content: center; font-size: 17px;
  background: var(--ds-info-bg); color: var(--ds-info);
}
.ds-card-access-icon svg { width: 20px; height: 20px; }
.ds-card-access-icon.v-success { background: var(--ds-success-bg); color: var(--ds-success); }
.ds-card-access-icon.v-warning { background: var(--ds-warning-bg); color: var(--ds-warning); }
.ds-card-access-icon.v-danger { background: var(--ds-danger-bg); color: var(--ds-danger); }
.ds-card-access-icon.v-info { background: var(--ds-info-bg); color: var(--ds-info); }
.ds-card-access-icon.v-purple { background: var(--ds-purple-bg); color: var(--ds-purple-500); }
.ds-card-access-icon.v-orange { background: var(--ds-orange-bg); color: #EA580C; }
.ds-card-access-icon.v-cyan { background: var(--ds-cyan-bg); color: #0891B2; }

/* Chips de icono en oscuro (componentes compartidos, ver admin-shell.css/
   portal-client-shell.css/dashboard-shell.css para el mismo tratamiento en
   los especificos de cada superficie, y --ds-icon-tile-* en themes/dark.css
   para la formula y el porque): fondo tonal oscuro y semitransparente +
   icono en su tono claro/brillante + borde e iluminacion sutiles, en vez del
   fondo SOLIDO + icono blanco anterior. Solo en oscuro, en claro los
   pasteles siguen igual. */
:root[data-theme="dark"] .ds-card-kpi-icon,
:root[data-theme="dark"] .ds-card-kpi-icon.v-info,
:root[data-theme="dark"] .ds-kpi-icon,
:root[data-theme="dark"] .ds-card-access-icon,
:root[data-theme="dark"] .ds-card-access-icon.v-info {
  background: var(--ds-icon-tile-info-bg);
  color: var(--ds-icon-tile-info-fg);
  border: 1px solid var(--ds-icon-tile-info-border);
  box-shadow: var(--ds-icon-tile-info-shadow);
}
:root[data-theme="dark"] .ds-card-kpi-icon.v-success,
:root[data-theme="dark"] .ds-card-access-icon.v-success {
  background: var(--ds-icon-tile-success-bg);
  color: var(--ds-icon-tile-success-fg);
  border: 1px solid var(--ds-icon-tile-success-border);
  box-shadow: var(--ds-icon-tile-success-shadow);
}
:root[data-theme="dark"] .ds-card-kpi-icon.v-warning,
:root[data-theme="dark"] .ds-card-access-icon.v-warning {
  background: var(--ds-icon-tile-warning-bg);
  color: var(--ds-icon-tile-warning-fg);
  border: 1px solid var(--ds-icon-tile-warning-border);
  box-shadow: var(--ds-icon-tile-warning-shadow);
}
:root[data-theme="dark"] .ds-card-kpi-icon.v-danger,
:root[data-theme="dark"] .ds-card-access-icon.v-danger {
  background: var(--ds-icon-tile-danger-bg);
  color: var(--ds-icon-tile-danger-fg);
  border: 1px solid var(--ds-icon-tile-danger-border);
  box-shadow: var(--ds-icon-tile-danger-shadow);
}
:root[data-theme="dark"] .ds-card-kpi-icon.v-purple,
:root[data-theme="dark"] .ds-card-access-icon.v-purple {
  background: var(--ds-icon-tile-purple-bg);
  color: var(--ds-icon-tile-purple-fg);
  border: 1px solid var(--ds-icon-tile-purple-border);
  box-shadow: var(--ds-icon-tile-purple-shadow);
}
:root[data-theme="dark"] .ds-card-kpi-icon.v-orange,
:root[data-theme="dark"] .ds-card-access-icon.v-orange {
  background: var(--ds-icon-tile-orange-bg);
  color: var(--ds-icon-tile-orange-fg);
  border: 1px solid var(--ds-icon-tile-orange-border);
  box-shadow: var(--ds-icon-tile-orange-shadow);
}
:root[data-theme="dark"] .ds-card-kpi-icon.v-cyan,
:root[data-theme="dark"] .ds-card-access-icon.v-cyan {
  background: var(--ds-icon-tile-cyan-bg);
  color: var(--ds-icon-tile-cyan-fg);
  border: 1px solid var(--ds-icon-tile-cyan-border);
  box-shadow: var(--ds-icon-tile-cyan-shadow);
}
/* Estados interactivos: .ds-card-access y .ds-card-interactive son los
   contenedores clicables reales de estos chips (ver arriba/.ds-card-interactive
   en este mismo archivo) -- sube apenas el brillo en hover/focus, sin glow ni
   animacion. .ds-card.is-disabled ya baja la opacidad de toda la tarjeta
   (linea 25 de este archivo), asi que el chip de icono se atenua con ella
   sin necesidad de una regla aparte. */
:root[data-theme="dark"] .ds-card-access:hover .ds-card-access-icon,
:root[data-theme="dark"] .ds-card-access:focus-visible .ds-card-access-icon,
:root[data-theme="dark"] .ds-card-interactive:hover .ds-card-kpi-icon,
:root[data-theme="dark"] .ds-card-interactive:focus-visible .ds-card-kpi-icon,
:root[data-theme="dark"] .ds-card-interactive:hover .ds-kpi-icon,
:root[data-theme="dark"] .ds-card-interactive:focus-visible .ds-kpi-icon {
  filter: brightness(1.15);
}
.ds-card-access-title { font-size: var(--ds-fs-subtitle); font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
.ds-card-access-desc { font-size: var(--ds-fs-caption); color: var(--ds-text-secondary); line-height: 1.4; }
.ds-card-access-arrow { color: var(--ds-accent); font-size: 13px; margin-top: auto; transition: transform var(--ds-transition-fast); }
.ds-card-access:hover .ds-card-access-arrow { transform: translateX(3px); }

/* Badge no interactivo: texto, icono decorativo y contador corto.
   Sin text-transform:uppercase -- el texto se muestra tal cual lo pasa el
   caller (Ej. "Activo", no "ACTIVO"); pedido explicito para que ningun
   badge de estado (Usuarios, Empresas, Mi Empresa, etc.) quede en mayuscula
   forzada, en ambos portales. Cada caller ya pasa el texto en el casing
   correcto (ver dsBadge en design-system.js). */
.ds-badge {
  display: inline-flex; align-items: center; gap: var(--ds-space-half);
  border: var(--ds-badge-border-width) solid var(--ds-border);
  border-radius: var(--ds-radius-badge);
  font-weight: var(--ds-fw-bold);
  /* line-height:1 (antes 'normal', ~1.2): con leading extra el line-box del
     texto queda mas alto que sus glifos, y el punto de estado (centrado por
     align-items respecto a ESE line-box, no al alto visible de las letras)
     quedaba corrido hacia arriba -- reportado "el punto no esta en la mitad
     del texto". Con line-height:1 el line-box coincide con el alto real de
     la fuente y el centrado optico coincide con el geometrico. */
  letter-spacing: normal; line-height: 1; white-space: nowrap;
}
.ds-badge-sm { padding: var(--ds-badge-padding-y-sm) var(--ds-badge-padding-x-sm); font-size: var(--ds-badge-font-size-sm); }
.ds-badge-md { padding: var(--ds-badge-padding-y-md) var(--ds-badge-padding-x-md); font-size: var(--ds-badge-font-size-md); }
.ds-badge-primary { background: var(--ds-primary-badge-bg); border-color: var(--ds-primary-badge-bg); color: var(--ds-primary-badge-text); }
.ds-badge-success { background: var(--ds-success-bg); border-color: var(--ds-success-badge-border); color: var(--ds-success-badge-text); }
.ds-badge-warning { background: var(--ds-warning-bg); border-color: var(--ds-warning-badge-border); color: var(--ds-warning-badge-text); }
.ds-badge-danger { background: var(--ds-danger-bg); border-color: var(--ds-danger-badge-border); color: var(--ds-danger-badge-text); }
.ds-badge-info { background: var(--ds-info-bg); border-color: var(--ds-info-badge-border); color: var(--ds-info-badge-text); }
.ds-badge-neutral { background: var(--ds-neutral-bg); border-color: var(--ds-neutral-badge-border); color: var(--ds-neutral-badge-text); }
/* 3 variantes de la Paleta de Estados (ver themes/dark.css) sin equivalente
   previo en dsBadge: Proximo a vencer, En revision, Informativo. */
.ds-badge-orange { background: var(--ds-orange-bg); border-color: var(--ds-orange-badge-border); color: var(--ds-orange-badge-text); }
.ds-badge-purple { background: var(--ds-purple-bg); border-color: var(--ds-purple-badge-border); color: var(--ds-purple-badge-text); }
.ds-badge-cyan { background: var(--ds-cyan-bg); border-color: var(--ds-cyan-badge-border); color: var(--ds-cyan-badge-text); }
/* Roles (dsRoleBadge): clasificacion, no estado -- sin punto, paleta
   reducida a gris neutro + un azul LM muy tenue solo para Administrador. */
.ds-badge-role-neutral { background: var(--ds-neutral-bg); border-color: var(--ds-neutral-badge-border); color: var(--ds-neutral-badge-text); }
.ds-badge-role-admin { background: var(--ds-role-admin-bg); border-color: var(--ds-role-admin-badge-border); color: var(--ds-role-admin-badge-text); }
.ds-badge.is-disabled, .ds-badge[aria-disabled="true"] { opacity: var(--ds-badge-disabled-opacity); }
.ds-badge-icon, .ds-badge-icon svg { width: 1em; height: 1em; flex: none; }
.ds-badge-count { font-variant-numeric: tabular-nums; }
/* Punto de estado (dsBadge opt. `dot`): 7px, currentColor -- hereda el color
   semantico del texto del badge, ya correcto en claro/oscuro sin tokens
   nuevos. Reutiliza el mismo criterio que .status-dot (admin-shell.css /
   portal-client-shell.css). */
/* Pulso suave (pedido explicito "que sea reactivo, no un punto fijo"):
   opacity+scale, sin box-shadow/blur -- no es el "efecto glow" que se pidio
   evitar para el fondo del badge, solo el punto de 7px respira. Se apaga con
   prefers-reduced-motion, mismo criterio que .admin-toast/.pcli-toast. */
.ds-badge-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; animation: ds-badge-dot-pulse 2s ease-in-out infinite; }
@keyframes ds-badge-dot-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .5; transform: scale(.8); } }
@media (prefers-reduced-motion: reduce) { .ds-badge-dot { animation: none; } }

/* Alert compone Card + Badge; no define motion, autocierre ni comportamiento. */
.ds-alert { padding: var(--ds-space-2); border-radius: var(--ds-radius-card); box-shadow: none; }
.ds-alert-info { background: var(--ds-info-bg); border-color: var(--ds-info-badge-border); }
.ds-alert-success { background: var(--ds-success-bg); border-color: var(--ds-success-badge-border); }
.ds-alert-warning { background: var(--ds-warning-bg); border-color: var(--ds-warning-badge-border); }
.ds-alert-danger { background: var(--ds-danger-bg); border-color: var(--ds-danger-badge-border); }
.ds-alert-content { display: flex; align-items: flex-start; gap: var(--ds-space-1); }
.ds-alert-icon { width: var(--ds-icon-md); height: var(--ds-icon-md); flex: none; color: var(--ds-text); }
.ds-alert-copy { min-width: 0; display: grid; gap: var(--ds-space-half); }
/* justify-items:stretch es el default de un grid item -- sin esto, el
   badge de tono (dsBadge(ALERT_LABELS[tone]...) en dsAlert()) se estira al
   ancho completo de la columna del grid en vez de quedar del tamaño de su
   propio texto (reportado: "Información" se veia como una franja ancha en
   vez de una pildora). La descripcion (<p>) sigue estirandose normal para
   poder ajustar el texto en varias lineas -- solo se acota el badge.
   RESTAURADO 2026-08-23: ver comentario en globals.css sobre el core.css
   hand-added que un `npm run build:css` posterior borro sin querer. */
.ds-alert-copy > .ds-badge { justify-self: start; }
.ds-alert-description { margin: 0; color: var(--ds-text); font-size: var(--ds-fs-body); line-height: 1.5; }
.ds-alert-dismiss { flex: none; }
.ds-alert .ds-card-footer { justify-content: flex-start; }

/* Adaptador DS-010: conserva exactamente el aviso irreversible de Empresas. */
.admin-modal-danger-text.ds-alert-legacy {
  display: block; padding: 0; border: 0; border-radius: 0; box-shadow: none;
  background: var(--ds-transparent); color: var(--ds-text);
  font-size: var(--ds-fs-caption); line-height: 1.6;
}

/* ============================== VISTA PREVIA DE DOCUMENTOS (Documentos, ver
   previewDocumento() en admin.js/portal-client.js) ==============================
   Visor grande (iframe/img, la mayor parte del ancho) + panel lateral de
   informacion/estado/alertas de vencimiento -- referencia visual pedida por
   el usuario: visor documental profesional a la izquierda, panel contextual
   a la derecha. ~90-95% del ancho / ~90-94% del alto del viewport, muy por
   encima del .ds-modal-lg estandar (720px) -- clase propia en vez de un
   4to tamano generico en globals.css porque nada mas en el sistema necesita
   un modal tan grande. Movido aca (antes solo en admin-shell.css) porque
   Portal Cliente reusa el mismo componente para su propia vista previa de
   Documentos (con el card de Estado interactivo en vez de solo-lectura).
   AL FINAL del archivo a proposito: .docprev-info-icon necesita ganarle en
   la cascada a .ds-card-access-icon (mismo elemento, misma especificidad,
   ambas clases) para quedar en 30px en vez de 44px -- con este bloque antes
   en el archivo, .ds-card-access-icon (mas abajo) ganaba el empate y el
   icono salia sobredimensionado, aplastado contra el divisor de la fila
   siguiente (reportado: "iconos muy pegados a la linea divisoria"). */
.docprev-modal {
  width: 94vw; max-width: 94vw;
  height: calc(var(--app-vh, 1vh) * 92); max-height: calc(var(--app-vh, 1vh) * 92);
  display: flex; flex-direction: column;
}
.docprev-body { flex: 1; min-height: 0; display: flex; overflow: hidden; }

/* position:relative -- ancla el boton flotante de descarga de imagenes (ver
   .docprev-image-download-btn mas abajo). */
.docprev-viewer { position: relative; flex: 1; min-width: 0; display: flex; background: var(--ds-bg-secondary); }
.docprev-viewer-frame { flex: 1; display: flex; }
.docprev-viewer-frame iframe { flex: 1; width: 100%; height: 100%; border: 0; }
.docprev-viewer-frame img { max-width: 100%; max-height: 100%; margin: auto; display: block; object-fit: contain; }
.docprev-viewer-frame > p { margin: auto; padding: 2rem; text-align: center; color: var(--ds-text-muted); }

/* Prueba: sin barra superior propia en este modal (pedido explicito) -- un
   PDF ya trae su descarga en la barra nativa del visor del navegador; para
   imagenes hay un boton flotante propio (abajo). Circulo oscuro fijo
   (no --ds-surface/--ds-card-bg) a proposito: tiene que leerse igual sobre
   CUALQUIER imagen, sin depender de si el tema es claro u oscuro. */
.docprev-image-download-btn {
  position: absolute; right: 16px; bottom: 16px;
  width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(17, 24, 39, .72); border: 1px solid rgba(255, 255, 255, .16);
  color: #fff; cursor: pointer; box-shadow: var(--ds-shadow-md);
  transition: background var(--ds-transition-fast);
}
.docprev-image-download-btn:hover { background: rgba(17, 24, 39, .88); }
.docprev-image-download-btn svg { width: 18px; height: 18px; }

.docprev-panel {
  flex: 0 0 380px; width: 380px; max-width: 380px; min-height: 0;
  display: flex; flex-direction: column;
  border-left: 1px solid var(--ds-border); background: var(--ds-surface);
}
/* Fila de tabs -- ahora tambien carga la X de cerrar (pedido explicito: sin
   barra superior, el cierre se muda al lado de "Historial de estados"). El
   padding/border que antes tenia .docprev-tabs solo se mueve a esta fila. */
.docprev-tabs-row { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px 10px 16px; border-bottom: 1px solid var(--ds-border); }
.docprev-tabs { flex: 1; min-width: 0; }
/* Portal Cliente: sin "Historial de estados" (pedido explicito), un solo
   panel ya no necesita tabs -- titulo estatico en su lugar, mismo tamaño/
   peso que tenia el tab activo para no cambiar el aspecto de la fila. */
.docprev-tabs-title { flex: 1; min-width: 0; margin: 0; font-size: 13px; font-weight: var(--ds-fw-semibold); color: var(--ds-text); }
/* Un poco mas chica que el tamaño default de .ds-modal-close (29px) -- en
   este contexto comparte fila con los tabs y el ancho es acotado (panel de
   380px), cada px cuenta para que "Información del documento" no dispare el
   scroll horizontal de .ds-tabs. */
/* margin-top negativo: centrado por caja ya daba ~1px de diferencia contra
   el texto del tab, pero el subrayado activo (box-shadow inset, abajo del
   tab) le suma peso visual a la mitad inferior de la fila -- ese desbalance
   óptico hacia que la X se viera corrida hacia abajo (reportado). */
.docprev-tabs-close { flex-shrink: 0; padding: 5px; margin-top: -2px; }
.docprev-tabs-close svg { width: 12px; height: 12px; }
.docprev-panel-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 16px; }
.docprev-panel-scroll [role="tabpanel"] { display: grid; gap: 14px; }
.docprev-panel-scroll [role="tabpanel"][hidden] { display: none; }

.docprev-info-card { display: grid; gap: 14px; }
.docprev-info-card .profile-info-row + .profile-info-row { padding-top: 14px; border-top: 1px solid var(--ds-border); }
/* Solo tamaño (30px, a juego con el resto del panel) -- el color lo da
   .ds-card-access-icon.v-* (ver docPreviewInfoRow en admin.js/portal-client.js),
   que ya resuelve claro/oscuro por si solo (mas arriba en este archivo). */
.docprev-info-icon { width: 30px; height: 30px; flex-shrink: 0; border-radius: 8px; margin-top: 1px; }
.docprev-info-icon svg, .docprev-info-icon i { width: 15px; height: 15px; }

.docprev-status-card { display: grid; gap: 10px; }
.docprev-status-head { display: flex; align-items: center; gap: 12px; }
.docprev-status-desc { margin: 0; font-size: 12.5px; color: var(--ds-text-muted); line-height: 1.5; }

.docprev-alert-card { display: grid; gap: 12px; }
.docprev-alert-head { display: flex; align-items: flex-start; gap: 12px; }
.docprev-alert-copy { display: grid; gap: 3px; min-width: 0; }
.docprev-alert-copy h4 { margin: 0; font-size: 13.5px; color: var(--ds-text); }
.docprev-alert-copy p { margin: 0; font-size: 12.5px; color: var(--ds-text-muted); line-height: 1.5; }
.docprev-alert-summary { font-size: 12px; color: var(--ds-text-secondary); font-weight: 600; }

/* "Configurar alertas" (modal chico apilado encima, ver #modalDocumentAlertConfig -- Admin) */
.docprev-alert-days { display: grid; gap: 8px; padding: 12px; border: 1px solid var(--ds-border); border-radius: var(--ds-radius-card); background: var(--ds-bg-secondary); }
.docprev-alert-days.is-disabled { opacity: var(--ds-button-disabled-opacity); pointer-events: none; }
.docprev-alert-hint { margin: 0; font-size: 11.5px; color: var(--ds-text-muted); }

/* Historial de estados (Admin -- Portal Cliente ya no tiene esta pestaña,
   ver renderDocPreviewInfoTab en portal-client.js) -- reusa .audit-timeline
   (misma estructura visual, sin duplicar la regla del riel/punto) solo con
   el texto propio de esta vista. */
.docprev-timeline-item strong { display: block; font-size: 13px; color: var(--ds-text); }
.docprev-timeline-item span { display: block; color: var(--ds-text-muted); font-size: .75rem; margin-top: 2px; }

.docprev-panel-handle { display: none; flex: 0 0 auto; align-items: center; justify-content: center; padding: 8px; cursor: pointer; background: none; border: 0; }
.docprev-panel-handle::before { content: ''; width: 36px; height: 4px; border-radius: 2px; background: var(--ds-border); }

/* Responsive: el visor conserva casi todo el viewport, el panel pasa a
   bottom sheet (colapsado, con un tirador para expandirlo) en vez de
   compartir el ancho con el visor -- pedido explicito ("no reduzcas el PDF
   hasta hacerlo ilegible"). */
@media (max-width: 900px) {
  .docprev-modal { width: 100vw; max-width: 100vw; height: calc(var(--app-vh, 1vh) * 100); max-height: none; border-radius: 0; }
  .docprev-body { flex-direction: column; position: relative; }
  .docprev-panel {
    position: absolute; inset: auto 0 0 0; flex: 0 0 auto; width: 100%; max-width: 100%;
    max-height: 75%; border-left: 0; border-top: 1px solid var(--ds-border);
    border-radius: 16px 16px 0 0; box-shadow: 0 -12px 30px rgba(0, 0, 0, .18);
    transform: translateY(calc(100% - 46px)); transition: transform var(--ds-transition-base);
  }
  .docprev-panel.is-expanded { transform: translateY(0); }
  .docprev-panel-handle { display: flex; }
}

/* ===================== MOBILE-FIRST / PWA — Admin + Portal Cliente (2026-08-31) =====================
   Adaptación de arquitectura de información (no solo CSS de compresión), módulo por
   módulo, pedida explícitamente por el usuario -- alcance ampliado a Portal Cliente
   el mismo día. Vive acá (bundleado en core.css) y no en admin-shell.css porque
   portal-client.html no carga ese archivo -- ambos portales sí cargan core.css.
   Piloto: Empresas (Admin). Cero cambios en desktop/tablet (>640px): todo bajo
   @media (max-width:640px). */

/* ---- Lista Enriquecida (reemplaza la tabla con scroll horizontal en mobile) ----
   La MISMA data de la tabla desktop, solo reflowed verticalmente -- ninguna columna
   se pierde. Patrón A de la clasificación pedida ("lista enriquecida"): identidad+
   estado arriba, pares etiqueta/valor abajo, flecha indica que la fila es tocable
   (abre el mismo drawer/detalle que ya existía como única acción de fila). Nombrado
   genérico (.ds-mobile-list-*, no .empresas-list-*) a propósito -- se reusa tal cual
   en Usuarios, Nómina, Vacaciones, Carga (Admin). */
.ds-mobile-list { display: none; }
.ds-desktop-table { display: block; }
@media (max-width: 640px) {
  .ds-desktop-table { display: none !important; }
  /* Admin: .admin-table-wrap ya trae display:block !important (admin-shell.css,
     "MOBILE FINAL OVERRIDES", pensado para las tablas que SÍ muestran scroll
     horizontal) -- un solo !important de igual especificidad no le gana si
     admin-shell.css carga después de core.css en el documento (empate de
     especificidad se resuelve por orden de aparición). El refuerzo de 2 clases
     vive en admin-shell.css junto a esa regla (single source of truth de POR QUÉ
     hace falta), no acá -- acá solo el caso genérico/Portal Cliente. */
  .ds-mobile-list { display: flex; flex-direction: column; gap: 10px; padding: 12px; }
  .ds-mobile-list-row {
    position: relative; display: flex; flex-direction: column; gap: 10px;
    width: 100%; padding: 12px 34px 12px 12px; text-align: left; font-family: inherit;
    background: var(--ds-surface); border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius-card); cursor: pointer;
    transition: border-color var(--ds-transition-fast), box-shadow var(--ds-transition-fast);
  }
  .ds-mobile-list-row:active { border-color: var(--ds-accent); box-shadow: var(--ds-shadow-sm); }
  /* min-width:0 es necesario (no solo en -identity, más abajo): al ser flex
     item de .ds-mobile-list-row (columna) Y a la vez flex container propio,
     su min-width por defecto ("auto") se resuelve contra el contenido de SUS
     hijos -- sin esto, un nombre largo hacía que esta fila creciera más ancha
     que la propia tarjeta y el texto se saliera del borde/radio (bug real,
     reportado con captura en Empresas: "EQUIPOS Y BARCAZAS DE LA COSTA SAS"
     desbordando). Mismo fix clásico que .ds-mobile-list-row-identity. */
  .ds-mobile-list-row-head { display: flex; align-items: center; gap: 10px; min-width: 0; }
  .ds-mobile-list-row-identity { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
  .ds-mobile-list-row-identity strong { font-size: 13.5px; color: var(--ds-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ds-mobile-list-row-sub { font-size: 11px; color: var(--ds-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ds-mobile-list-row-head .admin-badge { flex-shrink: 0; }
  .ds-mobile-list-row-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; padding-top: 10px; border-top: 1px solid var(--ds-border); }
  .ds-mobile-list-row-meta-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .ds-mobile-list-row-meta-item-wide { grid-column: 1 / -1; }
  .ds-mobile-list-row-meta-item span:first-child { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ds-text-muted); }
  .ds-mobile-list-row-meta-item strong { font-size: 12px; color: var(--ds-text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ds-mobile-list-row-arrow { position: absolute; top: 50%; right: 10px; transform: translateY(-50%); color: var(--ds-text-muted); display: flex; }
  .ds-mobile-list-row-arrow svg { width: var(--ds-icon-control); height: var(--ds-icon-control); }
  .ds-mobile-list-empty { padding: 8px 4px; }

  /* Variante "estática" (cualquier lista cuya fila tenga VARIAS acciones en un
     menú "⋮", no una sola acción de tap-en-toda-la-fila): <div>, no <button> --
     nada pasa al tocar la fila en sí, así que no debe verse/comportarse como
     tappable. El botón "⋮" real vive en la esquina donde .ds-mobile-list-row
     pone su flecha, mismo lugar, pero con área de toque propia (36px,
     min-height cómodo) en vez de un ícono decorativo. */
  .ds-mobile-list-row.ds-mobile-list-row-static { cursor: default; }
  .ds-mobile-list-row.ds-mobile-list-row-static:active { border-color: var(--ds-border); box-shadow: none; }
  .ds-mobile-list-row-menu-btn {
    position: absolute; top: 10px; right: 10px; z-index: 1;
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0; border: 1px solid var(--ds-border); border-radius: var(--ds-radius-btn);
    background: var(--ds-surface); color: var(--ds-text-secondary); cursor: pointer;
  }
  .ds-mobile-list-row-menu-btn svg { width: var(--ds-icon-control); height: var(--ds-icon-control); }
  .ds-mobile-list-row-menu-btn:active { border-color: var(--ds-accent); color: var(--ds-accent); }

  /* Fila estática con 2 acciones inline (ej. Editar+Eliminar) -- ni el patrón
     "toda la fila abre un drawer" ni el patrón "⋮ con 3+ acciones" encajan
     cuando son exactamente 2 acciones ya diferenciadas (una normal, una
     v-danger) -- botones de ancho igual, lado a lado, en vez de un menú
     flotante para solo 2 opciones. */
  .ds-mobile-list-row-actions { display: flex; gap: 8px; padding-top: 10px; border-top: 1px solid var(--ds-border); }
  /* .admin-btn (Portal Admin) / .ds-btn (Portal Cliente) -- mismo componente
     de botón, 2 nombres de clase distintos según el portal. */
  .ds-mobile-list-row-actions .admin-btn, .ds-mobile-list-row-actions .ds-btn { flex: 1; justify-content: center; }

  /* Variante para 1-2 acciones que YA son botones de ícono compactos propios
     (ej. .request-row-action en Portal Cliente, 30x30px) -- en flujo normal
     (NO position:absolute como .ds-mobile-list-row-arrow/-menu-btn): un grupo
     de 2 íconos de 30px necesita ~66px, más de lo que el padding-right de
     34px de la fila reserva -- superpuesto arriba a la derecha invadiría el
     badge de estado de la cabecera. Fila propia alineada a la derecha, mismo
     borde superior que .ds-mobile-list-row-actions, sin estirar los botones. */
  .ds-mobile-list-row-icon-actions { display: flex; justify-content: flex-end; gap: 6px; padding-top: 10px; border-top: 1px solid var(--ds-border); }

  /* Equivalente mobile de un <tfoot> de totales de una tabla (ej. "Total 4
     empleados · Disponible: X días") -- una fila apilada no tiene dónde poner
     un total por columna, así que se resume en una sola línea antes de la
     lista. Vacío (sin contenido) no ocupa espacio. */
  .ds-mobile-list-summary { padding: 10px 12px 0; font-size: 12px; color: var(--ds-text-secondary); font-weight: 600; }
  .ds-mobile-list-summary:empty { display: none; }
}

/* ---- Filtros: "[Buscar] [Filtros]" con bottom sheet (patrón F, sección 10) ----
   El buscador queda siempre visible; los demás filtros se ocultan del toolbar
   inline en mobile y se reubican dentro del bottom sheet al tocar "Filtros" (ver
   openEmpresasFilterSheet en admin.js -- reubica el nodo real, no lo duplica). El
   botón vive siempre en el DOM; se muestra recién en mobile para no alterar el
   toolbar de escritorio. */
/* !important necesario: el adaptador de Design System (design-system.js,
   adoptDesignSystemSurface) le agrega ds-btn/ds-btn-secondary a cualquier
   <button> genérico -- incluido este -- y esa clase trae su propio
   display:flex con la misma o mayor especificidad, ganándole a esta regla sin
   !important (bug real, encontrado con playwright-cli: "Filtros" quedaba
   visible en escritorio junto a Limpiar/Aplicar/Nueva Factura en Facturación). */
.ds-mobile-filter-trigger { display: none !important; }
@media (max-width: 640px) {
  /* Scoped a .admin-toolbar (no un .ds-mobile-filter-field global) a propósito:
     un .ds-mobile-filter-field reubicado dentro del sheet (ver más abajo) ya no
     tiene ese ancestro -- vive en .ds-drawer-body -- así que esta regla deja de
     matchear ahí solo. Un intento anterior con ".ds-mobile-filter-field
     {display:none!important}" sin scope terminaba ocultando los campos
     TAMBIÉN adentro del sheet, porque !important le gana a cualquier regla NO
     !important sin importar dónde viva el elemento (bug real, encontrado con
     playwright-cli: el sheet de Filtros de Facturación se veía vacío).
     !important sigue haciendo falta acá (no por el scope, sino porque
     Facturación reubica un wrapper con style="display:flex" inline para que el
     par Limpiar/Aplicar siga lado a lado -- un inline le gana a cualquier regla
     externa sin !important), pero como la regla ya no matchea dentro del
     sheet, ahí el inline queda intacto sin competencia. */
  .admin-toolbar .ds-mobile-filter-field { display: none !important; }
  .ds-mobile-filter-trigger { display: inline-flex !important; align-items: center; gap: 6px; white-space: nowrap; }
  /* Dentro del sheet (ver .ds-drawer-sheet en globals.css) los mismos campos
     pasan a ocupar todo el ancho del panel, uno debajo del otro, en vez de su
     ancho "inline" acotado del toolbar de escritorio. Selector genérico sobre
     .ds-mobile-filter-field (no solo .ds-select-picker) porque no todos los
     campos reubicados son un select-picker suelto -- Usuarios (Admin) reubica
     .admin-pagination-size (label "Ver" + select-picker anidado), Empresas
     reubica el select-picker directo. */
  .ds-drawer-sheet .ds-mobile-filter-field { display: block; width: 100%; margin-bottom: 12px; }
  .ds-drawer-sheet .ds-mobile-filter-field:last-child { margin-bottom: 0; }
  .ds-drawer-sheet .ds-select-picker-trigger { width: 100%; }
  .ds-drawer-sheet .admin-pagination-size { display: flex; align-items: center; gap: 10px; }
  .ds-drawer-sheet .admin-pagination-size .ds-select-picker { flex: 1; }
}

/*# sourceMappingURL=core.css.map */
