/* ==========================================================================
   FacturaIslay ERP — Design System (fi-design-system.css)
   ==========================================================================

   FASE UX GLOBAL 1.0 / 2.0 — Fase 0: Infraestructura.

   Este archivo es la ÚNICA fuente oficial de:
     - Variables CSS / tokens (color, tipografía, espaciado, alturas de
       control, radios, sombras, transiciones, iconografía).
     - Componentes visuales reutilizables bajo el prefijo `.fi-*`.

   Documentación completa: docs/FI-DESIGN-SYSTEM.md

   REGLAS DE ESTA FASE (no romper lo existente):
     - Prohibido redefinir selectores de Bootstrap/AdminLTE o etiquetas
       globales: `body`, `html`, `.btn`, `.form-control`, `table`, `.box`,
       `.box-header`, `.box-body`, etc. Este archivo nunca debe cambiar
       cómo se ve un módulo que no lo esté usando explícitamente.
     - Todo vive en `:root` (inerte por definición) o en clases `.fi-*`
       que ningún módulo usa todavía. Cargar este archivo no cambia nada
       visualmente hasta que un módulo adopte una clase `.fi-*` en su
       propio marcado (migración progresiva, módulo por módulo).
     - No se modifica Bootstrap, AdminLTE, DataTables ni ningún vendor.
     - Los componentes que dependen de interacción (dropdown, tabs, modal)
       se apoyan en el JS ya existente de Bootstrap 3 (`data-toggle`,
       `.in`/`.active`), no se agrega JS propio en esta fase.

   NOTA — tipografía (Inter): existe una decisión previa documentada en
   docs/FI-DESIGN-SYSTEM-TIPOGRAFIA.md (`--fi-font-stack`) que quedó
   revertida en el archivo real. Se difiere a propósito: `cajas.css` ya
   tiene 12 reglas `font-family: var(--cj-font) !important` dormidas
   (var(--cj-font) → var(--fi-font-stack)) que se activarían solo con
   declarar el token, cambiando un módulo en producción durante una fase
   que debe ser 100% inerte. Se retoma en una fase de tipografía dedicada.
   ========================================================================== */

:root {
  /* ---------------------------------------------------------------------
     COLOR — paleta primaria (grupo ya mayoritario según auditoría global)
     --------------------------------------------------------------------- */
  --fi-primary: #2563eb;
  --fi-primary-dark: #1d4ed8;
  --fi-primary-light: #3b82f6;
  --fi-primary-soft: #eff6ff;

  --fi-success: #059669;
  --fi-success-soft: #dcfce7;
  --fi-warning: #d97706;
  --fi-warning-soft: #fef3c7;
  --fi-danger: #dc2626;
  --fi-danger-soft: #fee2e2;
  --fi-info: #0ea5e9;
  --fi-info-soft: #e0f2fe;

  /* Escala neutra (slate) — ya casi universal en los módulos modernizados */
  --fi-slate-50: #f8fafc;
  --fi-slate-100: #f1f5f9;
  --fi-slate-200: #e2e8f0;
  --fi-slate-300: #cbd5e1;
  --fi-slate-400: #94a3b8;
  --fi-slate-500: #64748b;
  --fi-slate-600: #475569;
  --fi-slate-700: #334155;
  --fi-slate-800: #1e293b;
  --fi-slate-900: #0f172a;

  /* ---------------------------------------------------------------------
     TIPOGRAFÍA — solo tamaños/pesos. La familia tipográfica se define en
     una fase dedicada (ver nota arriba); hasta entonces se hereda la
     fuente ambiente de cada módulo.
     --------------------------------------------------------------------- */
  --fi-font-xs: 12px;
  --fi-font-sm: 13px;
  --fi-font-base: 14px;
  --fi-font-md: 15px;
  --fi-font-lg: 16px;
  --fi-font-xl: 20px;
  --fi-font-2xl: 24px;

  --fi-line-tight: 1.2;
  --fi-line-normal: 1.5;
  --fi-line-relaxed: 1.6;

  --fi-weight-medium: 500;
  --fi-weight-bold: 700;

  /* ---------------------------------------------------------------------
     ESPACIADO — grid de 4px
     --------------------------------------------------------------------- */
  --fi-space-1: 4px;
  --fi-space-2: 8px;
  --fi-space-3: 12px;
  --fi-space-4: 16px;
  --fi-space-5: 20px;
  --fi-space-6: 24px;
  --fi-space-8: 32px;

  /* ---------------------------------------------------------------------
     ALTURAS DE CONTROL — botones, inputs, selects
     --------------------------------------------------------------------- */
  --fi-control-h-sm: 32px;
  --fi-control-h: 38px;
  --fi-control-h-lg: 44px;

  /* ---------------------------------------------------------------------
     TABLAS
     --------------------------------------------------------------------- */
  --fi-table-cell-y: 14px;
  --fi-table-cell-x: 16px;
  --fi-table-row-min-h: 48px;

  /* ---------------------------------------------------------------------
     RADIOS
     --------------------------------------------------------------------- */
  --fi-radius-sm: 8px;
  --fi-radius: 12px;
  --fi-radius-lg: 16px;
  --fi-radius-pill: 999px;

  /* ---------------------------------------------------------------------
     SOMBRAS — familia rgba(15,23,42,…), ya validada en Entregas Parciales
     y Productos-admin.
     --------------------------------------------------------------------- */
  --fi-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --fi-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 4px 16px rgba(15, 23, 42, 0.04);
  --fi-shadow-lg: 0 20px 40px rgba(15, 23, 42, 0.12);

  /* ---------------------------------------------------------------------
     TRANSICIONES
     --------------------------------------------------------------------- */
  --fi-transition-fast: 0.12s ease;
  --fi-transition: 0.18s ease;

  /* ---------------------------------------------------------------------
     ICONOGRAFÍA
     --------------------------------------------------------------------- */
  --fi-icon-sm: 14px;
  --fi-icon: 16px;
  --fi-icon-lg: 20px;
  --fi-icon-box-sm: 36px;
  --fi-icon-box: 44px;
  --fi-icon-box-lg: 52px;

  /* ---------------------------------------------------------------------
     Z-INDEX
     --------------------------------------------------------------------- */
  --fi-z-dropdown: 1050;
}

/* ============================================================
   BOTONES — .fi-btn
   ============================================================ */
.fi-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: var(--fi-control-h);
  padding: 0 18px;
  border-radius: var(--fi-radius-sm);
  border: 1px solid transparent;
  font-size: var(--fi-font-sm);
  font-weight: var(--fi-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  background: var(--fi-slate-100);
  color: var(--fi-slate-700);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--fi-transition), border-color var(--fi-transition),
    transform var(--fi-transition), box-shadow var(--fi-transition);
}

.fi-btn:hover {
  background: var(--fi-slate-200);
}

.fi-btn:disabled,
.fi-btn--disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.fi-btn--sm {
  height: var(--fi-control-h-sm);
  padding: 0 14px;
  font-size: var(--fi-font-xs);
}

.fi-btn--lg {
  height: var(--fi-control-h-lg);
  padding: 0 22px;
  font-size: var(--fi-font-md);
}

.fi-btn--primary {
  background: var(--fi-primary);
  color: #ffffff;
  box-shadow: 0 2px 8px rgba(37, 99, 235, 0.25);
}

.fi-btn--primary:not(:disabled):hover {
  background: var(--fi-primary-dark);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.32);
}

.fi-btn--ghost {
  background: #ffffff;
  border-color: var(--fi-slate-200);
  color: var(--fi-slate-700);
}

.fi-btn--ghost:not(:disabled):hover {
  background: var(--fi-slate-50);
  border-color: var(--fi-slate-500);
  transform: translateY(-1px);
}

.fi-btn--success {
  background: var(--fi-success);
  color: #ffffff;
}

.fi-btn--success:not(:disabled):hover {
  background: #047857;
}

.fi-btn--danger {
  background: var(--fi-danger);
  color: #ffffff;
}

.fi-btn--danger:not(:disabled):hover {
  background: #b91c1c;
}

/* ============================================================
   INPUTS / SELECTS — .fi-input / .fi-select
   ============================================================ */
.fi-input,
.fi-select {
  height: var(--fi-control-h);
  width: 100%;
  box-sizing: border-box;
  padding: 0 14px;
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-sm);
  font-size: var(--fi-font-md);
  color: var(--fi-slate-900);
  background: #ffffff;
  transition: border-color var(--fi-transition), box-shadow var(--fi-transition);
}

.fi-input:focus,
.fi-select:focus {
  outline: none;
  border-color: var(--fi-primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.fi-input:disabled,
.fi-select:disabled {
  background: var(--fi-slate-50);
  color: var(--fi-slate-400);
  cursor: not-allowed;
}

.fi-input--sm,
.fi-select--sm {
  height: var(--fi-control-h-sm);
  font-size: var(--fi-font-sm);
  padding: 0 10px;
}

.fi-input--lg,
.fi-select--lg {
  height: var(--fi-control-h-lg);
  font-size: var(--fi-font-lg);
}

/* ============================================================
   CARDS — .fi-card
   ============================================================ */
.fi-card {
  background: #ffffff;
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius);
  box-shadow: var(--fi-shadow);
  overflow: hidden;
}

.fi-card__header {
  padding: var(--fi-space-4) var(--fi-space-5);
  border-bottom: 1px solid var(--fi-slate-200);
}

.fi-card__body {
  padding: var(--fi-space-5);
}

.fi-card__footer {
  padding: var(--fi-space-4) var(--fi-space-5);
  border-top: 1px solid var(--fi-slate-200);
}

.fi-card--flush .fi-card__body {
  padding: 0;
}

/* ============================================================
   KPI — .fi-kpi (icono + valor, tira de estadísticas)
   ============================================================ */
.fi-kpi {
  display: flex;
  align-items: center;
  gap: var(--fi-space-4);
  background: #ffffff;
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius);
  box-shadow: var(--fi-shadow);
  padding: var(--fi-space-5) var(--fi-space-4);
  position: relative;
  overflow: hidden;
  transition: transform var(--fi-transition), box-shadow var(--fi-transition);
}

.fi-kpi::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
}

.fi-kpi:hover {
  transform: translateY(-3px);
  box-shadow: var(--fi-shadow-lg);
}

.fi-kpi__icon {
  width: var(--fi-icon-box);
  height: var(--fi-icon-box);
  border-radius: var(--fi-radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fi-icon-lg);
  flex-shrink: 0;
}

.fi-kpi__info {
  flex: 1;
  min-width: 0;
}

.fi-kpi__label {
  margin: 0;
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-500);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.fi-kpi__value {
  margin: 4px 0 2px;
  font-size: var(--fi-font-2xl);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
  line-height: var(--fi-line-tight);
}

.fi-kpi__hint {
  color: var(--fi-slate-500);
  font-size: var(--fi-font-xs);
}

.fi-kpi--primary::before { background: var(--fi-primary); }
.fi-kpi--primary .fi-kpi__icon { background: var(--fi-primary-soft); color: var(--fi-primary); }

.fi-kpi--success::before { background: var(--fi-success); }
.fi-kpi--success .fi-kpi__icon { background: var(--fi-success-soft); color: var(--fi-success); }

.fi-kpi--warning::before { background: var(--fi-warning); }
.fi-kpi--warning .fi-kpi__icon { background: var(--fi-warning-soft); color: var(--fi-warning); }

.fi-kpi--danger::before { background: var(--fi-danger); }
.fi-kpi--danger .fi-kpi__icon { background: var(--fi-danger-soft); color: var(--fi-danger); }

.fi-kpi--info::before { background: var(--fi-info); }
.fi-kpi--info .fi-kpi__icon { background: var(--fi-info-soft); color: var(--fi-info); }

.fi-kpi--neutral::before { background: var(--fi-slate-500); }
.fi-kpi--neutral .fi-kpi__icon { background: var(--fi-slate-100); color: var(--fi-slate-500); }

/* ============================================================
   STAT CARD — .fi-stat-card (métrica única destacada + tendencia)
   ============================================================ */
.fi-stat-card {
  background: #ffffff;
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius);
  box-shadow: var(--fi-shadow);
  padding: var(--fi-space-5);
}

.fi-stat-card__label {
  margin: 0;
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-500);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.fi-stat-card__value {
  margin: var(--fi-space-2) 0;
  font-size: var(--fi-font-2xl);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
  line-height: var(--fi-line-tight);
}

.fi-stat-card__trend {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
}

.fi-stat-card__trend--up { color: var(--fi-success); }
.fi-stat-card__trend--down { color: var(--fi-danger); }

.fi-stat-card__caption {
  margin-top: 4px;
  font-size: var(--fi-font-xs);
  color: var(--fi-slate-400);
}

/* ============================================================
   TABLA — .fi-table-wrap / .fi-table
   ============================================================ */
.fi-table-wrap {
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-sm);
  overflow: hidden;
  overflow-x: auto;
}

/* Cuando una tabla tiene un menú de acciones por fila (.fi-actions), ese
   menú es position:absolute y queda recortado por el overflow de arriba
   al abrirse cerca del final de la tabla. Mientras el menú está abierto,
   un pequeño script propio de cada módulo (ver Ventas/Entregas Parciales)
   agrega esta clase para permitir que se dibuje fuera de los límites de
   la tabla; al cerrarse se quita y el contenedor vuelve a su recorte/
   scroll normal. No cambia la apariencia habitual de la tabla, solo
   mientras el menú está visible. Patrón validado primero en Ventas. */
.fi-table-wrap.fi-menu-open {
  overflow: visible;
}

.fi-table {
  width: 100%;
  margin: 0;
  border-collapse: collapse;
}

.fi-table thead th {
  background: var(--fi-slate-50);
  color: var(--fi-slate-500);
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: var(--fi-table-cell-y) var(--fi-table-cell-x);
  border-bottom: 2px solid var(--fi-slate-200);
  white-space: nowrap;
  text-align: left;
}

.fi-table tbody td {
  padding: var(--fi-table-cell-y) var(--fi-table-cell-x);
  font-size: var(--fi-font-md);
  color: var(--fi-slate-700);
  border-top: 1px solid var(--fi-slate-100);
  vertical-align: middle;
  line-height: var(--fi-line-normal);
}

.fi-table tbody tr {
  min-height: var(--fi-table-row-min-h);
}

.fi-table tbody tr:hover {
  background: var(--fi-slate-50);
}

.fi-table__num {
  text-align: right;
  white-space: nowrap;
}

/* ============================================================
   TABLA RESPONSIVE — fila expandible (Directriz oficial ERP 2026)
   En mobile (<768px) las columnas informativas se ocultan y se
   accede a ellas mediante un botón "+" que expande una fila de
   detalle, en vez de depender de scroll horizontal como solución
   principal. Patrón equivalente al de DataTables Responsive /
   Odoo / ERPNext. El botón de control solo existe/se muestra en
   ese rango; en tablet/laptop/desktop la tabla se ve completa,
   igual que antes de esta directriz.
   ============================================================ */
/* Especificidad reforzada (.fi-table th/td.*) a propósito: Bootstrap trae
   la regla `table td[class*="col-"], table th[class*="col-"] { display:
   table-cell; }` (reset para clases de grilla .col-* usadas dentro de
   tablas) que coincide por casualidad con estas clases (contienen la
   subcadena "col-") y con mayor especificidad que un simple selector de
   clase — sin este refuerzo, Bootstrap ganaba la cascada y la columna
   nunca se ocultaba en mobile. No se tocó bootstrap.min.css (archivo
   compartido, fuera de alcance). */
.fi-table th.fi-table__col-toggle,
.fi-table td.fi-table__col-toggle {
  width: 36px;
  text-align: center;
  display: none;
}

.fi-row-expand-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-pill);
  background: var(--fi-slate-50);
  color: var(--fi-slate-600);
  font-size: var(--fi-font-xs);
  cursor: pointer;
  transition: background-color var(--fi-transition), color var(--fi-transition), border-color var(--fi-transition);
}

/* Área táctil mínima de 44x44 (Directriz Mobile First) sin agrandar el
   círculo visual — el patrón visual pequeño (28px) es correcto para una
   fila de tabla densa, pero el objetivo de toque real se garantiza con
   una zona de clic invisible más grande superpuesta al botón. */
.fi-row-expand-toggle::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

.fi-row-expand-toggle:hover {
  background: var(--fi-primary-soft);
  color: var(--fi-primary);
  border-color: var(--fi-primary);
}

.fi-row-expand-toggle[aria-expanded="true"] {
  background: var(--fi-primary);
  color: #ffffff;
  border-color: var(--fi-primary);
}

/* Animación suave de expansión/colapso: se anima un contenedor interno
   (max-height + opacity) en vez de alternar `hidden`/display, que no es
   animable. El colspan/borde/padding de la <td> se neutralizan siempre
   (abierta o cerrada) para que la fila no deje un hueco ni una línea
   residual mientras está colapsada. */
.fi-table tbody tr.fi-row-detail > td {
  padding: 0 !important;
  border-top: none !important;
}

.fi-row-detail__inner {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.28s ease, opacity 0.2s ease;
}

.fi-row-detail.is-open .fi-row-detail__inner {
  max-height: 280px;
  opacity: 1;
}

.fi-row-detail__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--fi-space-3) var(--fi-space-4);
  padding: var(--fi-space-3) var(--fi-space-2);
  background: var(--fi-slate-50);
  border-radius: var(--fi-radius-sm);
}

.fi-row-detail__item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.fi-row-detail__label {
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--fi-slate-500);
}

.fi-row-detail__value {
  font-size: var(--fi-font-md);
  color: var(--fi-slate-900);
  word-break: break-word;
}

@media (max-width: 767px) {
  .fi-table th.fi-table__col-toggle,
  .fi-table td.fi-table__col-toggle {
    display: table-cell;
  }

  .fi-table th.fi-table__col-collapsible,
  .fi-table td.fi-table__col-collapsible {
    display: none;
  }

  /* La fila compacta (control + # + Nombre + Acciones + Activo) debe
     caber sin scroll horizontal en 360-430px — el padding/tamaño de
     celda estándar (pensado para la tabla completa de escritorio) era
     demasiado generoso para 4-5 columnas visibles en ese ancho. */
  .fi-table thead th,
  .fi-table tbody td {
    padding: 10px 4px;
  }

  .fi-table th.fi-table__col-toggle,
  .fi-table td.fi-table__col-toggle {
    width: 24px;
  }

  .fi-row-expand-toggle {
    width: 22px;
    height: 22px;
    font-size: 10px;
  }

  .fi-table tbody td .fi-btn--sm {
    padding: 0 5px;
  }

  .fi-table tbody td .fi-badge {
    padding: 4px 6px;
    letter-spacing: 0;
    font-size: 10px;
  }

  /* Permite que el nombre/razón social (contenido más largo e
     impredecible de la fila) se ajuste por debajo del ancho de su
     palabra más larga — sin esto, nombres largos ("COOPERATIVA",
     "AGROPECUARIA"...) fijaban un ancho mínimo de columna que forzaba
     scroll horizontal en el resto de la fila. */
  .fi-table tbody td.fi-table__col-primary {
    word-break: break-word;
  }
}

/* ============================================================
   PAGINATION FOOTER — .fi-pagination-* (contador de registros +
   numeración). El HTML de la fila (.fi-pagination-row/-bar/-meta/-nav)
   se genera en vistas/tables/dataTables.php por cada módulo; la
   numeración en sí (ul.pagination, active/disabled, onclick="loadX(n)")
   sigue siendo 100% de Paginacion (vistas/tables/pagination.php) — no es
   DataTables. Aquí solo se moderniza su apariencia.

   Componente único de paginación para todo el ERP: nace en el Bloque 3.4
   de Ventas, y se promueve aquí al repetirse el mismo patrón en Entregas
   Parciales — ningún módulo debe mantener ya su propia copia local.
   ============================================================ */
.fi-pagination-row > td {
  padding: var(--fi-space-4) !important;
  border-top: 1px solid var(--fi-slate-200);
  background: var(--fi-slate-50);
  box-shadow: none !important;
  text-align: left;
}

.fi-pagination-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--fi-space-3);
}

.fi-pagination-meta {
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-500);
  white-space: nowrap;
}

.fi-pagination-nav .pagination {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0;
}

.fi-pagination-nav .pagination > li > a,
.fi-pagination-nav .pagination > li > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--fi-control-h);
  height: var(--fi-control-h);
  padding: 0 var(--fi-space-3);
  margin: 0;
  border-radius: var(--fi-radius-pill) !important;
  border: 1px solid var(--fi-slate-200);
  background: #ffffff;
  color: var(--fi-slate-700);
  font-size: var(--fi-font-sm);
  font-weight: 600;
  line-height: 1;
  transition: background-color var(--fi-transition), border-color var(--fi-transition), color var(--fi-transition);
}

.fi-pagination-nav .pagination > li > a:hover {
  background: var(--fi-slate-50);
  border-color: var(--fi-slate-500);
  color: var(--fi-slate-900);
}

.fi-pagination-nav .pagination > .active > a,
.fi-pagination-nav .pagination > .active > span {
  background: var(--fi-primary);
  border-color: var(--fi-primary);
  color: #ffffff;
}

.fi-pagination-nav .pagination > .active > a:hover {
  background: var(--fi-primary-dark);
  border-color: var(--fi-primary-dark);
  color: #ffffff;
}

.fi-pagination-nav .pagination > .disabled > a,
.fi-pagination-nav .pagination > .disabled > span {
  background: var(--fi-slate-50);
  border-color: var(--fi-slate-200);
  color: var(--fi-slate-300);
  cursor: not-allowed;
}

/* ============================================================
   BADGE — .fi-badge (estado)
   ============================================================ */
.fi-badge {
  display: inline-flex;
  align-items: center;
  padding: 5px 14px;
  border-radius: var(--fi-radius-pill);
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  white-space: nowrap;
  background: var(--fi-slate-100);
  color: var(--fi-slate-500);
}

.fi-badge--success { background: var(--fi-success-soft); color: var(--fi-success); }
.fi-badge--warning { background: var(--fi-warning-soft); color: var(--fi-warning); }
.fi-badge--danger { background: var(--fi-danger-soft); color: var(--fi-danger); }
.fi-badge--primary { background: var(--fi-primary-soft); color: var(--fi-primary); }
.fi-badge--info { background: var(--fi-info-soft); color: var(--fi-info); }

/* Auditoría de Excelencia: cuando el badge es un <button> (ej. toggle
   Activo/Inactivo de Clientes), necesita la misma retroalimentación de
   :hover que el resto de elementos interactivos del sistema — antes solo
   cambiaba el cursor, sin feedback visual. No afecta a badges no
   interactivos (<span>), que no coinciden con este selector. */
button.fi-badge {
  border: none;
  transition: filter var(--fi-transition);
}

button.fi-badge:hover {
  filter: brightness(0.93);
}

/* ============================================================
   CHIP — .fi-chip (filtro/etiqueta, distinto de badge de estado)
   ============================================================ */
.fi-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: var(--fi-radius-pill);
  background: var(--fi-slate-100);
  color: var(--fi-slate-700);
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-medium);
  border: 1px solid transparent;
}

.fi-chip--active {
  background: var(--fi-primary-soft);
  color: var(--fi-primary);
  border-color: rgba(37, 99, 235, 0.25);
}

.fi-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  cursor: pointer;
  color: inherit;
  opacity: 0.7;
}

.fi-chip__remove:hover {
  opacity: 1;
  background: rgba(15, 23, 42, 0.08);
}

/* ============================================================
   AVATAR — .fi-avatar
   ============================================================ */
.fi-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--fi-slate-200);
  color: var(--fi-slate-700);
  font-weight: var(--fi-weight-bold);
  overflow: hidden;
  flex-shrink: 0;
}

.fi-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fi-avatar--sm { width: 28px; height: 28px; font-size: var(--fi-font-xs); }
.fi-avatar--md { width: 38px; height: 38px; font-size: var(--fi-font-sm); }
.fi-avatar--lg { width: 52px; height: 52px; font-size: var(--fi-font-lg); }

/* ============================================================
   PAGE HEADER — .fi-page-header (icono + título + subtítulo)
   ============================================================ */
.fi-page-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--fi-space-4);
  padding: var(--fi-space-5) var(--fi-space-6);
  background: linear-gradient(135deg, #1e3a8a 0%, var(--fi-primary) 55%, var(--fi-primary-light) 100%);
  border-radius: var(--fi-radius);
  box-shadow: var(--fi-shadow);
  color: #ffffff;
}

.fi-page-header__icon {
  flex-shrink: 0;
  width: var(--fi-icon-box-lg);
  height: var(--fi-icon-box-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.15);
  border-radius: var(--fi-radius-sm);
  font-size: var(--fi-font-xl);
}

.fi-page-header__titles {
  min-width: 0;
  flex: 1;
}

.fi-page-header__title {
  margin: 0;
  font-size: var(--fi-font-2xl);
  font-weight: var(--fi-weight-bold);
  letter-spacing: -0.02em;
  line-height: var(--fi-line-tight);
}

.fi-page-header__subtitle {
  margin: 4px 0 0;
  font-size: var(--fi-font-sm);
  opacity: 0.9;
}

.fi-page-header__actions {
  display: flex;
  align-items: center;
  gap: var(--fi-space-2);
  flex-shrink: 0;
}

/* Botones de acción dentro del header (ej. "Nuevo Cliente") — mismo
   tratamiento en todos los módulos que adopten .fi-page-header.
   Altura mínima 44px (Directriz UX Mobile First, ERP 2026 — objetivo
   táctil mínimo recomendado): estaba en --fi-control-h-sm (32px),
   insuficiente para pulsar cómodamente en móvil. */
.fi-page-header__actions .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  background: rgba(255, 255, 255, 0.95);
  color: var(--fi-slate-700);
  border: 1px solid transparent;
  border-radius: var(--fi-radius-sm);
  padding: 0 var(--fi-space-3);
  font-size: var(--fi-font-xs);
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--fi-transition), color var(--fi-transition);
}

.fi-page-header__actions .btn:hover {
  background: var(--fi-primary-dark);
  color: #ffffff;
  text-decoration: none;
}

/* ============================================================
   TOOLBAR — .fi-toolbar (buscador + filtro + acciones)
   ============================================================ */
.fi-toolbar {
  display: flex;
  align-items: center;
  gap: var(--fi-space-3);
  flex-wrap: wrap;
  background: var(--fi-slate-50);
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-sm);
  padding: var(--fi-space-4);
}

.fi-toolbar__search {
  flex: 1 1 260px;
  min-width: 200px;
}

.fi-toolbar__filter {
  flex: 0 0 auto;
  min-width: 190px;
}

.fi-toolbar__actions {
  display: flex;
  gap: var(--fi-space-2);
  margin-left: auto;
  flex-wrap: wrap;
}

/* ============================================================
   SEARCHBAR — .fi-searchbar (standalone, también usado en toolbar)
   ============================================================ */
.fi-searchbar {
  position: relative;
}

.fi-searchbar__icon {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--fi-slate-500);
  font-size: var(--fi-font-sm);
  pointer-events: none;
}

.fi-searchbar__input {
  width: 100%;
  height: var(--fi-control-h);
  padding: 0 14px 0 36px;
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-sm);
  font-size: var(--fi-font-md);
  background: #ffffff;
  box-sizing: border-box;
  transition: border-color var(--fi-transition), box-shadow var(--fi-transition);
}

.fi-searchbar__input:focus {
  outline: none;
  border-color: var(--fi-primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

/* ============================================================
   COMPACT HEADER — .fi-compact-header (identidad "módulo catálogo")
   Alternativa a .fi-page-header para módulos donde el banner con
   degradado resulta excesivo. Fondo propio (--fi-slate-50, ya se
   invierte en modo oscuro) para no depender del fondo de página
   real, que no es dark-mode-aware fuera de los componentes .fi-*.
   ============================================================ */
.fi-compact-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--fi-space-4);
  margin-bottom: var(--fi-space-4);
  background: var(--fi-slate-50);
  border-radius: var(--fi-radius-sm);
  padding: var(--fi-space-4) var(--fi-space-5);
}

.fi-compact-header__eyebrow {
  margin: 0 0 4px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--fi-slate-400);
  font-weight: var(--fi-weight-bold);
}

.fi-compact-header__title-row {
  display: flex;
  align-items: center;
  gap: var(--fi-space-3);
}

.fi-compact-header__title-row h1 {
  margin: 0;
  font-size: 24px;
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
}

.fi-compact-header__count {
  font-size: 12px;
  font-weight: var(--fi-weight-bold);
  color: var(--fi-primary);
  background: var(--fi-primary-soft);
  border-radius: var(--fi-radius-pill);
  padding: 2px 10px;
}

.fi-compact-header__actions {
  display: flex;
  align-items: center;
  gap: var(--fi-space-3);
}

.fi-compact-header__search {
  width: 240px;
  max-width: 100%;
}

@media (max-width: 767px) {
  .fi-compact-header__actions {
    width: 100%;
  }

  .fi-compact-header__search {
    width: auto;
    flex: 1;
  }
}

/* ============================================================
   TABLA PREMIUM — .fi-table--premium (identidad "módulo catálogo")
   Variante de composición de .fi-table: sin fondo en el encabezado
   de columnas, sin líneas verticales, y una barra de acento que se
   desliza en el borde izquierdo de la fila al pasar el mouse. No es
   un componente nuevo — son reglas adicionales sobre las mismas
   celdas/filas de siempre.
   ============================================================ */
.fi-table--premium thead th {
  background: transparent;
  border-bottom: 1px solid var(--fi-slate-200);
}

@media (min-width: 768px) {
  .fi-table--premium tbody td {
    padding: var(--fi-space-4) var(--fi-space-5);
  }
}

/* En mobile, con la columna Fecha oculta (display:none), el layout
   de tabla "auto" redistribuye ese espacio libre entre las columnas
   visibles (toggle/acciones crecían muy por encima de su ancho real,
   aplastando la de categoría). Forzar width:100% en la columna de
   categoría hace que reclame el espacio sobrante, mientras
   toggle/acciones se ajustan a su contenido — aislado a esta
   variante de tabla, no toca .fi-table base. */
@media (max-width: 767px) {
  .fi-table--premium .fi-table__col-primary {
    width: 100%;
  }

  .fi-table--premium th.fi-table__col-toggle,
  .fi-table--premium td.fi-table__col-toggle,
  .fi-table--premium th:last-child,
  .fi-table--premium td:last-child {
    width: 1%;
    white-space: nowrap;
  }
}

/* Auditoría transversal de alineación (Sprint 6, ERP 2026): esta barra de
   acento vivía como `::before` del propio `<tr>`. Chromium trata un
   pseudo-elemento generado directamente sobre una fila de tabla como una
   celda anónima más al calcular `table-layout: auto`, corriendo el ancho
   de cada columna real una posición hacia la derecha entre `<thead>` y
   `<tbody>` (reproducido y aislado fuera de la app: mismo bug con y sin
   el resto del Design System, desaparece al mover el `::before` a una
   celda real). Se traslada a `.fi-table__col-primary` — no a `:first-child`,
   porque en Categorías/Usuarios/Roles la primera celda real es
   `.fi-table__col-toggle` (`display:none` en escritorio, donde un
   pseudo-elemento tampoco se pintaría). Mismo resultado visual en
   escritorio (la columna primaria ES el borde izquierdo visible de la
   fila); en mobile la barra nace en el borde de la columna primaria, no
   en el borde físico de la fila — diferencia de unos 24-36px,
   imperceptible en una decoración de hover. Afecta a todos los módulos
   que usan `.fi-table--premium` (Categorías, Usuarios, Roles). */
.fi-table--premium tbody tr:not(.fi-pagination-row):not(.fi-row-detail) .fi-table__col-primary {
  position: relative;
}

.fi-table--premium tbody tr:not(.fi-pagination-row):not(.fi-row-detail) .fi-table__col-primary::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--fi-primary);
  transform: scaleY(0);
  transition: transform var(--fi-transition-fast);
}

.fi-table--premium tbody tr:not(.fi-pagination-row):not(.fi-row-detail):hover .fi-table__col-primary::before {
  transform: scaleY(1);
}

.fi-table--premium tbody tr.fi-pagination-row:hover,
.fi-table--premium tbody tr.fi-row-detail:hover {
  background: transparent;
}

.fi-table--premium .fi-btn--ghost:hover {
  transform: scale(1.06);
}

.fi-table__row-name {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
  font-size: var(--fi-font-md);
}

.fi-table__row-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--fi-primary);
  flex-shrink: 0;
  display: inline-block;
}

.fi-pagination-row--minimal > td {
  background: transparent;
  border-top: 1px solid var(--fi-slate-100);
}

/* ============================================================
   LOCATION GRID — .fi-location-grid / .fi-location-card
   Identidad "configuración empresarial" para módulos con pocas
   entidades ricas en datos (ej. Sucursales) — el paradigma tabla no
   aplica bien ahí (Clientes/Proveedores/Categorías sí lo usan,
   porque manejan muchos registros simples). Totalmente fluido: sin
   anchos fijos, sin cantidad de columnas codificada — auto-fit deja
   que las tarjetas existentes crezcan cuando hay pocas, y que el
   grid se reacomode solo cuando hay muchas.
   ============================================================ */
.fi-location-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--fi-space-4);
}

@media (min-width: 768px) {
  .fi-location-grid {
    grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  }
}

.fi-location-card {
  display: flex;
  flex-direction: column;
  padding: var(--fi-space-5);
  transition: box-shadow var(--fi-transition), border-color var(--fi-transition), transform var(--fi-transition);
}

.fi-location-card:hover {
  box-shadow: var(--fi-shadow);
  border-color: var(--fi-slate-300);
  transform: translateY(-2px);
}

.fi-location-card__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--fi-space-2);
  margin-bottom: var(--fi-space-3);
}

.fi-location-card__code {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--fi-primary-soft);
  color: var(--fi-primary);
  font-weight: var(--fi-weight-bold);
  font-size: 13px;
  letter-spacing: 0.4px;
  border-radius: var(--fi-radius-sm);
  padding: 4px 10px;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
}

.fi-location-card__tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-500);
  background: var(--fi-slate-100);
  border-radius: var(--fi-radius-pill);
  padding: 3px 9px;
  white-space: nowrap;
}

.fi-location-card__name {
  margin: 0 0 var(--fi-space-3);
  font-size: var(--fi-font-lg);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
  line-height: var(--fi-line-normal);
}

.fi-location-card__meta {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-500);
  margin-bottom: 6px;
  line-height: var(--fi-line-normal);
}

.fi-location-card__meta i {
  width: 14px;
  margin-top: 3px;
  color: var(--fi-slate-400);
  font-size: 12px;
  flex-shrink: 0;
}

.fi-location-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fi-space-3);
  margin-top: auto;
  padding-top: var(--fi-space-4);
  border-top: 1px solid var(--fi-slate-100);
}

.fi-location-card__status {
  font-size: var(--fi-font-xs);
  color: var(--fi-slate-500);
  font-weight: var(--fi-weight-bold);
}

/* Switch Activo/Inactivo — reemplaza visualmente el plugin
   bootstrapToggle (misma semántica: <input type="checkbox"> +
   evento change) por un control propio del Design System. */
.fi-switch {
  position: relative;
  display: inline-flex;
  width: 40px;
  height: 22px;
  flex-shrink: 0;
}

.fi-switch input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.fi-switch__track {
  position: absolute;
  inset: 0;
  background: var(--fi-slate-200);
  border-radius: var(--fi-radius-pill);
  transition: background-color var(--fi-transition);
  pointer-events: none;
}

.fi-switch__track::before {
  content: '';
  position: absolute;
  height: 16px;
  width: 16px;
  left: 3px;
  top: 3px;
  background: #ffffff;
  border-radius: 50%;
  transition: transform var(--fi-transition);
  box-shadow: var(--fi-shadow-sm);
}

.fi-switch input:checked ~ .fi-switch__track {
  background: var(--fi-success);
}

.fi-switch input:checked ~ .fi-switch__track::before {
  transform: translateX(18px);
}

.fi-switch input:focus-visible ~ .fi-switch__track {
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.25);
}

/* ============================================================
   ALERT BANNER — .fi-alert-banner (avisos dentro de formularios)
   ============================================================ */
.fi-alert-banner {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  background: var(--fi-warning-soft);
  color: var(--fi-warning);
  border-radius: var(--fi-radius-sm);
  padding: var(--fi-space-3) var(--fi-space-4);
  font-size: var(--fi-font-sm);
  font-weight: var(--fi-weight-bold);
  margin-bottom: var(--fi-space-4);
  line-height: var(--fi-line-normal);
}

.fi-alert-banner i {
  margin-top: 2px;
  flex-shrink: 0;
}

.fi-alert-banner--info {
  background: var(--fi-info-soft);
  color: var(--fi-info);
  font-weight: 400;
}

/* ============================================================
   ACTIONS — .fi-actions (botón "..." + menú de fila)
   ============================================================ */
.fi-actions {
  display: inline-block;
  position: relative;
}

.fi-actions__btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid transparent;
  background: transparent;
  color: var(--fi-slate-500);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fi-font-md);
  cursor: pointer;
  transition: background-color var(--fi-transition), color var(--fi-transition);
}

.fi-actions__btn:hover,
.fi-actions__btn:focus {
  background: var(--fi-slate-100);
  color: var(--fi-slate-900);
  outline: none;
}

.fi-actions__menu {
  border-radius: var(--fi-radius-sm);
  border: 1px solid var(--fi-slate-200);
  box-shadow: var(--fi-shadow);
  padding: 6px;
  min-width: 190px;
  z-index: var(--fi-z-dropdown);
}

.fi-actions__menu > li > a,
.fi-actions__menu > li > button {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--fi-radius-sm);
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-700);
}

.fi-actions__menu > li > a:hover,
.fi-actions__menu > li > button:hover {
  background: var(--fi-slate-50);
  color: var(--fi-slate-900);
}

.fi-actions__menu i {
  width: 14px;
  color: var(--fi-slate-500);
}

/* ============================================================
   DROPDOWN — .fi-dropdown (genérico; se apoya en el JS de
   Bootstrap 3 .dropdown / data-toggle="dropdown")
   ============================================================ */
.fi-dropdown {
  position: relative;
  display: inline-block;
}

.fi-dropdown__btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: var(--fi-control-h);
  padding: 0 16px;
  border-radius: var(--fi-radius-sm);
  border: 1px solid var(--fi-slate-200);
  background: #ffffff;
  color: var(--fi-slate-700);
  font-size: var(--fi-font-sm);
  font-weight: var(--fi-weight-medium);
  cursor: pointer;
}

.fi-dropdown__btn:hover {
  background: var(--fi-slate-50);
}

.fi-dropdown__menu {
  border-radius: var(--fi-radius-sm);
  border: 1px solid var(--fi-slate-200);
  box-shadow: var(--fi-shadow);
  padding: 6px;
  min-width: 200px;
  z-index: var(--fi-z-dropdown);
}

.fi-dropdown__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--fi-radius-sm);
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-700);
  cursor: pointer;
}

.fi-dropdown__item:hover {
  background: var(--fi-slate-50);
  color: var(--fi-slate-900);
}

.fi-dropdown__divider {
  height: 1px;
  background: var(--fi-slate-100);
  margin: 6px 4px;
}

/* ============================================================
   TABS — .fi-tabs (genérico; se apoya en el JS de Bootstrap 3
   .nav-tabs / .tab-content / data-toggle="tab")
   ============================================================ */
.fi-tabs__nav {
  display: flex;
  gap: var(--fi-space-2);
  border-bottom: 1px solid var(--fi-slate-200);
  margin: 0 0 var(--fi-space-4);
}

.fi-tabs__link {
  padding: 10px var(--fi-space-3);
  font-size: var(--fi-font-sm);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-500);
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: color var(--fi-transition), border-color var(--fi-transition);
}

.fi-tabs__link:hover {
  color: var(--fi-slate-900);
}

.fi-tabs__link.active {
  color: var(--fi-primary);
  border-bottom-color: var(--fi-primary);
}

.fi-tabs__content {
  padding-top: var(--fi-space-2);
}

/* ============================================================
   PROGRESS — .fi-progress
   ============================================================ */
.fi-progress {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 120px;
}

.fi-progress__track {
  flex: 1;
  height: 8px;
  border-radius: var(--fi-radius-pill);
  background: var(--fi-slate-100);
  overflow: hidden;
}

.fi-progress__fill {
  height: 100%;
  border-radius: var(--fi-radius-pill);
  background: var(--fi-slate-500);
  transition: width var(--fi-transition);
}

.fi-progress__fill--success { background: var(--fi-success); }
.fi-progress__fill--warning { background: var(--fi-warning); }
.fi-progress__fill--danger { background: var(--fi-danger); }
.fi-progress__fill--primary { background: var(--fi-primary); }

.fi-progress__label {
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-700);
  min-width: 32px;
  text-align: right;
}

/* ============================================================
   EMPTY STATE — .fi-empty-state (listas/tablas sin resultados)
   ============================================================ */
.fi-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--fi-space-8) var(--fi-space-4);
  color: var(--fi-slate-500);
}

.fi-empty-state__icon {
  width: var(--fi-icon-box-lg);
  height: var(--fi-icon-box-lg);
  border-radius: 50%;
  background: var(--fi-slate-100);
  color: var(--fi-slate-400);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fi-font-xl);
  margin-bottom: var(--fi-space-3);
}

.fi-empty-state__title {
  margin: 0 0 4px;
  font-size: var(--fi-font-lg);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-700);
}

.fi-empty-state__desc {
  margin: 0;
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-400);
  max-width: 360px;
}

.fi-empty-state__action {
  margin-top: var(--fi-space-4);
}

/* ============================================================
   MODAL — .fi-modal (envoltorio de estilo sobre el .modal de
   Bootstrap 3; el JS de apertura/cierre sigue siendo el de Bootstrap)
   ============================================================ */
.fi-modal .modal-content {
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-sm);
  box-shadow: var(--fi-shadow-lg);
  overflow: hidden;
}

.fi-modal__header {
  border-bottom: 1px solid var(--fi-slate-200);
  padding: var(--fi-space-4) var(--fi-space-5) var(--fi-space-3);
  background: #ffffff;
  position: relative;
}

.fi-modal__heading {
  display: flex;
  align-items: center;
  gap: var(--fi-space-3);
  padding-right: 28px;
}

.fi-modal__titles {
  min-width: 0;
}

.fi-modal__icon {
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: var(--fi-radius-sm);
  background: var(--fi-primary-soft);
  border: 1px solid #bfdbfe;
  color: var(--fi-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
}

.fi-modal__title {
  margin: 0;
  font-size: var(--fi-font-lg);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
  line-height: var(--fi-line-tight);
}

.fi-modal__subtitle {
  margin: 2px 0 0;
  font-size: var(--fi-font-xs);
  color: var(--fi-slate-500);
}

.fi-modal__close {
  position: absolute;
  top: 12px;
  right: 14px;
  margin: 0;
  font-size: 22px;
  font-weight: 300;
  color: var(--fi-slate-500);
  opacity: 1;
}

.fi-modal__close:hover {
  color: var(--fi-slate-900);
}

.fi-modal__body {
  background: #ffffff;
  padding: var(--fi-space-4) var(--fi-space-5);
}

.fi-modal__footer {
  border-top: 1px solid var(--fi-slate-200);
  padding: var(--fi-space-3) var(--fi-space-5) var(--fi-space-4);
  background: #ffffff;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--fi-space-2);
}

/* ============================================================
   INFO GRID — .fi-info-grid (ficha de datos: documento, cliente,
   fecha, estado... en columnas de etiqueta + valor). Útil para
   cualquier modal o panel que muestre los datos de un registro antes
   de operar sobre él (ventas, compras, guías, órdenes de producción).
   Primer consumidor: Entregas Parciales (modal de detalle).
   ============================================================ */
.fi-info-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--fi-space-3);
  background: var(--fi-slate-50);
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius-sm);
  padding: var(--fi-space-4);
}

.fi-info-grid__item {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.fi-info-grid__label {
  font-size: var(--fi-font-xs);
  font-weight: var(--fi-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--fi-slate-500);
}

.fi-info-grid__value {
  font-size: var(--fi-font-md);
  font-weight: 600;
  color: var(--fi-slate-900);
}

/* ============================================================
   ETIQUETAS DE FORMULARIO DENTRO DE .fi-modal (Auditoría de
   Excelencia — Sprint 1, módulo Clientes, ERP 2026)

   Bootstrap 3 pinta <label> en #333 fijo (no ligado a ningún token) —
   en modo claro se leía bien por coincidencia, pero en Dark Mode
   quedaba casi invisible (gris oscuro sobre fondo casi negro). Se fija
   al token de tinta secundaria, que ya invierte correctamente en Dark
   Mode (ver bloque más abajo).
   ============================================================ */
.fi-modal label {
  color: var(--fi-slate-700);
  font-weight: var(--fi-weight-bold);
  font-size: var(--fi-font-sm);
}

/* ============================================================
   UTILIDADES DE ESPACIADO (Auditoría de Excelencia — Sprint 1,
   módulo Clientes, ERP 2026)

   No existían en este catálogo — `clientes.php` usaba `.fi-mt-4` (ya
   definida en admin-cifra.css, Panel Administrador) sin efecto real
   aquí, dejando la card pegada al header (0px de margen real). Mismos
   nombres y mismos valores que su equivalente del Panel — no se
   inventa una escala nueva, solo se completa la que faltaba de este
   lado.
   ============================================================ */
.fi-mt-2 { margin-top: var(--fi-space-2) !important; }
.fi-mt-3 { margin-top: var(--fi-space-3) !important; }
.fi-mt-4 { margin-top: var(--fi-space-4) !important; }
.fi-mt-5 { margin-top: var(--fi-space-5) !important; }
.fi-mt-6 { margin-top: var(--fi-space-8) !important; }

/* ============================================================
   DARK MODE (Sprint 1 — módulo Clientes, ERP 2026)

   Este Design System no tenía ninguna regla de Dark Mode todavía
   (ver docs/FACTURAISLAY_ERP_2026_DECISIONES_ARQUITECTONICAS.md, §2.1).
   Este bloque cubre únicamente los tokens y componentes que el módulo
   Clientes realmente usa (Card, Table, Badge, Btn, Modal, Toolbar,
   Searchbar, Input/Select, Pagination, Page Header) — no es la migración
   completa de Fase 0.5 (esa sigue pendiente de aprobación aparte, ver
   docs/FACTURAISLAY_ERP_2026_PREPARACION_DESIGN_SYSTEM.md). Cada módulo
   que adopte este Design System en su propio sprint debe extender este
   bloque con los componentes adicionales que use, no reemplazarlo.

   Técnica: se invierte la escala --fi-slate-* (50↔900) para que todo
   componente que ya consume estas variables (la gran mayoría) herede el
   tema oscuro automáticamente. Los pocos componentes con `background:
   #ffffff` escrito literal (no ligado a un token) se sobrescriben aparte,
   solo los que Clientes usa.
   ============================================================ */
@media (prefers-color-scheme: dark) {
  :root {
    --fi-slate-50: #1a2233;
    --fi-slate-100: #212b3d;
    --fi-slate-200: #2c3852;
    --fi-slate-300: #3d4a68;
    --fi-slate-400: #5b6b8c;
    --fi-slate-500: #8895b3;
    --fi-slate-600: #aab4cc;
    --fi-slate-700: #c8d0e3;
    --fi-slate-800: #e2e6f0;
    --fi-slate-900: #f4f6fb;
  }

  .fi-card,
  .fi-btn--ghost,
  .fi-input,
  .fi-select,
  .fi-searchbar__input,
  .fi-modal__header,
  .fi-modal__body,
  .fi-modal__footer,
  .fi-kpi,
  .fi-access-group,
  .fi-pagination-nav .pagination > li > a,
  .fi-pagination-nav .pagination > li > span {
    background: var(--fi-slate-50);
  }

  .fi-input,
  .fi-select,
  .fi-searchbar__input {
    color: var(--fi-slate-900);
  }

  .fi-input:disabled,
  .fi-select:disabled {
    background: var(--fi-slate-100);
  }
}

/* ============================================================
   KPI ROW — .fi-kpi-row (envoltorio en grid fluido para varias
   .fi-kpi, mismo criterio auto-fit que .fi-location-grid: crece las
   tarjetas existentes cuando hay pocas, reacomoda cuando hay más).
   Primer consumidor: Usuarios (Sprint 5, ERP 2026).
   ============================================================ */
.fi-kpi-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--fi-space-4);
  margin-bottom: var(--fi-space-4);
}

@media (min-width: 480px) {
  .fi-kpi-row {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  }
}

/* ============================================================
   AVATAR — variantes de color sólido (Sprint 5, módulo Usuarios,
   ERP 2026). Cuando el usuario no tiene foto, el avatar muestra sus
   iniciales sobre un color determinístico (misma semilla → mismo
   color siempre) elegido entre los 5 tonos semánticos ya existentes
   en el sistema — no se inventa una paleta nueva, solo se aplican en
   modo "sólido" (texto blanco) en vez de "soft".
   ============================================================ */
.fi-avatar--primary { background: var(--fi-primary); color: #ffffff; }
.fi-avatar--success { background: var(--fi-success); color: #ffffff; }
.fi-avatar--warning { background: var(--fi-warning); color: #ffffff; }
.fi-avatar--danger { background: var(--fi-danger); color: #ffffff; }
.fi-avatar--info { background: var(--fi-info); color: #ffffff; }

/* ============================================================
   USER CELL — .fi-user-cell (avatar + nombre/usuario, celda
   principal de una fila de persona). Sprint 5, módulo Usuarios.
   ============================================================ */
.fi-user-cell {
  display: flex;
  align-items: center;
  gap: var(--fi-space-3);
  min-width: 0;
}

.fi-user-cell__info {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.fi-user-cell__name {
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-900);
  font-size: var(--fi-font-md);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.fi-user-cell__username {
  font-size: var(--fi-font-xs);
  color: var(--fi-slate-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================================================
   LAST SEEN — .fi-last-seen (último acceso). Distingue de un
   vistazo actividad reciente (punto verde + tiempo relativo) de
   "nunca ingresó" (texto atenuado, sin punto). Sprint 5, Usuarios.
   ============================================================ */
.fi-last-seen {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-600);
}

.fi-last-seen__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--fi-success);
  flex-shrink: 0;
  box-shadow: 0 0 0 3px var(--fi-success-soft);
}

.fi-last-seen--never {
  color: var(--fi-slate-400);
  font-style: italic;
}

/* ============================================================
   PHOTO UPLOAD — .fi-photo-upload (experiencia de subida de foto
   de perfil en los modales Nuevo/Editar Usuario). Solo presentación:
   el input de archivo sigue siendo el mismo elemento con el mismo
   id/name/evento, solo se oculta visualmente y se activa a través
   de la <label for="..."> que lo envuelve. Sprint 5, Usuarios.
   ============================================================ */
.fi-photo-upload {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--fi-space-3);
  padding: var(--fi-space-5) var(--fi-space-4);
  background: var(--fi-slate-50);
  border: 1px dashed var(--fi-slate-300);
  border-radius: var(--fi-radius);
  text-align: center;
}

.fi-photo-upload__preview {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--fi-slate-200);
  border: 3px solid var(--fi-slate-50);
  box-shadow: var(--fi-shadow);
  flex-shrink: 0;
}

.fi-photo-upload__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fi-photo-upload__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.fi-photo-upload__hint {
  margin: 0;
  font-size: var(--fi-font-xs);
  color: var(--fi-slate-400);
}

/* ============================================================
   BTN-GROUP + fi-btn (Auditoría Final de Excelencia — Sprint 5,
   módulo Usuarios, ERP 2026)

   Bootstrap solo aplica `.btn-group > .btn { float: left }` a
   hijos con la clase `.btn` — los botones de acción del Design
   System (`.fi-btn`) no la llevan, así que dentro de un
   `.btn-group` se apilaban verticalmente en vez de quedar uno
   junto al otro (bug preexistente desde que Clientes/Proveedores/
   Categorías adoptaron `.fi-btn` en sus columnas de Acciones,
   nunca detectado porque no se había verificado el layout exacto
   de ese grupo — `float: left` no resolvía el shrink-to-fit del
   contenedor de forma fiable). Se usa `:has()` para que solo
   afecte a un `.btn-group` que realmente contenga un `.fi-btn`,
   sin tocar `.btn-group` en el resto de la aplicación (zonas
   legacy que siguen usando `.btn` real, con su propio float).
   ============================================================ */
.btn-group:has(> .fi-btn) {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ============================================================
   ACCESS GROUPS — .fi-access-groups / .fi-access-group /
   .fi-access-item (matriz de permisos agrupada por categoría
   funcional). Identidad "Centro de Administración de Roles y
   Permisos" — Sprint 6, ERP 2026. Reemplaza la grilla plana de
   checkboxes sueltos del módulo Roles.
   ============================================================ */
.fi-access-groups {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--fi-space-4);
}

@media (min-width: 768px) {
  .fi-access-groups {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1200px) {
  .fi-access-groups {
    grid-template-columns: repeat(3, 1fr);
  }
}

.fi-access-group {
  border: 1px solid var(--fi-slate-200);
  border-radius: var(--fi-radius);
  overflow: hidden;
  background: #ffffff;
}

.fi-access-group__header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--fi-space-3) var(--fi-space-4);
  background: var(--fi-slate-50);
  border-bottom: 1px solid var(--fi-slate-200);
}

.fi-access-group__icon {
  width: 28px;
  height: 28px;
  border-radius: var(--fi-radius-sm);
  background: var(--fi-primary-soft);
  color: var(--fi-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  flex-shrink: 0;
}

.fi-access-group__title {
  font-size: var(--fi-font-sm);
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-800);
  flex: 1;
}

.fi-access-group__count {
  font-size: 11px;
  font-weight: var(--fi-weight-bold);
  color: var(--fi-slate-500);
  background: var(--fi-slate-100);
  border-radius: var(--fi-radius-pill);
  padding: 2px 8px;
  flex-shrink: 0;
}

.fi-access-group__body {
  padding: var(--fi-space-2);
  display: flex;
  flex-direction: column;
}

.fi-access-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--fi-radius-sm);
  cursor: pointer;
  transition: background-color var(--fi-transition-fast);
}

.fi-access-item:hover {
  background: var(--fi-slate-50);
}

.fi-access-item__box {
  width: 18px;
  height: 18px;
  border-radius: 5px;
  border: 1.5px solid var(--fi-slate-300);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: #ffffff;
  font-size: 10px;
  transition: background-color var(--fi-transition-fast), border-color var(--fi-transition-fast);
}

/* El ícono de check vive siempre en el DOM pero solo se hace visible
   cuando el checkbox real está marcado — si solo dependiera del color
   (blanco sobre fondo transparente) quedaría accidentalmente visible
   en Dark Mode al mostrarse blanco sobre un fondo oscuro. */
.fi-access-item__box i {
  opacity: 0;
}

.fi-access-item input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.fi-access-item input:checked ~ .fi-access-item__box {
  background: var(--fi-primary);
  border-color: var(--fi-primary);
}

.fi-access-item input:checked ~ .fi-access-item__box i {
  opacity: 1;
}

.fi-access-item input:focus-visible ~ .fi-access-item__box {
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.25);
}

.fi-access-item__label {
  font-size: var(--fi-font-sm);
  color: var(--fi-slate-700);
}
