/* ══════════════════════════════════════════════════════════
   core/components.css — Componentes del sistema de diseño
   Requiere core/tokens.css antes.

   Índice
     0. Base            8. Filtros y búsqueda    15. Menú desplegable
     1. Botones         9. Tablas                16. Íconos
     2. Campos         10. Estado vacío          17. Lista de datos
     3. Segmentado     11. Carga (spinner)       18. Barra de progreso
     4. Badges         12. Modal y drawer
     5. Alertas        13. Toasts
     6. Tarjetas       14. Patrones existentes (KPIs, tiles, progreso…)
     7. Encabezado de página
   Guía de uso: docs/sistema-de-diseno.md

   Nombres heredados: algunas reglas también cubren clases viejas
   para que todo el Portal se vea igual YA,
   antes de migrar cada vista. Están marcadas "heredado" — no usarlas en
   código nuevo; se borran cuando la última vista deje de usarlas.
   ══════════════════════════════════════════════════════════ */

/* ── 0. Base ─────────────────────────────────────────────── */
*, *::before, *::after{ box-sizing: border-box; }
html{ scrollbar-gutter: stable; -webkit-text-size-adjust: 100%; }
body{
  margin: 0;
  font-family: var(--font-sans);
  color: var(--text);
  background: var(--bg-canvas);
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--duration-base) ease, color var(--duration-base) ease;
}
[hidden]{ display: none !important; }
::selection{ background: var(--primary-subtle-hover); }

/* Scroll bloqueado mientras hay un modal/drawer abierto: el contenido de
   fondo no se desplaza debajo del overlay. */
html:has(dialog.modal[open], dialog.drawer[open]){ overflow: hidden; }

.sr-only{
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Foco de teclado visible en todo lo interactivo que no tenga uno propio. */
:where(a, button, [role="button"], summary, input, select, textarea, [tabindex]):focus-visible{
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Scroll de marca */
*{ scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar{ width: 10px; height: 10px; }
*::-webkit-scrollbar-track{ background: transparent; }
*::-webkit-scrollbar-thumb{
  background-color: var(--border-strong); border-radius: var(--radius-full);
  border: 2px solid transparent; background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover{ background-color: var(--text-subtle); }
*::-webkit-scrollbar-corner{ background: transparent; }

@keyframes ui-spin{ to{ transform: rotate(360deg); } }
@keyframes ui-fade-in{ from{ opacity: 0; } }
@keyframes ui-fade-out{ to{ opacity: 0; } }


/* ── 1. Botones ──────────────────────────────────────────────
   .btn               secundario (por defecto)
   .btn-primary       acción principal — una por vista/diálogo
   .btn-ghost         acción terciaria, barras de herramientas
   .btn-danger        destructiva confirmada (dentro de un diálogo)
   .btn-danger-soft   destructiva en listados (menos peso visual)
   .btn-link          acción de texto
   Tamaños: .btn-sm / .btn-lg · Forma: .btn-icon · .btn-block
   Estado: .is-loading (lo pone core/ui.js al enviar un formulario)   */
.btn{
  --btn-bg: var(--bg-surface);
  --btn-bg-hover: var(--bg-subtle);
  --btn-fg: var(--text);
  --btn-border: var(--border-strong);
  --btn-border-hover: var(--text-subtle);
  --btn-shadow: var(--shadow-xs);

  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: var(--control-md); padding: 0 14px;
  border: 1px solid var(--btn-border); border-radius: var(--radius-sm);
  background: var(--btn-bg); color: var(--btn-fg);
  box-shadow: var(--btn-shadow);
  font: inherit; font-size: 13.5px; font-weight: var(--weight-semibold); line-height: 1.2;
  white-space: nowrap; text-decoration: none; cursor: pointer; user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease,
              color var(--duration-fast) ease, box-shadow var(--duration-fast) ease;
}
.btn:hover{
  background: var(--btn-bg-hover); border-color: var(--btn-border-hover); color: var(--btn-fg);
}
.btn:active{ box-shadow: none; }
.btn:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.btn i{ font-size: 1.05em; line-height: 1; }

.btn-primary{
  --btn-bg: var(--primary-solid); --btn-bg-hover: var(--primary-solid-hover);
  --btn-fg: var(--text-on-primary);
  --btn-border: var(--primary-solid); --btn-border-hover: var(--primary-solid-hover);
}
.btn-secondary{ /* igual al base: nombre explícito para legibilidad */ }
.btn-ghost{
  --btn-bg: transparent; --btn-bg-hover: var(--bg-muted);
  --btn-border: transparent; --btn-border-hover: transparent; --btn-shadow: none;
  --btn-fg: var(--text-muted);
}
.btn-ghost:hover{ color: var(--text); }
.btn-danger{
  --btn-bg: var(--danger-solid); --btn-bg-hover: color-mix(in srgb, var(--danger-solid) 86%, #000);
  --btn-fg: var(--text-on-primary); --btn-border: var(--danger-solid); --btn-border-hover: color-mix(in srgb, var(--danger-solid) 86%, #000);
}
.btn-danger-soft{
  --btn-bg: var(--bg-surface); --btn-bg-hover: var(--danger-subtle);
  --btn-fg: var(--danger-text);
  --btn-border: color-mix(in srgb, var(--danger) 30%, var(--border));
  --btn-border-hover: color-mix(in srgb, var(--danger) 60%, transparent);
}
.btn-link{
  --btn-bg: transparent; --btn-bg-hover: var(--primary-subtle);
  --btn-border: transparent; --btn-border-hover: transparent; --btn-shadow: none;
  --btn-fg: var(--primary-text);
  padding: 0 10px;
}

.btn-sm{ min-height: var(--control-sm); padding: 0 10px; font-size: var(--text-sm); gap: 6px; }
.btn-lg{ min-height: var(--control-lg); padding: 0 20px; font-size: 14.5px; }
.btn-icon{ width: var(--control-md); min-width: var(--control-md); padding: 0; }
.btn-sm.btn-icon{ width: var(--control-sm); min-width: var(--control-sm); }
.btn-lg.btn-icon{ width: var(--control-lg); min-width: var(--control-lg); }
.btn-block{ display: flex; width: 100%; }

.btn:is([disabled], [aria-disabled="true"], .is-disabled){
  opacity: .5; cursor: not-allowed; pointer-events: none; box-shadow: none;
}
.btn.is-loading{ color: transparent !important; pointer-events: none; }
.btn.is-loading::after{
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--btn-fg); border-right-color: transparent;
  animation: ui-spin .7s linear infinite;
}

.btn-group{ display: inline-flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }

/* Botón que envuelve un <input type="file"> invisible (subir en una fila) */
.file-btn{ position: relative; overflow: hidden; }
.file-btn input[type="file"]{ position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; }


/* ── 2. Campos ──────────────────────────────────────────────
   <div class="field">
     <label class="field-label" for="x">Nombre <span class="req">*</span></label>
     <input class="input" id="x">
     <p class="field-hint">Texto de ayuda</p>
     <p class="field-error">Mensaje de error</p>      (con aria-invalid en el input)
   </div>                                                                */
.field{ display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field-label{
  font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text);
  line-height: var(--leading-tight);
}
.field-label .req{ color: var(--danger); margin-left: 2px; }
.field-label .opt{ color: var(--text-subtle); font-weight: var(--weight-regular); margin-left: 4px; }
.field-hint{ margin: 0; font-size: 12px; color: var(--text-muted); line-height: var(--leading-normal); }
.field-error{
  margin: 0; font-size: 12px; color: var(--danger-text); line-height: var(--leading-normal);
  display: flex; align-items: flex-start; gap: 6px;
}

.input, .select, .textarea{
  display: block; width: 100%;
  min-height: var(--control-md); padding: 8px 12px;
  border: 1px solid var(--border-control); border-radius: var(--radius-sm);
  background: var(--bg-surface); color: var(--text);
  font: inherit; font-size: var(--text-base); line-height: 1.4;
  transition: border-color var(--duration-fast) ease, box-shadow var(--duration-fast) ease, background-color var(--duration-fast) ease;
}
.input::placeholder, .textarea::placeholder{ color: var(--text-subtle); opacity: 1; }
.input:hover, .select:hover, .textarea:hover{ border-color: var(--text-muted); }
.input:focus, .select:focus, .textarea:focus{
  outline: none; border-color: var(--primary); box-shadow: var(--focus-ring);
}
.input:is(:disabled, [readonly]), .select:disabled, .textarea:is(:disabled, [readonly]){
  background: var(--bg-muted); color: var(--text-muted); cursor: not-allowed;
}
.input[readonly], .textarea[readonly]{ cursor: text; }
:is(.input, .select, .textarea)[aria-invalid="true"], .field.is-invalid :is(.input, .select, .textarea){
  border-color: var(--danger);
}
:is(.input, .select, .textarea)[aria-invalid="true"]:focus{
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 22%, transparent);
}
.select{
  appearance: none; -webkit-appearance: none; padding-right: 36px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23857f84' viewBox='0 0 16 16'%3E%3Cpath d='M1.65 5.65a.5.5 0 0 1 .7 0L8 11.29l5.65-5.64a.5.5 0 0 1 .7.7l-6 6a.5.5 0 0 1-.7 0l-6-6a.5.5 0 0 1 0-.7'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 12px;
}
.textarea{ min-height: 92px; padding: 10px 12px; resize: vertical; line-height: var(--leading-normal); }
.input-sm{ min-height: var(--control-sm); padding: 4px 10px; font-size: var(--text-sm); }
.select-inline{ display: inline-block; width: auto; max-width: 240px; }

/* Campo con ícono dentro (búsqueda, etc.) */
.input-group{ position: relative; display: flex; align-items: center; min-width: 0; }
.input-group > .input-icon{
  position: absolute; left: 12px; color: var(--text-subtle); pointer-events: none; font-size: 15px; line-height: 1;
}
.input-group > .input{ padding-left: 36px; }
.input-group > .input-action{ position: absolute; right: 4px; }
.input-group:has(> .input-action) > .input{ padding-right: 40px; }

/* Checkbox / radio / switch */
.check{
  display: flex; align-items: flex-start; gap: 10px;
  font-size: var(--text-base); line-height: 1.4; cursor: pointer; color: var(--text);
}
.check input[type="checkbox"]:not(.switch), .check input[type="radio"],
input[type="checkbox"].checkbox, input[type="radio"].radio{
  width: 16px; height: 16px; margin: 2px 0 0; flex: 0 0 auto;
  accent-color: var(--primary); cursor: pointer;
}
.check-desc{ display: block; color: var(--text-muted); font-size: var(--text-sm); margin-top: 2px; }
.check-group{ display: flex; flex-wrap: wrap; gap: 10px 20px; }

.switch{
  appearance: none; -webkit-appearance: none; flex: 0 0 auto;
  position: relative; width: 36px; height: 20px; margin: 0; cursor: pointer;
  border-radius: var(--radius-full); background: var(--border-control);
  transition: background-color var(--duration-base) ease;
}
.switch::after{
  content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--text-on-primary); box-shadow: var(--shadow-xs);
  transition: transform var(--duration-base) var(--ease-out);
}
.switch:checked{ background: var(--primary-solid); }
.switch:checked::after{ transform: translateX(16px); }
.switch:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.switch:disabled{ opacity: .5; cursor: not-allowed; }

/* Zona de archivo: el <input type="file"> real cubre toda la zona
   (clic y arrastrar funcionan nativos); core/ui.js solo muestra el nombre. */
.file-drop{
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 22px 16px; text-align: center;
  border: 1.5px dashed var(--border-strong); border-radius: var(--radius-md);
  background: var(--bg-subtle); color: var(--text-muted); font-size: var(--text-sm);
  transition: border-color var(--duration-fast) ease, background-color var(--duration-fast) ease;
}
.file-drop > i{ font-size: 24px; color: var(--primary); }
.file-drop strong{ color: var(--text); font-weight: var(--weight-semibold); }
.file-drop input[type="file"]{ position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.file-drop:hover, .file-drop.is-dragover{ border-color: var(--primary); background: var(--primary-subtle); }
.file-drop:focus-within{ border-color: var(--primary); box-shadow: var(--focus-ring); }
.file-drop.has-file{ border-style: solid; border-color: var(--primary); }
.file-drop-name{ font-weight: var(--weight-semibold); color: var(--text); word-break: break-all; }

/* Maquetación de formularios */
.form-stack{ display: flex; flex-direction: column; gap: var(--space-4); }
.form-grid{ display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
.form-grid > .field--full, .form-grid > .span-2{ grid-column: 1 / -1; }
.form-section + .form-section{ margin-top: var(--space-6); padding-top: var(--space-6); border-top: 1px solid var(--border); }
.form-section-title{ margin: 0 0 4px; font-size: var(--text-md); font-weight: var(--weight-semibold); }
.form-section-desc{ margin: 0 0 var(--space-4); font-size: var(--text-sm); color: var(--text-muted); }
.form-actions{ display: flex; justify-content: flex-end; gap: var(--space-2); flex-wrap: wrap; }
@media (max-width: 560px){ .form-grid{ grid-template-columns: 1fr; } }


/* ── 3. Control segmentado / pestañas en píldora ─────────────
   Botones:  <div class="segmented" role="tablist"><button class="segmented-item is-active">…
   Radios:   <div class="segmented"><input type="radio" id=a><label for=a>…
   */
.segmented{
  display: inline-flex; gap: 2px; padding: 3px; max-width: 100%;
  background: var(--bg-muted); border-radius: 10px;
  overflow-x: auto; scrollbar-width: none;
}
.segmented::-webkit-scrollbar{ display: none; }
.segmented-item, .segmented > label{
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 32px; padding: 0 14px; border: 0; border-radius: 8px;
  background: transparent; color: var(--text-muted);
  font: inherit; font-size: 13px; font-weight: var(--weight-semibold); white-space: nowrap;
  text-decoration: none; cursor: pointer;
  transition: background-color var(--duration-fast) ease, color var(--duration-fast) ease, box-shadow var(--duration-fast) ease;
}
.segmented-item:hover, .segmented > label:hover{ color: var(--text); }
.segmented-item:is(.is-active, .active, [aria-selected="true"]),
.segmented > input:checked + label{
  background: var(--bg-raised); color: var(--primary-text); box-shadow: var(--shadow-xs);
}
.segmented-item:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.segmented > input{ position: absolute; opacity: 0; pointer-events: none; }
.segmented > input:focus-visible + label{ box-shadow: var(--focus-ring); }
.segmented--block{ display: flex; width: 100%; }
.segmented--block > *{ flex: 1 1 0; }


/* ── 4. Badges ───────────────────────────────────────────────
   .badge + .badge-{primary|success|warning|danger|info} · .badge-dot
   .badge-accent = .badge-primary (nombre que llega desde la BD en KPIs). */
.badge{
  display: inline-flex; align-items: center; gap: 5px;
  min-height: 22px; padding: 2px 9px; border-radius: var(--radius-full);
  background: var(--bg-muted); color: var(--text);
  font-size: var(--text-xs); font-weight: var(--weight-semibold); line-height: 1.3;
  white-space: nowrap; vertical-align: middle;
}
.badge-primary, .badge-accent{ background: var(--primary-subtle); color: var(--primary-text); }
.badge-success{ background: var(--success-subtle); color: var(--success-text); }
.badge-warning{ background: var(--warning-subtle); color: var(--warning-text); }
.badge-danger{ background: var(--danger-subtle); color: var(--danger-text); }
.badge-info{ background: var(--info-subtle); color: var(--info-text); }
.badge-neutral{ background: var(--bg-muted); color: var(--text-muted); }
.badge-outline{
  background: transparent; border: 1px solid var(--primary); color: var(--primary-text);
  transition: background-color var(--duration-fast) ease, color var(--duration-fast) ease;
}
a.badge-outline:hover{ background: var(--primary-solid); color: var(--text-on-primary); }
.badge-dot::before{
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto;
}
/* Sello de versión de documento (tabla de documentos recientes) */
.tag-stamp{
  display: inline-block; border: 1.5px solid var(--primary); color: var(--primary-text);
  font-weight: var(--weight-bold); font-size: 10.5px; padding: 1px 6px; border-radius: 3px;
}


/* ── 5. Alertas ──────────────────────────────────────────────
   <div class="alert alert-success" role="status">
     <i class="bi bi-check-circle-fill alert-icon"></i>
     <div class="alert-content"><p class="alert-title">…</p><p class="alert-text">…</p></div>
   </div>                                                               */
.alert{
  --alert-accent: var(--info); --alert-bg: var(--info-subtle); --alert-fg: var(--info-text);
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: 12px 14px; margin: 0 0 var(--space-5);
  border: 1px solid color-mix(in srgb, var(--alert-accent) 28%, transparent);
  border-radius: var(--radius-md); background: var(--alert-bg); color: var(--text);
  font-size: var(--text-base); line-height: var(--leading-normal);
}
.alert-success{ --alert-accent: var(--success); --alert-bg: var(--success-subtle); --alert-fg: var(--success-text); }
.alert-warning{ --alert-accent: var(--warning); --alert-bg: var(--warning-subtle); --alert-fg: var(--warning-text); }
.alert-danger{ --alert-accent: var(--danger); --alert-bg: var(--danger-subtle); --alert-fg: var(--danger-text); }
.alert-icon{ flex: 0 0 auto; font-size: 17px; line-height: 1.35; color: var(--alert-accent); }
.alert-content{ flex: 1; min-width: 0; }
.alert-title{ margin: 0; font-weight: var(--weight-semibold); color: var(--alert-fg); }
.alert-text{ margin: 2px 0 0; color: var(--text); }
.alert-title + .alert-text{ color: var(--text-muted); }
.alert-actions{ display: flex; gap: var(--space-2); margin-top: var(--space-3); flex-wrap: wrap; }
.alert-close{
  flex: 0 0 auto; margin: -4px -6px -4px 0; width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-muted); cursor: pointer;
}
.alert-close:hover{ background: color-mix(in srgb, var(--alert-accent) 14%, transparent); color: var(--text); }


/* ── 6. Tarjetas ─────────────────────────────────────────── */
.box-card{
  background: var(--bg-surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  padding: var(--space-6);
}
.box-card--flat{ box-shadow: none; }
.box-card--compact{ padding: var(--space-4); }
.box-card-header{
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.box-card-title{ margin: 0; font-size: var(--text-md); font-weight: var(--weight-semibold); line-height: var(--leading-tight); }
.box-card-desc{ margin: 4px 0 0; font-size: var(--text-sm); color: var(--text-muted); }
.box-card-footer{
  display: flex; justify-content: flex-end; gap: var(--space-2);
  margin: var(--space-5) calc(var(--space-6) * -1) calc(var(--space-6) * -1);
  padding: var(--space-3) var(--space-6);
  border-top: 1px solid var(--border); background: var(--bg-subtle);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}

/* Tile: grilla de elementos clicables (apps, mapa, accesos) — plano hasta
   el hover, así la grilla no suma peso visual constante. */
.tile-grid{ display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--space-4); }
.tile{
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: 18px; text-align: left;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-surface); color: inherit; text-decoration: none; cursor: pointer;
  transition: box-shadow var(--duration-base) ease, border-color var(--duration-base) ease, transform var(--duration-base) var(--ease-out);
}
.tile:hover{ box-shadow: var(--shadow-md); border-color: var(--border-strong); transform: translateY(-1px); }
.tile:focus-visible{ outline: none; box-shadow: var(--focus-ring); }


/* ── 7. Encabezado de página ─────────────────────────────────
   <header class="page-header">
     <div class="page-header-main">
       <a class="page-back" href="…"><i class="bi bi-arrow-left"></i> Volver a …</a>
       <p class="page-eyebrow">Talento Humano</p>
       <h1 class="page-title">Hojas de vida</h1>
       <p class="page-desc">…</p>
     </div>
     <div class="page-actions">…botones…</div>
   </header>
                                                                       */
.page-header{
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: var(--space-4) var(--space-6);
  margin: 0 0 var(--space-8);
}
.page-header-main{ flex: 1 1 420px; min-width: 0; }
.page-back{
  display: inline-flex; align-items: center; gap: 6px; margin: 0 0 var(--space-3);
  font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-muted); text-decoration: none;
  border-radius: var(--radius-xs);
}
.page-back:hover{ color: var(--primary-text); }
@media (pointer: coarse){ .page-back{ min-height: 40px; } }
.page-back i{ transition: transform var(--duration-fast) ease; }
.page-back:hover i{ transform: translateX(-2px); }
.page-eyebrow{
  display: flex; align-items: center; gap: 6px; margin: 0 0 6px;
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--primary-text);
}
.page-title{
  margin: 0 0 6px;
  font-size: var(--text-3xl); font-weight: var(--weight-bold);
  line-height: var(--leading-tight); letter-spacing: -.02em; color: var(--text);
}
.page-desc{
  margin: 0 0 var(--space-8); max-width: 72ch;
  font-size: 14.5px; line-height: var(--leading-relaxed); color: var(--text-muted);
}
.page-header .page-title{ margin-bottom: 0; }
.page-header .page-desc{ margin: 8px 0 0; }
.page-actions{ display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
@media (max-width: 640px){
  .page-header{ margin-bottom: var(--space-6); }
  .page-actions{ width: 100%; }
  .page-actions > .btn{ flex: 1 1 auto; }
}

/* Encabezado de sección dentro de una página */
.section-header{
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: var(--space-2) var(--space-4); margin: 0 0 var(--space-3);
}
.section-heading{
  display: flex; align-items: center; gap: var(--space-2);
  margin: 0; font-size: var(--text-lg); font-weight: var(--weight-semibold); line-height: var(--leading-tight);
}
.section-heading i{ color: var(--primary); font-size: .95em; }
.section-desc{ margin: 2px 0 0; font-size: var(--text-sm); color: var(--text-muted); }
.section-header + .section-desc{ margin: -4px 0 var(--space-3); }
.section-header--spaced{ margin-top: var(--space-10); }
.section-header .section-desc{ margin: 0; }
.section-header .btn-link{ min-height: var(--control-sm); font-size: var(--text-sm); }
.page-section + .page-section{ margin-top: var(--space-10); }

.section-title{ margin: 0 0 14px; }
.subsection{ border-top: 1px solid var(--border); padding-top: var(--space-6); margin-top: var(--space-6); }
.chip-row{ display: flex; flex-wrap: wrap; gap: var(--space-2); }

.text-muted{ color: var(--text-muted); }
.text-accent{ color: var(--primary-text); font-weight: var(--weight-bold); }


/* ── 8. Filtros y búsqueda ───────────────────────────────────
   <div class="filter-bar">
     <form class="input-group search-field" role="search">…</form>
     <div class="chips">…<button class="chip" aria-pressed="true">…</div>
     <div class="filter-bar-end">…acción principal…</div>
   </div>                                                               */
.filter-bar{
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3);
  margin: 0 0 var(--space-4);
}
.filter-bar .search-field{ flex: 1 1 260px; max-width: 420px; }
.filter-bar .select{ width: auto; min-width: 160px; }
.filter-bar-end{ margin-left: auto; display: flex; gap: var(--space-2); flex-wrap: wrap; }
.chips{ display: flex; flex-wrap: wrap; gap: 6px; }
.chip{
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 30px; padding: 0 12px; border-radius: var(--radius-full);
  border: 1px solid var(--border-strong); background: var(--bg-surface); color: var(--text-muted);
  font: inherit; font-size: var(--text-sm); font-weight: var(--weight-medium);
  white-space: nowrap; cursor: pointer; text-decoration: none;
  transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease, color var(--duration-fast) ease;
}
.chip:hover{ color: var(--text); border-color: var(--text-subtle); }
.chip:is(.is-active, .active, [aria-pressed="true"]){
  background: var(--primary-subtle); border-color: color-mix(in srgb, var(--primary) 40%, transparent); color: var(--primary-text);
}
.chip:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.chip-count{ font-size: 11px; color: inherit; opacity: .75; }
@media (max-width: 640px){
  .filter-bar .search-field{ flex-basis: 100%; max-width: none; }
  .filter-bar-end{ margin-left: 0; width: 100%; }
  .filter-bar-end > .btn{ flex: 1; }
  .chips{ flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin: 0 -4px; padding: 2px 4px; }
}


/* ── 9. Tablas ───────────────────────────────────────────────
   <div class="table-wrap">
     <table class="table table--stack">…</table>
   </div>
   .table-wrap   contenedor con borde y scroll horizontal propio.
   .table--stack en móvil cada fila pasa a ser una tarjeta con etiquetas
                 (.table--stack-md: ya desde 960px, para tablas muy anchas)
                 (core/ui.js copia el texto de cada <th> al data-label de su
                 celda; la 1ª celda queda como título de la tarjeta).
   .col-actions  celda de acciones (derecha, sin cortar).
   .col-num      números alineados a la derecha.
   tr[data-href] / .is-clickable  filas navegables (únicas con cursor de mano). */
.table-wrap{
  /* position:relative: sin esto, los .sr-only (position:absolute) de las
     cabeceras escapan del scroll de la tabla y ensanchan toda la página. */
  position: relative;
  background: var(--bg-surface);
  border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-xs);
  overflow-x: auto;
}
.table{
  width: 100%; border-collapse: separate; border-spacing: 0;
  font-size: var(--text-base); color: var(--text);
  background: var(--bg-surface);
  border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-xs);
}
.table-wrap > .table{ border: 0; border-radius: 0; box-shadow: none; background: transparent; }
.table th{
  padding: 10px 16px; text-align: left; vertical-align: middle;
  font-size: 12px; font-weight: var(--weight-semibold); color: var(--text-muted);
  background: var(--bg-subtle); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table thead th:first-child{ border-top-left-radius: calc(var(--radius-md) - 1px); }
.table thead th:last-child{ border-top-right-radius: calc(var(--radius-md) - 1px); }
.table td{
  padding: 12px 16px; vertical-align: middle;
  border-bottom: 1px solid var(--border); font-variant-numeric: tabular-nums;
}
.table tbody tr:last-child td{ border-bottom: 0; }
.table tbody tr{ transition: background-color var(--duration-fast) ease; }
.table tbody tr:hover{ background: var(--bg-subtle); }
.table tbody tr:is([data-href], .is-clickable){ cursor: pointer; }
.table .col-num{ text-align: right; }
.table .col-center{ text-align: center; }
.table .col-actions{ width: 1%; white-space: nowrap; text-align: right; }
.table .cell-muted, .table .col-muted{ color: var(--text-muted); }
.table .cell-strong{ font-weight: var(--weight-semibold); }
.cell-stack{ display: flex; flex-direction: column; gap: 2px; }
.table-actions{ display: inline-flex; align-items: center; justify-content: flex-end; gap: 4px; }
.table-section-row td{
  padding: 8px 16px; background: var(--bg-subtle);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--text-muted);
}
.table--compact th{ padding: 8px 12px; }
.table--compact td{ padding: 8px 12px; }
.table-wrap--sticky{ max-height: min(70vh, 720px); overflow: auto; }
.table-wrap--sticky thead th{ position: sticky; top: 0; z-index: 2; }
.table-wrap--sticky .col-sticky{ position: sticky; left: 0; z-index: 1; background: var(--bg-surface); }
.table-wrap--sticky thead .col-sticky{ z-index: 3; background: var(--bg-subtle); }
.table-footer{
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  padding: 10px 16px; border-top: 1px solid var(--border); font-size: var(--text-sm); color: var(--text-muted);
}

@media (max-width: 640px){
  .table--stack, .table--stack tbody, .table--stack tr, .table--stack td{ display: block; width: 100%; }
  .table--stack thead{ position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table--stack tr{ padding: 14px 16px; border-bottom: 1px solid var(--border); }
  .table--stack tbody tr:last-child{ border-bottom: 0; }
  .table--stack td{
    display: grid; grid-template-columns: minmax(92px, 38%) minmax(0, 1fr); gap: var(--space-3);
    padding: 4px 0; border: 0; text-align: left;
    /* Correos y otras cadenas largas sin espacios (ver .cell-muted con <br>)
       no tenían dónde partirse y se salían de la tarjeta a 320-390px. */
    overflow-wrap: anywhere;
  }
  .table--stack td > *{ grid-column: 2; justify-self: start; min-width: 0; overflow-wrap: anywhere; }
  .table--stack td::before{ content: attr(data-label); font-size: 12px; font-weight: var(--weight-semibold); color: var(--text-muted); }
  .table--stack td:first-child{ display: block; padding-bottom: 8px; font-weight: var(--weight-semibold); font-size: var(--text-md); }
  .table--stack td:first-child::before,
  .table--stack td:is([data-label=""], .col-actions, [colspan])::before{ content: none; }
  .table--stack td:is([data-label=""], [colspan]){ display: block; }
  .table--stack td.col-actions{ display: flex; justify-content: flex-start; width: 100%; padding-top: 10px; }
  .table--stack .col-num{ text-align: left; }
  /* Roles/estados con texto largo (ej. "Administrador de dirección") se
     salían de la tarjeta: el badge es nowrap por diseño, pero en tarjeta
     apilada sí puede partirse a varias líneas. */
  .table--stack td .badge{ white-space: normal; overflow-wrap: anywhere; max-width: 100%; text-align: left; }

}

/* .table--stack-md: tablas con muchas columnas (usuarios, empleados…)
   pasan a tarjetas ya en tablet, en vez de esconder las acciones tras un
   scroll horizontal. Lleva también .table--stack (etiquetas por JS). */
@media (max-width: 960px){
  .table--stack-md, .table--stack-md tbody, .table--stack-md tr, .table--stack-md td{ display: block; width: 100%; }
  .table--stack-md thead{ position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table--stack-md tr{ padding: 14px 16px; border-bottom: 1px solid var(--border); }
  .table--stack-md tbody tr:last-child{ border-bottom: 0; }
  .table--stack-md td{
    display: grid; grid-template-columns: minmax(92px, 38%) minmax(0, 1fr); gap: var(--space-3);
    padding: 4px 0; border: 0; text-align: left;
    overflow-wrap: anywhere;
  }
  .table--stack-md td > *{ grid-column: 2; justify-self: start; min-width: 0; overflow-wrap: anywhere; }
  .table--stack-md td::before{ content: attr(data-label); font-size: 12px; font-weight: var(--weight-semibold); color: var(--text-muted); }
  .table--stack-md td:first-child{ display: block; padding-bottom: 8px; font-weight: var(--weight-semibold); font-size: var(--text-md); }
  .table--stack-md td:first-child::before,
  .table--stack-md td:is([data-label=""], .col-actions, [colspan])::before{ content: none; }
  .table--stack-md td:is([data-label=""], [colspan]){ display: block; }
  .table--stack-md td.col-actions{ display: flex; justify-content: flex-start; width: 100%; padding-top: 10px; }
  .table--stack-md .col-num{ text-align: left; }
  .table--stack-md td .badge{ white-space: normal; overflow-wrap: anywhere; max-width: 100%; text-align: left; }

}

@media (max-width: 640px){
  /* Tablas aún sin .table--stack ni .table-wrap: al menos scroll propio,
     sin empujar toda la página. */
  .table:not(.table--stack){ display: block; overflow-x: auto; }
  .table-wrap > .table:not(.table--stack){ display: table; }
}


/* ── 10. Estado vacío ────────────────────────────────────────
   <div class="empty-state">
     <div class="ic"><i class="bi bi-inbox"></i></div>
     <h4>Título</h4><p>Explicación</p>
     <div class="empty-state-actions">…</div>
   </div>
   .empty-state--compact para dentro de tarjetas/widgets/celdas.        */
.empty-state{
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--space-10) var(--space-6); margin: 0;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-md);
  background: var(--bg-surface); color: var(--text);
}
.empty-state .ic{
  display: grid; place-items: center; width: 48px; height: 48px; margin-bottom: var(--space-3);
  border-radius: 50%; background: var(--primary-subtle); color: var(--primary); font-size: 21px;
}
.empty-state :is(h3, h4, .empty-state-title){ margin: 0; font-size: var(--text-md); font-weight: var(--weight-semibold); }
.empty-state p{ margin: 6px 0 0; max-width: 52ch; color: var(--text-muted); font-size: var(--text-base); line-height: var(--leading-normal); }
.empty-state-actions, .empty-state form{ display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); margin-top: var(--space-5); }
.empty-state--compact{
  flex-direction: row; align-items: center; text-align: left; gap: var(--space-3);
  padding: 14px 16px;
}
.empty-state--compact .ic{ width: 34px; height: 34px; margin: 0; font-size: 16px; flex: 0 0 auto; }
.empty-state--compact p{ margin: 0; font-size: var(--text-sm); }
.empty-state--bare{ border: 0; background: transparent; }


/* ── 11. Carga ───────────────────────────────────────────── */
.spinner{
  display: inline-block; width: 18px; height: 18px; vertical-align: middle; flex: 0 0 auto;
  border: 2px solid color-mix(in srgb, currentColor 22%, transparent); border-top-color: currentColor;
  border-radius: 50%; animation: ui-spin .7s linear infinite;
}
.spinner-sm{ width: 14px; height: 14px; }
.spinner-lg{ width: 28px; height: 28px; border-width: 3px; }
.loading-block{
  display: flex; align-items: center; justify-content: center; gap: var(--space-3);
  padding: var(--space-8); color: var(--text-muted); font-size: var(--text-sm);
}
@keyframes ui-shimmer{ to{ background-position: -200% 0; } }
.skeleton{
  display: block; min-height: 12px; border-radius: var(--radius-xs);
  background: linear-gradient(90deg, var(--bg-muted) 25%, color-mix(in srgb, var(--bg-muted) 45%, var(--bg-surface)) 50%, var(--bg-muted) 75%);
  background-size: 200% 100%; animation: ui-shimmer 1.4s ease-in-out infinite;
}
.skeleton-text{ height: 12px; margin: 8px 0; }
.skeleton-title{ height: 18px; width: 45%; margin-bottom: 12px; }
.skeleton-circle{ border-radius: 50%; }
@media (prefers-reduced-motion: reduce){ .skeleton, .spinner, .btn.is-loading::after{ animation-duration: 2.4s; } }


/* ── 12. Modal y drawer ──────────────────────────────────────
   Ambos son <dialog> nativo (foco atrapado, Esc, capa superior, inert en
   el fondo). core/ui.js agrega: abrir con [data-open="id"], cerrar con
   [data-close], clic en el overlay, animación de salida y devolución del
   foco al botón que lo abrió.

   <dialog class="modal" id="x" aria-labelledby="x-t">
     <form method="post" action="…">          (opcional: display:contents)
       <header class="modal-header">
         <div class="modal-heading"><h2 class="modal-title" id="x-t">…</h2><p class="modal-desc">…</p></div>
         <button type="button" class="modal-close" data-close aria-label="Cerrar"><i class="bi bi-x-lg"></i></button>
       </header>
       <div class="modal-body">…campos…</div>
       <footer class="modal-footer">
         <button type="button" class="btn" data-close>Cancelar</button>
         <button class="btn btn-primary">Guardar</button>
       </footer>
     </form>
   </dialog>
   Drawer: igual, con class="drawer". Tamaños: .modal-sm/.modal-lg, .drawer-lg.
   En móvil el modal pasa a hoja inferior y el drawer ocupa todo el ancho. */
dialog.modal, dialog.drawer{
  padding: 0; margin: auto; border: 1px solid var(--border);
  max-width: none; max-height: none; overflow: hidden;
  background: var(--bg-surface); color: var(--text);
  box-shadow: var(--shadow-lg);
  font-family: var(--font-sans); font-size: var(--text-base);
}
dialog.modal[open], dialog.drawer[open]{ display: flex; flex-direction: column; }
dialog.modal > form, dialog.drawer > form{ display: contents; }
dialog.modal::backdrop, dialog.drawer::backdrop{
  background: rgba(24, 18, 22, .52); /* = --bg-overlay (claro); hardcoded porque ::backdrop no hereda var() en todos los navegadores */
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
}
body[data-tema="oscuro"] dialog:is(.modal, .drawer)::backdrop{ background: rgba(6, 4, 8, .66); }

.modal-header{
  flex: 0 0 auto; display: flex; align-items: flex-start; gap: var(--space-3);
  padding: 20px 24px 4px;
}
.modal-heading{ flex: 1 1 auto; min-width: 0; }
.modal-title{
  margin: 0; font-size: var(--text-lg); font-weight: var(--weight-semibold);
  line-height: var(--leading-tight); letter-spacing: -.01em;
}
.modal-desc{ margin: 4px 0 0; font-size: 13.5px; line-height: var(--leading-normal); color: var(--text-muted); }
.modal-icon{
  flex: 0 0 auto; display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: 50%; font-size: 18px;
  background: var(--primary-subtle); color: var(--primary);
}
.modal-icon--danger{ background: var(--danger-subtle); color: var(--danger); }
.modal-icon--success{ background: var(--success-subtle); color: var(--success); }
.modal-close{
  flex: 0 0 auto; margin: -4px -8px 0 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-muted); font-size: 15px; cursor: pointer;
  transition: background-color var(--duration-fast) ease, color var(--duration-fast) ease;
}
.modal-close:hover{ background: var(--bg-muted); color: var(--text); }
.modal-close:focus-visible{ outline: none; box-shadow: var(--focus-ring); }
.modal-body{
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px 24px 24px;
}
.modal-body > .segmented:first-child{ margin-bottom: var(--space-4); }
/* Barra fija entre cabecera y cuerpo (pestañas de un modal con varias
   acciones, cada una su propio <form data-tab-panel>). */
.modal-toolbar{ flex: 0 0 auto; padding: 12px 24px 0; }
.modal-footer{
  flex: 0 0 auto; display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap;
  gap: var(--space-2);
  padding: 14px 24px; border-top: 1px solid var(--border); background: var(--bg-subtle);
}
.modal-footer-start{ margin-right: auto; font-size: var(--text-sm); color: var(--text-muted); }

/* Modal centrado */
dialog.modal{
  width: min(520px, calc(100vw - 32px));
  max-height: min(760px, calc(100dvh - 48px));
  border-radius: var(--radius-lg);
}
dialog.modal.modal-sm{ width: min(420px, calc(100vw - 32px)); }
dialog.modal.modal-lg{ width: min(760px, calc(100vw - 32px)); }
dialog.modal[open]{ animation: ui-modal-in var(--duration-slow) var(--ease-out); }
dialog.modal[open]::backdrop{ animation: ui-fade-in var(--duration-slow) ease; }
dialog.modal.is-closing{ animation: ui-modal-out 150ms ease-in forwards; }
dialog.modal.is-closing::backdrop{ animation: ui-fade-out 150ms ease-in forwards; }
@keyframes ui-modal-in{ from{ opacity: 0; transform: translateY(10px) scale(.98); } }
@keyframes ui-modal-out{ to{ opacity: 0; transform: translateY(6px) scale(.98); } }

/* Confirmación (la arma core/ui.js): ícono + texto, sin cuerpo */
dialog.modal-confirm .modal-header{ padding: 22px 24px 20px; gap: var(--space-4); }
dialog.modal-confirm .modal-desc{ margin-top: 6px; }

/* Drawer lateral */
dialog.drawer{
  position: fixed; inset: 0 0 0 auto; margin: 0;
  width: min(480px, 100vw); height: 100dvh;
  border-width: 0 0 0 1px; border-radius: var(--radius-lg) 0 0 var(--radius-lg);
}
dialog.drawer.drawer-sm{ width: min(400px, 100vw); }
dialog.drawer.drawer-lg{ width: min(640px, 100vw); }
dialog.drawer .modal-header{ padding: 20px 24px 16px; border-bottom: 1px solid var(--border); }
dialog.drawer .modal-body{ padding: 24px; }
dialog.drawer[open]{ animation: ui-drawer-in var(--duration-slow) var(--ease-out); }
dialog.drawer[open]::backdrop{ animation: ui-fade-in var(--duration-slow) ease; }
dialog.drawer.is-closing{ animation: ui-drawer-out 180ms var(--ease-in-out) forwards; }
dialog.drawer.is-closing::backdrop{ animation: ui-fade-out 180ms ease forwards; }
@keyframes ui-drawer-in{ from{ transform: translateX(100%); } }
@keyframes ui-drawer-out{ to{ transform: translateX(100%); } }

@media (max-width: 600px){
  dialog.modal, dialog.modal.modal-sm, dialog.modal.modal-lg{
    width: 100%; max-height: 92dvh; margin: auto 0 0;
    border-width: 1px 0 0; border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
  dialog.modal[open]{ animation-name: ui-sheet-in; }
  dialog.modal.is-closing{ animation: ui-sheet-out 180ms var(--ease-in-out) forwards; }
  dialog.drawer, dialog.drawer.drawer-sm, dialog.drawer.drawer-lg{ width: 100vw; border-radius: 0; border-width: 0; }
  .modal-header{ padding: 18px 18px 4px; }
  dialog.drawer .modal-header{ padding: 16px 18px 14px; }
  .modal-body, dialog.drawer .modal-body{ padding: 14px 18px 20px; }
  .modal-toolbar{ padding: 12px 18px 0; }
  .modal-footer{ padding: 12px 18px calc(12px + env(safe-area-inset-bottom)); }
  .modal-footer > .btn{ flex: 1 1 0; }
  .modal-footer-start{ flex-basis: 100%; }
  /* Un .segmented--block de 3-4 pestañas (ej. "Agregar" del explorador
     documental: Carpeta/Archivo/Drive/Nuevo) no cabe en una fila a este
     ancho — .segmented trae overflow-x:auto sin ninguna pista visual de
     scroll, así que la pestaña activa puede quedar fuera de vista contra
     el borde del modal. Envolver en 2 filas es más legible que un scroll
     invisible. */
  .segmented--block{ flex-wrap: wrap; overflow: visible; }
  .segmented--block > *{ flex: 1 1 40%; }
}
@keyframes ui-sheet-in{ from{ transform: translateY(100%); } }
@keyframes ui-sheet-out{ to{ transform: translateY(100%); } }


/* ── 13. Toasts ──────────────────────────────────────────────
   Se crean con UI.toast({ type, title, text }) — ver core/ui.js. */
.toast-region{
  position: fixed; top: 16px; right: 16px; z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--space-2);
  width: min(380px, calc(100vw - 32px)); pointer-events: none;
}
.toast{
  --toast-accent: var(--info);
  position: relative; overflow: hidden; pointer-events: auto;
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: 12px 12px 14px 14px;
  background: var(--bg-surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-md);
  font-size: var(--text-base); line-height: var(--leading-normal);
  animation: ui-toast-in var(--duration-slow) var(--ease-out);
}
.toast.is-leaving{ animation: ui-toast-out 160ms ease-in forwards; }
.toast-success{ --toast-accent: var(--success); }
.toast-warning{ --toast-accent: var(--warning); }
.toast-error, .toast-danger{ --toast-accent: var(--danger); }
.toast-icon{ flex: 0 0 auto; font-size: 18px; line-height: 1.25; color: var(--toast-accent); }
.toast-avatar{ flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%; object-fit: cover; }
.toast-content{ flex: 1; min-width: 0; }
.toast-title{ margin: 0; font-weight: var(--weight-semibold); }
.toast-text{ margin: 2px 0 0; font-size: var(--text-sm); color: var(--text-muted); }
.toast-close{
  flex: 0 0 auto; margin: -4px -4px 0 0; width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text-subtle); cursor: pointer;
}
.toast-close:hover{ background: var(--bg-muted); color: var(--text); }
.toast-progress{
  position: absolute; left: 0; bottom: 0; height: 3px; width: 100%;
  background: var(--toast-accent); opacity: .7; transform-origin: left;
  animation: ui-toast-progress linear forwards;
}
.toast:is(:hover, :focus-within) .toast-progress{ animation-play-state: paused; }
@keyframes ui-toast-in{ from{ opacity: 0; transform: translateY(-8px); } }
@keyframes ui-toast-out{ to{ opacity: 0; transform: translateX(16px); } }
@keyframes ui-toast-progress{ to{ transform: scaleX(0); } }
@media (max-width: 600px){
  .toast-region{ left: 12px; right: 12px; top: 12px; width: auto; }
}


/* ── 14. Patrones existentes ─────────────────────────────── */

/* KPIs */
.kpis{
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs); overflow: hidden;
}
.kpi{ position: relative; padding: 18px 20px; border-right: 1px solid var(--border); }
.kpi:last-child{ border-right: 0; }
@media (max-width: 640px){
  /* La grilla auto-fit cae a 1 columna en pantallas angostas: el separador
     vertical deja de verse (queda pegado al borde derecho de la tarjeta).
     Se cambia a un separador horizontal entre métricas apiladas. */
  .kpi{ border-right: 0; border-bottom: 1px solid var(--border); }
  .kpi:last-child{ border-bottom: 0; }
}
.kpi-head{ display: flex; align-items: center; gap: 7px; }
.kpi-ic{ font-size: 13px; color: var(--primary); }
.kpi-label, .kpi-value{ margin: 0; }
.kpi-label{ font-size: 12px; font-weight: var(--weight-semibold); color: var(--text-muted); }
.kpi-value{ font-weight: var(--weight-bold); font-size: 28px; letter-spacing: -.03em; font-variant-numeric: tabular-nums; padding: 6px 0 4px; }
.kpi-foot{ display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); min-height: 22px; }
.kpi-spark{ flex: 0 0 auto; display: flex; opacity: .85; }

/* Barra de progreso */
.progress-cell{ width: 180px; }
.progress-track{ display: block; height: 6px; background: var(--bg-muted); border-radius: var(--radius-full); overflow: hidden; }
.progress-fill{ display: block; height: 6px; background: var(--primary); border-radius: var(--radius-full); transition: width .6s var(--ease-out); }

/* Estado vacío dentro de una grilla de KPIs: ocupa toda la fila, sin
   borde propio (la grilla ya es la caja). */
:is(.kpis, .modulo-kpis) > .empty-state{ grid-column: 1 / -1; border: 0; }


/* ── 15. Menú desplegable ────────────────────────────────────
   <div class="dropdown">
     <button class="btn btn-ghost btn-icon" data-dropdown="menuX"
             aria-expanded="false" aria-controls="menuX" aria-label="…">…</button>
     <div class="dropdown-menu" id="menuX" role="menu" hidden>
       <p class="dropdown-label">Sección</p>
       <button class="dropdown-item" role="menuitem">…</button>
       <hr class="dropdown-divider">
       <a class="dropdown-item" role="menuitem" href="…">…</a>
     </div>
   </div>
   core/ui.js: abre con clic/toque/Enter/Espacio, flechas ↑↓/Inicio/Fin
   entre ítems, Esc o clic fuera cierra y devuelve el foco.
   .dropdown-menu--end alinea el menú al borde derecho del disparador. */
.dropdown{ position: relative; display: inline-flex; }
.dropdown-menu{
  position: absolute; top: calc(100% + 6px); left: 0; z-index: var(--z-dropdown);
  min-width: 200px; max-width: min(320px, calc(100vw - 24px)); padding: var(--space-1);
  background: var(--bg-surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-md); box-shadow: var(--shadow-md);
  animation: ui-menu-in var(--duration-base) var(--ease-out);
}
.dropdown-menu[hidden]{ display: none; }
.dropdown-menu--end{ left: auto; right: 0; }
@keyframes ui-menu-in{ from{ opacity: 0; transform: translateY(-4px); } }
.dropdown-label{
  margin: 0; padding: 8px 10px 4px;
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--text-muted);
}
.dropdown-item{
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 36px; padding: 0 10px; margin: 0;
  border: 0; border-radius: var(--radius-sm); background: transparent; color: var(--text);
  font: inherit; font-size: var(--text-base); text-align: left; text-decoration: none; cursor: pointer;
}
.dropdown-item > i{ width: 18px; flex: 0 0 auto; text-align: center; color: var(--text-muted); }
.dropdown-item:hover, .dropdown-item:focus-visible{ background: var(--bg-muted); outline: none; }
.dropdown-item:focus-visible{ box-shadow: var(--focus-ring); }
.dropdown-item[aria-checked="true"]{ color: var(--primary-text); font-weight: var(--weight-semibold); }
.dropdown-item[aria-checked="true"] > i{ color: inherit; }
.dropdown-item-check{ margin-left: auto; visibility: hidden; }
.dropdown-item[aria-checked="true"] .dropdown-item-check{ visibility: visible; }
.dropdown-item--danger{ color: var(--danger-text); }
.dropdown-item--danger > i{ color: inherit; }
.dropdown-divider{ height: 1px; margin: var(--space-1) 0; border: 0; background: var(--border); }
@media (pointer: coarse){ .dropdown-item{ min-height: 44px; } }


/* ── 16. Íconos ──────────────────────────────────────────────
   Una sola familia (Bootstrap Icons). Los íconos decorativos llevan
   aria-hidden="true"; los botones solo-ícono, aria-label. */
.bi{ line-height: 1; vertical-align: -.125em; }
.btn > .bi, .badge > .bi, .chip > .bi{ vertical-align: 0; }


/* ── 17. Lista de datos (clave → valor) ─────────────────────── */
.data-list{ margin: 0; border: 1px solid var(--border); border-radius: var(--radius-md); }
.data-list > div{ display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-4); padding: 12px 14px; }
.data-list > div + div{ border-top: 1px solid var(--border); }
.data-list dt{ font-size: var(--text-sm); color: var(--text-muted); }
.data-list dd{ margin: 0; font-weight: var(--weight-semibold); text-align: right; overflow-wrap: anywhere; }


/* ── 18. Barra de progreso con etiqueta ─────────────────────── */
.meter{ padding: 9px 0; }
.meter + .meter{ border-top: 1px solid var(--border); }
.meter-head{ display: flex; justify-content: space-between; gap: var(--space-3); padding-bottom: 6px; font-size: var(--text-sm); }
.meter-head strong{ font-variant-numeric: tabular-nums; }
