/*! dev-design-system.css — generado por build.js. NO editar a mano. */

/* ===== tokens.css ===== */
/* ==========================================================================
   DESIGN TOKENS
   Paleta: FFFCF2 (crema/blanco) · CCC5B9 (arena) · 403D39 (café oscuro)
           252422 (negro) · EB5E28 (naranja, color primario)

   Regla de la paleta:
   - Modo claro: los "blancos" del sistema usan FFFCF2 (no #ffffff puro).
   - Modo oscuro: los "negros" del sistema usan 252422 (no #000000 puro).

   Para cambiar la paleta de un proyecto nuevo generado a partir de esta
   plantilla, este es el UNICO archivo que se debe modificar.

   ---- Arquitectura: BASE vs DERIVADO ----
   Solo hay ~14 colores que se escriben "a mano" (sección BASE de cada
   bloque): primary, secondary, info, success, danger, warning, sidebar-bg,
   bg, surface, border, text, text-inverse (x2, uno por modo) + los 14 de
   la paleta extendida (fijos, son decorativos, no tienen variantes).

   TODO lo demás -hover, -light/tinte, -ring de foco, -muted, -subtle,
   -raised, -strong, sidebar-hover/text- se CALCULA desde esos con
   color-mix(), no se hardcodea aparte. Antes había que tocar 3-4 variables
   por cada color para que un botón, su hover y su versión "suave" se vieran
   consistentes; ahora basta con cambiar el color BASE una sola vez y todo
   lo demás se recalcula solo, en los dos modos.

   Requiere navegadores con soporte de color-mix() — Chrome/Edge 111+,
   Firefox 113+, Safari 16.4+ (todos los navegadores actuales de escritorio
   y móvil desde 2023). Si algún día hay que soportar un navegador más
   viejo, agregar un @supports not (color-mix(...)) con los valores
   hardcodeados de respaldo.

   ---- Cómo se obtiene el bloque [data-theme="dark"] ----
   Primary / Secondary / Info / Success / Danger / Warning son colores de
   marca: se declaran UNA sola vez en :root y no cambian entre modos (por
   eso no aparecen otra vez en los bloques de abajo). Lo que sí cambia por
   modo son los neutros (bg, surface, sidebar-bg, border, text) y, con
   ellos, la DIRECCIÓN del mix de cada derivado (p. ej. el hover de un
   botón oscurece en modo claro pero aclara en modo oscuro, para siempre
   alejarse del fondo). Esta misma lógica de adaptación es la que usa el
   editor de /Home/Visualizador.
   ========================================================================== */

:root {
  /* ==================== BASE — colores de marca y status ====================
     Mismos en los dos modos. Cambiar aquí = todo lo que usa estos colores
     (botones, badges, alerts, focus rings, links...) se recalcula solo. */
  --dev-color-primary: #2e7d32;
  --dev-color-secondary: #1e2a38;
  --dev-color-info: #006ba1;
  --dev-color-success: #2e7d32;
  --dev-color-danger: #ef5350;
  --dev-color-warning: #ffbd57;

  /* ==================== Texto sobre relleno SÓLIDO de color fijo ====================
     Los colores de marca y el sidebar NO cambian entre modos, así que su
     texto de contraste tampoco debe cambiar. Por eso estos "on-*" viven en
     :root (fijos) y NO usan --dev-color-text-inverse, que sí se invierte por
     modo y en OSCURO volvía el texto oscuro sobre un relleno de color (botón
     primary, badge sólido, item activo del sidebar, etc. = texto negro).
     Regla: si cambias un color de marca por uno CLARO, pon aquí su on-* en
     un tono oscuro (p. ej. #252422). */
  --dev-color-on-primary: #ffffff;
  --dev-color-on-secondary: #ffffff;
  --dev-color-on-info: #ffffff;
  --dev-color-on-success: #ffffff;
  --dev-color-on-danger: #ffffff;
  --dev-color-on-warning: color-mix(in srgb, var(--dev-color-warning) 52%, black);
  /* El sidebar es oscuro en ambos modos: su texto siempre es claro. */
  --dev-color-on-sidebar: #ffffff;

  /* ==================== Paleta extendida (categórica / decorativa) ====================
     Ordenada por familia de tonalidad y luminosidad (1 = más clara).
     Uso: tags, gráficas, avatares, o cualquier elemento que necesite
     distinguir categorías sin depender de los colores semánticos.
     Son valores finales (no se derivan): es la misma paleta en claro y
     oscuro porque son colores de marca, no de tema. */
  --dev-color-red-1: #ef5350;
  --dev-color-red-2: #b71c1c;

  --dev-color-orange-1: #ef6c00;
  --dev-color-orange-2: #c79a00;

  --dev-color-yellow-1: #ffbd57;

  --dev-color-green-1: #2e7d32;
  --dev-color-green-2: #256b2a;

  --dev-color-teal-1: #00a7ce;
  --dev-color-teal-2: #006ba1;

  --dev-color-blue-1: #1976d2;
  --dev-color-blue-2: #006ba1;

  --dev-color-purple-1: #536be2;
  --dev-color-purple-2: #364b8b;
  --dev-color-purple-3: #637099;

  /* ---- Tipografia ---- */
  --dev-font-family-base: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --dev-font-size-sm: 0.875rem;
  --dev-font-size-base: 1rem;
  --dev-font-size-lg: 1.125rem;
  --dev-font-weight-normal: 400;
  --dev-font-weight-medium: 500;
  --dev-font-weight-bold: 600;

  /* ---- Espaciados ---- */
  --dev-space-xs: 0.25rem;
  --dev-space-sm: 0.5rem;
  --dev-space-md: 1rem;
  --dev-space-lg: 1.5rem;
  --dev-space-xl: 2.5rem;

  /* ---- Radios ---- */
  --dev-radius-sm: 0.25rem;
  --dev-radius-md: 0.375rem;
  --dev-radius-lg: 0.5rem;
  --dev-radius-pill: 50rem;

  /* ---- Transiciones ---- */
  --dev-transition-fast: 120ms ease-in-out;
  --dev-transition-base: 200ms ease-in-out;
}

/* ==========================================================================
   MODO CLARO
   ========================================================================== */
:root,
[data-theme="light"] {
  /* ==================== BASE — neutros que sí cambian por modo ==================== */
  --dev-color-bg: #f8f8fb;
  --dev-color-surface: #ffffff;
  --dev-color-sidebar-bg: #333333;
  --dev-color-border: #ebedf2;
  --dev-color-text: #434d6b;
  --dev-color-text-inverse: #ffffff;

  /* ==================== DERIVADO — dirección "modo claro" ====================
     Hover oscurece (hacia negro), los tintes "-light" se aclaran (hacia
     blanco): así siempre se alejan del fondo claro de la página. */
  --dev-color-primary-hover: color-mix(in srgb, var(--dev-color-primary) 82%, black);
  --dev-color-primary-light: color-mix(in srgb, var(--dev-color-primary) 14%, white);
  --dev-color-primary-ring: color-mix(in srgb, var(--dev-color-primary) 25%, transparent);

  --dev-color-secondary-hover: color-mix(in srgb, var(--dev-color-secondary) 78%, black);
  --dev-color-secondary-light: color-mix(in srgb, var(--dev-color-secondary) 14%, white);

  --dev-color-info-hover: color-mix(in srgb, var(--dev-color-info) 78%, black);
  --dev-color-info-light: color-mix(in srgb, var(--dev-color-info) 14%, white);

  --dev-color-success-hover: color-mix(in srgb, var(--dev-color-success) 82%, black);
  --dev-color-success-light: color-mix(in srgb, var(--dev-color-success) 14%, white);

  --dev-color-danger-hover: color-mix(in srgb, var(--dev-color-danger) 82%, black);
  --dev-color-danger-light: color-mix(in srgb, var(--dev-color-danger) 14%, white);

  --dev-color-warning-hover: color-mix(in srgb, var(--dev-color-warning) 82%, black);
  --dev-color-warning-light: color-mix(in srgb, var(--dev-color-warning) 14%, white);
  --dev-color-warning-text: color-mix(in srgb, var(--dev-color-warning) 52%, black);

  /* ---- Texto de componentes "suaves" (badge/alert en tono claro) ----
     Se pinta sobre el fondo -light. En modo CLARO ese fondo es claro, así
     que el texto es el propio color de marca (oscuro = buen contraste).
     En modo OSCURO el fondo -light se vuelve casi negro, por eso el texto
     se ACLARA (ver bloque dark). Sin esto, secondary/info (#403d39) y el
     warning-text quedaban oscuros sobre fondo oscuro = ilegibles. */
  --dev-color-primary-soft-text: var(--dev-color-primary);
  --dev-color-secondary-soft-text: var(--dev-color-secondary);
  --dev-color-info-soft-text: var(--dev-color-info);
  --dev-color-success-soft-text: var(--dev-color-success);
  --dev-color-danger-soft-text: var(--dev-color-danger);
  --dev-color-warning-soft-text: var(--dev-color-warning-text);

  /* ---- Colores oscuros como texto/borde SOBRE la superficie de la página ----
     secondary/info son cafés oscuros; como texto de un outline-button o un
     link se leen bien sobre el fondo claro. En modo OSCURO ese mismo texto
     sobre el fondo oscuro es casi invisible, así que allá se aclara. */
  --dev-color-secondary-on-surface: var(--dev-color-secondary);
  --dev-color-info-on-surface: var(--dev-color-info);

  /* Superficies derivadas del fondo/superficie base */
  --dev-color-bg-subtle: color-mix(in srgb, var(--dev-color-bg) 96%, black);
  --dev-color-surface-raised: color-mix(in srgb, var(--dev-color-surface) 94%, black);
  --dev-color-surface-overlay: color-mix(in srgb, var(--dev-color-primary) 6%, transparent);
  --dev-color-border-strong: color-mix(in srgb, var(--dev-color-border) 55%, black);

  /* Texto muted: el texto principal fundido hacia el fondo de la página */
  --dev-color-text-muted: color-mix(in srgb, var(--dev-color-text) 68%, var(--dev-color-bg));

  /* Sidebar: el resaltado activo SIEMPRE es el primario (identidad de marca) */
  --dev-color-sidebar-active: #00a7ce;
  --dev-color-sidebar-hover: #4d4d4d;
  --dev-color-sidebar-text: color-mix(in srgb, var(--dev-color-on-sidebar) 78%, var(--dev-color-sidebar-bg));
  --dev-color-sidebar-text-active: var(--dev-color-on-sidebar);

  /* ---- Sombras (neutras, no dependen de la paleta de marca) ---- */
  --dev-shadow-sm: 0 1px 2px rgba(30, 42, 56, 0.06);
  --dev-shadow-md: 0 1px 4px rgba(30, 42, 56, 0.08);
  --dev-shadow-lg: 0 4px 12px rgba(30, 42, 56, 0.12);
  --dev-shadow-dropdown: 0 4px 12px rgba(30, 42, 56, 0.14);
}

/* ==========================================================================
   MODO OSCURO — mismos colores BASE de marca (:root), pero neutros y
   dirección de mezcla propios. Ver la explicación completa arriba.
   ========================================================================== */
[data-theme="dark"] {
  /* ==================== BASE — neutros del modo oscuro ==================== */
  --dev-color-bg: #191b27;
  --dev-color-surface: #1f2231;
  --dev-color-sidebar-bg: #1a1a1a;
  --dev-color-border: #333333;
  --dev-color-text: #f8f8fb;
  --dev-color-text-inverse: #191b27;

  /* ==================== DERIVADO — dirección "modo oscuro" ====================
     Hover aclara (hacia blanco), los tintes "-light" se oscurecen (hacia
     negro): así siempre se alejan del fondo oscuro de la página. */
  --dev-color-primary-hover: color-mix(in srgb, var(--dev-color-primary) 82%, white);
  --dev-color-primary-light: color-mix(in srgb, var(--dev-color-primary) 18%, black);
  --dev-color-primary-ring: color-mix(in srgb, var(--dev-color-primary) 30%, transparent);

  --dev-color-secondary-hover: color-mix(in srgb, var(--dev-color-secondary) 78%, white);
  --dev-color-secondary-light: color-mix(in srgb, var(--dev-color-secondary) 18%, black);

  --dev-color-info-hover: color-mix(in srgb, var(--dev-color-info) 78%, white);
  --dev-color-info-light: color-mix(in srgb, var(--dev-color-info) 18%, black);

  --dev-color-success-hover: color-mix(in srgb, var(--dev-color-success) 82%, white);
  --dev-color-success-light: color-mix(in srgb, var(--dev-color-success) 18%, black);

  --dev-color-danger-hover: color-mix(in srgb, var(--dev-color-danger) 82%, white);
  --dev-color-danger-light: color-mix(in srgb, var(--dev-color-danger) 18%, black);

  --dev-color-warning-hover: color-mix(in srgb, var(--dev-color-warning) 82%, white);
  --dev-color-warning-light: color-mix(in srgb, var(--dev-color-warning) 18%, black);
  --dev-color-warning-text: color-mix(in srgb, var(--dev-color-warning) 52%, black);

  /* Texto suave: el fondo -light aquí es oscuro, así que el texto se aclara
     mezclando el color de marca hacia blanco. Cada color usa su propia
     proporción para caer siempre en zona legible (los oscuros como
     secondary/info necesitan más blanco que primary/danger). */
  --dev-color-primary-soft-text: color-mix(in srgb, var(--dev-color-primary) 72%, white);
  --dev-color-secondary-soft-text: color-mix(in srgb, var(--dev-color-secondary) 45%, white);
  --dev-color-info-soft-text: color-mix(in srgb, var(--dev-color-info) 45%, white);
  --dev-color-success-soft-text: color-mix(in srgb, var(--dev-color-success) 62%, white);
  --dev-color-danger-soft-text: color-mix(in srgb, var(--dev-color-danger) 65%, white);
  --dev-color-warning-soft-text: color-mix(in srgb, var(--dev-color-warning) 78%, white);

  /* Aclarados para leerse sobre el fondo oscuro (outline-button / links). */
  --dev-color-secondary-on-surface: color-mix(in srgb, var(--dev-color-secondary) 42%, white);
  --dev-color-info-on-surface: color-mix(in srgb, var(--dev-color-info) 42%, white);

  --dev-color-bg-subtle: color-mix(in srgb, var(--dev-color-bg) 92%, white);
  --dev-color-surface-raised: color-mix(in srgb, var(--dev-color-surface) 88%, white);
  --dev-color-surface-overlay: color-mix(in srgb, var(--dev-color-primary) 8%, transparent);
  --dev-color-border-strong: color-mix(in srgb, var(--dev-color-border) 55%, white);

  --dev-color-text-muted: color-mix(in srgb, var(--dev-color-text) 70%, var(--dev-color-bg));

  --dev-color-sidebar-active: #00a7ce;
  --dev-color-sidebar-hover: #4d4d4d;
  --dev-color-sidebar-text: color-mix(in srgb, var(--dev-color-on-sidebar) 78%, var(--dev-color-sidebar-bg));
  --dev-color-sidebar-text-active: var(--dev-color-on-sidebar);

  --dev-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.22);
  --dev-shadow-md: 0 1px 4px rgba(0, 0, 0, 0.28);
  --dev-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.35);
  --dev-shadow-dropdown: 0 4px 12px rgba(0, 0, 0, 0.4);
}


/* ===== base.css ===== */
/* ==========================================================================
   BASE
   Reset ligero y estilos globales de tipografia sobre Bootstrap 5.3.8.
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  font-size: 14px;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

body {
  font-family: var(--dev-font-family-base);
  background-color: var(--dev-color-bg-subtle);
  color: var(--dev-color-text);
  margin: 0;
}

/* En móvil, inputs/selects a >=16px para evitar el zoom automático de iOS */
@media (max-width: 767.98px) {
  .form-control,
  .form-select,
  .dev-input,
  .dev-select,
  input,
  select,
  textarea {
    font-size: 16px !important;
  }
}

a {
  color: var(--dev-color-primary);
}

a:hover {
  color: var(--dev-color-primary-hover);
}

::selection {
  background-color: var(--dev-color-primary-light);
}

.dev-focusable:focus,
.dev-focusable:focus-visible {
  outline: none;
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light), 0 0 0 0.05rem var(--dev-color-primary);
}

/* ==========================================================================
   REBOOT
   Reset tipografico sobre elementos HTML nativos (no clases dev-*), al
   estilo de Bootstrap Reboot. Aplica en toda la plantilla sin necesidad de
   agregar ninguna clase: heredan la paleta y escala tipografica del tema.
   ========================================================================== */

h1, h2, h3, h4, h5, h6 {
  margin-top: 0;
  margin-bottom: var(--dev-space-sm);
  font-weight: var(--dev-font-weight-bold);
  line-height: 1.25;
  color: var(--dev-color-text);
}

h1 { font-size: calc(var(--dev-font-size-base) * 2.25); }
h2 { font-size: calc(var(--dev-font-size-base) * 1.85); }
h3 { font-size: calc(var(--dev-font-size-base) * 1.5); }
h4 { font-size: calc(var(--dev-font-size-base) * 1.25); }
h5 { font-size: var(--dev-font-size-lg); }
h6 { font-size: var(--dev-font-size-base); }

p {
  margin-top: 0;
  margin-bottom: var(--dev-space-md);
}

ol, ul {
  margin-top: 0;
  margin-bottom: var(--dev-space-md);
  padding-left: 2rem;
}

ol ol, ul ul, ol ul, ul ol {
  margin-bottom: 0;
}

dt {
  font-weight: var(--dev-font-weight-bold);
}

dd {
  margin-bottom: var(--dev-space-sm);
  margin-left: 0;
}

hr {
  margin: var(--dev-space-lg) 0;
  color: var(--dev-color-border);
  border: 0;
  border-top: 1px solid var(--dev-color-border);
  opacity: 1;
}

small {
  font-size: 0.8em;
}

mark {
  padding: 0.1875em 0.375em;
  background-color: var(--dev-color-warning);
  color: var(--dev-color-text);
  border-radius: var(--dev-radius-sm);
}

abbr[title] {
  text-decoration: underline dotted;
  cursor: help;
  text-decoration-skip-ink: none;
}

code, kbd, pre, samp {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 0.9em;
}

pre {
  display: block;
  margin-top: 0;
  margin-bottom: var(--dev-space-md);
  padding: var(--dev-space-md);
  overflow: auto;
  background-color: var(--dev-color-surface-raised);
  border-radius: var(--dev-radius-sm);
  color: var(--dev-color-text);
}

code {
  padding: 0.15em 0.4em;
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-primary-hover);
  border-radius: var(--dev-radius-sm);
  word-wrap: break-word;
}

pre code {
  padding: 0;
  background-color: transparent;
  color: inherit;
}

figure {
  margin: 0 0 var(--dev-space-md);
}

img, svg {
  vertical-align: middle;
}

table {
  border-collapse: collapse;
}

caption {
  padding-top: var(--dev-space-sm);
  padding-bottom: var(--dev-space-sm);
  color: var(--dev-color-text-muted);
  text-align: left;
}


/* ===== content/typography.css ===== */
/* ==========================================================================
   TIPOGRAFIA (BEM)
   Bloques: dev-display, dev-lead, dev-blockquote, dev-list, dev-mark
   Complementa el reset de base.css (Reboot) con variantes de contenido:
   titulos grandes, texto introductorio, citas y listas sin viñeta.
   ========================================================================== */

/* ---- Display headings ---- */
.dev-display-1,
.dev-display-2,
.dev-display-3,
.dev-display-4 {
  font-weight: var(--dev-font-weight-medium);
  line-height: 1.15;
  color: var(--dev-color-text);
  margin-bottom: var(--dev-space-md);
}

.dev-display-1 { font-size: calc(var(--dev-font-size-base) * 5); }
.dev-display-2 { font-size: calc(var(--dev-font-size-base) * 4.25); }
.dev-display-3 { font-size: calc(var(--dev-font-size-base) * 3.5); }
.dev-display-4 { font-size: calc(var(--dev-font-size-base) * 2.75); }

/* ---- Texto introductorio ---- */
.dev-lead {
  font-size: var(--dev-font-size-lg);
  font-weight: var(--dev-font-weight-normal);
  color: var(--dev-color-text-muted);
}

/* ---- Utilidades de texto ---- */
.dev-text--muted { color: var(--dev-color-text-muted); }
.dev-text--small { font-size: var(--dev-font-size-sm); }
.dev-text--bold { font-weight: var(--dev-font-weight-bold); }

/* ---- Cita ---- */
.dev-blockquote {
  margin: 0 0 var(--dev-space-md);
  padding-left: var(--dev-space-md);
  border-left: 0.25rem solid var(--dev-color-primary);
  font-size: var(--dev-font-size-lg);
}

.dev-blockquote__footer {
  display: block;
  margin-top: var(--dev-space-sm);
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
}

.dev-blockquote__footer::before {
  content: "\2014\00A0"; /* — */
}

/* ---- Listas ---- */
.dev-list--unstyled {
  padding-left: 0;
  list-style: none;
}

.dev-list--inline {
  padding-left: 0;
  list-style: none;
}

.dev-list--inline .dev-list__item {
  display: inline-block;
}

.dev-list--inline .dev-list__item:not(:last-child) {
  margin-right: var(--dev-space-sm);
}

/* ---- Resaltado ---- */
.dev-mark {
  padding: 0.1875em 0.375em;
  background-color: var(--dev-color-warning);
  color: var(--dev-color-text);
  border-radius: var(--dev-radius-sm);
}


/* ===== content/images.css ===== */
/* ==========================================================================
   IMAGENES (BEM)
   Bloque: dev-img
   Modificadores: dev-img--thumbnail, dev-img--rounded, dev-img--circle
   Helper: dev-img-fluid (respuesta a contenedor, sin modificador porque
   aplica siempre igual, como .img-fluid de Bootstrap).
   ========================================================================== */

.dev-img-fluid {
  max-width: 100%;
  height: auto;
}

.dev-img--thumbnail {
  padding: 0.25rem;
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  max-width: 100%;
  height: auto;
}

.dev-img--rounded {
  border-radius: var(--dev-radius-md);
}

.dev-img--circle {
  border-radius: 50%;
}


/* ===== content/figures.css ===== */
/* ==========================================================================
   FIGURES (BEM)
   Bloque: dev-figure
   Elementos: dev-figure__img, dev-figure__caption
   Uso: <figure class="dev-figure"><img class="dev-figure__img" .../>
        <figcaption class="dev-figure__caption">...</figcaption></figure>
   ========================================================================== */

.dev-figure {
  display: inline-block;
  margin: 0 0 var(--dev-space-md);
}

.dev-figure__img {
  max-width: 100%;
  height: auto;
  border-radius: var(--dev-radius-md);
  margin-bottom: var(--dev-space-sm);
}

.dev-figure__caption {
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
  text-align: center;
}


/* ===== components/layout.css ===== */
/* ==========================================================================
   LAYOUT (BEM) — shell / sidebar / topbar
   Bloques: dev-shell, dev-sidebar, dev-main, dev-topbar, dev-user-chip,
            dev-sidebar-overlay, dev-scrolltop, dev-toast-list
   Estructura estándar de toda vista autenticada:
   <div class="dev-shell">
     <nav class="dev-sidebar">...</nav>
     <div class="dev-main">
       <header class="dev-topbar">...</header>
       <main class="dev-content">...</main>
     </div>
   </div>
   ========================================================================== */

.dev-shell {
  display: flex;
  min-height: 100vh;
  width: 100%;
  max-width: 100%;
}

/* ---- Sidebar (bloque: dev-sidebar) ---- */
.dev-sidebar {
  width: 240px;
  background-color: var(--dev-color-sidebar-bg);
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  height: 100dvh;
  z-index: 1040;
  transition: width var(--dev-transition-base), transform var(--dev-transition-base);
  overflow: hidden;
  padding-left: env(safe-area-inset-left);
}

.dev-sidebar--icon-only {
  width: 64px;
}

.dev-sidebar--mobile-open {
  transform: translateX(0);
}

.dev-sidebar__brand {
  padding: 14px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  flex-shrink: 0;
}

.dev-sidebar__brand-link {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  overflow: hidden;
  white-space: nowrap;
}

.dev-sidebar__brand-icon {
  width: 36px;
  height: 36px;
  min-width: 36px;
  background: var(--dev-color-primary);
  border-radius: var(--dev-radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
}

.dev-sidebar__brand-icon img {
  width: 22px;
  height: 22px;
  object-fit: contain;
  filter: brightness(0) invert(1);
}

.dev-sidebar__brand-name {
  font-size: 14px;
  font-weight: var(--dev-font-weight-bold);
  /* El sidebar SIEMPRE es oscuro (en los dos modos), por eso usa el token
     fijo --dev-color-sidebar-text-active y no --dev-color-text-inverse
     (ese sí se invierte con el tema y en modo oscuro quedaba con tinta
     oscura sobre el panel oscuro, es decir, invisible). */
  color: var(--dev-color-sidebar-text-active);
  white-space: nowrap;
}

.dev-sidebar__brand-ver {
  font-size: 10px;
  color: var(--dev-color-sidebar-text);
  opacity: 0.7;
  white-space: nowrap;
}

.dev-sidebar__nav {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 8px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}

.dev-sidebar__section-label {
  font-size: 10px;
  font-weight: var(--dev-font-weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.3);
  padding: 12px 12px 4px;
  white-space: nowrap;
  overflow: hidden;
  transition: opacity var(--dev-transition-fast);
}

.dev-sidebar__footer {
  padding: 8px;
  flex-shrink: 0;
}

.dev-sidebar__footer-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  color: rgba(255, 255, 255, 0.3);
  font-size: 12px;
  overflow: hidden;
  white-space: nowrap;
  border-radius: var(--dev-radius-md);
}

.dev-sidebar__footer-divider {
  height: 1px;
  margin: 4px 4px 6px;
  background: rgba(255, 255, 255, 0.07);
}

.dev-sidebar--icon-only .dev-sidebar__footer-item {
  justify-content: center;
}

/* ---- Nav link (bloque: dev-nav-link) ---- */
.dev-nav-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  color: var(--dev-color-sidebar-text);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: var(--dev-font-weight-normal);
  border-radius: var(--dev-radius-md);
  transition: background var(--dev-transition-fast), color var(--dev-transition-fast);
  margin-bottom: 2px;
  overflow: hidden;
  white-space: nowrap;
}

.dev-nav-link:hover {
  background-color: rgba(255, 255, 255, 0.08);
  color: var(--dev-color-sidebar-text-active);
}

.dev-nav-link--active {
  background-color: var(--dev-color-sidebar-active);
  color: var(--dev-color-on-primary);
  font-weight: var(--dev-font-weight-medium);
}

.dev-nav-link--toggle {
  width: 100%;
  border: none;
  background: none;
  text-align: left;
}

/* Especificidad explícita: sin esto, .dev-nav-link--toggle (declarado
   después) le gana a .dev-nav-link--active y el botón "UI Kit" se queda
   sin el fondo naranja al estar dentro de la sección activa. */
.dev-nav-link--toggle.dev-nav-link--active {
  background-color: var(--dev-color-sidebar-active);
  color: var(--dev-color-on-primary);
}

.dev-nav-link__icon {
  width: 20px;
  min-width: 20px;
  text-align: center;
  font-size: 14px;
  flex-shrink: 0;
}

.dev-nav-link__text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dev-nav-link__chevron {
  margin-left: auto;
  font-size: 10px;
  transition: transform var(--dev-transition-fast);
}

.dev-nav-link--toggle[aria-expanded="true"] .dev-nav-link__chevron {
  transform: rotate(180deg);
}

.dev-sidebar--icon-only .dev-nav-link__text,
.dev-sidebar--icon-only .dev-sidebar__brand-name,
.dev-sidebar--icon-only .dev-sidebar__brand-ver,
.dev-sidebar--icon-only .dev-sidebar__section-label {
  opacity: 0;
  width: 0;
  pointer-events: none;
}

.dev-sidebar--icon-only .dev-nav-link {
  justify-content: center;
  padding: 10px 0;
}

.dev-sidebar--icon-only .dev-sidebar__brand-link {
  justify-content: center;
}

.dev-sidebar--icon-only .dev-sidebar__brand {
  padding: 14px 10px;
}

/* ---- Submenú (bloque: dev-nav-submenu) ---- */
.dev-nav-submenu {
  list-style: none;
  margin: 0;
  padding: 2px 0 4px 0;
}

.dev-nav-submenu__group {
  font-size: 10px;
  font-weight: var(--dev-font-weight-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.3);
  padding: 10px 12px 2px 34px;
  white-space: nowrap;
  overflow: hidden;
}

.dev-nav-submenu__link {
  display: block;
  padding: 6px 12px 6px 34px;
  color: var(--dev-color-sidebar-text);
  text-decoration: none;
  font-size: 13px;
  border-radius: var(--dev-radius-sm);
  margin: 0 4px 1px 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: background var(--dev-transition-fast), color var(--dev-transition-fast);
}

.dev-nav-submenu__link:hover {
  background-color: rgba(255, 255, 255, 0.08);
  color: var(--dev-color-sidebar-text-active);
}

.dev-nav-submenu__link--active {
  background-color: rgba(255, 255, 255, 0.12);
  color: var(--dev-color-sidebar-text-active);
  font-weight: var(--dev-font-weight-medium);
}

/* En modo icon-only se ocultan los submenús (no aplica el colapso) */
.dev-sidebar--icon-only .dev-nav-submenu,
.dev-sidebar--icon-only .dev-nav-link__chevron {
  display: none;
}

/* ---- Main area (bloque: dev-main) ---- */
.dev-main {
  margin-left: 240px;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-width: 0;
  max-width: 100%;
  overflow-x: hidden;
  transition: margin-left var(--dev-transition-base);
}

.dev-main--icon-only {
  margin-left: 64px;
}

/* ---- Topbar (bloque: dev-topbar) ---- */
.dev-topbar {
  height: 60px;
  background-color: var(--dev-color-surface);
  border-bottom: 1px solid var(--dev-color-border);
  display: flex;
  align-items: center;
  padding: 0 24px;
  padding-right: calc(24px + env(safe-area-inset-right));
  position: sticky;
  top: 0;
  z-index: 1030;
  gap: 8px;
  box-shadow: 0 1px 0 var(--dev-color-border);
}

.dev-topbar__toggle {
  background: none;
  border: none;
  color: var(--dev-color-text-muted);
  width: 36px;
  height: 36px;
  border-radius: var(--dev-radius-md);
  cursor: pointer;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--dev-transition-fast), color var(--dev-transition-fast);
  flex-shrink: 0;
}

.dev-topbar__toggle:hover {
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}

.dev-topbar__title {
  font-size: 14px;
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dev-topbar__spacer {
  flex: 1;
}

.dev-topbar__datetime {
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.25;
}

.dev-topbar__date {
  font-size: 13px;
  font-weight: var(--dev-font-weight-medium, 500);
  color: var(--dev-color-text);
  white-space: nowrap;
}

.dev-topbar__time {
  font-size: 11px;
  color: var(--dev-color-text-muted);
  white-space: nowrap;
}

.dev-topbar__actions {
  display: flex;
  align-items: center;
  gap: 2px;
}

.dev-topbar__divider {
  width: 1px;
  height: 20px;
  background: var(--dev-color-border);
  margin: 0 6px;
}

.dev-topbar__icon-btn {
  background: none;
  border: none;
  color: var(--dev-color-text-muted);
  width: 36px;
  height: 36px;
  border-radius: var(--dev-radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 15px;
  transition: background var(--dev-transition-fast), color var(--dev-transition-fast);
}

.dev-topbar__icon-btn:hover {
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}

/* ---- User chip (bloque: dev-user-chip) ---- */
.dev-user-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  border-radius: var(--dev-radius-md);
  cursor: pointer;
  border: 1px solid var(--dev-color-border);
  background: none;
  color: var(--dev-color-text);
  transition: background var(--dev-transition-fast), border-color var(--dev-transition-fast);
  margin-left: 4px;
}

.dev-user-chip:hover {
  background-color: var(--dev-color-surface-raised);
  border-color: var(--dev-color-border-strong);
}

.dev-user-chip__avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: var(--dev-font-weight-bold);
  overflow: hidden;
  flex-shrink: 0;
}

.dev-user-chip__avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.dev-user-chip__name {
  font-size: 13px;
  font-weight: var(--dev-font-weight-medium);
  max-width: 140px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ---- Content area ---- */
.dev-content {
  flex: 1;
  padding: 28px 32px;
  max-width: 100%;
  min-width: 0;
  overflow-x: hidden;
}

/* ---- Overlay móvil (bloque: dev-sidebar-overlay) ---- */
.dev-sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(37, 36, 34, 0.4);
  z-index: 1039;
}

.dev-sidebar-overlay--show {
  display: block;
}

/* ---- Scroll to top (bloque: dev-scrolltop) ---- */
.dev-scrolltop {
  position: fixed;
  bottom: 24px;
  right: 24px;
  width: 36px;
  height: 36px;
  background-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
  border: none;
  border-radius: var(--dev-radius-md);
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: var(--dev-shadow-md);
  z-index: 999;
  transition: opacity var(--dev-transition-fast);
}

.dev-scrolltop--visible {
  display: flex;
}

.dev-scrolltop:hover {
  background-color: var(--dev-color-primary-hover);
}

/* ---- Toast (bloque: dev-toast-list / dev-toast) — reemplaza toastr ----
   Posiciones: dev-toast-list--top-start|top-center|top-end|
               bottom-start|bottom-center|bottom-end
   Sin modificador = bottom-end (comportamiento anterior, por compatibilidad). */
.dev-toast-list {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  max-width: calc(100vw - 40px);
}

.dev-toast-list--top-start    { top: 20px; left: 20px; bottom: auto; right: auto; }
.dev-toast-list--top-center   { top: 20px; left: 50%; bottom: auto; right: auto; transform: translateX(-50%); }
.dev-toast-list--top-end      { top: 20px; right: 20px; bottom: auto; left: auto; }
.dev-toast-list--bottom-start { bottom: 20px; left: 20px; top: auto; right: auto; }
.dev-toast-list--bottom-center{ bottom: 20px; left: 50%; top: auto; right: auto; transform: translateX(-50%); }
.dev-toast-list--bottom-end   { bottom: 20px; right: 20px; top: auto; left: auto; }

.dev-toast-list--top-start .dev-toast,
.dev-toast-list--top-center .dev-toast,
.dev-toast-list--top-end .dev-toast {
  margin-top: 0;
  margin-bottom: 8px;
}

.dev-toast {
  color: var(--dev-color-on-primary);
  padding: 12px 18px;
  border-radius: var(--dev-radius-md);
  box-shadow: var(--dev-shadow-lg);
  font-size: 13.5px;
  min-width: 240px;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
}

.dev-toast__close {
  background: none;
  border: none;
  color: var(--dev-color-on-primary);
  margin-left: auto;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
}

.dev-toast--success { background-color: var(--dev-color-success); }
.dev-toast--danger  { background-color: var(--dev-color-danger); }
.dev-toast--warning { background-color: var(--dev-color-warning); color: var(--dev-color-warning-text); }
.dev-toast--warning .dev-toast__close { color: var(--dev-color-warning-text); }
.dev-toast--info    { background-color: var(--dev-color-primary); }

/* ---- Responsive ---- */
@media (max-width: 991.98px) {
  .dev-sidebar { transform: translateX(-240px); width: 240px; }
  .dev-sidebar--icon-only { width: 240px; }
  .dev-main, .dev-main--icon-only { margin-left: 0 !important; }
  .dev-content {
    padding: 14px 12px;
    padding-left: calc(12px + env(safe-area-inset-left));
    padding-right: calc(12px + env(safe-area-inset-right));
  }
  .dev-topbar {
    padding: 0 12px;
    padding-right: calc(12px + env(safe-area-inset-right));
  }
  .dev-topbar__title { max-width: 160px; }
}

@media (max-width: 767.98px) {
  .dev-content { padding: 10px 8px; }
}

@media (max-width: 575.98px) {
  .dev-content { padding: 8px 6px; }
  .dev-topbar { padding: 0 8px; gap: 2px; height: 54px; }
  .dev-topbar__toggle { width: 32px; height: 32px; font-size: 15px; }
  .dev-topbar__title { display: none; }
  .dev-topbar__icon-btn { width: 32px; height: 32px; font-size: 14px; }
  .dev-topbar__divider { margin: 0 2px; }
  .dev-user-chip { padding: 3px 6px 3px 3px; margin-left: 0; }
  .dev-user-chip__avatar { width: 26px; height: 26px; font-size: 10px; }
}


/* ===== components/buttons.css ===== */
/* ==========================================================================
   BOTONES (BEM)
   Bloque: dev-btn
   Modificadores: dev-btn--primary|secondary|success|danger|warning|info
                  dev-btn--outline-*  dev-btn--ghost
                  dev-btn--sm|lg|icon|pill
   Uso: <button class="dev-btn dev-btn--primary">Guardar</button>
   ========================================================================== */

.dev-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--dev-space-xs);
  font-family: var(--dev-font-family-base);
  font-size: var(--dev-font-size-base);
  font-weight: var(--dev-font-weight-medium);
  line-height: 1.4;
  padding: 0.55rem 1.1rem;
  border-radius: var(--dev-radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--dev-transition-fast), border-color var(--dev-transition-fast),
              color var(--dev-transition-fast), box-shadow var(--dev-transition-fast);
}

.dev-btn:focus,
.dev-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light);
}

.dev-btn:disabled,
.dev-btn.disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.dev-btn--sm {
  padding: 0.3rem 0.75rem;
  font-size: var(--dev-font-size-sm);
  border-radius: var(--dev-radius-sm);
}

.dev-btn--lg {
  padding: 0.75rem 1.5rem;
  font-size: var(--dev-font-size-lg);
  border-radius: var(--dev-radius-lg);
}

.dev-btn--icon {
  padding: 0.55rem;
  border-radius: var(--dev-radius-md);
  aspect-ratio: 1 / 1;
}

.dev-btn--pill {
  border-radius: var(--dev-radius-pill);
}

/* ---- Modificador: relleno solido ---- */
.dev-btn--primary   { background-color: var(--dev-color-primary);   border-color: var(--dev-color-primary);   color: var(--dev-color-on-primary); }
.dev-btn--primary:hover   { background-color: var(--dev-color-primary-hover);   border-color: var(--dev-color-primary-hover); }

.dev-btn--secondary { background-color: var(--dev-color-secondary); border-color: var(--dev-color-secondary); color: var(--dev-color-on-secondary); }
.dev-btn--secondary:hover { background-color: var(--dev-color-secondary-hover); border-color: var(--dev-color-secondary-hover); }

.dev-btn--success   { background-color: var(--dev-color-success);   border-color: var(--dev-color-success);   color: var(--dev-color-on-success); }
.dev-btn--success:hover   { background-color: var(--dev-color-success-hover);   border-color: var(--dev-color-success-hover); }

.dev-btn--danger    { background-color: var(--dev-color-danger);    border-color: var(--dev-color-danger);    color: var(--dev-color-on-danger); }
.dev-btn--danger:hover    { background-color: var(--dev-color-danger-hover);    border-color: var(--dev-color-danger-hover); }

.dev-btn--warning   { background-color: var(--dev-color-warning);   border-color: var(--dev-color-warning);   color: var(--dev-color-on-warning); }
.dev-btn--warning:hover   { background-color: var(--dev-color-warning-hover);   border-color: var(--dev-color-warning-hover); }

.dev-btn--info      { background-color: var(--dev-color-info);      border-color: var(--dev-color-info);      color: var(--dev-color-on-info); }
.dev-btn--info:hover      { background-color: var(--dev-color-info-hover);      border-color: var(--dev-color-info-hover); }

/* ---- Modificador: outline ----
   Texto/borde usan la versión "-on-surface" (se aclara en modo oscuro) para
   los colores oscuros como secondary/info; en hover el relleno es sólido y
   el texto pasa a on-* (fijo). */
.dev-btn--outline-primary   { background-color: transparent; border-color: var(--dev-color-primary);   color: var(--dev-color-primary); }
.dev-btn--outline-primary:hover   { background-color: var(--dev-color-primary);   color: var(--dev-color-on-primary); }

.dev-btn--outline-secondary { background-color: transparent; border-color: var(--dev-color-secondary-on-surface); color: var(--dev-color-secondary-on-surface); }
.dev-btn--outline-secondary:hover { background-color: var(--dev-color-secondary); border-color: var(--dev-color-secondary); color: var(--dev-color-on-secondary); }

.dev-btn--outline-success   { background-color: transparent; border-color: var(--dev-color-success);   color: var(--dev-color-success); }
.dev-btn--outline-success:hover   { background-color: var(--dev-color-success);   color: var(--dev-color-on-success); }

.dev-btn--outline-danger    { background-color: transparent; border-color: var(--dev-color-danger);    color: var(--dev-color-danger); }
.dev-btn--outline-danger:hover    { background-color: var(--dev-color-danger);    color: var(--dev-color-on-danger); }

.dev-btn--outline-warning   { background-color: transparent; border-color: var(--dev-color-warning);   color: var(--dev-color-warning-text); }
.dev-btn--outline-warning:hover   { background-color: var(--dev-color-warning);   color: var(--dev-color-on-warning); }

.dev-btn--outline-info      { background-color: transparent; border-color: var(--dev-color-info-on-surface);      color: var(--dev-color-info-on-surface); }
.dev-btn--outline-info:hover      { background-color: var(--dev-color-info);      border-color: var(--dev-color-info); color: var(--dev-color-on-info); }

/* ---- Modificador: ghost (sin borde) ---- */
.dev-btn--ghost {
  background-color: transparent;
  border-color: transparent;
  color: var(--dev-color-text);
}

.dev-btn--ghost:hover {
  background-color: var(--dev-color-bg);
}


/* ===== components/inputs.css ===== */
/* ==========================================================================
   INPUTS / FORMULARIOS (BEM)
   Bloques: dev-label, dev-input, dev-textarea, dev-help-text,
            dev-input-group, dev-check, dev-switch
   Uso: <input class="dev-input" />  |  <label class="dev-label">
   Estados: dev-input--error, dev-input--success  |  :disabled nativo
   ========================================================================== */

.dev-label {
  display: inline-block;
  margin-bottom: var(--dev-space-xs);
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-medium);
  color: var(--dev-color-text);
}

.dev-label--required::after {
  content: " *";
  color: var(--dev-color-danger);
}

.dev-input,
.dev-textarea {
  display: block;
  width: 100%;
  font-family: var(--dev-font-family-base);
  font-size: var(--dev-font-size-base);
  color: var(--dev-color-text);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  padding: 0.55rem 0.85rem;
  transition: border-color var(--dev-transition-fast), box-shadow var(--dev-transition-fast);
}

.dev-textarea {
  min-height: 6rem;
  resize: vertical;
}

.dev-input::placeholder,
.dev-textarea::placeholder {
  color: var(--dev-color-text-muted);
}

.dev-input:focus,
.dev-textarea:focus {
  outline: none;
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light);
}

.dev-input:disabled,
.dev-textarea:disabled {
  background-color: var(--dev-color-bg);
  color: var(--dev-color-text-muted);
  cursor: not-allowed;
}

.dev-input--sm { padding: 0.35rem 0.65rem; font-size: var(--dev-font-size-sm); }
.dev-input--lg { padding: 0.75rem 1rem; font-size: var(--dev-font-size-lg); }

.dev-input--error {
  border-color: var(--dev-color-danger);
}
.dev-input--error:focus {
  box-shadow: 0 0 0 0.2rem rgba(217, 48, 37, 0.15);
}

.dev-input--success {
  border-color: var(--dev-color-success);
}
.dev-input--success:focus {
  box-shadow: 0 0 0 0.2rem rgba(47, 158, 68, 0.15);
}

.dev-help-text {
  display: block;
  margin-top: var(--dev-space-xs);
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
}

.dev-help-text--error {
  color: var(--dev-color-danger);
}

/* ---- Grupo con icono ---- */
.dev-input-group {
  display: flex;
  align-items: stretch;
}

.dev-input-group .dev-input {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.dev-input-group__addon {
  display: flex;
  align-items: center;
  padding: 0 0.85rem;
  background-color: var(--dev-color-bg);
  border: 1px solid var(--dev-color-border);
  border-left: none;
  border-top-right-radius: var(--dev-radius-md);
  border-bottom-right-radius: var(--dev-radius-md);
  color: var(--dev-color-text-muted);
}

/* ---- Checkbox / Radio / Switch ---- */
.dev-check {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  cursor: pointer;
}

.dev-check input[type="checkbox"],
.dev-check input[type="radio"] {
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--dev-color-primary);
  cursor: pointer;
}

.dev-switch {
  position: relative;
  display: inline-block;
  width: 2.75rem;
  height: 1.5rem;
}

.dev-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.dev-switch__track {
  position: absolute;
  inset: 0;
  background-color: var(--dev-color-border-strong);
  border-radius: var(--dev-radius-pill);
  transition: background-color var(--dev-transition-fast);
}

.dev-switch__track::before {
  content: "";
  position: absolute;
  height: 1.15rem;
  width: 1.15rem;
  left: 0.18rem;
  top: 0.18rem;
  background-color: var(--dev-color-surface);
  border-radius: 50%;
  transition: transform var(--dev-transition-fast);
}

.dev-switch input:checked + .dev-switch__track {
  background-color: var(--dev-color-primary);
}

.dev-switch input:checked + .dev-switch__track::before {
  transform: translateX(1.25rem);
}

/* ---- Range ---- */
.dev-range {
  width: 100%;
  height: 1.2rem;
  padding: 0;
  background: transparent;
  appearance: none;
}

.dev-range::-webkit-slider-runnable-track {
  height: 0.35rem;
  background-color: var(--dev-color-border);
  border-radius: var(--dev-radius-pill);
}

.dev-range::-moz-range-track {
  height: 0.35rem;
  background-color: var(--dev-color-border);
  border-radius: var(--dev-radius-pill);
}

.dev-range::-webkit-slider-thumb {
  appearance: none;
  margin-top: -0.4rem;
  width: 1.1rem;
  height: 1.1rem;
  background-color: var(--dev-color-primary);
  border-radius: 50%;
  border: 0;
  cursor: pointer;
  transition: box-shadow var(--dev-transition-fast);
}

.dev-range::-moz-range-thumb {
  width: 1.1rem;
  height: 1.1rem;
  background-color: var(--dev-color-primary);
  border-radius: 50%;
  border: 0;
  cursor: pointer;
}

.dev-range:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light);
}

.dev-range:disabled::-webkit-slider-thumb {
  background-color: var(--dev-color-text-muted);
  cursor: not-allowed;
}

/* ---- Floating labels ---- */
.dev-form-floating {
  position: relative;
}

.dev-form-floating > .dev-input,
.dev-form-floating > .dev-select {
  height: calc(3.2rem + 2px);
  padding: 1.2rem 0.85rem 0.4rem;
}

.dev-form-floating > .dev-form-floating__label {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 0.85rem;
  pointer-events: none;
  border: 1px solid transparent;
  transform-origin: 0 0;
  transition: opacity var(--dev-transition-fast), transform var(--dev-transition-fast);
  color: var(--dev-color-text-muted);
  font-size: var(--dev-font-size-base);
}

.dev-form-floating > .dev-input:focus ~ .dev-form-floating__label,
.dev-form-floating > .dev-input:not(:placeholder-shown) ~ .dev-form-floating__label,
.dev-form-floating > .dev-select ~ .dev-form-floating__label {
  opacity: 0.75;
  transform: scale(0.82) translateY(-0.55rem) translateX(0.15rem);
}

/* ---- Validacion ---- */
.dev-help-text--success {
  color: var(--dev-color-success);
}

.dev-input--error:invalid,
.dev-input--success:valid {
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 1rem;
}


/* ===== components/selects.css ===== */
/* ==========================================================================
   SELECTS (BEM)
   Bloque: dev-select
   Modificadores: dev-select--sm, dev-select--lg, dev-select--enhanced
   Uso: <select class="dev-select">...</select>
   Buscador: agregar data-dev-search al <select> (automatico desde 8
   opciones); data-dev-search="off" lo desactiva. Ver dev-select.js
   Nota: si el select usa bootstrap-select (buscador), agregar ademas
   la clase dev-select--enhanced y ver design-system/js/components/select.js
   ========================================================================== */

.dev-select {
  display: block;
  width: 100%;
  font-family: var(--dev-font-family-base);
  font-size: 0.845rem;
  color: var(--dev-color-text);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  padding: 0.5rem 2.25rem 0.5rem 0.75rem;
  appearance: none;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%236b6459' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 16px 12px;
  transition: border-color var(--dev-transition-fast), box-shadow var(--dev-transition-fast);
}

.dev-select:focus {
  outline: none;
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-ring);
}

.dev-select:disabled {
  background-color: var(--dev-color-bg);
  color: var(--dev-color-text-muted);
  cursor: not-allowed;
}

/* El navegador dibuja el listado desplegado (los <option>) con su propio
   render nativo; sin esto, en modo oscuro se abre con fondo blanco/texto
   negro sin importar la paleta. color-scheme le dice al navegador qué
   paleta base de UI nativa usar, y el color/background explícito en
   <option> alinea los <option> con la superficie del tema (Chrome/Edge/
   Firefox lo respetan; Safari usa su propio render y lo ignora). */
.dev-select,
.dev-select option {
  color-scheme: light;
}

[data-theme="dark"] .dev-select,
[data-theme="dark"] .dev-select option {
  color-scheme: dark;
}

.dev-select option {
  background-color: var(--dev-color-surface);
  color: var(--dev-color-text);
}

.dev-select--sm { padding: 0.25rem 2rem 0.25rem 0.5rem; font-size: 0.8rem; border-radius: var(--dev-radius-sm); }
.dev-select--lg { padding: 0.75rem 2.5rem 0.75rem 1rem; font-size: var(--dev-font-size-lg); }

/* ==========================================================================
   SELECT CON MENÚ PROPIO (dev-select.js)
   El listado nativo no se puede estilizar en Chrome/Edge; aquí se reemplaza
   por un menú dev-* con borde y opción resaltada en PRIMARY. El <select>
   nativo queda oculto pero presente (valor + evento change).
   ========================================================================== */
.dev-select-wrap {
  position: relative;
  display: block;
  width: 100%;
}

/* Oculta el <select> nativo dentro del wrap (se conserva para el form). */
.dev-select-wrap > select.dev-select {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

/* Disparador: mismo aspecto que .dev-select */
.dev-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  font-family: var(--dev-font-family-base);
  font-size: 0.845rem;
  text-align: left;
  color: var(--dev-color-text);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  transition: border-color var(--dev-transition-fast), box-shadow var(--dev-transition-fast);
}

.dev-select-trigger:focus,
.dev-select-trigger:focus-visible {
  outline: none;
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-ring);
}

.dev-select-wrap--open .dev-select-trigger {
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-ring);
}

.dev-select-trigger:disabled {
  background-color: var(--dev-color-bg);
  color: var(--dev-color-text-muted);
  cursor: not-allowed;
}

.dev-select-trigger__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dev-select-trigger__caret {
  flex-shrink: 0;
  color: var(--dev-color-text-muted);
  transition: transform var(--dev-transition-fast);
}

.dev-select-wrap--open .dev-select-trigger__caret {
  transform: rotate(180deg);
}

.dev-select-wrap--sm .dev-select-trigger { padding: 0.25rem 0.5rem; font-size: 0.8rem; border-radius: var(--dev-radius-sm); }
.dev-select-wrap--lg .dev-select-trigger { padding: 0.75rem 1rem; font-size: var(--dev-font-size-lg); }

/* ---- Menú (con borde, tokens del tema) ---- */
.dev-select-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 60;
  display: none;
  flex-direction: column;
  max-height: 15rem;
  overflow-y: auto;
  padding: 0.25rem;
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  box-shadow: var(--dev-shadow-dropdown);
}

.dev-select-wrap--open .dev-select-menu {
  display: flex;
}

/* Contenedor de las opciones (hermano del buscador). */
.dev-select-menu__list {
  display: flex;
  flex-direction: column;
}

/* ---- Buscador dentro del menú (data-dev-search / >= 8 opciones) ----
   Es un campo relleno, sin borde propio: el menú ya está delimitado, un
   segundo marco adentro se ve como doble borde. Queda fijo arriba mientras
   la lista de opciones hace scroll. */
.dev-select-menu__search {
  position: sticky;
  top: -0.25rem;
  z-index: 1;
  margin: -0.25rem -0.25rem 0.25rem;
  padding: 0.35rem;
  background-color: var(--dev-color-surface);
}

.dev-select-search {
  display: block;
  width: 100%;
  font-family: var(--dev-font-family-base);
  font-size: 0.845rem;
  color: var(--dev-color-text);
  background-color: var(--dev-color-bg-subtle);
  border: 0;
  border-radius: var(--dev-radius-sm);
  padding: 0.4rem 0.6rem;
}

.dev-select-search::placeholder {
  color: var(--dev-color-text-muted);
}

.dev-select-search:focus {
  outline: none;
  box-shadow: 0 0 0 0.15rem var(--dev-color-primary-ring);
}

/* Mensaje cuando el filtro no deja ninguna opción visible. */
.dev-select-menu__empty {
  padding: 0.55rem 0.65rem;
  font-size: 0.845rem;
  color: var(--dev-color-text-muted);
  text-align: center;
}

/* Opción oculta por el filtro del buscador. */
.dev-select-option--filtered {
  display: none;
}

/* ---- Opción: highlight PRIMARY (no el gris del sistema) ---- */
.dev-select-option {
  padding: 0.45rem 0.65rem;
  border-radius: var(--dev-radius-sm);
  font-size: 0.845rem;
  color: var(--dev-color-text);
  cursor: pointer;
  white-space: nowrap;
}

.dev-select-option--active {
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
}

.dev-select-option--selected {
  background-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
  font-weight: var(--dev-font-weight-medium);
}

.dev-select-option--selected.dev-select-option--active {
  background-color: var(--dev-color-primary-hover);
  color: var(--dev-color-on-primary);
}

.dev-select-option--disabled {
  color: var(--dev-color-text-muted);
  cursor: not-allowed;
}

/* ---- bootstrap-select re-skin (cuando dev-select--enhanced esta activo) ---- */
.dev-select--enhanced + .bootstrap-select > .dropdown-toggle {
  background-color: var(--dev-color-surface) !important;
  border: 1px solid var(--dev-color-border) !important;
  border-radius: var(--dev-radius-md) !important;
  color: var(--dev-color-text) !important;
}

.dev-select--enhanced + .bootstrap-select > .dropdown-toggle:focus {
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light) !important;
}

.dev-select--enhanced + .bootstrap-select .dropdown-menu .active > a {
  background-color: var(--dev-color-primary) !important;
}


/* ===== components/datepicker.css ===== */
/* ==========================================================================
   DATEPICKER (BEM)
   Bloque: dev-datepicker (input) + dev-datepicker-panel (calendario)
   Uso:  <input class="dev-input dev-datepicker" name="fecha" />
         <input type="date" class="dev-input" name="fecha" />   (se convierte solo)

   El calendario NATIVO de <input type="date"> lo dibuja el navegador/sistema
   operativo: no acepta los tokens de la paleta ni el modo oscuro, y se ve
   distinto en cada navegador. Por eso dev-datepicker.js oculta ese
   calendario y despliega este panel, hecho con las mismas variables
   --dev-color-* que el resto del sistema (mismo borde, mismo radio, misma
   sombra y el mismo resaltado PRIMARY que usa dev-select).

   Modificadores del panel: --up (se abre hacia arriba cuando no cabe abajo)
   Estados del día: --outside --today --selected --focus --disabled
   ========================================================================== */

.dev-datepicker-wrap {
  position: relative;
  display: block;
  width: 100%;
}

/* Espacio a la derecha para el botón del calendario. */
.dev-datepicker-wrap > .dev-datepicker {
  padding-right: 2.4rem;
}

/* Oculta el icono del calendario NATIVO por si el input siguiera siendo
   type="date" en algún navegador (Chrome/Edge lo dibujan dentro del campo). */
.dev-datepicker::-webkit-calendar-picker-indicator,
.dev-datepicker::-webkit-inner-spin-button {
  display: none;
  -webkit-appearance: none;
}

.dev-datepicker__toggle {
  position: absolute;
  top: 50%;
  right: 0.5rem;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  background: none;
  border: 0;
  border-radius: var(--dev-radius-sm);
  color: var(--dev-color-text-muted);
  cursor: pointer;
  transition: color var(--dev-transition-fast), background-color var(--dev-transition-fast);
}

.dev-datepicker__toggle:hover,
.dev-datepicker-wrap--open .dev-datepicker__toggle {
  color: var(--dev-color-primary);
  background-color: var(--dev-color-primary-light);
}

.dev-datepicker__toggle:focus-visible {
  outline: none;
  box-shadow: 0 0 0 0.15rem var(--dev-color-primary-ring);
}

.dev-datepicker__toggle:disabled {
  color: var(--dev-color-text-muted);
  cursor: not-allowed;
}

/* ---- Panel ---- */
.dev-datepicker-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 60;
  display: none;
  width: 18rem;
  max-width: 100%;
  padding: var(--dev-space-sm);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  box-shadow: var(--dev-shadow-dropdown);
  color: var(--dev-color-text);
  font-size: var(--dev-font-size-sm);
}

.dev-datepicker-wrap--open .dev-datepicker-panel {
  display: block;
}

/* Sin espacio abajo en la ventana: el panel sube. */
.dev-datepicker-panel--up {
  top: auto;
  bottom: calc(100% + 4px);
}

/* ---- Encabezado: mes / año + flechas ---- */
.dev-datepicker__header {
  display: flex;
  align-items: center;
  gap: var(--dev-space-xs);
  margin-bottom: var(--dev-space-sm);
}

.dev-datepicker__selects {
  display: flex;
  flex: 1 1 auto;
  gap: var(--dev-space-xs);
  min-width: 0;
}

.dev-datepicker__selects > * {
  flex: 1 1 0;
  min-width: 0;
}

.dev-datepicker__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 1.85rem;
  height: 1.85rem;
  padding: 0;
  background-color: transparent;
  border: 0;
  border-radius: var(--dev-radius-sm);
  color: var(--dev-color-text);
  cursor: pointer;
  transition: background-color var(--dev-transition-fast), color var(--dev-transition-fast);
}

.dev-datepicker__nav:hover {
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
}

.dev-datepicker__nav:focus-visible {
  outline: none;
  box-shadow: 0 0 0 0.15rem var(--dev-color-primary-ring);
}

.dev-datepicker__nav:disabled {
  color: var(--dev-color-text-muted);
  cursor: not-allowed;
  background-color: transparent;
}

/* ---- Rejilla ---- */
.dev-datepicker__weekdays,
.dev-datepicker__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.dev-datepicker__weekday {
  padding: 0.25rem 0;
  text-align: center;
  font-size: 0.72rem;
  font-weight: var(--dev-font-weight-bold);
  text-transform: uppercase;
  color: var(--dev-color-text-muted);
}

.dev-datepicker__day {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 2rem;
  padding: 0;
  background-color: transparent;
  border: 0;
  border-radius: var(--dev-radius-sm);
  color: var(--dev-color-text);
  font-family: var(--dev-font-family-base);
  font-size: var(--dev-font-size-sm);
  cursor: pointer;
  transition: background-color var(--dev-transition-fast), color var(--dev-transition-fast);
}

.dev-datepicker__day:hover {
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
}

/* Días del mes anterior/siguiente que rellenan la cuadrícula. */
.dev-datepicker__day--outside {
  color: var(--dev-color-text-muted);
}

/* Hoy: punto inferior, no un borde (mismo criterio que dev-card). */
.dev-datepicker__day--today {
  position: relative;
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-primary-soft-text);
}

.dev-datepicker__day--today::after {
  content: "";
  position: absolute;
  bottom: 0.2rem;
  left: 50%;
  transform: translateX(-50%);
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 50%;
  background-color: currentColor;
}

/* Día bajo el cursor del teclado (flechas). */
.dev-datepicker__day--focus {
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
}

.dev-datepicker__day--selected,
.dev-datepicker__day--selected:hover,
.dev-datepicker__day--selected.dev-datepicker__day--focus {
  background-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
  font-weight: var(--dev-font-weight-medium);
}

.dev-datepicker__day--disabled,
.dev-datepicker__day--disabled:hover {
  color: var(--dev-color-text-muted);
  background-color: transparent;
  opacity: 0.45;
  cursor: not-allowed;
}

/* ---- Pie: acciones rápidas ---- */
.dev-datepicker__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--dev-space-sm);
  margin-top: var(--dev-space-sm);
}


/* ===== components/badges.css ===== */
/* ==========================================================================
   BADGES (BEM)
   Bloque: dev-badge
   Modificadores: dev-badge--primary|secondary|success|danger|warning|info
   Uso: <span class="dev-badge dev-badge--primary">Nuevo</span>
   ========================================================================== */

.dev-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.6rem;
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-medium);
  border-radius: var(--dev-radius-pill);
  line-height: 1.2;
  border: 1px solid transparent;
}

.dev-badge--primary   { background-color: var(--dev-color-primary-light); color: var(--dev-color-primary-soft-text); }
.dev-badge--secondary { background-color: var(--dev-color-secondary-light); color: var(--dev-color-secondary-soft-text); }
.dev-badge--success   { background-color: var(--dev-color-success-light); color: var(--dev-color-success-soft-text); }
.dev-badge--danger    { background-color: var(--dev-color-danger-light); color: var(--dev-color-danger-soft-text); }
.dev-badge--warning   { background-color: var(--dev-color-warning-light); color: var(--dev-color-warning-soft-text); }
.dev-badge--info      { background-color: var(--dev-color-info-light); color: var(--dev-color-info-soft-text); }


/* ===== components/chips.css ===== */
/* ==========================================================================
   CHIPS / TAGS (BEM)
   Bloque: dev-chip
   Etiqueta compacta para filtros seleccionados, categorías o tags de un
   input multivalor. Tono suave (igual criterio que dev-badge/dev-alert).

   Uso:
     <span class="dev-chip">Etiqueta</span>
     <span class="dev-chip dev-chip--primary">Filtro activo</span>
     <span class="dev-chip" data-dev-color="teal-2">Categoría</span>

     <!-- Removible: el botón dispara devChipRemove(this) (ver global.js),
          que quita el chip del DOM y lanza el evento "dev-chip:remove" en el
          contenedor padre (útil para sincronizar un input de filtros). -->
     <span class="dev-chip">
       Activos
       <button type="button" class="dev-chip__remove" aria-label="Quitar"
               onclick="devChipRemove(this)"><i data-lucide="x" class="dev-icon"></i></button>
     </span>

     <!-- Seleccionable (checkbox real oculto, toggle visual al clic) -->
     <label class="dev-chip dev-chip--selectable">
       <input type="checkbox" hidden>
       Filtro
     </label>
   ========================================================================== */

.dev-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.75rem;
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-medium);
  line-height: 1.2;
  border-radius: var(--dev-radius-pill);
  background-color: var(--dev-color-bg-subtle);
  color: var(--dev-color-text);
  border: 1px solid transparent;
  white-space: nowrap;
  transition: background-color var(--dev-transition-fast), color var(--dev-transition-fast);
}

.dev-chip--sm { padding: 0.15rem 0.6rem; font-size: 0.75rem; }
.dev-chip--lg { padding: 0.45rem 0.9rem; font-size: var(--dev-font-size-base); }

/* ---- Colores fijos ---- */
.dev-chip--primary   { background-color: var(--dev-color-primary-light); color: var(--dev-color-primary-soft-text); }
.dev-chip--secondary { background-color: var(--dev-color-secondary-light); color: var(--dev-color-secondary-soft-text); }
.dev-chip--success   { background-color: var(--dev-color-success-light); color: var(--dev-color-success-soft-text); }
.dev-chip--danger    { background-color: var(--dev-color-danger-light); color: var(--dev-color-danger-soft-text); }
.dev-chip--warning   { background-color: var(--dev-color-warning-light); color: var(--dev-color-warning-soft-text); }
.dev-chip--info      { background-color: var(--dev-color-info-light); color: var(--dev-color-info-soft-text); }

/* ---- Botón de eliminar ---- */
.dev-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  padding: 0;
  margin: 0 -0.15rem 0 0.1rem;
  border: 0;
  background: transparent;
  color: inherit;
  opacity: 0.65;
  cursor: pointer;
  border-radius: 50%;
  transition: opacity var(--dev-transition-fast), background-color var(--dev-transition-fast);
}
.dev-chip__remove:hover { opacity: 1; background-color: rgba(0, 0, 0, 0.08); }
[data-theme="dark"] .dev-chip__remove:hover { background-color: rgba(255, 255, 255, 0.12); }
.dev-chip__remove .dev-icon { width: 0.7rem; height: 0.7rem; }

/* ---- Seleccionable (checkbox oculto) ---- */
.dev-chip--selectable {
  cursor: pointer;
  background-color: transparent;
  border-color: var(--dev-color-border);
  user-select: none;
}
.dev-chip--selectable:hover { background-color: var(--dev-color-bg-subtle); }
.dev-chip--selectable:has(input:checked) {
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
  border-color: var(--dev-color-primary);
}
.dev-chip--selectable:has(input:focus-visible) {
  outline: 2px solid var(--dev-color-primary-ring);
  outline-offset: 1px;
}

/* ---- Contenedor de chips (envuelve en varias líneas con espaciado) ---- */
.dev-chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--dev-space-xs);
  align-items: center;
}


/* ===== components/alerts.css ===== */
/* ==========================================================================
   ALERTS (BEM)
   Bloque: dev-alert
   Modificadores: dev-alert--primary|success|danger|warning|info
   Uso: <div class="dev-alert dev-alert--success">Mensaje</div>
   ========================================================================== */

.dev-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--dev-space-sm);
  padding: var(--dev-space-md);
  border: 1px solid transparent;
  border-radius: var(--dev-radius-md);
  font-size: var(--dev-font-size-base);
}

.dev-alert--primary { background-color: var(--dev-color-primary-light); border-color: var(--dev-color-primary); color: var(--dev-color-primary-soft-text); }
.dev-alert--success { background-color: var(--dev-color-success-light); border-color: var(--dev-color-success); color: var(--dev-color-success-soft-text); }
.dev-alert--danger  { background-color: var(--dev-color-danger-light);  border-color: var(--dev-color-danger);  color: var(--dev-color-danger-soft-text); }
.dev-alert--warning { background-color: var(--dev-color-warning-light); border-color: var(--dev-color-warning); color: var(--dev-color-warning-soft-text); }
.dev-alert--info     { background-color: var(--dev-color-info-light);   border-color: var(--dev-color-info);   color: var(--dev-color-info-soft-text); }


/* ===== components/cards.css ===== */
/* ==========================================================================
   CARDS (BEM)
   Bloque: dev-card
   Elementos: dev-card__header, dev-card__title, dev-card__subtitle,
              dev-card__body, dev-card__footer, dev-card__actions,
              dev-card__media
   Uso: <div class="dev-card"><div class="dev-card__header">...</div>
        <div class="dev-card__body">...</div></div>

   ---- REGLA DEL SISTEMA: LA CARD NO LLEVA BORDES ----
   La tarjeta se separa del fondo por SUPERFICIE (color propio) y SOMBRA,
   nunca por una linea. Esto incluye las divisiones internas: el header y el
   footer se distinguen del body con un fondo levemente distinto
   (--dev-card-subtle), no con border-top/border-bottom.

   Por eso, ademas, esta PROHIBIDO el bordeado de un solo lado
   (border-top / border-right / border-bottom / border-left, o una "barra de
   acento" lateral o superior): un borde parcial rompe la simetria del
   contenedor y deja de verse igual entre modo claro y oscuro. El bloque
   final de este archivo lo fuerza con `border: 0 !important` sobre la card
   y todos sus elementos, para que ninguna clase utilitaria de Bootstrap
   (border, border-start, border-primary...) ni un style suelto puedan
   reintroducirlo. Si necesitas destacar una tarjeta, usa un color
   (dev-card--primary, dev-card--solid, data-dev-color) o una elevacion
   (dev-card--raised, dev-card--floating), no un borde.

   ---- Variantes ----
   Tamano (padding + tipografia + radio): --xs --sm (base) --lg --xl
   Ancho:      --w-xs --w-sm --w-md --w-lg --w-xl --w-full
   Color suave:  --primary --secondary --info --success --danger --warning --muted
   Color solido: --solid junto con cualquiera de los anteriores
   Elevacion:  --flat --raised --floating --interactive
   Estructura: --plain (header/footer sin fondo propio)
   Cualquier otro color de la paleta: data-dev-color="teal-2" (ver global.js)
   ========================================================================== */

.dev-card {
  /* Superficie y texto de la tarjeta. Todas las variantes de color solo
     reescriben estas dos variables; lo demas (fondo del header, texto
     atenuado) se recalcula con color-mix a partir de ellas, asi que
     funciona igual en claro, en oscuro y con data-dev-color. */
  --dev-card-bg: var(--dev-color-surface);
  --dev-card-text: var(--dev-color-text);
  --dev-card-accent: var(--dev-card-text);
  --dev-card-subtle: color-mix(in srgb, var(--dev-card-bg) 93%, var(--dev-card-text));
  --dev-card-muted: color-mix(in srgb, var(--dev-card-text) 65%, var(--dev-card-bg));

  /* Escala (la sobreescriben --xs/--sm/--lg/--xl) */
  --dev-card-pad-x: var(--dev-space-lg);
  --dev-card-pad-y: var(--dev-space-md);
  --dev-card-font-size: var(--dev-font-size-base);
  --dev-card-radius: var(--dev-radius-lg);
  --dev-card-shadow: var(--dev-shadow-sm);

  display: flex;
  flex-direction: column;
  background-color: var(--dev-card-bg);
  color: var(--dev-card-text);
  font-size: var(--dev-card-font-size);
  border-radius: var(--dev-card-radius);
  box-shadow: var(--dev-card-shadow);
  overflow: hidden;
  transition: box-shadow var(--dev-transition-base), transform var(--dev-transition-base);
}

/* ---- Elementos ---- */
.dev-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--dev-space-sm);
  padding: var(--dev-card-pad-y) var(--dev-card-pad-x);
  background-color: var(--dev-card-subtle);
  color: var(--dev-card-accent);
  font-weight: var(--dev-font-weight-bold);
}

.dev-card__body {
  padding: var(--dev-card-pad-x);
  flex: 1 1 auto;
}

.dev-card__footer {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  padding: var(--dev-card-pad-y) var(--dev-card-pad-x);
  background-color: var(--dev-card-subtle);
}

.dev-card__title {
  margin: 0 0 var(--dev-space-xs);
  font-size: calc(var(--dev-card-font-size) * 1.05);
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-card-accent);
}

.dev-card__subtitle {
  margin: 0 0 var(--dev-space-sm);
  font-size: calc(var(--dev-card-font-size) * 0.875);
  color: var(--dev-card-muted);
}

/* Zona de botones/iconos alineada a la derecha (en header o footer). */
.dev-card__actions {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  margin-left: auto;
}

/* Imagen a sangre: la card ya tiene overflow:hidden, asi que respeta el radio. */
.dev-card__media {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
}

/* ---- Variante de estructura: header/footer sin fondo propio ---- */
.dev-card--plain .dev-card__header,
.dev-card--plain .dev-card__footer {
  background-color: transparent;
}

/* ---- Tamanos ---- */
.dev-card--xs {
  --dev-card-pad-x: var(--dev-space-sm);
  --dev-card-pad-y: var(--dev-space-xs);
  --dev-card-font-size: 0.78rem;
  --dev-card-radius: var(--dev-radius-sm);
}

.dev-card--sm {
  --dev-card-pad-x: var(--dev-space-md);
  --dev-card-pad-y: var(--dev-space-sm);
  --dev-card-font-size: var(--dev-font-size-sm);
  --dev-card-radius: var(--dev-radius-md);
}

.dev-card--lg {
  --dev-card-pad-x: var(--dev-space-xl);
  --dev-card-pad-y: var(--dev-space-lg);
  --dev-card-font-size: var(--dev-font-size-lg);
}

.dev-card--xl {
  --dev-card-pad-x: calc(var(--dev-space-xl) * 1.3);
  --dev-card-pad-y: var(--dev-space-xl);
  --dev-card-font-size: 1.25rem;
}

/* ---- Anchos estandar (siempre acotados al contenedor) ---- */
.dev-card--w-xs,
.dev-card--w-sm,
.dev-card--w-md,
.dev-card--w-lg,
.dev-card--w-xl {
  max-width: 100%;
}

.dev-card--w-xs { width: 14rem; }
.dev-card--w-sm { width: 18rem; }
.dev-card--w-md { width: 22rem; }
.dev-card--w-lg { width: 28rem; }
.dev-card--w-xl { width: 36rem; }
.dev-card--w-full { width: 100%; }

/* ---- Elevacion ---- */
.dev-card--flat { --dev-card-shadow: none; }
.dev-card--raised { --dev-card-shadow: var(--dev-shadow-md); }
.dev-card--floating { --dev-card-shadow: var(--dev-shadow-lg); }

.dev-card--interactive {
  cursor: pointer;
}

.dev-card--interactive:hover,
.dev-card--interactive:focus-visible {
  box-shadow: var(--dev-shadow-lg);
  transform: translateY(-2px);
  outline: none;
}

/* ---- Color: tono SUAVE (fondo tenue + titulo del color) ----
   Mismo criterio que dev-badge/dev-alert: el fondo usa el token -light
   (que ya se invierte por modo) y el titulo el -soft-text. El texto del
   cuerpo se queda en el color de texto normal para no perder legibilidad
   en parrafos largos. */
.dev-card--primary {
  --dev-card-bg: var(--dev-color-primary-light);
  --dev-card-accent: var(--dev-color-primary-soft-text);
}

.dev-card--secondary {
  --dev-card-bg: var(--dev-color-secondary-light);
  --dev-card-accent: var(--dev-color-secondary-soft-text);
}

.dev-card--info {
  --dev-card-bg: var(--dev-color-info-light);
  --dev-card-accent: var(--dev-color-info-soft-text);
}

.dev-card--success {
  --dev-card-bg: var(--dev-color-success-light);
  --dev-card-accent: var(--dev-color-success-soft-text);
}

.dev-card--danger {
  --dev-card-bg: var(--dev-color-danger-light);
  --dev-card-accent: var(--dev-color-danger-soft-text);
}

.dev-card--warning {
  --dev-card-bg: var(--dev-color-warning-light);
  --dev-card-accent: var(--dev-color-warning-soft-text);
}

/* Neutral: la superficie "hundida" del tema, util para secciones auxiliares. */
.dev-card--muted {
  --dev-card-bg: var(--dev-color-bg-subtle);
  --dev-card-accent: var(--dev-color-text-muted);
}

/* ---- Color: relleno SOLIDO (--solid + un color) ----
   El texto usa el token on-* fijo del color, que no se invierte por modo
   (misma regla que dev-btn solido). */
.dev-card--solid.dev-card--primary {
  --dev-card-bg: var(--dev-color-primary);
  --dev-card-text: var(--dev-color-on-primary);
  --dev-card-accent: var(--dev-color-on-primary);
}

.dev-card--solid.dev-card--secondary {
  --dev-card-bg: var(--dev-color-secondary);
  --dev-card-text: var(--dev-color-on-secondary);
  --dev-card-accent: var(--dev-color-on-secondary);
}

.dev-card--solid.dev-card--info {
  --dev-card-bg: var(--dev-color-info);
  --dev-card-text: var(--dev-color-on-info);
  --dev-card-accent: var(--dev-color-on-info);
}

.dev-card--solid.dev-card--success {
  --dev-card-bg: var(--dev-color-success);
  --dev-card-text: var(--dev-color-on-success);
  --dev-card-accent: var(--dev-color-on-success);
}

.dev-card--solid.dev-card--danger {
  --dev-card-bg: var(--dev-color-danger);
  --dev-card-text: var(--dev-color-on-danger);
  --dev-card-accent: var(--dev-color-on-danger);
}

.dev-card--solid.dev-card--warning {
  --dev-card-bg: var(--dev-color-warning);
  --dev-card-text: var(--dev-color-on-warning);
  --dev-card-accent: var(--dev-color-on-warning);
}

.dev-card--solid.dev-card--muted {
  --dev-card-bg: var(--dev-color-sidebar-bg);
  --dev-card-text: var(--dev-color-on-sidebar);
  --dev-card-accent: var(--dev-color-on-sidebar);
}

/* ==========================================================================
   BLOQUE FINAL — PROHIBICION DE BORDES (ver nota del encabezado)
   Va al final para ganar por orden de cascada, y con !important para que
   tampoco lo reintroduzcan las utilidades de Bootstrap (.border,
   .border-start, .border-primary...) ni un style inline.
   ========================================================================== */
.dev-card,
.dev-card__header,
.dev-card__body,
.dev-card__footer,
.dev-card__title,
.dev-card__subtitle,
.dev-card__actions,
.dev-card__media {
  border: 0 !important;
}


/* ===== components/tables.css ===== */
/* ==========================================================================
   TABLAS (BEM)
   Bloque: dev-table
   Modificadores: dev-table--striped, dev-table--bordered, dev-table--hover
   Uso: <table class="dev-table dev-table--striped"> ... </table>
   ========================================================================== */

.dev-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--dev-font-size-base);
  background-color: var(--dev-color-surface);
}

.dev-table thead th {
  text-align: left;
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text-muted);
  font-size: var(--dev-font-size-sm);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 0.75rem 1rem;
  border-bottom: 2px solid var(--dev-color-border);
}

.dev-table tbody td {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--dev-color-border);
  vertical-align: middle;
}

.dev-table--striped tbody tr:nth-child(odd) {
  background-color: var(--dev-color-bg);
}

.dev-table--hover tbody tr:hover {
  background-color: var(--dev-color-primary-light);
}

.dev-table--bordered th,
.dev-table--bordered td {
  border: 1px solid var(--dev-color-border);
}

/* ==========================================================================
   TABLA AVANZADA (columnas ocultables + detalle colapsable)
   Requiere design-system/js/components/dev-table.js. Se activa con el wrapper
   .dev-table-wrap[data-dev-table]; el detalle por fila con .dev-table--collapsible.
   ========================================================================== */

.dev-table-wrap {
  width: 100%;
  overflow-x: auto;
}

/* ---- Barra de herramientas (buscador + botón "Columnas" + export) ---- */
.dev-table-toolbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--dev-space-sm);
  margin-bottom: var(--dev-space-sm);
}

/* Agrupa exportar/columnas para poder moverlos tal cual al pie con
   data-dev-toolbar="footer" (ver .dev-table-footer__left). */
.dev-table-toolbar__actions {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  margin-left: auto;
}

/* ---- Encabezado en tres filas (data-dev-toolbar="split") ----
   Fila 1: contador total de registros.
   Fila 2: export/columnas.
   Fila 3: selector "Mostrar N registros" (izq.) + buscador (der.). */
.dev-table-head {
  display: flex;
  flex-direction: column;
  gap: var(--dev-space-sm);
  margin-bottom: var(--dev-space-md);
}

.dev-table-head__stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--dev-space-sm);
}

/* Dentro del stack los botones se alinean a la izquierda (sin el auto margin
   que los empuja a la derecha en la barra superior clásica). */
.dev-table-head__stack .dev-table-toolbar__actions {
  margin-left: 0;
}

.dev-table-head__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--dev-space-md);
  margin-top: var(--dev-space-xs);
}

/* El selector "Mostrar N registros" respira un poco más dentro del encabezado. */
.dev-table-head__bottom .dev-table-footer__size {
  gap: var(--dev-space-md);
  font-size: var(--dev-font-size-base);
}

/* El selector ya viene mejorado por dev-select.js: el ancho lo manda el wrap. */
.dev-table-head__bottom .dev-select-wrap {
  min-width: 5.5rem;
}

/* ---- Contador total de registros: solo texto, sin caja ni icono ---- */
.dev-table-count {
  font-size: var(--dev-font-size-lg);
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text);
  line-height: 1.2;
}

/* ---- Botones de exportar: color de marca por formato ---- */
.dev-table-export--excel .dev-icon {
  color: #1d6f42;
}

.dev-table-export--pdf .dev-icon {
  color: #c0392b;
}

.dev-table-export--excel:hover {
  border-color: #1d6f42;
  color: #1d6f42;
}

.dev-table-export--pdf:hover {
  border-color: #c0392b;
  color: #c0392b;
}

/* ---- Buscador: icono + campo en UN SOLO contenedor (el borde lo pinta el
   wrapper y el input va transparente, para que no se vean dos cajas) ---- */
.dev-table-search {
  display: flex;
  align-items: center;
  max-width: 20rem;
  width: 100%;
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  transition: border-color var(--dev-transition-fast), box-shadow var(--dev-transition-fast);
}

.dev-table-search:focus-within {
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light);
}

.dev-table-search__addon {
  display: flex;
  align-items: center;
  padding-left: 0.65rem;
  color: var(--dev-color-text-muted);
}

.dev-table-search__input,
.dev-table-search__input:focus {
  width: 100%;
  background-color: transparent;
  border: none;
  border-radius: inherit;
  box-shadow: none;
  outline: none;
}

/* Oculta la "x" nativa de input[type=search] (UI del navegador). */
.dev-table-search__input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

/* ---- Encabezados ordenables ---- */
.dev-table__th--sortable {
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}

.dev-table__th--sortable:hover {
  color: var(--dev-color-text);
}

.dev-table__th--sortable:focus-visible {
  outline: 2px solid var(--dev-color-primary);
  outline-offset: -2px;
}

.dev-table__sort-icon {
  display: inline-flex;
  vertical-align: -0.3em;
  margin-left: 0.3rem;
  color: var(--dev-color-text-muted);
}

/* ---- Columnas redimensionables (arrastrar el borde derecho del <th>) ---- */
.dev-table--resizable thead th {
  position: relative;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dev-table__resizer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 6px;
  cursor: col-resize;
  touch-action: none;
  z-index: 5;
}

.dev-table__resizer::after {
  content: "";
  position: absolute;
  top: 18%;
  bottom: 18%;
  left: 2px;
  width: 2px;
  border-radius: 2px;
  background-color: var(--dev-color-border);
  transition: background-color var(--dev-transition-fast);
}

.dev-table__resizer:hover::after,
.dev-table--resizing .dev-table__resizer::after {
  background-color: var(--dev-color-primary);
}

/* Mientras se arrastra, evita selección de texto en toda la tabla. */
.dev-table--resizing,
.dev-table--resizing * {
  cursor: col-resize !important;
  -webkit-user-select: none;
  user-select: none;
}

.dev-table-cols {
  position: relative;
}

.dev-table-cols__menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  min-width: 180px;
  display: none;
  flex-direction: column;
  padding: var(--dev-space-xs);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  box-shadow: var(--dev-shadow-dropdown);
}

.dev-table-cols__menu--open {
  display: flex;
}

.dev-table-cols__option {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  padding: 0.4rem 0.55rem;
  border-radius: var(--dev-radius-sm);
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text);
  cursor: pointer;
}

.dev-table-cols__option:hover {
  background-color: var(--dev-color-bg);
}

.dev-table-cols__option input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--dev-color-primary);
  cursor: pointer;
}

/* Variante como <button> (menú "Ajustar anchos"): mismo look que las
   opciones con checkbox, pero sin estilos nativos de botón. */
.dev-table-cols__option--btn {
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  font: inherit;
}

/* ---- Columna de selección (checkboxes, data-dev-selectable) ---- */
.dev-table__select-cell {
  width: 1%;
  white-space: nowrap;
  text-align: center;
}

.dev-table__select-cell input[type="checkbox"] {
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--dev-color-primary);
  cursor: pointer;
}

.dev-table__row--selected > td {
  background-color: var(--dev-color-primary-light);
}

/* ---- Barra de acciones en lote (aparece al seleccionar >=1 fila) ---- */
.dev-table-bulkbar {
  display: none;
  align-items: center;
  gap: var(--dev-space-sm);
  padding: 0.5rem 0.75rem;
  margin-bottom: var(--dev-space-sm);
  border-radius: var(--dev-radius-md);
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
}

.dev-table-bulkbar--visible {
  display: flex;
}

.dev-table-bulkbar__count {
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-bold);
  white-space: nowrap;
}

.dev-table-bulkbar__actions {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  flex-wrap: wrap;
}

.dev-table-bulkbar__clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  margin-left: auto;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  cursor: pointer;
  flex-shrink: 0;
}
.dev-table-bulkbar__clear:hover { background-color: rgba(0, 0, 0, 0.08); }
[data-theme="dark"] .dev-table-bulkbar__clear:hover { background-color: rgba(255, 255, 255, 0.12); }

/* ---- Columna de acción "Ver detalles" (siempre la primera) ---- */
.dev-table__action-cell {
  width: 1%;
  white-space: nowrap;
  text-align: center;
}

.dev-table__action {
  color: var(--dev-color-text-muted);
}
.dev-table__action:hover {
  color: var(--dev-color-primary);
  background-color: var(--dev-color-primary-light);
}

/* ---- Columna y botón de expansión del detalle ---- */
.dev-table__toggle-cell {
  width: 1%;
  white-space: nowrap;
  text-align: center;
}

.dev-table__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  padding: 0;
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-sm);
  background-color: var(--dev-color-surface);
  color: var(--dev-color-text-muted);
  cursor: pointer;
  transition: transform var(--dev-transition-fast), color var(--dev-transition-fast),
              background-color var(--dev-transition-fast), border-color var(--dev-transition-fast);
}

.dev-table__toggle:hover {
  color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
}

.dev-table__row--open .dev-table__toggle {
  transform: rotate(90deg);
  color: var(--dev-color-on-primary);
  background-color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
}

/* ---- Fila de detalle ---- */
.dev-table__detail-row > td {
  padding: 0;
  background-color: var(--dev-color-bg-subtle);
  border-bottom: 1px solid var(--dev-color-border);
}

.dev-table__detail {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--dev-space-sm) var(--dev-space-lg);
  padding: var(--dev-space-md) var(--dev-space-lg);
}

.dev-table__detail-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.dev-table__detail-label {
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.dev-table__detail-value {
  color: var(--dev-color-text);
}

.dev-table__detail-empty {
  color: var(--dev-color-text-muted);
  font-size: var(--dev-font-size-sm);
}

/* ---- Encabezados agrupados: fila extra en el <thead> que agrupa varias
   columnas relacionadas (p.ej. varias columnas por empresa) bajo un mismo
   rótulo. Ver dev-table.js para el marcado esperado. ---- */
.dev-table__group-row th {
  text-align: center;
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text);
  text-transform: none;
  letter-spacing: normal;
  padding: 0.5rem 1rem;
  border-bottom: 1px solid var(--dev-color-border);
  border-left: 1px solid var(--dev-color-border);
}

.dev-table__group-row th:first-child {
  border-left: none;
}

/* Bandas de color opcionales: agregar la misma modificadora
   (dev-table__group--1 ... --6) al <th> del grupo y a los <th>/<td> de las
   columnas que pertenecen a ese grupo. */
.dev-table__group--1 { background-color: var(--dev-color-primary-light); }
.dev-table__group--2 { background-color: var(--dev-color-info-light); }
.dev-table__group--3 { background-color: var(--dev-color-success-light); }
.dev-table__group--4 { background-color: var(--dev-color-warning-light); }
.dev-table__group--5 { background-color: var(--dev-color-danger-light); }
.dev-table__group--6 { background-color: var(--dev-color-secondary-light); }

.dev-table__group-row th.dev-table__group--1 { border-bottom: 2px solid var(--dev-color-primary); }
.dev-table__group-row th.dev-table__group--2 { border-bottom: 2px solid var(--dev-color-info); }
.dev-table__group-row th.dev-table__group--3 { border-bottom: 2px solid var(--dev-color-success); }
.dev-table__group-row th.dev-table__group--4 { border-bottom: 2px solid var(--dev-color-warning); }
.dev-table__group-row th.dev-table__group--5 { border-bottom: 2px solid var(--dev-color-danger); }
.dev-table__group-row th.dev-table__group--6 { border-bottom: 2px solid var(--dev-color-secondary); }

/* ---- Auto-colapso responsivo: las columnas toman su ancho natural para
   poder medir el desbordamiento; JS oculta las que no caben. ---- */
.dev-table--responsive th,
.dev-table--responsive td {
  white-space: nowrap;
}

/* ---- Pie: selector de tamaño + contador + paginación ---- */
.dev-table-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--dev-space-md);
  margin-top: var(--dev-space-md);
}

.dev-table-footer__left {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--dev-space-md);
}

.dev-table-footer__size {
  display: inline-flex;
  align-items: center;
  gap: var(--dev-space-sm);
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
  margin: 0;
}

.dev-table-footer__select {
  width: auto;
  min-width: 4.5rem;
}

.dev-table-footer__info {
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
}

.dev-table-footer__pager {
  margin: 0;
}


/* ===== components/button-group.css ===== */
/* ==========================================================================
   BUTTON GROUP (BEM)
   Bloque: dev-btn-group
   Uso: <div class="dev-btn-group"><button class="dev-btn dev-btn--outline-secondary">...
   Sin dependencia de JS de Bootstrap — es solo agrupación visual de dev-btn.
   ========================================================================== */

.dev-btn-group {
  display: inline-flex;
}

.dev-btn-group > .dev-btn {
  border-radius: 0;
}

.dev-btn-group > .dev-btn:not(:first-child) {
  margin-left: -1px;
}

.dev-btn-group > .dev-btn:first-child {
  border-top-left-radius: var(--dev-radius-md);
  border-bottom-left-radius: var(--dev-radius-md);
}

.dev-btn-group > .dev-btn:last-child {
  border-top-right-radius: var(--dev-radius-md);
  border-bottom-right-radius: var(--dev-radius-md);
}

.dev-btn-group > .dev-btn:hover,
.dev-btn-group > .dev-btn:focus {
  z-index: 1;
}

.dev-btn-group--vertical {
  display: inline-flex;
  flex-direction: column;
}

.dev-btn-group--vertical > .dev-btn:not(:first-child) {
  margin-left: 0;
  margin-top: -1px;
}

.dev-btn-group--vertical > .dev-btn:first-child {
  border-radius: var(--dev-radius-md) var(--dev-radius-md) 0 0;
}

.dev-btn-group--vertical > .dev-btn:last-child {
  border-radius: 0 0 var(--dev-radius-md) var(--dev-radius-md);
}


/* ===== components/progress.css ===== */
/* ==========================================================================
   PROGRESS (BEM)
   Bloque: dev-progress
   Elemento: dev-progress__bar (modificadores --success|--danger|--warning|--striped)
   Uso: <div class="dev-progress"><div class="dev-progress__bar" style="width:60%"></div></div>
   ========================================================================== */

.dev-progress {
  display: flex;
  height: 0.85rem;
  overflow: hidden;
  background-color: var(--dev-color-surface-raised);
  border-radius: var(--dev-radius-pill);
}

.dev-progress__bar {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--dev-color-on-primary);
  font-size: 0.65rem;
  background-color: var(--dev-color-primary);
  transition: width var(--dev-transition-base);
  white-space: nowrap;
}

.dev-progress__bar--success { background-color: var(--dev-color-success); }
.dev-progress__bar--danger  { background-color: var(--dev-color-danger); }
.dev-progress__bar--warning { background-color: var(--dev-color-warning); color: var(--dev-color-warning-text); }

.dev-progress__bar--striped {
  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%,
    transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
  background-size: 1rem 1rem;
}


/* ===== components/spinners.css ===== */
/* ==========================================================================
   SPINNERS (BEM)
   Bloque: dev-spinner
   Modificadores: dev-spinner--grow, dev-spinner--sm
   Uso: <span class="dev-spinner"></span>
   ========================================================================== */

.dev-spinner {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  vertical-align: -0.125em;
  border: 0.25em solid var(--dev-color-primary-light);
  border-right-color: var(--dev-color-primary);
  border-radius: 50%;
  animation: dev-spinner-rotate 0.75s linear infinite;
}

.dev-spinner--sm {
  width: 1rem;
  height: 1rem;
  border-width: 0.2em;
}

.dev-spinner--grow {
  border: 0;
  background-color: var(--dev-color-primary);
  border-radius: 50%;
  opacity: 0;
  animation: dev-spinner-grow 0.75s linear infinite;
}

@keyframes dev-spinner-rotate {
  to { transform: rotate(360deg); }
}

@keyframes dev-spinner-grow {
  0% { transform: scale(0); opacity: 0; }
  50% { opacity: 1; }
  100% { transform: scale(1); opacity: 0; }
}


/* ===== components/pagination.css ===== */
/* ==========================================================================
   PAGINATION (BEM)
   Bloque: dev-pagination
   Elementos: dev-pagination__item, dev-pagination__link
   Modificadores en el item: --active, --disabled
   ========================================================================== */

.dev-pagination {
  display: flex;
  list-style: none;
  padding-left: 0;
  margin: 0;
  gap: 0.25rem;
}

.dev-pagination__link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 2.25rem;
  height: 2.25rem;
  padding: 0 0.6rem;
  color: var(--dev-color-primary);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  text-decoration: none;
  font-size: var(--dev-font-size-sm);
  transition: background-color var(--dev-transition-fast), color var(--dev-transition-fast);
}

.dev-pagination__link:hover {
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-hover);
}

.dev-pagination__item--active .dev-pagination__link {
  background-color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
}

.dev-pagination__item--disabled .dev-pagination__link {
  color: var(--dev-color-text-muted);
  pointer-events: none;
  background-color: var(--dev-color-bg);
}


/* ===== components/list-group.css ===== */
/* ==========================================================================
   LIST GROUP (BEM)
   Bloque: dev-list-group
   Elemento: dev-list-group__item (modificador --action para hover/click,
   --active, --disabled)
   ========================================================================== */

.dev-list-group {
  display: flex;
  flex-direction: column;
  padding-left: 0;
  margin: 0;
  border-radius: var(--dev-radius-md);
  overflow: hidden;
  border: 1px solid var(--dev-color-border);
}

.dev-list-group__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--dev-space-sm);
  padding: 0.75rem 1rem;
  background-color: var(--dev-color-surface);
  color: var(--dev-color-text);
  text-decoration: none;
  border-bottom: 1px solid var(--dev-color-border);
}

.dev-list-group__item:last-child {
  border-bottom: none;
}

.dev-list-group__item--action {
  cursor: pointer;
  transition: background-color var(--dev-transition-fast);
}

.dev-list-group__item--action:hover {
  background-color: var(--dev-color-bg);
}

.dev-list-group__item--active {
  background-color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
}

.dev-list-group__item--disabled {
  color: var(--dev-color-text-muted);
  pointer-events: none;
  background-color: var(--dev-color-bg);
}


/* ===== components/modal.css ===== */
/* ==========================================================================
   MODAL
   Se usa el modal nativo de Bootstrap 5 (.modal, .modal-dialog, .modal-content,
   data-bs-toggle="modal") porque su JS controla foco, backdrop y animaciones;
   renombrarlo a BEM rompería ese contrato. Esta hoja solo tematiza las
   piezas visuales con los tokens dev-* (claro y oscuro).

   Complemento opcional: dev-modal__header / dev-modal__body / dev-modal__footer
   se pueden usar DENTRO de .modal-content para espaciados consistentes,
   pero .modal-header/.modal-body/.modal-footer nativos también funcionan.
   ========================================================================== */

.modal-content {
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-lg);
  box-shadow: var(--dev-shadow-lg);
}

.modal-header,
.modal-footer {
  border-color: var(--dev-color-border);
}

.modal-title {
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text);
}

.modal-body {
  color: var(--dev-color-text);
}

.dev-modal__header,
.dev-modal__footer {
  display: flex;
  align-items: center;
  padding: 1rem 1.25rem;
  border-color: var(--dev-color-border);
}

.dev-modal__header { border-bottom: 1px solid var(--dev-color-border); justify-content: space-between; }
.dev-modal__footer { border-top: 1px solid var(--dev-color-border); justify-content: flex-end; gap: var(--dev-space-sm); }

.dev-modal__title {
  font-weight: var(--dev-font-weight-bold);
  margin: 0;
}

.dev-modal__body {
  padding: 1.25rem;
  color: var(--dev-color-text);
}


/* ===== components/tabs.css ===== */
/* ==========================================================================
   NAVS & TABS
   Se usan los componentes nativos de Bootstrap 5 (.nav-tabs, .nav-pills,
   .tab-content, .tab-pane, data-bs-toggle="tab") porque su JS controla el
   cambio de panel activo. Esta hoja tematiza ambas variantes con los
   tokens dev-* (claro y oscuro).
   ========================================================================== */

.nav-tabs {
  border-bottom-color: var(--dev-color-border);
}

.nav-tabs .nav-link {
  color: var(--dev-color-text-muted);
  border: 1px solid transparent;
  border-top-left-radius: var(--dev-radius-md);
  border-top-right-radius: var(--dev-radius-md);
}

.nav-tabs .nav-link:hover {
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}

.nav-tabs .nav-link.active {
  color: var(--dev-color-primary);
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border) var(--dev-color-border) var(--dev-color-surface);
}

.nav-pills .nav-link {
  color: var(--dev-color-text-muted);
  border-radius: var(--dev-radius-pill);
}

.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
  background-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
}

.tab-content {
  padding-top: var(--dev-space-md);
  color: var(--dev-color-text);
}


/* ===== components/steps.css ===== */
/* ==========================================================================
   STEPS / PASOS (BEM)
   Bloque: dev-steps
   Uso: stepper para procesos por fases (wizards, checkout, formularios en
   varios pasos, seguimiento de estado). Numeración automática vía CSS
   counters — solo se agregan los elementos, sin escribir el número a mano.

   <ol class="dev-steps">
     <li class="dev-steps__item dev-steps__item--completed">
       <span class="dev-steps__marker"></span>
       <span class="dev-steps__content">
         <span class="dev-steps__title">Datos</span>
         <span class="dev-steps__description">Información básica</span>
       </span>
     </li>
     ...
   </ol>

   Elementos:
     dev-steps__item         cada paso (bloque = <ol>, item = <li>)
     dev-steps__marker       círculo con el número (o check si --completed)
     dev-steps__marker-icon  ícono opcional dentro del marcador (dev-icon)
     dev-steps__content      envoltorio de título + descripción
     dev-steps__title
     dev-steps__description

   Modificadores de estado (en dev-steps__item):
     --active     paso actual (aro + texto de acento)
     --completed  paso ya hecho (relleno de acento + check, oculta el número)
     --error      paso con error (color danger)
     --disabled   paso no disponible (atenuado, sin puntero)

   Orientación (en dev-steps):
     (sin modificador)            horizontal (por defecto)
     dev-steps--vertical          vertical, orden normal (1→2→3→4→5 de arriba a abajo)
     dev-steps--vertical-reverse  vertical, orden invertido (5→4→3→2→1 de arriba a abajo)
     * el orden de los elementos en el HTML NO cambia, solo se voltea la
       presentación (útil para líneas de tiempo "más reciente primero").

   Tamaños:     dev-steps--sm | (base) | dev-steps--lg
   Animaciones: dev-steps--anim-fade | dev-steps--anim-pulse | dev-steps--anim-progress
   Color:       data-dev-color="teal-2" en el bloque .dev-steps (ver global.js,
                función devApplyAutoContrast) — acepta color base/status/paleta
                extendida o hex, igual que dev-btn/dev-badge/etc.
   ========================================================================== */

.dev-steps {
  --dev-steps-accent: var(--dev-color-primary);
  --dev-steps-marker-size: 2rem;
  --dev-steps-gap: var(--dev-space-lg);

  display: flex;
  align-items: flex-start;
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: dev-steps-counter;
}

/* ---- Item base (horizontal por defecto) ---- */
.dev-steps__item {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--dev-space-sm);
  text-align: center;
  padding-inline: var(--dev-space-sm);
  counter-increment: dev-steps-counter;
}
.dev-steps__item:first-child { padding-inline-start: 0; }
.dev-steps__item:last-child { padding-inline-end: 0; }

/* Conector horizontal: línea entre el marcador de este paso y el siguiente */
.dev-steps__item:not(:last-child)::after {
  content: "";
  position: absolute;
  top: calc(var(--dev-steps-marker-size) / 2);
  left: calc(50% + (var(--dev-steps-marker-size) / 2));
  width: calc(100% - var(--dev-steps-marker-size));
  height: 2px;
  background-color: var(--dev-color-border);
  transition: background-color var(--dev-transition-base);
  z-index: 0;
}
.dev-steps__item--completed:not(:last-child)::after { background-color: var(--dev-steps-accent); }
.dev-steps__item--error:not(:last-child)::after { background-color: var(--dev-color-danger); }

/* ---- Marcador ---- */
.dev-steps__marker {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--dev-steps-marker-size);
  height: var(--dev-steps-marker-size);
  border-radius: 50%;
  background-color: var(--dev-color-surface);
  border: 2px solid var(--dev-color-border);
  color: var(--dev-color-text-muted);
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-bold);
  line-height: 1;
  transition: background-color var(--dev-transition-base), border-color var(--dev-transition-base),
    color var(--dev-transition-base), box-shadow var(--dev-transition-base);
}
.dev-steps__marker::before { content: counter(dev-steps-counter); }
/* Si el marcador trae un ícono propio (dev-steps__marker-icon), no mostrar el número */
.dev-steps__marker:has(.dev-steps__marker-icon)::before { content: none; }

.dev-steps__marker-icon { width: 55%; height: 55%; }

/* Paso actual: aro de acento */
.dev-steps__item--active .dev-steps__marker {
  border-color: var(--dev-steps-accent);
  color: var(--dev-steps-accent);
  background-color: color-mix(in srgb, var(--dev-steps-accent) 12%, var(--dev-color-surface));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--dev-steps-accent) 18%, transparent);
}
.dev-steps__item--active .dev-steps__title {
  color: var(--dev-steps-accent);
  font-weight: var(--dev-font-weight-bold);
}

/* Paso completado: relleno de acento + check en vez del número */
.dev-steps__item--completed .dev-steps__marker {
  background-color: var(--dev-steps-accent);
  border-color: var(--dev-steps-accent);
  color: var(--dev-color-on-primary);
}
.dev-steps__item--completed .dev-steps__marker::before { content: none; }
.dev-steps__item--completed .dev-steps__marker::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.45em;
  height: 0.85em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translate(-50%, -65%) rotate(45deg);
}

/* Paso con error */
.dev-steps__item--error .dev-steps__marker {
  border-color: var(--dev-color-danger);
  color: var(--dev-color-danger);
  background-color: color-mix(in srgb, var(--dev-color-danger) 12%, var(--dev-color-surface));
}

/* Paso deshabilitado */
.dev-steps__item--disabled { opacity: 0.5; pointer-events: none; }

/* ---- Contenido ---- */
.dev-steps__content { display: flex; flex-direction: column; gap: 0.15rem; max-width: 12rem; }
.dev-steps__title {
  font-size: var(--dev-font-size-base);
  font-weight: var(--dev-font-weight-medium);
  color: var(--dev-color-text);
  transition: color var(--dev-transition-base);
}
.dev-steps__description {
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
}

/* ==========================================================================
   ORIENTACIÓN VERTICAL
   ========================================================================== */
.dev-steps--vertical,
.dev-steps--vertical-reverse {
  flex-direction: column;
  align-items: stretch;
  width: 100%;
}
.dev-steps--vertical-reverse { flex-direction: column-reverse; }

.dev-steps--vertical .dev-steps__item,
.dev-steps--vertical-reverse .dev-steps__item {
  flex-direction: row;
  align-items: flex-start;
  text-align: left;
  padding-inline: 0;
  padding-top: var(--dev-steps-gap);
}
.dev-steps--vertical .dev-steps__content,
.dev-steps--vertical-reverse .dev-steps__content {
  max-width: none;
  padding-top: 0.15rem;
}

/* Orden normal (1→5 de arriba a abajo): el primero no lleva línea/espacio arriba */
.dev-steps--vertical .dev-steps__item:first-child { padding-top: 0; }
/* Orden invertido (5→4→3→2→1 de arriba a abajo, mismo HTML 1→5): el que
   queda visualmente arriba de todos es el ÚLTIMO elemento del HTML. */
.dev-steps--vertical-reverse .dev-steps__item:last-child { padding-top: 0; }

/* El conector horizontal no aplica en vertical */
.dev-steps--vertical .dev-steps__item::after,
.dev-steps--vertical-reverse .dev-steps__item::after {
  content: none;
}

/* Conector vertical: línea arriba del marcador, dentro del padding-top */
.dev-steps--vertical .dev-steps__item:not(:first-child)::before,
.dev-steps--vertical-reverse .dev-steps__item:not(:last-child)::before {
  content: "";
  position: absolute;
  top: 0;
  left: calc(var(--dev-steps-marker-size) / 2);
  transform: translateX(-50%);
  width: 2px;
  height: var(--dev-steps-gap);
  background-color: var(--dev-color-border);
  transition: background-color var(--dev-transition-base);
}

/* Colorea el tramo si el paso "anterior" visualmente (arriba) fue completado.
   El segundo caso usa :has() — soporte amplio en navegadores actuales; sin
   soporte, la línea queda en color neutro (degradación sin romper el layout). */
.dev-steps--vertical .dev-steps__item--completed + .dev-steps__item::before {
  background-color: var(--dev-steps-accent);
}
.dev-steps--vertical-reverse .dev-steps__item:has(+ .dev-steps__item--completed)::before {
  background-color: var(--dev-steps-accent);
}

.dev-steps--vertical .dev-steps__marker,
.dev-steps--vertical-reverse .dev-steps__marker {
  margin-right: var(--dev-space-md);
}

/* ==========================================================================
   TAMAÑOS
   ========================================================================== */
.dev-steps--sm { --dev-steps-marker-size: 1.5rem; --dev-steps-gap: var(--dev-space-md); }
.dev-steps--sm .dev-steps__marker { font-size: 0.7rem; }
.dev-steps--sm .dev-steps__title { font-size: var(--dev-font-size-sm); }
.dev-steps--sm .dev-steps__description { font-size: 0.75rem; }

.dev-steps--lg { --dev-steps-marker-size: 2.75rem; --dev-steps-gap: var(--dev-space-xl); }
.dev-steps--lg .dev-steps__marker { font-size: var(--dev-font-size-base); }
.dev-steps--lg .dev-steps__title { font-size: var(--dev-font-size-lg); }

/* ==========================================================================
   ANIMACIONES
   ========================================================================== */

/* --anim-fade: cada paso entra con fundido + deslizado, en cascada.
   Arranca en pausa (congelado en el fotograma inicial gracias a "backwards")
   y solo corre cuando el bloque recibe la clase --in-view — la agrega
   design-system/js/global.js con un IntersectionObserver la primera vez que
   el elemento entra en el viewport. Sin esto, la animación correría una sola
   vez al cargar la página y ya habría terminado para cuando el usuario haga
   scroll hasta esta sección: se vería estático, como si "no animara". */
.dev-steps--anim-fade .dev-steps__item {
  animation: dev-steps-fade-in-y 420ms ease-out backwards paused;
}
.dev-steps--anim-fade.dev-steps--in-view .dev-steps__item {
  animation-play-state: running;
}
.dev-steps--anim-fade.dev-steps--vertical .dev-steps__item,
.dev-steps--anim-fade.dev-steps--vertical-reverse .dev-steps__item {
  animation-name: dev-steps-fade-in-x;
}
.dev-steps--anim-fade .dev-steps__item:nth-child(1) { animation-delay: 0ms; }
.dev-steps--anim-fade .dev-steps__item:nth-child(2) { animation-delay: 70ms; }
.dev-steps--anim-fade .dev-steps__item:nth-child(3) { animation-delay: 140ms; }
.dev-steps--anim-fade .dev-steps__item:nth-child(4) { animation-delay: 210ms; }
.dev-steps--anim-fade .dev-steps__item:nth-child(5) { animation-delay: 280ms; }
.dev-steps--anim-fade .dev-steps__item:nth-child(6) { animation-delay: 350ms; }
.dev-steps--anim-fade .dev-steps__item:nth-child(n+7) { animation-delay: 420ms; }

@keyframes dev-steps-fade-in-y {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
@keyframes dev-steps-fade-in-x {
  from { opacity: 0; transform: translateX(-8px); }
  to { opacity: 1; transform: none; }
}

/* --anim-pulse: el paso activo late (anillo de acento) para llamar la atención */
.dev-steps--anim-pulse .dev-steps__item--active .dev-steps__marker {
  animation: dev-steps-pulse 1.8s ease-out infinite;
}
@keyframes dev-steps-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--dev-steps-accent) 45%, transparent); }
  70%  { box-shadow: 0 0 0 10px color-mix(in srgb, var(--dev-steps-accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--dev-steps-accent) 0%, transparent); }
}

/* --anim-progress: el conector se "rellena" de acento de forma animada.
   Controla el avance con la variable --dev-steps-fill (0% a 100%) en línea:
   <li class="dev-steps__item" style="--dev-steps-fill:65%">...</li>
   Es una transition (no @keyframes): solo se anima cuando --dev-steps-fill
   CAMBIA de valor, no en la carga inicial de la página. global.js detecta
   el valor inicial de cada item, lo pone en 0% y lo restaura cuando el
   bloque entra en el viewport, para que el relleno sí se vea animar. Si
   luego cambias --dev-steps-fill por tu cuenta (ej. avance de un wizard),
   la transition ya definida aquí se dispara sola, sin JS adicional. */
.dev-steps--anim-progress .dev-steps__item::after {
  background-image: linear-gradient(var(--dev-steps-accent), var(--dev-steps-accent));
  background-repeat: no-repeat;
  background-color: var(--dev-color-border);
  background-size: var(--dev-steps-fill, 0%) 100%;
  transition: background-size 700ms ease;
}
.dev-steps--anim-progress.dev-steps--vertical .dev-steps__item::before,
.dev-steps--anim-progress.dev-steps--vertical-reverse .dev-steps__item::before {
  background-image: linear-gradient(var(--dev-steps-accent), var(--dev-steps-accent));
  background-repeat: no-repeat;
  background-color: var(--dev-color-border);
  background-size: 100% var(--dev-steps-fill, 0%);
  transition: background-size 700ms ease;
}


/* ===== components/timeline.css ===== */
/* ==========================================================================
   TIMELINE (BEM)
   Bloque: dev-timeline
   Uso: bitácora de eventos / actividad tipo GitHub (historial de commits,
   línea de tiempo de un issue/PR, auditoría, seguimiento de un pedido).
   A diferencia de dev-steps (proceso con avance 1→N y numeración), aquí
   cada item es un evento independiente: puede traer hora, descripción,
   avatar y tags libres, sin implicar progreso ni pasos "completados".

   <ol class="dev-timeline">
     <li class="dev-timeline__item dev-timeline__item--success">
       <span class="dev-timeline__marker"></span>
       <div class="dev-timeline__content">
         <div class="dev-timeline__header">
           <span class="dev-timeline__title">Solicitud aprobada</span>
           <span class="dev-timeline__time">Hoy, 10:05 am</span>
         </div>
         <p class="dev-timeline__description">Aprobada por Recursos Humanos.</p>
         <div class="dev-timeline__meta">
           <span class="dev-badge dev-badge--success">Aprobada</span>
         </div>
       </div>
     </li>
     ...
   </ol>

   Elementos:
     dev-timeline__item          cada evento (bloque = <ol>, item = <li>)
     dev-timeline__marker        punto/círculo sobre la línea conectora
     dev-timeline__marker-icon   ícono opcional dentro del marcador (dev-icon,
                                  agranda el marcador automáticamente vía :has())
     dev-timeline__marker--avatar  marcador como avatar (imagen o iniciales)
     dev-timeline__content       envoltorio del contenido del evento
     dev-timeline__header        fila título + hora
     dev-timeline__title
     dev-timeline__time
     dev-timeline__description
     dev-timeline__meta          fila de tags/badges/chips libres
     dev-timeline__card          envoltorio opcional tipo "burbuja" (fondo +
                                  borde), para comentarios o detalle largo

   Modificadores de color (en dev-timeline__item), afectan el marcador:
     --primary | --success | --danger | --warning | --info
     (sin modificador: neutro/gris, igual que un evento "informativo")
     --current   evento actual / más reciente — marcador con aro pulsante
                 y título en negritas (ideal para resaltar el HEAD/último
                 estado, como en el historial de commits de GitHub)

   Orientación (en dev-timeline):
     (sin modificador)     vertical, de arriba a abajo (orden del HTML)
     dev-timeline--reverse vertical, presentación invertida (más reciente
                            arriba), mismo truco que dev-steps--vertical-reverse:
                            el HTML no cambia de orden, solo se voltea la vista.
     dev-timeline--horizontal  cadena horizontal (historial de commits estilo
                                git log), contenido apilado bajo cada marcador.

   Tamaños:     dev-timeline--sm | (base) | dev-timeline--lg
   Animaciones: dev-timeline--anim-fade | dev-timeline--anim-pulse | dev-timeline--anim-line
   Color:       data-dev-color="teal-2" en el bloque .dev-timeline (acento
                general) o en un .dev-timeline__item individual (acento solo
                de ese evento) — ver global.js, función devApplyAutoContrast.
   ========================================================================== */

.dev-timeline {
  --dev-timeline-marker-size: 0.85rem;
  --dev-timeline-gap: var(--dev-space-lg);
  --dev-timeline-accent: var(--dev-color-primary);

  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* ---- Item base (vertical por defecto) ---- */
.dev-timeline__item {
  --dev-timeline-item-accent: var(--dev-color-text-muted);

  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--dev-space-md);
  padding-top: var(--dev-timeline-gap);
}
.dev-timeline__item:first-child { padding-top: 0; }

/* Conector vertical: línea arriba del marcador, dentro del padding-top */
.dev-timeline__item:not(:first-child)::before {
  content: "";
  position: absolute;
  top: 0;
  left: calc(var(--dev-timeline-marker-size) / 2);
  transform: translateX(-50%);
  width: 2px;
  height: var(--dev-timeline-gap);
  background-color: var(--dev-color-border);
  transition: background-color var(--dev-transition-base);
}

/* Color de marcador por modificador de estado */
.dev-timeline__item--primary { --dev-timeline-item-accent: var(--dev-color-primary); }
.dev-timeline__item--success { --dev-timeline-item-accent: var(--dev-color-success); }
.dev-timeline__item--danger  { --dev-timeline-item-accent: var(--dev-color-danger); }
.dev-timeline__item--warning { --dev-timeline-item-accent: var(--dev-color-warning); }
.dev-timeline__item--info    { --dev-timeline-item-accent: var(--dev-color-info); }

/* ---- Marcador (punto por defecto) ---- */
.dev-timeline__marker {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--dev-timeline-marker-size);
  height: var(--dev-timeline-marker-size);
  margin-top: 0.3rem;
  border-radius: 50%;
  background-color: var(--dev-timeline-item-accent);
  /* Aro del color de fondo: separa visualmente el punto de la línea conectora */
  box-shadow: 0 0 0 3px var(--dev-color-surface);
  transition: background-color var(--dev-transition-base), box-shadow var(--dev-transition-base);
}

/* Marcador con ícono propio: se agranda y pasa a estilo "aro" (como dev-steps) */
.dev-timeline__marker:has(.dev-timeline__marker-icon) {
  width: calc(var(--dev-timeline-marker-size) * 2.1);
  height: calc(var(--dev-timeline-marker-size) * 2.1);
  margin-top: 0;
  background-color: color-mix(in srgb, var(--dev-timeline-item-accent) 12%, var(--dev-color-surface));
  border: 2px solid var(--dev-timeline-item-accent);
  color: var(--dev-timeline-item-accent);
  box-shadow: none;
}
.dev-timeline__marker-icon { width: 55%; height: 55%; }

/* Marcador como avatar (imagen o iniciales) */
.dev-timeline__marker--avatar {
  width: calc(var(--dev-timeline-marker-size) * 2.4);
  height: calc(var(--dev-timeline-marker-size) * 2.4);
  margin-top: 0;
  overflow: hidden;
  background-color: var(--dev-color-secondary);
  color: var(--dev-color-on-primary);
  font-size: 0.7rem;
  font-weight: var(--dev-font-weight-bold);
  box-shadow: 0 0 0 3px var(--dev-color-surface);
}
.dev-timeline__marker--avatar img { width: 100%; height: 100%; object-fit: cover; }

/* Evento actual/más reciente: aro de acento + título en negritas */
.dev-timeline__item--current .dev-timeline__marker {
  box-shadow: 0 0 0 3px var(--dev-color-surface), 0 0 0 5px var(--dev-timeline-item-accent);
}
.dev-timeline__item--current .dev-timeline__marker:has(.dev-timeline__marker-icon) {
  box-shadow: 0 0 0 3px var(--dev-timeline-item-accent);
}
.dev-timeline__item--current .dev-timeline__title {
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-timeline-item-accent);
}

/* ---- Contenido ---- */
.dev-timeline__content { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; flex: 1 1 auto; }
.dev-timeline__header { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.4rem 0.6rem; }
.dev-timeline__title {
  font-size: var(--dev-font-size-base);
  font-weight: var(--dev-font-weight-medium);
  color: var(--dev-color-text);
  transition: color var(--dev-transition-base);
}
.dev-timeline__time {
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
  margin-inline-start: auto;
  white-space: nowrap;
}
.dev-timeline__description { font-size: var(--dev-font-size-sm); color: var(--dev-color-text-muted); }
.dev-timeline__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin-top: 0.15rem; }

/* Burbuja opcional para comentarios/detalle largo dentro del contenido */
.dev-timeline__card {
  margin-top: 0.25rem;
  padding: var(--dev-space-sm) var(--dev-space-md);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
}

/* ==========================================================================
   ORIENTACIÓN
   ========================================================================== */

/* --reverse: mismo HTML (orden cronológico normal), pero se voltea la
   presentación para mostrar el evento más reciente arriba. */
.dev-timeline--reverse { flex-direction: column-reverse; }
.dev-timeline--reverse .dev-timeline__item { padding-top: 0; padding-bottom: var(--dev-timeline-gap); }
.dev-timeline--reverse .dev-timeline__item:last-child { padding-bottom: 0; }
.dev-timeline--reverse .dev-timeline__item::before { content: none; }
.dev-timeline--reverse .dev-timeline__item:not(:last-child)::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: calc(var(--dev-timeline-marker-size) / 2);
  transform: translateX(-50%);
  width: 2px;
  height: var(--dev-timeline-gap);
  background-color: var(--dev-color-border);
  transition: background-color var(--dev-transition-base);
}

/* --horizontal: cadena de eventos en fila (historial de commits estilo git log) */
.dev-timeline--horizontal {
  flex-direction: row;
  align-items: flex-start;
  overflow-x: auto;
  padding-bottom: var(--dev-space-sm);
}
.dev-timeline--horizontal .dev-timeline__item {
  flex-direction: column;
  align-items: center;
  text-align: center;
  flex-shrink: 0;
  padding-top: 0;
  padding-inline-start: var(--dev-timeline-gap);
}
.dev-timeline--horizontal .dev-timeline__item:first-child { padding-inline-start: 0; }
.dev-timeline--horizontal .dev-timeline__item::before { content: none; }
.dev-timeline--horizontal .dev-timeline__item:not(:first-child)::after {
  content: "";
  position: absolute;
  top: calc(var(--dev-timeline-marker-size) / 2 + 0.3rem);
  left: 0;
  transform: translateY(-50%);
  width: var(--dev-timeline-gap);
  height: 2px;
  background-color: var(--dev-color-border);
  transition: background-color var(--dev-transition-base);
}
.dev-timeline--horizontal .dev-timeline__marker:has(.dev-timeline__marker-icon),
.dev-timeline--horizontal .dev-timeline__marker--avatar {
  margin-top: 0;
}
.dev-timeline--horizontal .dev-timeline__content { align-items: center; max-width: 9.5rem; }
.dev-timeline--horizontal .dev-timeline__header { flex-direction: column; gap: 0.1rem; }
.dev-timeline--horizontal .dev-timeline__time { margin-inline-start: 0; }
.dev-timeline--horizontal .dev-timeline__meta { justify-content: center; }

/* ==========================================================================
   TAMAÑOS
   ========================================================================== */
.dev-timeline--sm { --dev-timeline-marker-size: 0.65rem; --dev-timeline-gap: var(--dev-space-md); }
.dev-timeline--sm .dev-timeline__title { font-size: var(--dev-font-size-sm); }
.dev-timeline--sm .dev-timeline__description,
.dev-timeline--sm .dev-timeline__time { font-size: 0.75rem; }

.dev-timeline--lg { --dev-timeline-marker-size: 1.1rem; --dev-timeline-gap: var(--dev-space-xl); }
.dev-timeline--lg .dev-timeline__title { font-size: var(--dev-font-size-lg); }
.dev-timeline--lg .dev-timeline__description { font-size: var(--dev-font-size-base); }

/* ==========================================================================
   ANIMACIONES
   ========================================================================== */

/* --anim-fade: cada evento entra con fundido + deslizado, en cascada.
   Arranca en pausa (congelado en el fotograma inicial gracias a "backwards")
   y solo corre cuando el bloque recibe la clase --in-view — la agrega
   design-system/js/global.js con un IntersectionObserver la primera vez que
   el elemento entra en el viewport. Sin esto, la animación correría una sola
   vez al cargar la página y ya habría terminado para cuando el usuario haga
   scroll hasta esta sección: se vería estático, como si "no animara". */
.dev-timeline--anim-fade .dev-timeline__item {
  animation: dev-timeline-fade-in-y 420ms ease-out backwards paused;
}
.dev-timeline--anim-fade.dev-timeline--in-view .dev-timeline__item {
  animation-play-state: running;
}
.dev-timeline--anim-fade.dev-timeline--horizontal .dev-timeline__item {
  animation-name: dev-timeline-fade-in-x;
}
.dev-timeline--anim-fade .dev-timeline__item:nth-child(1) { animation-delay: 0ms; }
.dev-timeline--anim-fade .dev-timeline__item:nth-child(2) { animation-delay: 80ms; }
.dev-timeline--anim-fade .dev-timeline__item:nth-child(3) { animation-delay: 160ms; }
.dev-timeline--anim-fade .dev-timeline__item:nth-child(4) { animation-delay: 240ms; }
.dev-timeline--anim-fade .dev-timeline__item:nth-child(5) { animation-delay: 320ms; }
.dev-timeline--anim-fade .dev-timeline__item:nth-child(6) { animation-delay: 400ms; }
.dev-timeline--anim-fade .dev-timeline__item:nth-child(n+7) { animation-delay: 480ms; }

@keyframes dev-timeline-fade-in-y {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes dev-timeline-fade-in-x {
  from { opacity: 0; transform: translateX(10px); }
  to   { opacity: 1; transform: none; }
}

/* --anim-pulse: el evento --current late (aro de acento) para llamar la atención */
.dev-timeline--anim-pulse .dev-timeline__item--current .dev-timeline__marker {
  animation: dev-timeline-pulse 1.8s ease-out infinite;
}
@keyframes dev-timeline-pulse {
  0%   { box-shadow: 0 0 0 3px var(--dev-color-surface), 0 0 0 5px color-mix(in srgb, var(--dev-timeline-item-accent) 55%, transparent); }
  70%  { box-shadow: 0 0 0 3px var(--dev-color-surface), 0 0 0 11px color-mix(in srgb, var(--dev-timeline-item-accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 3px var(--dev-color-surface), 0 0 0 5px color-mix(in srgb, var(--dev-timeline-item-accent) 0%, transparent); }
}

/* --anim-line: la línea conectora se "dibuja" progresivamente al entrar,
   en cascada junto con --anim-fade (misma escalera de retrasos). Misma
   pausa-hasta-in-view que --anim-fade, para que se vea al hacer scroll. */
.dev-timeline--anim-line .dev-timeline__item:not(:first-child)::before {
  animation: dev-timeline-draw-y 420ms ease-out backwards paused;
  transform-origin: top;
}
.dev-timeline--anim-line.dev-timeline--reverse .dev-timeline__item:not(:last-child)::after {
  animation: dev-timeline-draw-y 420ms ease-out backwards paused;
  transform-origin: bottom;
}
.dev-timeline--anim-line.dev-timeline--horizontal .dev-timeline__item:not(:first-child)::after {
  animation: dev-timeline-draw-x 420ms ease-out backwards paused;
  transform-origin: left;
}
.dev-timeline--anim-line.dev-timeline--in-view .dev-timeline__item::before,
.dev-timeline--anim-line.dev-timeline--in-view .dev-timeline__item::after {
  animation-play-state: running;
}
.dev-timeline--anim-line .dev-timeline__item:nth-child(2)::before,
.dev-timeline--anim-line .dev-timeline__item:nth-child(2)::after { animation-delay: 60ms; }
.dev-timeline--anim-line .dev-timeline__item:nth-child(3)::before,
.dev-timeline--anim-line .dev-timeline__item:nth-child(3)::after { animation-delay: 140ms; }
.dev-timeline--anim-line .dev-timeline__item:nth-child(4)::before,
.dev-timeline--anim-line .dev-timeline__item:nth-child(4)::after { animation-delay: 220ms; }
.dev-timeline--anim-line .dev-timeline__item:nth-child(5)::before,
.dev-timeline--anim-line .dev-timeline__item:nth-child(5)::after { animation-delay: 300ms; }
.dev-timeline--anim-line .dev-timeline__item:nth-child(n+6)::before,
.dev-timeline--anim-line .dev-timeline__item:nth-child(n+6)::after { animation-delay: 380ms; }

/* Incluyen la traslación de centrado del elemento (translateX/Y -50%) para
   no pisar el posicionamiento estático mientras dura la animación. */
@keyframes dev-timeline-draw-y {
  from { transform: translateX(-50%) scaleY(0); }
  to   { transform: translateX(-50%) scaleY(1); }
}
@keyframes dev-timeline-draw-x {
  from { transform: translateY(-50%) scaleX(0); }
  to   { transform: translateY(-50%) scaleX(1); }
}


/* ===== components/kanban.css ===== */
/* ==========================================================================
   KANBAN (BEM)
   Bloque: dev-kanban
   Uso: tablero por columnas con tarjetas arrastrables (drag & drop), tipo
   Notion/Trello. Se activa con design-system/js/components/dev-kanban.js
   (mejora progresiva: sin JS se ve el tablero estático, con JS se puede
   arrastrar). Requiere marcar el tablero con [data-dev-kanban].

   <div class="dev-kanban" data-dev-kanban>
     <div class="dev-kanban__column" data-dev-color="danger">
       <div class="dev-kanban__column-header">
         <span class="dev-kanban__column-dot"></span>
         <span class="dev-kanban__column-title">Pendiente</span>
         <span class="dev-kanban__column-count">2</span>
       </div>
       <div class="dev-kanban__column-body" data-dev-kanban-list>
         <div class="dev-kanban__card" draggable="true">
           <div class="dev-kanban__card-title">Erogaciones Documentación</div>
           <div class="dev-kanban__card-badges">
             <span class="dev-badge dev-badge--danger">Alta</span>
           </div>
           <div class="dev-kanban__card-footer">
             <span class="dev-kanban__card-avatar">AE</span>
             <span class="dev-kanban__card-date">2 jun 2026</span>
           </div>
         </div>
       </div>
       <button type="button" class="dev-kanban__add"><i data-lucide="plus" class="dev-icon"></i> Nueva tarjeta</button>
     </div>
     ...
   </div>

   Elementos:
     dev-kanban__column         columna (bloque de estado)
     dev-kanban__column-header  encabezado: punto de color + título + contador
     dev-kanban__column-dot     punto de acento (toma --dev-kanban-accent)
     dev-kanban__column-title
     dev-kanban__column-count   contador de tarjetas (lo actualiza dev-kanban.js)
     dev-kanban__column-body    zona donde caen las tarjetas [data-dev-kanban-list]
     dev-kanban__card           tarjeta arrastrable (draggable="true")
     dev-kanban__card-title
     dev-kanban__card-badges    envoltorio de dev-badge (prioridad, etc.)
     dev-kanban__card-footer    envoltorio de avatar + fecha
     dev-kanban__card-avatar    iniciales en círculo
     dev-kanban__card-date
     dev-kanban__add            botón "Nueva tarjeta" (placeholder, sin lógica)

   Estados (los pone dev-kanban.js durante el arrastre):
     dev-kanban__card--dragging        la tarjeta que se está moviendo
     dev-kanban__column-body--over     columna sobre la que está el arrastre
     dev-kanban__placeholder           hueco de inserción (línea punteada)

   Tamaños:     dev-kanban--sm | (base) | dev-kanban--lg
   Animaciones: dev-kanban--anim-fade (entrada en cascada de las tarjetas)
                dev-kanban--anim-pulse (la columna respira al recibir el arrastre)
                dev-kanban--anim-lift (la tarjeta se inclina y "levanta" más al arrastrarla)
   Color:       data-dev-color="teal-2" en .dev-kanban__column (ver global.js) —
                pinta el punto, el borde de acento y el resaltado al soltar.
   ========================================================================== */

.dev-kanban {
  --dev-kanban-column-w: 17.5rem;
  display: flex;
  align-items: flex-start;
  gap: var(--dev-space-lg);
  overflow-x: auto;
  padding-bottom: var(--dev-space-sm);
}

/* ---- Columna ---- */
.dev-kanban__column {
  --dev-kanban-accent: var(--dev-color-secondary);
  flex: 0 0 var(--dev-kanban-column-w);
  width: var(--dev-kanban-column-w);
  display: flex;
  flex-direction: column;
  max-height: 32rem;
  background-color: var(--dev-color-bg-subtle);
  border-radius: var(--dev-radius-lg);
  padding: var(--dev-space-sm);
}

.dev-kanban__column-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: var(--dev-space-xs) var(--dev-space-sm) var(--dev-space-sm);
}

.dev-kanban__column-dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background-color: var(--dev-kanban-accent);
  flex-shrink: 0;
}

.dev-kanban__column-title {
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text);
}

.dev-kanban__column-count {
  margin-left: auto;
  font-size: 0.7rem;
  font-weight: var(--dev-font-weight-medium);
  color: var(--dev-color-text-muted);
  background-color: var(--dev-color-surface-raised);
  padding: 0.1rem 0.5rem;
  border-radius: var(--dev-radius-pill);
}

/* ---- Zona de tarjetas (drop zone) ---- */
.dev-kanban__column-body {
  display: flex;
  flex-direction: column;
  gap: var(--dev-space-sm);
  min-height: 3rem;
  padding: 0.15rem;
  overflow-y: auto;
  border-radius: var(--dev-radius-md);
  transition: background-color var(--dev-transition-base);
}

.dev-kanban__column-body--over {
  background-color: color-mix(in srgb, var(--dev-kanban-accent) 10%, transparent);
}

/* Hueco de inserción mientras se arrastra una tarjeta */
.dev-kanban__placeholder {
  height: 2.75rem;
  border: 2px dashed var(--dev-kanban-accent);
  border-radius: var(--dev-radius-md);
  background-color: color-mix(in srgb, var(--dev-kanban-accent) 6%, transparent);
  flex-shrink: 0;
}

/* ---- Tarjeta ---- */
.dev-kanban__card {
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-left: 3px solid var(--dev-kanban-accent);
  border-radius: var(--dev-radius-md);
  padding: var(--dev-space-sm) var(--dev-space-md);
  box-shadow: var(--dev-shadow-sm);
  cursor: grab;
  transition: box-shadow var(--dev-transition-base), transform var(--dev-transition-fast), opacity var(--dev-transition-fast);
}
.dev-kanban__card:active { cursor: grabbing; }
.dev-kanban__card:hover { box-shadow: var(--dev-shadow-md); }

.dev-kanban__card--dragging {
  opacity: 0.4;
}

.dev-kanban__card-title {
  font-weight: var(--dev-font-weight-medium);
  color: var(--dev-color-text);
  margin-bottom: 0.4rem;
}

.dev-kanban__card-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.5rem;
}

.dev-kanban__card-footer {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.75rem;
  color: var(--dev-color-text-muted);
}

.dev-kanban__card-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background-color: var(--dev-color-secondary);
  color: var(--dev-color-on-secondary);
  font-size: 0.65rem;
  font-weight: var(--dev-font-weight-bold);
  flex-shrink: 0;
}

/* Tarjeta recién soltada: destello breve del acento (lo dispara dev-kanban.js) */
.dev-kanban__card--dropped { animation: dev-kanban-drop-flash 900ms ease-out; }
@keyframes dev-kanban-drop-flash {
  0%   { box-shadow: 0 0 0 3px color-mix(in srgb, var(--dev-kanban-accent) 55%, transparent); }
  100% { box-shadow: var(--dev-shadow-sm); }
}

/* ---- Botón "Nueva tarjeta" ---- */
.dev-kanban__add {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
  margin-top: var(--dev-space-sm);
  padding: 0.45rem var(--dev-space-sm);
  background: transparent;
  border: 1px dashed var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  color: var(--dev-color-text-muted);
  font-size: var(--dev-font-size-sm);
  cursor: pointer;
  transition: background-color var(--dev-transition-fast), color var(--dev-transition-fast), border-color var(--dev-transition-fast);
}
.dev-kanban__add:hover {
  color: var(--dev-color-text);
  border-color: var(--dev-color-border-strong);
  background-color: var(--dev-color-surface-raised);
}

/* ==========================================================================
   TAMAÑOS
   ========================================================================== */
.dev-kanban--sm { --dev-kanban-column-w: 14.5rem; }
.dev-kanban--sm .dev-kanban__card { padding: 0.5rem 0.65rem; }
.dev-kanban--sm .dev-kanban__card-title { font-size: var(--dev-font-size-sm); }

.dev-kanban--lg { --dev-kanban-column-w: 21rem; }
.dev-kanban--lg .dev-kanban__card { padding: var(--dev-space-md) var(--dev-space-lg); }
.dev-kanban--lg .dev-kanban__card-title { font-size: var(--dev-font-size-lg); }

/* ==========================================================================
   ANIMACIONES
   ========================================================================== */

/* --anim-fade: las tarjetas entran con fundido + deslizado, en cascada */
.dev-kanban--anim-fade .dev-kanban__card {
  animation: dev-kanban-fade-in 380ms ease-out backwards;
}
.dev-kanban--anim-fade .dev-kanban__card:nth-child(1) { animation-delay: 0ms; }
.dev-kanban--anim-fade .dev-kanban__card:nth-child(2) { animation-delay: 60ms; }
.dev-kanban--anim-fade .dev-kanban__card:nth-child(3) { animation-delay: 120ms; }
.dev-kanban--anim-fade .dev-kanban__card:nth-child(4) { animation-delay: 180ms; }
.dev-kanban--anim-fade .dev-kanban__card:nth-child(n+5) { animation-delay: 240ms; }
@keyframes dev-kanban-fade-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* --anim-pulse: la columna "respira" mientras recibe un arrastre encima */
.dev-kanban--anim-pulse .dev-kanban__column-body--over {
  animation: dev-kanban-pulse 1.1s ease-in-out infinite;
}
@keyframes dev-kanban-pulse {
  0%, 100% { background-color: color-mix(in srgb, var(--dev-kanban-accent) 8%, transparent); }
  50%      { background-color: color-mix(in srgb, var(--dev-kanban-accent) 18%, transparent); }
}

/* --anim-lift: la tarjeta se inclina y se "levanta" más al arrastrarla */
.dev-kanban--anim-lift .dev-kanban__card--dragging {
  transform: rotate(-2deg) scale(1.03);
  box-shadow: var(--dev-shadow-lg);
}


/* ===== components/icons.css ===== */
/* ==========================================================================
   ICONOS (BEM)  —  Lucide local
   Bloque: dev-icon
   Motor: Lucide (design-system/js/vendor/lucide.min.js). Uso:
     <i data-lucide="eye" class="dev-icon"></i>
   Al cargar, lucide.createIcons() (llamado en global.js) reemplaza el <i>
   por un <svg> conservando las clases dev-icon. El SVG usa stroke:currentColor,
   así que el icono toma el color del texto por defecto y se puede recolorear
   con las variantes --primary/--success/... o con data-dev-color.

   Modificadores:
     Tamaño : --xs --sm --md(def) --lg --xl --2xl   (en em: escalan con la fuente)
     Grosor : --thin --bold
     Color  : --primary --secondary --success --danger --warning --info --muted
     Animar : --spin
   ========================================================================== */

.dev-icon {
  display: inline-block;
  width: 1.25em;
  height: 1.25em;
  vertical-align: -0.15em;
  flex-shrink: 0;
  stroke-width: 2;
  color: inherit;
}

/* Por si se usa como contenedor con un <svg> dentro en vez de reemplazo directo. */
.dev-icon > svg { width: 100%; height: 100%; display: block; }

/* ---- Tamaños ---- */
.dev-icon--xs  { width: 0.875em; height: 0.875em; }
.dev-icon--sm  { width: 1em;     height: 1em; }
.dev-icon--md  { width: 1.25em;  height: 1.25em; }
.dev-icon--lg  { width: 1.5em;   height: 1.5em; }
.dev-icon--xl  { width: 2em;     height: 2em; }
.dev-icon--2xl { width: 2.75em;  height: 2.75em; }

/* ---- Grosor de trazo ---- */
.dev-icon--thin { stroke-width: 1.5; }
.dev-icon--bold { stroke-width: 2.5; }

/* ---- Colores (currentColor) ---- */
.dev-icon--primary   { color: var(--dev-color-primary); }
.dev-icon--secondary { color: var(--dev-color-secondary-on-surface); }
.dev-icon--success   { color: var(--dev-color-success); }
.dev-icon--danger    { color: var(--dev-color-danger); }
.dev-icon--warning   { color: var(--dev-color-warning-text); }
.dev-icon--info      { color: var(--dev-color-info-on-surface); }
.dev-icon--muted     { color: var(--dev-color-text-muted); }

/* ---- Animación ---- */
.dev-icon--spin { animation: dev-icon-spin 1s linear infinite; }

@keyframes dev-icon-spin { to { transform: rotate(360deg); } }


/* ===== components/avatar.css ===== */
/* ==========================================================================
   AVATAR (BEM)
   Bloque: dev-avatar
   Imagen o iniciales, tamaños, estado (online/away/busy/offline) y grupo
   apilado (dev-avatar-group).

   Uso:
     <span class="dev-avatar"><img src="foto.jpg" alt="Nombre"></span>
     <span class="dev-avatar dev-avatar--lg" data-dev-color="teal-2">JD</span>
     <span class="dev-avatar dev-avatar--online"><img src="foto.jpg" alt=""></span>

     <div class="dev-avatar-group">
       <span class="dev-avatar"><img src="a.jpg" alt=""></span>
       <span class="dev-avatar"><img src="b.jpg" alt=""></span>
       <span class="dev-avatar dev-avatar--more">+3</span>
     </div>

   Color de las iniciales: por defecto usa el primario; se puede fijar
   data-dev-color="..." (mismo mecanismo que dev-badge/dev-btn, ver global.js)
   o una modificadora --primary|secondary|success|danger|warning|info.
   ========================================================================== */

.dev-avatar {
  --dev-avatar-size: 2.5rem;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--dev-avatar-size);
  height: var(--dev-avatar-size);
  border-radius: var(--dev-radius-pill);
  overflow: hidden;
  background-color: var(--dev-color-primary-light);
  color: var(--dev-color-primary-soft-text);
  font-size: calc(var(--dev-avatar-size) * 0.4);
  font-weight: var(--dev-font-weight-bold);
  line-height: 1;
  text-transform: uppercase;
  flex-shrink: 0;
  user-select: none;
}

.dev-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---- Tamaños ---- */
.dev-avatar--xs { --dev-avatar-size: 1.5rem; }
.dev-avatar--sm { --dev-avatar-size: 2rem; }
.dev-avatar--lg { --dev-avatar-size: 3.25rem; }
.dev-avatar--xl { --dev-avatar-size: 4.5rem; }

/* ---- Colores fijos (mismo criterio que dev-badge: tinte suave) ---- */
.dev-avatar--primary   { background-color: var(--dev-color-primary-light); color: var(--dev-color-primary-soft-text); }
.dev-avatar--secondary { background-color: var(--dev-color-secondary-light); color: var(--dev-color-secondary-soft-text); }
.dev-avatar--success   { background-color: var(--dev-color-success-light); color: var(--dev-color-success-soft-text); }
.dev-avatar--danger    { background-color: var(--dev-color-danger-light); color: var(--dev-color-danger-soft-text); }
.dev-avatar--warning   { background-color: var(--dev-color-warning-light); color: var(--dev-color-warning-soft-text); }
.dev-avatar--info      { background-color: var(--dev-color-info-light); color: var(--dev-color-info-soft-text); }

/* ---- Indicador de estado (punto en la esquina inferior derecha) ---- */
.dev-avatar--online::after,
.dev-avatar--away::after,
.dev-avatar--busy::after,
.dev-avatar--offline::after {
  content: "";
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: 28%;
  height: 28%;
  min-width: 0.5rem;
  min-height: 0.5rem;
  border-radius: 50%;
  border: 2px solid var(--dev-color-surface);
}
.dev-avatar--online::after  { background-color: var(--dev-color-success); }
.dev-avatar--away::after    { background-color: var(--dev-color-warning); }
.dev-avatar--busy::after    { background-color: var(--dev-color-danger); }
.dev-avatar--offline::after { background-color: var(--dev-color-border-strong); }

/* ---- Grupo apilado (superposición tipo "facepile") ---- */
.dev-avatar-group {
  display: inline-flex;
  align-items: center;
}

.dev-avatar-group .dev-avatar {
  border: 2px solid var(--dev-color-surface);
  margin-left: -0.6rem;
}

.dev-avatar-group .dev-avatar:first-child { margin-left: 0; }

.dev-avatar-group .dev-avatar--more {
  background-color: var(--dev-color-bg-subtle);
  color: var(--dev-color-text-muted);
  font-size: calc(var(--dev-avatar-size) * 0.32);
}


/* ===== components/empty-state.css ===== */
/* ==========================================================================
   EMPTY STATE (BEM)
   Bloque: dev-empty-state
   Mensaje para tablas/listas/paneles sin datos: icono, título, descripción
   y una acción opcional. Pensado para vivir dentro de un dev-card o de un
   dev-table-wrap cuando no hay filas.

   Uso:
     <div class="dev-empty-state">
       <i data-lucide="inbox" class="dev-icon dev-empty-state__icon"></i>
       <p class="dev-empty-state__title">Sin resultados</p>
       <p class="dev-empty-state__desc">No encontramos registros con esos filtros.</p>
       <button class="dev-btn dev-btn--primary dev-btn--sm">Limpiar filtros</button>
     </div>

   Tamaños: --sm (para espacios chicos, p. ej. dentro de una tabla) y --lg
   (pantalla completa / página vacía).
   ========================================================================== */

.dev-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--dev-space-xs);
  padding: var(--dev-space-xl) var(--dev-space-md);
  color: var(--dev-color-text-muted);
}

.dev-empty-state__icon {
  width: 2.5rem;
  height: 2.5rem;
  margin-bottom: var(--dev-space-sm);
  color: var(--dev-color-text-muted);
  opacity: 0.6;
  stroke-width: 1.5;
}

.dev-empty-state__title {
  margin: 0;
  font-size: var(--dev-font-size-lg);
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text);
}

.dev-empty-state__desc {
  margin: 0 0 var(--dev-space-sm);
  max-width: 32rem;
  font-size: var(--dev-font-size-sm);
}

/* ---- Tamaños ---- */
.dev-empty-state--sm {
  padding: var(--dev-space-md) var(--dev-space-sm);
}
.dev-empty-state--sm .dev-empty-state__icon { width: 1.75rem; height: 1.75rem; margin-bottom: var(--dev-space-xs); }
.dev-empty-state--sm .dev-empty-state__title { font-size: var(--dev-font-size-base); }

.dev-empty-state--lg {
  padding: var(--dev-space-xl) var(--dev-space-lg);
}
.dev-empty-state--lg .dev-empty-state__icon { width: 3.5rem; height: 3.5rem; }
.dev-empty-state--lg .dev-empty-state__title { font-size: 1.375rem; }


/* ===== components/skeleton.css ===== */
/* ==========================================================================
   SKELETON (BEM)
   Bloque: dev-skeleton
   Placeholders "shimmer" para estados de carga (antes de que llegue el
   contenido real). Puramente decorativo — reemplazar por el contenido real
   cuando la data esté lista (no requiere JS).

   Uso:
     <div class="dev-skeleton dev-skeleton--text"></div>
     <div class="dev-skeleton dev-skeleton--text dev-skeleton--w-60"></div>
     <span class="dev-skeleton dev-skeleton--avatar"></span>
     <div class="dev-skeleton dev-skeleton--block" style="height:120px"></div>

     <!-- Fila de tabla completa -->
     <div class="dev-skeleton-row">
       <span class="dev-skeleton dev-skeleton--avatar dev-skeleton--sm"></span>
       <div class="dev-skeleton dev-skeleton--text dev-skeleton--w-40"></div>
       <div class="dev-skeleton dev-skeleton--text dev-skeleton--w-20"></div>
     </div>

   Respeta prefers-reduced-motion (el shimmer se detiene, queda un tono fijo).
   ========================================================================== */

.dev-skeleton {
  position: relative;
  display: block;
  background-color: var(--dev-color-bg-subtle);
  border-radius: var(--dev-radius-sm);
  overflow: hidden;
}

.dev-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background-image: linear-gradient(
    90deg,
    transparent,
    var(--dev-color-surface-raised),
    transparent
  );
  animation: dev-skeleton-shimmer 1.5s ease-in-out infinite;
}

@keyframes dev-skeleton-shimmer {
  100% { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .dev-skeleton::after { animation: none; display: none; }
}

/* ---- Variantes de forma ---- */
.dev-skeleton--text {
  height: 0.85em;
  width: 100%;
  border-radius: var(--dev-radius-sm);
  margin: 0.25em 0;
}

.dev-skeleton--avatar {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--dev-radius-pill);
  flex-shrink: 0;
}
.dev-skeleton--avatar.dev-skeleton--sm { width: 2rem; height: 2rem; }
.dev-skeleton--avatar.dev-skeleton--lg { width: 3.25rem; height: 3.25rem; }

.dev-skeleton--block {
  width: 100%;
  height: 6rem;
  border-radius: var(--dev-radius-md);
}

.dev-skeleton--btn {
  width: 5.5rem;
  height: 2.25rem;
  border-radius: var(--dev-radius-md);
}

/* ---- Anchos relativos (para simular líneas de texto de largo variable) ---- */
.dev-skeleton--w-20 { width: 20%; }
.dev-skeleton--w-40 { width: 40%; }
.dev-skeleton--w-60 { width: 60%; }
.dev-skeleton--w-80 { width: 80%; }

/* ---- Fila (avatar + líneas), como placeholder de una fila de tabla/lista ---- */
.dev-skeleton-row {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  padding: var(--dev-space-sm) 0;
}
.dev-skeleton-row > div { flex: 1; }


/* ===== components/rating.css ===== */
/* ==========================================================================
   RATING (BEM)
   Bloque: dev-rating
   Estrellas de calificación. Dos modos, sin JS:

   1) SOLO LECTURA (mostrar un valor, p. ej. en una card de producto):
        <div class="dev-rating" style="--dev-rating-value: 3.5"
             aria-label="3.5 de 5 estrellas"></div>
      El relleno se dibuja con un gradiente de fondo recortado al texto de
      las 5 estrellas (::before), proporcional a --dev-rating-value (0–5,
      admite decimales para media estrella).

   2) INTERACTIVA (formulario, elige el usuario): radios reales (accesibles,
      funcionan con teclado) en orden INVERSO en el DOM pero mostrados en
      orden normal con flex "row-reverse" — así el truco de CSS
      ~ (general sibling) puede pintar "esta estrella y las anteriores".
        <div class="dev-rating dev-rating--input">
          <input type="radio" name="calif" id="r5" value="5"><label for="r5">5</label>
          <input type="radio" name="calif" id="r4" value="4"><label for="r4">4</label>
          <input type="radio" name="calif" id="r3" value="3"><label for="r3">3</label>
          <input type="radio" name="calif" id="r2" value="2"><label for="r2">2</label>
          <input type="radio" name="calif" id="r1" value="1"><label for="r1">1</label>
        </div>
      (El marcado va de 5 a 1 a propósito; visualmente se ve de 1 a 5 porque
      el contenedor invierte la dirección con flex-direction: row-reverse.)

   Color: por defecto usa --dev-color-warning (ámbar, convención universal
   de "estrellas"); se puede sobreescribir con data-dev-color o una
   modificadora dev-rating--primary|success|danger|info|secondary.
   ========================================================================== */

.dev-rating {
  --dev-rating-color: var(--dev-color-warning);
  --dev-rating-size: 1.25rem;
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  line-height: 1;
}

.dev-rating--primary   { --dev-rating-color: var(--dev-color-primary); }
.dev-rating--secondary { --dev-rating-color: var(--dev-color-secondary); }
.dev-rating--success   { --dev-rating-color: var(--dev-color-success); }
.dev-rating--danger    { --dev-rating-color: var(--dev-color-danger); }
.dev-rating--info      { --dev-rating-color: var(--dev-color-info); }

.dev-rating--sm { --dev-rating-size: 0.9rem; }
.dev-rating--lg { --dev-rating-size: 1.6rem; }

/* ---- Modo solo lectura: 5 estrellas de fondo + capa de relleno recortada ---- */
.dev-rating:not(.dev-rating--input) {
  position: relative;
  width: calc(var(--dev-rating-size) * 5 + 0.15rem * 4);
  height: var(--dev-rating-size);
  font-size: var(--dev-rating-size);
}

.dev-rating:not(.dev-rating--input)::before,
.dev-rating:not(.dev-rating--input)::after {
  content: "\2605\2605\2605\2605\2605"; /* ★★★★★ */
  position: absolute;
  inset: 0;
  white-space: nowrap;
  letter-spacing: 0.15rem;
}

.dev-rating:not(.dev-rating--input)::before {
  color: var(--dev-color-border-strong);
}

.dev-rating:not(.dev-rating--input)::after {
  color: var(--dev-rating-color);
  width: calc(var(--dev-rating-value, 0) / 5 * 100%);
  overflow: hidden;
}

/* ---- Modo interactivo: radios reales, orden invertido en el DOM ---- */
.dev-rating--input {
  flex-direction: row-reverse;
  justify-content: flex-end;
}

.dev-rating--input input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.dev-rating--input label {
  cursor: pointer;
  font-size: var(--dev-rating-size);
  color: var(--dev-color-border-strong);
  transition: color var(--dev-transition-fast), transform var(--dev-transition-fast);
}

.dev-rating--input label::before {
  content: "\2605"; /* ★ */
}

/* Estrella actual + todas las que están ANTES en el DOM (= después visualmente,
   por el row-reverse) se pintan del color activo. */
.dev-rating--input input:checked ~ label,
.dev-rating--input input:hover ~ label,
.dev-rating--input label:hover,
.dev-rating--input label:hover ~ label {
  color: var(--dev-rating-color);
}

.dev-rating--input label:hover { transform: scale(1.12); }

.dev-rating--input input:focus-visible ~ label:first-of-type {
  outline: 2px solid var(--dev-color-primary-ring);
  outline-offset: 2px;
  border-radius: var(--dev-radius-sm);
}

.dev-rating--input:has(input:disabled) label { cursor: default; }
.dev-rating--input:has(input:disabled) label:hover { transform: none; }


/* ===== components/tooltip.css ===== */
/* ==========================================================================
   TOOLTIP (BEM)
   Bloque: dev-tooltip
   Tooltip propio dev-* (alternativa a bootstrap [data-bs-toggle="tooltip"]
   cuando no se quiere cargar el JS de Bootstrap, o para más control de
   estilo). Ver design-system/js/components/dev-tooltip.js — se posiciona a
   sí mismo con JS (getBoundingClientRect) y se abre en hover/focus.

   Uso:
     <button class="dev-btn dev-btn--icon" data-dev-tooltip="Guardar cambios">
       <i data-lucide="save" class="dev-icon"></i>
     </button>
     <span data-dev-tooltip="Más información" data-dev-tooltip-pos="right">?</span>

   data-dev-tooltip-pos: top (default) | bottom | left | right.
   El bloque real (.dev-tooltip) lo crea dev-tooltip.js y lo agrega a <body>
   (no como hijo del disparador), para no quedar recortado por overflow:hidden
   de contenedores como dev-card o dev-table-wrap.
   ========================================================================== */

.dev-tooltip {
  position: fixed;
  z-index: 1090;
  max-width: 18rem;
  padding: 0.35rem 0.65rem;
  border-radius: var(--dev-radius-sm);
  background-color: var(--dev-color-text);
  color: var(--dev-color-bg);
  font-size: var(--dev-font-size-sm);
  line-height: 1.35;
  box-shadow: var(--dev-shadow-md);
  opacity: 0;
  transform: translateY(2px);
  transition: opacity var(--dev-transition-fast), transform var(--dev-transition-fast);
  pointer-events: none;
}

.dev-tooltip--visible {
  opacity: 1;
  transform: translateY(0);
}

.dev-tooltip::after {
  content: "";
  position: absolute;
  width: 0.5rem;
  height: 0.5rem;
  background-color: inherit;
  transform: rotate(45deg);
}

.dev-tooltip--top::after { bottom: -0.2rem; left: calc(50% - 0.25rem); }
.dev-tooltip--bottom::after { top: -0.2rem; left: calc(50% - 0.25rem); }
.dev-tooltip--left::after { right: -0.2rem; top: calc(50% - 0.25rem); }
.dev-tooltip--right::after { left: -0.2rem; top: calc(50% - 0.25rem); }

[data-dev-tooltip] { cursor: default; }


/* ===== components/upload.css ===== */
/* ==========================================================================
   UPLOAD / DROPZONE (BEM)
   Bloque: dev-upload
   Zona de arrastrar y soltar archivos sobre un <input type="file"> real
   (oculto), con lista de archivos seleccionados. Mejora progresiva: sin JS
   el input de archivo sigue funcionando (solo se ve menos "zona"); con JS
   (dev-upload.js) se activa drag&drop + la lista con nombre/tamaño/quitar.

   Uso:
     <div class="dev-upload" data-dev-upload>
       <input type="file" id="archivos" class="dev-upload__input" multiple hidden>
       <label for="archivos" class="dev-upload__zone">
         <i data-lucide="upload-cloud" class="dev-icon dev-upload__icon"></i>
         <span class="dev-upload__title">Arrastrá archivos aquí o hacé clic para elegir</span>
         <span class="dev-upload__hint">PDF, XLSX o imágenes — máx. 10 MB c/u</span>
       </label>
       <div class="dev-upload__list"></div>
     </div>
   ========================================================================== */

.dev-upload__input { display: none; }

.dev-upload__zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: var(--dev-space-lg);
  border: 2px dashed var(--dev-color-border);
  border-radius: var(--dev-radius-lg);
  background-color: var(--dev-color-bg-subtle);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--dev-transition-fast), background-color var(--dev-transition-fast);
}

.dev-upload__zone:hover {
  border-color: var(--dev-color-primary);
  background-color: var(--dev-color-primary-light);
}

.dev-upload--dragover .dev-upload__zone {
  border-color: var(--dev-color-primary);
  border-style: solid;
  background-color: var(--dev-color-primary-light);
}

.dev-upload__icon {
  width: 2rem;
  height: 2rem;
  color: var(--dev-color-text-muted);
}

.dev-upload__title {
  font-size: var(--dev-font-size-base);
  font-weight: var(--dev-font-weight-medium);
  color: var(--dev-color-text);
}

.dev-upload__hint {
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text-muted);
}

/* ---- Lista de archivos elegidos ---- */
.dev-upload__list {
  display: flex;
  flex-direction: column;
  gap: var(--dev-space-xs);
  margin-top: var(--dev-space-sm);
}
.dev-upload__list:empty { display: none; }

.dev-upload__item {
  display: flex;
  align-items: center;
  gap: var(--dev-space-sm);
  padding: 0.5rem 0.75rem;
  border-radius: var(--dev-radius-md);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
}

.dev-upload__item-icon {
  width: 1.1rem;
  height: 1.1rem;
  color: var(--dev-color-text-muted);
  flex-shrink: 0;
}

.dev-upload__item-name {
  flex: 1;
  min-width: 0;
  font-size: var(--dev-font-size-sm);
  color: var(--dev-color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dev-upload__item-size {
  font-size: 0.75rem;
  color: var(--dev-color-text-muted);
  flex-shrink: 0;
}

.dev-upload__item-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--dev-color-text-muted);
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color var(--dev-transition-fast), color var(--dev-transition-fast);
}
.dev-upload__item-remove:hover {
  background-color: var(--dev-color-danger-light);
  color: var(--dev-color-danger-soft-text);
}
.dev-upload__item-remove .dev-icon { width: 0.9rem; height: 0.9rem; }

.dev-upload__item--error {
  border-color: var(--dev-color-danger);
  background-color: var(--dev-color-danger-light);
}
.dev-upload__item--error .dev-upload__item-name,
.dev-upload__item--error .dev-upload__item-size {
  color: var(--dev-color-danger-soft-text);
}


/* ===== components/datatables.css ===== */
/* ==========================================================================
   DATATABLES (re-skin)
   Tematiza DataTables 1.13 + integración Bootstrap 5 + botones de exportar
   (Buttons) con los tokens dev-*. Se usa tal cual (markup/JS de DataTables
   intactos): solo alinea colores para que respete la paleta y el modo
   oscuro. Sin esto, en modo oscuro los controles (buscador, "Mostrando X de
   Y", selector de longitud) y sobre todo los botones de exportar salían con
   texto oscuro sobre fondo claro, rompiendo el tema.
   Todo usa variables, así que sirve igual en claro y oscuro sin duplicar.
   ========================================================================== */

/* ---- Textos y contenedores del wrapper ---- */
.dataTables_wrapper {
  color: var(--dev-color-text);
}
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_processing,
.dataTables_wrapper .dataTables_paginate {
  color: var(--dev-color-text);
}
.dataTables_wrapper .dataTables_length label,
.dataTables_wrapper .dataTables_filter label {
  color: var(--dev-color-text);
}

/* ---- Controles (buscador y selector de cantidad) ---- */
.dataTables_wrapper .dataTables_filter input,
.dataTables_wrapper .dataTables_length select {
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  color: var(--dev-color-text);
  padding: 0.35rem 0.6rem;
}
.dataTables_wrapper .dataTables_filter input:focus,
.dataTables_wrapper .dataTables_length select:focus {
  outline: none;
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-ring);
}
[data-theme="dark"] .dataTables_wrapper .dataTables_length select,
[data-theme="dark"] .dataTables_wrapper .dataTables_length select option {
  color-scheme: dark;
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}

/* ---- Paginación (integración Bootstrap: usa .page-link/.page-item, ya
   tematizados en bootstrap-overrides.css; aquí solo el estado disabled) ---- */
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled .page-link {
  color: var(--dev-color-text-muted);
}

/* ---- Botones de exportar (DataTables Buttons: Copiar/Excel/CSV/PDF/Imprimir) ---- */
.dt-buttons .dt-button,
.dt-button {
  background: var(--dev-color-surface);
  background-image: none;
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  color: var(--dev-color-text);
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-medium);
  padding: 0.4rem 0.85rem;
  margin-right: 0.35rem;
  transition: background-color var(--dev-transition-fast), border-color var(--dev-transition-fast), color var(--dev-transition-fast);
}
.dt-buttons .dt-button:hover,
.dt-button:hover:not(.disabled) {
  background: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
}
.dt-buttons .dt-button:focus,
.dt-button:focus:not(.disabled) {
  outline: none;
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-ring);
}
.dt-button.disabled,
.dt-buttons .dt-button.disabled {
  color: var(--dev-color-text-muted);
  opacity: 0.6;
}

/* ---- Menú de colecciones de botones (si se agrupan) ---- */
.dt-button-collection {
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  box-shadow: var(--dev-shadow-dropdown);
}
.dt-button-collection .dt-button {
  border: none;
  border-radius: 0;
  color: var(--dev-color-text);
}


/* ===== components/charts.css ===== */
/* ==========================================================================
   CHARTS (BEM)
   Bloque: dev-chart
   Envoltorio para gráficas Chart.js (design-system/js/components/dev-chart.js).
   El <canvas> se dimensiona al 100% del wrapper; el wrapper fija la altura
   con --dev-chart-height (IMPORTANTE: Chart.js con maintainAspectRatio:false
   necesita una altura explícita en el contenedor — con solo min-height el
   canvas puede crecer sin control).
   Uso:
     <div class="dev-chart-wrap"><canvas id="miGrafica"></canvas></div>
     <script>devChart.create("#miGrafica", { type: "bar", data: {...} });</script>

   Personalizar color (sin tocar JS): agregar al wrap (o a un ancestro, como
   la tarjeta que lo contiene) una modificadora
   dev-chart-wrap--primary|info|success|warning|danger|secondary, o fijar
   la variable directamente: style="--dev-chart-color: #7c3aed".
   El color se lee en JS con devChart.colorOf(canvas).

   Personalizar altura: style="--dev-chart-height: 320px" en el wrap, o la
   modificadora dev-chart-wrap--tall (320px) / --compact (160px).
   ========================================================================== */

.dev-chart-wrap {
  --dev-chart-height: 220px;
  position: relative;
  width: 100%;
  height: var(--dev-chart-height);
}

.dev-chart-wrap--compact { --dev-chart-height: 160px; }
.dev-chart-wrap--tall { --dev-chart-height: 320px; }

.dev-chart-wrap canvas {
  width: 100% !important;
  height: 100% !important;
}

/* ---- Modificadoras de color: fijan --dev-chart-color (se puede poner en el
   wrap o en un ancestro, como .dev-chart-card, y se hereda hacia abajo). ---- */
.dev-chart-wrap--primary,
.dev-chart-card--primary { --dev-chart-color: var(--dev-color-primary); }
.dev-chart-wrap--info,
.dev-chart-card--info { --dev-chart-color: var(--dev-color-info); }
.dev-chart-wrap--success,
.dev-chart-card--success { --dev-chart-color: var(--dev-color-success); }
.dev-chart-wrap--warning,
.dev-chart-card--warning { --dev-chart-color: var(--dev-color-warning); }
.dev-chart-wrap--danger,
.dev-chart-card--danger { --dev-chart-color: var(--dev-color-danger); }
.dev-chart-wrap--secondary,
.dev-chart-card--secondary { --dev-chart-color: var(--dev-color-secondary); }

/* ---- Grilla de tarjetas para catálogos/demos de varias gráficas ----
   align-content: start evita que el grid estire las filas para llenar el
   alto disponible del contenedor (si no, cada fila crece y deja un hueco
   vacío debajo de la gráfica). */
.dev-chart-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  grid-auto-rows: min-content;
  gap: var(--dev-space-md);
  align-content: start;
  align-items: start;
}

.dev-chart-card {
  display: flex;
  flex-direction: column;
  gap: var(--dev-space-sm);
  background-color: var(--dev-color-surface);
  border: 1px solid var(--dev-color-border);
  border-radius: var(--dev-radius-md);
  padding: var(--dev-space-md);
}

.dev-chart-card__title {
  font-size: var(--dev-font-size-sm);
  font-weight: var(--dev-font-weight-bold);
  color: var(--dev-color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}


/* ===== components/bootstrap-overrides.css ===== */
/* ==========================================================================
   BOOTSTRAP OVERRIDES
   Alinea las clases nativas de Bootstrap 5 (.btn-primary, .card, .table,
   .form-control, .dropdown-menu, etc.) con la paleta --dev-color-* y con
   el modo oscuro ([data-theme="dark"]). Necesario porque algunas vistas
   (login, validación de formularios) siguen usando componentes nativos
   de Bootstrap ademas de las clases dev-*.
   ========================================================================== */

.bg-primary { background-color: var(--dev-color-primary) !important; }
.text-primary { color: var(--dev-color-primary) !important; }
.border-primary { border-color: var(--dev-color-primary) !important; }
a { color: var(--dev-color-primary); }
a:hover { color: var(--dev-color-primary-hover); }

.btn-primary {
  color: var(--dev-color-on-primary);
  background-color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
}
.btn-primary:hover,
.btn-primary:focus {
  color: var(--dev-color-on-primary);
  background-color: var(--dev-color-primary-hover);
  border-color: var(--dev-color-primary-hover);
  box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--dev-color-primary) 50%, transparent);
}

.btn-outline-primary {
  color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
}
.btn-outline-primary:hover,
.btn-outline-primary:focus {
  color: var(--dev-color-on-primary);
  background-color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--dev-color-primary);
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-ring);
}

.alert-primary {
  color: var(--dev-color-primary-hover);
  background-color: var(--dev-color-primary-light);
  border-color: var(--dev-color-primary);
}

.page-link { color: var(--dev-color-primary); }
.page-item.active .page-link {
  background-color: var(--dev-color-primary);
  border-color: var(--dev-color-primary);
  color: var(--dev-color-on-primary);
}

.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
  background-color: var(--dev-color-primary);
}

/* ---- Dark mode: componentes nativos de Bootstrap ---- */
[data-theme="dark"] {
  color-scheme: dark;
}

[data-theme="dark"] .card {
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}
[data-theme="dark"] .card-header,
[data-theme="dark"] .card-footer {
  background-color: var(--dev-color-surface-raised);
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}

[data-theme="dark"] .table {
  color: var(--dev-color-text);
  border-color: var(--dev-color-border);
}
[data-theme="dark"] .table > :not(caption) > * > * {
  background-color: transparent;
  color: var(--dev-color-text);
  border-color: var(--dev-color-border);
}
[data-theme="dark"] .table-striped > tbody > tr:nth-of-type(odd) > * {
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}
[data-theme="dark"] .table-hover > tbody > tr:hover > * {
  background-color: rgba(255, 255, 255, 0.05);
  color: var(--dev-color-text);
}

[data-theme="dark"] .form-control,
[data-theme="dark"] .form-select {
  background-color: var(--dev-color-surface-raised);
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}

/* Mismo fix que en dev-select: sin esto el listado nativo de un
   .form-select abre en blanco aunque el resto de la página esté en oscuro. */
select,
select option,
.form-select,
.form-select option {
  color-scheme: light;
}
[data-theme="dark"] select,
[data-theme="dark"] select option,
[data-theme="dark"] .form-select,
[data-theme="dark"] .form-select option {
  color-scheme: dark;
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}
[data-theme="dark"] .form-control:focus,
[data-theme="dark"] .form-select:focus {
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}
[data-theme="dark"] .form-control::placeholder { color: var(--dev-color-text-muted); }
[data-theme="dark"] .form-label { color: var(--dev-color-text); }
[data-theme="dark"] .form-text { color: var(--dev-color-text-muted); }

[data-theme="dark"] .dropdown-menu {
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border);
}
[data-theme="dark"] .dropdown-item { color: var(--dev-color-text); }
[data-theme="dark"] .dropdown-item:hover,
[data-theme="dark"] .dropdown-item:focus {
  background-color: var(--dev-color-surface-raised);
  color: var(--dev-color-text);
}
[data-theme="dark"] .dropdown-divider { border-color: var(--dev-color-border); }

[data-theme="dark"] .modal-content {
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}
[data-theme="dark"] .modal-header,
[data-theme="dark"] .modal-footer {
  border-color: var(--dev-color-border);
}

[data-theme="dark"] .list-group-item {
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}

[data-theme="dark"] .bg-white { background-color: var(--dev-color-surface) !important; }
[data-theme="dark"] .bg-light { background-color: var(--dev-color-surface-raised) !important; }
[data-theme="dark"] .text-dark { color: var(--dev-color-text) !important; }
[data-theme="dark"] .text-muted { color: var(--dev-color-text-muted) !important; }
[data-theme="dark"] .border { border-color: var(--dev-color-border) !important; }
[data-theme="dark"] hr { border-color: var(--dev-color-border); }

/* ==========================================================================
   RESKIN LIGERO — componentes nativos de Bootstrap 5 sin reescritura BEM.
   Se usan tal cual (markup y JS de Bootstrap intactos) porque su lógica de
   interacción (foco, animación, posicionamiento) ya funciona bien; solo se
   tematizan con los tokens dev-* para que respeten la paleta y el modo oscuro.
   Componentes: Accordion, Breadcrumb, Carousel, Close button, Collapse,
   Navbar, Offcanvas, Placeholders, Popovers, Scrollspy, Tooltips.
   ========================================================================== */

/* ---- Accordion ---- */
.accordion-button {
  color: var(--dev-color-text);
  background-color: var(--dev-color-surface);
}
.accordion-button:not(.collapsed) {
  color: var(--dev-color-primary);
  background-color: var(--dev-color-primary-light);
}
.accordion-button:focus {
  box-shadow: 0 0 0 0.2rem var(--dev-color-primary-light);
}
.accordion-item {
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border);
}
.accordion-body {
  color: var(--dev-color-text);
}
[data-theme="dark"] .accordion-button { background-color: var(--dev-color-surface); color: var(--dev-color-text); }
[data-theme="dark"] .accordion-button::after { filter: invert(1) grayscale(100%) brightness(200%); }
[data-theme="dark"] .accordion-item { background-color: var(--dev-color-surface); border-color: var(--dev-color-border); }

/* ---- Breadcrumb ---- */
.breadcrumb-item + .breadcrumb-item::before {
  color: var(--dev-color-text-muted);
}
.breadcrumb-item.active {
  color: var(--dev-color-text-muted);
}
.breadcrumb-item a {
  color: var(--dev-color-primary);
  text-decoration: none;
}
.breadcrumb-item a:hover {
  color: var(--dev-color-primary-hover);
}

/* ---- Carousel ---- */
.carousel-indicators [data-bs-target] {
  background-color: var(--dev-color-primary);
}
.carousel-caption {
  background-color: rgba(37, 36, 34, 0.45);
  border-radius: var(--dev-radius-md);
  padding: var(--dev-space-sm) var(--dev-space-md);
}

/* ---- Close button ---- */
[data-theme="dark"] .btn-close {
  filter: invert(1) grayscale(100%) brightness(200%);
}

/* ---- Collapse ---- */
.collapse,
.collapsing {
  color: var(--dev-color-text);
}

/* ---- Navbar ---- */
.navbar {
  background-color: var(--dev-color-surface);
  border-bottom: 1px solid var(--dev-color-border);
}
.navbar-brand,
.navbar-nav .nav-link {
  color: var(--dev-color-text);
}
.navbar-nav .nav-link.active,
.navbar-nav .nav-link:hover {
  color: var(--dev-color-primary);
}
.navbar-toggler {
  border-color: var(--dev-color-border);
}

/* ---- Offcanvas ---- */
.offcanvas {
  background-color: var(--dev-color-surface);
  color: var(--dev-color-text);
}
.offcanvas-header {
  border-bottom: 1px solid var(--dev-color-border);
}
[data-theme="dark"] .offcanvas .btn-close {
  filter: invert(1) grayscale(100%) brightness(200%);
}

/* ---- Placeholders ---- */
.placeholder {
  background-color: var(--dev-color-border);
}
.placeholder-glow .placeholder {
  opacity: 0.6;
}

/* ---- Popovers ---- */
.popover {
  background-color: var(--dev-color-surface);
  border-color: var(--dev-color-border);
  box-shadow: var(--dev-shadow-dropdown);
}
.popover-header {
  background-color: var(--dev-color-surface-raised);
  border-color: var(--dev-color-border);
  color: var(--dev-color-text);
}
.popover-body {
  color: var(--dev-color-text);
}
.bs-popover-top > .popover-arrow::after { border-top-color: var(--dev-color-surface); }
.bs-popover-bottom > .popover-arrow::after { border-bottom-color: var(--dev-color-surface); }
.bs-popover-start > .popover-arrow::after { border-left-color: var(--dev-color-surface); }
.bs-popover-end > .popover-arrow::after { border-right-color: var(--dev-color-surface); }

/* ---- Tooltips ---- */
.tooltip .tooltip-inner {
  background-color: var(--dev-color-secondary);
  color: var(--dev-color-on-secondary);
}
.tooltip.bs-tooltip-top .tooltip-arrow::before { border-top-color: var(--dev-color-secondary); }
.tooltip.bs-tooltip-bottom .tooltip-arrow::before { border-bottom-color: var(--dev-color-secondary); }
.tooltip.bs-tooltip-start .tooltip-arrow::before { border-left-color: var(--dev-color-secondary); }
.tooltip.bs-tooltip-end .tooltip-arrow::before { border-right-color: var(--dev-color-secondary); }

/* ---- Scrollspy ----
   No agrega estilos propios: usa data-bs-spy="scroll" sobre un contenedor y
   marca .active en los .nav-link del nav objetivo, ya tematizados arriba
   (ver .dev-nav-submenu__link--active en layout.css para el caso del sidebar). */

/* ==========================================================================
   HELPERS — utilidades nativas de Bootstrap 5 (Clearfix, Color & background,
   Colored links, Focus ring, Icon link, Position, Ratio, Stacks, Stretched
   link, Text truncation, Vertical rule, Visually hidden). La mayoría
   funciona igual sin tocar nada; aquí solo se tematizan las que dependen
   de color para que respeten la paleta dev-* y el modo oscuro.
   ========================================================================== */

/* ---- Color & background / text-bg-* ---- */
.text-bg-primary   { background-color: var(--dev-color-primary) !important;   color: var(--dev-color-on-primary) !important; }
.text-bg-secondary { background-color: var(--dev-color-secondary) !important; color: var(--dev-color-on-secondary) !important; }
.text-bg-success   { background-color: var(--dev-color-success) !important;   color: var(--dev-color-on-success) !important; }
.text-bg-danger    { background-color: var(--dev-color-danger) !important;    color: var(--dev-color-on-danger) !important; }
.text-bg-warning   { background-color: var(--dev-color-warning) !important;   color: var(--dev-color-on-warning) !important; }
.text-bg-info      { background-color: var(--dev-color-info) !important;      color: var(--dev-color-on-info) !important; }
.bg-secondary { background-color: var(--dev-color-secondary) !important; }
.bg-success    { background-color: var(--dev-color-success) !important; }
.bg-danger     { background-color: var(--dev-color-danger) !important; }
.bg-warning    { background-color: var(--dev-color-warning) !important; }
.bg-info       { background-color: var(--dev-color-info) !important; }

/* ---- Colored links ---- */
.link-primary   { color: var(--dev-color-primary) !important; }
.link-primary:hover, .link-primary:focus { color: var(--dev-color-primary-hover) !important; }
.link-secondary { color: var(--dev-color-secondary-on-surface) !important; }
.link-success   { color: var(--dev-color-success) !important; }
.link-danger    { color: var(--dev-color-danger) !important; }
.link-warning   { color: var(--dev-color-warning-text) !important; }
.link-info      { color: var(--dev-color-info-on-surface) !important; }

/* ---- Focus ring (Bootstrap 5.3) ---- */
:root {
  --bs-focus-ring-color: color-mix(in srgb, var(--dev-color-primary) 35%, transparent);
}

/* ---- Icon link ---- */
.icon-link {
  color: var(--dev-color-primary);
}
.icon-link:hover {
  color: var(--dev-color-primary-hover);
}

/* ---- Vertical rule ---- */
.vr {
  background-color: var(--dev-color-border) !important;
}

