/* ── Tipografía ─────────────────────────────────────────────────────────────
   Inter es la fuente de las siete aplicaciones de la familia; ésta era la única
   con interfaz real que seguía con la pila del sistema, y es la divergencia que
   más se nota: cada glifo de las 50 pantallas era distinto al de las otras seis.

   Va servida desde el propio dominio, no por @import de Google Fonts como en
   las apps hermanas, y por dos motivos que mandan sobre el estándar:

     · La CSP declara `font-src 'self'` y `style-src 'self'`
       (SecurityHeadersMiddleware): ni la hoja importada ni el .woff2 de
       fonts.gstatic.com pasarían la política.
     · El proyecto no tiene Composer ni build step, así que todo lo de terceros
       se vendoriza a mano con su licencia al lado — igual que Chart.js y
       qrcodejs en public/js/vendor/. Ver public/fonts/LICENSE.txt (SIL OFL 1.1).

   Un solo archivo por subconjunto: la fuente es variable y cubre de 400 a 800,
   que son los cuatro pesos que usa la familia, en una petición en vez de
   cuatro. `font-display: swap` deja el texto legible desde el primer pintado
   con la pila del sistema detrás, que sigue siendo el respaldo de la cascada. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/inter-latin-var.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../fonts/inter-latin-ext-var.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: light;
  /* Toast del kit (ux.css): sin cabecera arriba en el back-office; con ella en el portal. */
  --ux-toast-top: 20px;

  /* Azules (estructura, headers, texto de marca) */
  --navy:       #192F50;
  --navy-mid:   #264168;
  --navy-light: #304F7B;

  /* Naranjas / dorado (marca, acción, foco, énfasis) */
  --gold:       #FF8300;
  --gold-light: #FFA83D;

  /* ── Derivados de marca ───────────────────────────────────────────────
     Acá viven los valores de la casa; para una empresa con colores propios
     los recalcula en el servidor App\Core\BrandPalette y los reescribe en un
     <style> del <head>, después de esta hoja. Ningún otro punto del
     repositorio vuelve a escribir un color de marca: antes había once reglas
     con el navy literal metido en un rgba(), de modo que una empresa con
     marca naranja veía sombras, píldoras y avisos azules.

     --navy es la TINTA de marca (57 de sus usos son texto o borde sobre
     blanco). Cuando el mismo color hace de superficie con algo escrito
     encima, la regla usa --brand-surface para el fondo y --on-brand para lo
     que va encima: --on-brand es blanco salvo que el color de la empresa no
     dé contraste suficiente, en cuyo caso pasa a tinta oscura. Son dos
     papeles incompatibles del mismo color y por eso llevan nombres distintos. */
  --brand-surface:       var(--navy);
  --on-brand:            #fff;                 /* tinta principal sobre la marca */
  --on-brand-soft:       rgba(255,255,255,.85);/* cuerpo del aviso de error */
  --on-brand-dim:        rgba(255,255,255,.65);/* enlace de menú en reposo */
  --on-brand-veil:       rgba(255,255,255,.1); /* divisores y fondo del ítem activo */
  --on-brand-film:       rgba(255,255,255,.06);/* velo del hover */
  /* Letra sobre el acento (--gold): botón de acción, paso activo, distintivo.
     A diferencia de --on-brand no se calcula por contraste: la empresa la elige,
     blanco o negro, y sin elección es blanco (ver BrandPalette). */
  --on-accent:           #fff;

  --brand-tint:          rgba(25,47,80,.08);   /* píldora neutra, filo de la tarjeta de login */
  --brand-tint-soft:     rgba(25,47,80,.06);   /* fondo del aviso informativo */
  --brand-shadow:        rgba(25,47,80,.06);   /* tarjetas, paneles y tablas */
  --brand-shadow-strong: rgba(25,47,80,.14);   /* menú de filtro, hover de las tarjetas-KPI */
  --brand-glow:          rgba(25,47,80,.25);   /* halo del botón primario */
  --brand-ring:          rgba(25,47,80,.28);   /* anillo de la casilla ocupada de la matriz */
  --brand-soft:          #eef2f8;              /* relleno del «proceso» del diagrama */
  --code-bg:             #eef0f4;              /* chip de código (CTRL-01, CONSENT) */
  --code-text:           #48536b;

  --accent-glow:         rgba(255,131,0,.25);  /* halo del botón secundario */
  --accent-tint:         #fffaf3;              /* hover de la zona de carga */

  /* Neutros. --cream-2 y --gray-2 son los dos escalones intermedios de la
     familia; los usa el degradado del esqueleto de carga (ver el bloque
     .sk-* al final de este archivo). */
  --cream:   #f5f0e8;
  --cream-2: #efe9de;
  --white:   #fff;
  --gray:    #e8e4dc;
  --gray-2:  #d9d3c7;
  --text:    #1a1a2e;
  --sub:     #5a6070;

  /* Líneas: borde de tarjeta, divisor interno, hover de fila */
  --line:      #ece6da;
  --line-soft: #f0ece3;
  --row-hover: #faf8f3;

  /* Kit de campos (§3.3 del estándar). Hasta acá el fondo era el mismo
     #faf8f3 del hover de fila y el borde salía de --line, el de las tarjetas:
     tres papeles distintos compartiendo dos valores. */
  --field-bg:     #fafaf8;
  --field-border: var(--gray);
  --field-focus:  var(--gold);

  /* Semánticos de estado (mismos en tablas, chips, stats y feedback).
     Son los valores del estándar (§3.2): los únicos de la familia calibrados a
     propósito para leerse como TEXTO sobre fondo claro. Los de antes acá
     —#2f8f4e y #c67a10— se quedaban en 4,07:1 y 3,39:1, y .state y .chip los
     dibujan a 11 y 10 px. --err ya coincidía. */
  --ok:    #1e8449;   /* activo / vigente / cumple */
  --warn:  #d1810c;   /* borrador / atención / parcial */
  --crit:  #c05f1c;   /* confidencial / crítico */
  --slate: #8a93a6;   /* interno / neutro */
  --err:   #c0392b;   /* error / vencido */

  /* Relleno: puntos, barras y conectores, donde no hay texto encima y el tono
     vivo se lee mejor que el oscuro. NUNCA como letra — es justo lo que hacía
     que estos valores no pasaran AA en el resto de la familia. */
  --ok-fill:   #2ecc71;
  --warn-fill: #e67e22;
  --err-fill:  #e74c3c;

  /* Letra sobre el tinte del mismo estado, donde el semántico a secas no
     contrasta con su propio fondo. Estaban escritos a mano en cuatro reglas. */
  --ok-text:   #256b3c;
  --warn-text: #94590b;

  /* Filo del aviso de error. Más claro que --err a propósito: es el único
     rojo que se dibuja sobre el azul marino (--navy), donde --err queda
     demasiado apagado para leerse como borde. Mismo tono que el resto de
     la familia de apps. */
  --err-line: #e74c3c;

  /* Barra lateral del chasis de operación (§2 del estándar: --sb-w/--sb-w-min
     con los mismos nombres y valores que Control-de-Horas y Seguimiento). */
  --sb-w:     264px;
  --sb-w-min: 76px;

  /* Radios de esquina: base, tarjeta grande, botón */
  --r:     6px;
  --r-lg:  14px;
  --r-btn: 10px;

  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;
  color: var(--text);
  background: var(--cream);
}

* { box-sizing: border-box; }
*::before, *::after { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  background: var(--cream);
  color: var(--text);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--navy-mid); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { color: var(--navy); }
h2 { font-size: 17px; font-weight: 700; margin: 0 0 0.9rem; }
h3 { font-size: 14px; font-weight: 700; margin: 0 0 0.6rem; }

.container { width: min(1280px, calc(100% - 2rem)); margin: 0 auto; }
.shell { padding: 1rem 0; }
.page { padding: 2rem 0 3rem; }

.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; }
.muted { color: var(--sub); }

/* Texto sólo para lectores de pantalla (cabeceras de columnas de acciones,
   etiquetas de botones que son puro ícono). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Portal público (layouts/portal.php, layouts/marketing.php) ───────── */
.site-header { background: var(--brand-surface); color: var(--on-brand); box-shadow: 0 2px 20px rgba(0,0,0,.4); border-bottom: 3px solid var(--gold); }
.site-header .shell { display: flex; justify-content: space-between; align-items: center; gap: 1rem; }
.brand { color: var(--on-brand); font-weight: 700; text-decoration: none; }
.brand:hover { text-decoration: none; color: var(--gold-light); }
.site-nav { display: flex; align-items: center; gap: 1rem; }
.site-nav a { color: var(--on-brand-dim); font-weight: 500; }
.site-nav a:hover { color: var(--on-brand); text-decoration: none; }
.site-nav .btn.secondary { padding: 6px 14px; font-size: 12px; box-shadow: none; }
.site-footer { text-align: center; border-top: 3px solid var(--gold); }
.site-footer .shell { padding: 1rem 0; font-size: 12px; color: var(--sub); }

/* ── Back-office (layouts/app.php): sidebar navy estática ─────────────── */
.app-shell { display: flex; align-items: stretch; min-height: 100vh; }
.sidebar {
  width: var(--sb-w);
  flex-shrink: 0;
  background: var(--brand-surface);
  color: var(--on-brand);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}
.sidebar-brand {
  display: block;
  padding: 1rem 1.1rem;
  color: var(--on-brand);
  font-weight: 700;
  font-size: 16px;
  border-bottom: 1px solid var(--on-brand-veil);
}
.sidebar-brand:hover { text-decoration: none; color: var(--gold-light); }
.sidebar-nav { display: flex; flex-direction: column; flex: 1; padding: 0.75rem 0; overflow-y: auto; }
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--on-brand-dim);
  font-size: 13px;
  font-weight: 500;
  padding: 0.55rem 1.1rem;
  border-left: 3px solid transparent;
  transition: background-color var(--ux-dur), color var(--ux-dur), border-color var(--ux-dur);
}
.sidebar-nav a:hover { background: var(--on-brand-film); color: var(--on-brand); text-decoration: none; }
.sidebar-nav a.active { background: var(--on-brand-veil); color: var(--on-brand); border-left-color: var(--gold); font-weight: 700; }
.nav-icon { flex-shrink: 0; width: 1.3em; display: inline-flex; align-items: center; justify-content: center; }
.sidebar-footer { padding: 1rem 1.1rem; border-top: 1px solid var(--on-brand-veil); }
.sidebar-company { display: block; color: var(--gold); font-size: 0.85rem; font-weight: 600; margin-bottom: 0.15rem; }
.sidebar-user { display: block; color: var(--on-brand-dim); font-size: 0.8rem; margin-bottom: 0.6rem; }
.sidebar-footer .btn {
  width: 100%;
  background: transparent;
  border-color: var(--gold);
  color: var(--gold);
}
.sidebar-footer .btn:hover { background: var(--gold); border-color: var(--gold); color: var(--navy); }
.sidebar-account {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.6rem;
  color: var(--on-brand-dim);
  font-size: 0.8rem;
  text-decoration: none;
}
.sidebar-account .ic { width: 14px; height: 14px; flex: none; }
.sidebar-account:hover { color: var(--gold); }

.app-content { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-content .page { flex: 1; }
/* El chasis de operación trabaja más ancho que el portal público: son tablas
   densas con muchas columnas. 1400 px centrados, como Control-de-Horas y
   Seguimiento (§2); el .container de 1280 sigue valiendo para el portal y la
   landing, que son texto. */
.app-content .container { width: min(1400px, calc(100% - 2rem)); }

.app-footer { padding: 1.5rem 0; text-align: center; font-size: 12px; color: var(--navy); }

/* ── Consola de plataforma (layouts/admin.php) ────────────────────────── */
/* Misma barra lateral navy que el back-office: lo que marca el contexto es
   el distintivo naranja bajo la marca, no un color distinto de chasis. */
.sidebar-brand-block { padding: 1rem 1.1rem; border-bottom: 1px solid var(--on-brand-veil); }
.sidebar-brand-block .sidebar-brand { padding: 0; border-bottom: none; }
.console-badge {
  display: inline-block;
  margin-top: 0.5rem;
  padding: 3px 8px;
  border: 1px solid var(--gold);
  border-radius: 4px;
  color: var(--gold);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}
.sidebar-section {
  margin: 1rem 0 0.35rem;
  padding: 0 1.1rem;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(255,255,255,.35);
}
.sidebar-nav > .sidebar-section:first-child { margin-top: 0; }
/* Módulo de la consola aún no construido: se ve, no se pulsa. */
.sidebar-soon {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 1.1rem;
  border-left: 3px solid transparent;
  color: rgba(255,255,255,.3);
  font-size: 13px;
  font-weight: 500;
  cursor: default;
}
.sidebar-soon em {
  margin-left: auto;
  font-size: 9px;
  font-style: normal;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: rgba(255,255,255,.25);
}

/* Recuento junto al título («Empresas 38»). */
.page-title-count { font-size: 20px; font-weight: 400; color: var(--slate); letter-spacing: 0; }

/* Subdominio bajo el nombre de la empresa, en la celda de la tabla. */
.cell-host { display: block; margin-top: 2px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; color: var(--sub); }
.plan-chip { letter-spacing: .8px; }

/* Botón redondo de «entrar como cliente», al final de cada fila. */
.btn-impersonate {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1.5px solid var(--gold);
  border-radius: 50%;
  background: #fff;
  color: var(--gold);
  cursor: pointer;
}
.btn-impersonate .ic { width: 14px; height: 14px; }
.btn-impersonate:hover { background: var(--gold); color: var(--on-accent); text-decoration: none; }

.table-note { margin: 0; padding: 0.9rem 18px; border-top: 1px solid var(--line-soft); font-size: 11.5px; color: var(--sub); }
.table-foot { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; padding: 0.9rem 18px; border-top: 1px solid var(--line-soft); font-size: 12px; color: var(--sub); }
.table-foot .pager { margin: 0; }

/* Estado vacío del listado de empresas. */
.empty-state { padding: 3rem 1rem; text-align: center; }
.empty-state-mark { width: 44px; height: 44px; margin: 0 auto 1.25rem; border: 2px dashed var(--gray); border-radius: 10px; }
.empty-state h2 { margin: 0 0 0.5rem; font-size: 17px; }
.empty-state p { max-width: 34ch; margin: 0 auto 1.5rem; color: var(--sub); font-size: 13.5px; line-height: 1.55; }

/* Panel «Requiere tu atención» del dashboard de plataforma. */
.attention-panel-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; margin-bottom: 0.9rem; }
.attention-panel-head h2 { margin: 0; }
.attention-pending { font-size: 12px; font-weight: 700; color: var(--gold); }
.attn-row { display: flex; align-items: center; gap: 0.85rem; padding: 0.65rem 0; border-top: 1px solid var(--line-soft); font-size: 13.5px; }
.attn-row:first-of-type { border-top: none; }
.attn-dot { flex-shrink: 0; width: 8px; height: 8px; border-radius: 50%; background: var(--slate); }
.attn-row.is-err .attn-dot { background: var(--err-fill); }
.attn-row.is-crit .attn-dot { background: var(--crit); }
.attn-row.is-warn .attn-dot { background: var(--warn-fill); }
.attn-text { flex: 1; min-width: 0; }
.attn-text strong { font-weight: 700; color: var(--navy); }
.attn-when { flex-shrink: 0; font-size: 12px; color: var(--sub); white-space: nowrap; }

/* Gráficos del dashboard: barras en CSS, sin librería (los del back-office
   usan Chart.js desde CDN, que acá no aporta para dos series simples). */
.bar-months { display: flex; align-items: flex-end; gap: 0.6rem; height: 130px; margin-top: 0.5rem; }
.bar-month { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 0.4rem; height: 100%; }
.bar-month .bar { width: 100%; min-height: 3px; border-radius: 4px 4px 0 0; background: var(--gray); }
.bar-month.is-now .bar { background: var(--gold); }
.bar-month .bar-label { font-size: 9.5px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--sub); }
.bar-month.is-now .bar-label { color: var(--navy); }

.bar-rows { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 0.5rem; }
.bar-row { display: grid; grid-template-columns: 84px 1fr 34px; align-items: center; gap: 0.75rem; }
.bar-row-label { font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--sub); }
.bar-track { height: 12px; border-radius: 6px; background: var(--line-soft); overflow: hidden; }
.bar-fill { height: 100%; border-radius: 6px; background: var(--brand-surface); }
.bar-fill.is-gold { background: var(--gold); }
.bar-fill.is-slate { background: var(--slate); }
.bar-row-value { font-size: 13px; font-weight: 700; color: var(--navy); text-align: right; font-variant-numeric: tabular-nums; }
/* Variante de la pestaña «Uso» de la consola: las columnas fijas del dashboard
   (84 px / 34 px) cortaban «Almacenamiento» y sacaban «0 MB / sin tope» fuera
   de la tarjeta. Acá la etiqueta y el valor miden lo que su texto. */
.bar-rows--wide .bar-row { grid-template-columns: max-content minmax(0, 1fr) max-content; }
.bar-rows--wide .bar-row-label { min-width: 7.5rem; }
.bar-rows--wide .bar-row-value { white-space: nowrap; }

/* ── Ficha de empresa ─────────────────────────────────────────────────── */
.tenant-layout { display: grid; grid-template-columns: minmax(240px, 300px) 1fr; gap: 1.25rem; align-items: start; }
@media (max-width: 860px) { .tenant-layout { grid-template-columns: 1fr; } }

.tenant-id-card { padding: 0; overflow: hidden; }
.tenant-id-head { padding: 1.3rem 1.4rem; background: var(--navy); color: #fff; }
.tenant-logo { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; margin-bottom: 1rem; border-radius: 8px; background: rgba(255,255,255,.18); font-size: 10px; color: inherit; opacity: .85; overflow: hidden; }
.tenant-logo img { width: 100%; height: 100%; object-fit: contain; }
/* Todo hereda el color de la cabecera: puede ser la marca de la empresa con
   letra negra (ver admin/tenants/show.php), no siempre azul con letra blanca. */
.tenant-id-head h2 { margin: 0 0 0.2rem; color: inherit; font-size: 18px; }
.tenant-id-host { display: block; margin-bottom: 0.9rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; color: inherit; opacity: .7; }
.tenant-id-tags { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.tenant-id-tags .state { color: inherit; }
.tenant-id-tags .chip-code { background: rgba(255,255,255,.22); color: inherit; }

.tenant-id-facts { padding: 0.4rem 1.4rem; }
.tenant-fact { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; padding: 0.55rem 0; border-bottom: 1px solid var(--line-soft); font-size: 13px; }
.tenant-fact:last-child { border-bottom: none; }
.tenant-fact dt { color: var(--sub); }
.tenant-fact dd { margin: 0; font-weight: 600; text-align: right; }

.tenant-id-counts { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--line); }
.tenant-count { padding: 1rem 1.4rem; }
.tenant-count + .tenant-count { border-left: 1px solid var(--line-soft); }
.tenant-count strong { display: block; font-size: 26px; font-weight: 700; line-height: 1; color: var(--navy); }
.tenant-count.is-crit strong { color: var(--crit); }
.tenant-count span { display: block; margin-top: 0.35rem; font-size: 9.5px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase; color: var(--sub); }

.tenant-id-actions { display: flex; flex-direction: column; gap: 0.6rem; padding: 1.1rem 1.4rem; border-top: 1px solid var(--line); }
.tenant-id-actions .btn, .tenant-id-actions form { width: 100%; }
.tenant-id-actions form .btn { width: 100%; }

/* Pestañas de la ficha. */
.tabs { display: flex; gap: 0.35rem; margin-bottom: 1.25rem; border-bottom: 1px solid var(--line); }
.tab {
  padding: 0.75rem 1.15rem;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--sub);
  white-space: nowrap;
}
.tab:hover { color: var(--navy); text-decoration: none; }
.tab.is-on { border-color: var(--line); background: var(--white); color: var(--navy); margin-bottom: -1px; padding-bottom: calc(0.75rem + 1px); }
.tab.is-danger { color: var(--err); }
.tab.is-danger.is-on { color: var(--err); }

.panel-stack { display: flex; flex-direction: column; gap: 1.25rem; }

/* Marca del cliente: muestras de color + previsualización. */
.brand-preview-row { display: grid; grid-template-columns: minmax(150px, 200px) 1fr; gap: 1.5rem; align-items: start; }
@media (max-width: 620px) { .brand-preview-row { grid-template-columns: 1fr; } }
.swatch-row { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; font-size: 12.5px; }
.swatch { flex-shrink: 0; width: 20px; height: 20px; border: 1px solid var(--line); border-radius: 5px; }
.swatch-hex { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 600; }
.brand-preview { border: 1px solid var(--line); border-radius: var(--r-btn); overflow: hidden; }
.brand-preview-bar { display: flex; align-items: center; gap: 0.6rem; padding: 0.7rem 0.9rem; color: #fff; font-size: 13px; font-weight: 700; }
.brand-preview-mark { width: 14px; height: 14px; border-radius: 4px; background: rgba(255,255,255,.5); }
.brand-preview-body { display: flex; align-items: center; gap: 0.9rem; padding: 0.9rem; background: var(--white); }
.brand-preview-lines { flex: 1; display: flex; flex-direction: column; gap: 0.4rem; }
.brand-preview-lines span { height: 7px; border-radius: 4px; background: var(--line-soft); }
.brand-preview-lines span:last-child { width: 60%; }
.brand-preview-btn { padding: 5px 12px; border-radius: 6px; color: #fff; font-size: 11px; font-weight: 700; }

/* Zona de peligro: cada acción con su explicación, nunca un botón suelto. */
.danger-card { border-color: rgba(192,57,43,.35); }
.danger-card h3 { color: var(--err); }
.danger-row { display: flex; justify-content: space-between; align-items: center; gap: 1.5rem; flex-wrap: wrap; }
.danger-row p { max-width: 60ch; margin: 0.35rem 0 0; color: var(--sub); font-size: 13px; line-height: 1.55; }
.danger-confirm { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line-soft); }
.danger-confirm input { max-width: 320px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* ── Asistente de alta ────────────────────────────────────────────────── */
.stepper { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1.5rem; padding: 1.1rem 1.4rem; }
.step { display: flex; align-items: center; gap: 0.6rem; font-size: 13px; font-weight: 700; color: var(--sub); white-space: nowrap; }
.step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--gray);
  color: var(--sub);
  font-size: 12px;
}
.step.is-done .step-num { background: var(--ok); color: #fff; }
.step.is-done { color: var(--text); }
.step.is-on .step-num { background: var(--gold); color: var(--on-accent); }
.step.is-on { color: var(--navy); }
.step-line { flex: 1; min-width: 20px; height: 1px; background: var(--line); }
.step.is-done + .step-line { background: var(--ok-fill); }
@media (max-width: 760px) { .step-label { display: none; } }

.wizard-card { max-width: 620px; margin: 0 auto; }
.wizard-card h2 { font-size: 19px; }
.wizard-card > p { margin: -0.5rem 0 1.5rem; color: var(--sub); font-size: 13.5px; }
.wizard-foot { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-top: 1.75rem; }
.wizard-step-count { font-size: 12px; color: var(--sub); }

/* Campo de subdominio: entrada + sufijo fijo del dominio. */
.slug-field { display: flex; align-items: stretch; border: 1.5px solid var(--line); border-radius: var(--r-btn); overflow: hidden; }
.slug-field:focus-within { border-color: var(--field-focus); outline: 2px solid var(--field-focus); outline-offset: 2px; }
.slug-field.is-ok { border-color: var(--ok); }
.slug-field.is-bad { border-color: var(--err); }
.slug-field input { border: none; border-radius: 0; background: var(--white); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.slug-field input:focus { outline: none; }
.slug-suffix { display: flex; align-items: center; padding: 0 14px; border-left: 1px solid var(--line); background: var(--field-bg); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; color: var(--sub); white-space: nowrap; }
.slug-verdict { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.55rem; font-size: 12.5px; font-weight: 700; }
.slug-verdict.is-ok { color: var(--ok); }
.slug-verdict.is-bad { color: var(--err); }
.slug-verdict .ic { width: 14px; height: 14px; }
.slug-rules { margin-top: 1.1rem; padding: 0.9rem 1rem; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--field-bg); font-size: 12.5px; color: var(--sub); }
.slug-rules p { margin: 0 0 0.5rem; }
.slug-rules p:last-child { margin-bottom: 0; }
/* Instrucciones de Plesk del paso «Base de datos»: la misma caja de reglas
   del subdominio, con una lista numerada adentro. */
.db-howto { margin: 0 0 1.25rem; line-height: 1.5; }
.db-howto ol { margin: 0 0 0.6rem; padding-left: 1.2rem; }
.db-howto ul { margin: 0.3rem 0 0; padding-left: 1.1rem; }
.db-howto li { margin-bottom: 0.35rem; }
.db-howto code { font-size: 11.5px; }
.slug-reserved { display: inline-block; margin: 2px 4px 2px 0; padding: 2px 7px; border-radius: 4px; background: rgba(192,57,43,.09); color: var(--err); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; }

/* Pantalla final del alta. */
.done-card { max-width: 620px; margin: 0 auto; border-top: 3px solid var(--ok); }
.done-title { display: flex; align-items: center; gap: 0.7rem; margin: 0 0 0.7rem; font-size: 19px; }
.done-title .ic { flex-shrink: 0; width: 22px; height: 22px; padding: 4px; border-radius: 50%; background: var(--ok); color: #fff; stroke-width: 3; }
.link-box { display: flex; align-items: center; gap: 1rem; margin: 1.4rem 0; padding: 0.9rem 1rem; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--field-bg); }
.link-box-label { display: block; margin-bottom: 0.45rem; font-size: 9.5px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase; color: var(--sub); }
.link-box code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; word-break: break-all; }

/* ── Buscador global de personas ──────────────────────────────────────── */
.people-search { position: relative; display: flex; align-items: center; margin-bottom: 1.75rem; }
.people-search .ic { position: absolute; left: 16px; width: 17px; height: 17px; color: var(--slate); pointer-events: none; }
.people-search input { padding: 15px 130px 15px 44px; border-width: 2px; border-color: var(--gold); background: var(--white); font-size: 15px; }
.people-search-count { position: absolute; right: 16px; font-size: 12px; color: var(--sub); white-space: nowrap; }

.people-group { margin-bottom: 1.1rem; }
.people-group-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; padding: 0 2px; }
.people-group-head .state { flex-shrink: 0; }
.people-group-name { font-size: 13.5px; font-weight: 700; color: var(--navy); }
.people-group-host { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; color: var(--sub); }
.people-group-link { margin-left: auto; }

.person-row { display: flex; align-items: center; gap: 0.9rem; padding: 0.85rem 1rem; }
.person-row + .person-row { border-top: 1px solid var(--line-soft); }
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--field-bg);
  border: 1px solid var(--line);
  font-size: 12px;
  font-weight: 700;
  color: var(--sub);
}
.person-id { min-width: 0; }
.person-id strong { display: block; font-size: 13.5px; color: var(--navy); }
.person-id span { display: block; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; color: var(--sub); }
.person-tags { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-left: auto; }
.person-actions { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }
.person-actions form { display: inline; }
@media (max-width: 720px) {
  .person-row { flex-wrap: wrap; }
  .person-tags, .person-actions { margin-left: 0; width: 100%; }
}

.tag-2fa { display: inline-block; padding: 3px 9px; border-radius: var(--r); background: rgba(30,132,73,.12); color: var(--ok-text); font-size: 10.5px; font-weight: 700; }
.tag-2fa.is-off { background: rgba(192,57,43,.1); color: var(--err); }

/* ── Suplantación: marco rojo permanente alrededor de toda la ventana ─── */
.impersonating { border: 4px solid var(--err); border-radius: 10px; min-height: 100vh; }
.impersonation-bar {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-wrap: wrap;
  padding: 0.7rem 1.1rem;
  background: var(--err);
  color: #fff;
  font-size: 13px;
}
.impersonation-tag {
  padding: 3px 9px;
  border: 1px solid rgba(255,255,255,.5);
  border-radius: 4px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}
.impersonation-bar strong { font-weight: 700; }
.impersonation-bar .muted-light { color: rgba(255,255,255,.75); }
.impersonation-bar form { margin-left: auto; }
.impersonation-bar .btn {
  background: #fff;
  border-color: #fff;
  color: var(--err);
  padding: 6px 14px;
  font-size: 11.5px;
}
.impersonation-bar .btn:hover { background: rgba(255,255,255,.88); border-color: rgba(255,255,255,.88); color: var(--err); }

/* ── Iconografía lineal (estilo Feather) ──────────────────────────────── */
.ic {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.125em;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
}

/* ── Encabezado de página: miga + título + acción principal ───────────── */
.page-head { margin-bottom: 1.25rem; }
.crumb { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--sub); margin-bottom: 0.35rem; }
.crumb a { color: var(--sub); }
.crumb a:hover { color: var(--gold); text-decoration: none; }
.crumb strong { color: var(--text); font-weight: 700; }
.page-head-row { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.page-title { margin: 0; font-size: 30px; font-weight: 700; letter-spacing: -0.5px; color: var(--navy); line-height: 1.15; }
.page-sub { margin: 0.4rem 0 0; color: var(--sub); font-size: 13.5px; }

/* ── Superficies: tarjetas / paneles ──────────────────────────────────── */
.card, .panel {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 1.25rem 1.4rem;
  box-shadow: 0 2px 14px var(--brand-shadow);
}
.card-eyebrow { margin: 0 0 1rem; font-size: 12px; font-weight: 700; letter-spacing: .4px; color: var(--sub); text-transform: uppercase; }

/* Tarjeta sobre la superficie de marca — la «una sola superficie navy por
   pantalla» del §7 #9, aquí la llamada principal del Portal del Titular.
   Estaba escrita con `background:var(--navy); color:white` y un `#fff` inline
   para ganarle por especificidad a `h1..h4 { color: var(--navy) }`. Eso es la
   Regla 1 incumplida en la única pantalla que ven personas de fuera de la
   empresa: con un primario claro heredado de antes de la puerta de luminancia,
   el titular veía blanco sobre blanco. Los tokens --on-brand* ya existen
   justamente para esto. */
.card-brand {
  background: var(--brand-surface);
  color: var(--on-brand);
  display: block;
}

.card-brand h1, .card-brand h2, .card-brand h3, .card-brand h4 { color: var(--on-brand); margin: 0 0 0.3rem; }
.card-brand p { color: var(--on-brand-soft); font-size: 0.9rem; }
.card-brand .card-brand-cta { color: var(--on-brand); font-weight: 600; margin-top: 0.75rem; }
.card-brand:hover { text-decoration: none; }
.empty { text-align: center; color: var(--sub); font-size: 13px; padding: 2rem 0; margin: 0; }

/* Dos columnas del mismo alto, con el botón anclado abajo en ambas. */
.split-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 1.25rem; align-items: stretch; }
.panel-form { display: flex; flex-direction: column; }
.panel-form > form { display: flex; flex-direction: column; flex: 1; }
.panel-foot { margin-top: auto; padding-top: 1.25rem; }

/* Alta plegable al inicio de una columna: visible sin bajar, pero sin empujar
   el listado hacia abajo mientras está cerrada. */
.panel-add > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.55rem;
  font-weight: 700; font-size: 14px; color: var(--navy);
}
.panel-add > summary::-webkit-details-marker { display: none; }
.panel-add > summary::before {
  content: "+"; flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%;
  background: var(--brand-surface); color: var(--on-brand); font-size: 15px; line-height: 19px; text-align: center;
}
.panel-add[open] > summary::before { content: "\2212"; }
.panel-add > summary:hover { color: var(--gold); }
.panel-add[open] > summary { margin-bottom: 1rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--line-soft); }

/* ── Barra de estadísticas de módulo ──────────────────────────────────── */
.statbar {
  display: flex;
  flex-wrap: wrap;
  background: var(--white);
  border: 1px solid var(--line);
  border-left: 5px solid var(--gold);
  border-radius: var(--r-lg);
  margin-bottom: 1rem;
  overflow: hidden;
}
.statbar-seg { flex: 1 1 150px; min-width: 0; padding: 1.05rem 1.4rem; border-left: 1px solid var(--line-soft); }
.statbar-seg:first-child { border-left: none; }
.statbar-value { display: flex; align-items: baseline; gap: 0.45rem; font-size: 28px; font-weight: 700; line-height: 1.05; color: var(--navy); }
.statbar-value.is-ok    { color: var(--ok); }
.statbar-value.is-warn  { color: var(--warn); }
.statbar-value.is-crit  { color: var(--crit); }
.statbar-value.is-slate { color: var(--slate); }
.statbar-pct { font-size: 12px; font-weight: 700; color: var(--gold); }
.statbar-label { margin-top: 0.35rem; font-size: 10px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; color: var(--sub); }

/* Segmento clicable: filtra el listado de abajo por lo que está contando. */
a.statbar-seg { display: block; color: inherit; transition: background .15s; }
a.statbar-seg:hover { background: var(--row-hover); text-decoration: none; }
a.statbar-seg.is-on { background: var(--row-hover); box-shadow: inset 0 -3px 0 var(--gold); }

/* ── Barra de filtros: buscador + segmentado + selects + toggle ───────── */
.filterbar { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.filterbar .search { flex: 1 1 260px; position: relative; display: flex; align-items: center; min-width: 0; }
.filterbar .search .ic { position: absolute; left: 14px; width: 15px; height: 15px; color: var(--slate); pointer-events: none; }
.filterbar .search input { padding-left: 38px; background: var(--white); }
.filterbar .btn { flex-shrink: 0; }

.segmented { display: inline-flex; gap: 2px; padding: 3px; background: var(--white); border: 1px solid var(--line); border-radius: var(--r-btn); }
.segmented .seg {
  display: inline-flex;
  align-items: center;
  border: none;
  background: transparent;
  border-radius: 7px;
  padding: 7px 15px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  color: var(--sub);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--ux-dur-fast), color var(--ux-dur-fast);
}
.segmented .seg:hover { color: var(--navy); text-decoration: none; }
.segmented .seg.is-on { background: var(--brand-surface); color: var(--on-brand); }

.switch {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0 0.4rem;
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  color: var(--sub);
  cursor: pointer;
}
.switch:hover { text-decoration: none; color: var(--navy); }
.switch-track { position: relative; flex-shrink: 0; width: 34px; height: 19px; border-radius: 99px; background: var(--gray); transition: background .2s; }
.switch-knob { position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform .2s; }
.switch.is-on { color: var(--navy); }
.switch.is-on .switch-track { background: var(--gold); }
.switch.is-on .switch-knob { transform: translateX(15px); }

/* Desplegable de filtro multivalor: <details> + lista de enlaces. Cada
   opción se aplica sola al pulsarla y se quita al volver a pulsarla; el
   panel queda abierto para poder marcar varias seguidas. */
.fdrop { position: relative; }
.fdrop > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 9px 12px 9px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-btn);
  background: var(--white);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--sub);
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}
.fdrop > summary::-webkit-details-marker { display: none; }
.fdrop > summary:hover { color: var(--navy); }
.fdrop > summary .caret { width: 12px; height: 12px; transition: transform .15s; }
.fdrop[open] > summary .caret { transform: rotate(180deg); }
.fdrop.is-on > summary { border-color: var(--navy); color: var(--navy); }
.fdrop-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 99px;
  background: var(--brand-surface);
  font-size: 10.5px;
  color: var(--on-brand);
}
.fdrop-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 5px);
  left: 0;
  min-width: 220px;
  max-height: 340px;
  overflow-y: auto;
  padding: 5px;
  border: 1px solid var(--line);
  border-radius: var(--r-btn);
  background: var(--white);
  box-shadow: 0 8px 26px var(--brand-shadow-strong);
}
.fdrop-opt {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 8px 10px;
  border-radius: var(--r);
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.fdrop-opt:hover { background: var(--row-hover); text-decoration: none; }
.fdrop-box {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  border: 1.5px solid var(--gray);
  border-radius: 4px;
  background: var(--white);
}
.fdrop-opt.is-on { color: var(--navy); }
.fdrop-opt.is-on .fdrop-box {
  border-color: var(--brand-surface);
  background: var(--brand-surface) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E") no-repeat center/11px;
}
.fdrop-clear {
  display: block;
  margin-top: 4px;
  padding: 8px 10px;
  border-top: 1px solid var(--line-soft);
  font-size: 12px;
  font-weight: 700;
  color: var(--sub);
}
.fdrop-clear:hover { color: var(--err); text-decoration: none; }

/* Píldoras de los filtros aplicados: cada una se quita con su ×. */
.filter-chips { display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap; margin: -0.35rem 0 1rem; }
.filter-chips-label { font-size: 10px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; color: var(--sub); }
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 5px 9px 5px 11px;
  border: 1px solid var(--line);
  border-radius: 99px;
  background: var(--white);
  font-size: 12px;
  font-weight: 700;
  color: var(--navy);
}
.filter-chip:hover { border-color: var(--err); color: var(--err); text-decoration: none; }
.filter-chip-x { font-size: 15px; line-height: 1; color: var(--slate); }
.filter-chip:hover .filter-chip-x { color: var(--err); }
.filter-clear { margin-left: 0.2rem; font-size: 12px; font-weight: 700; color: var(--sub); }
.filter-clear:hover { color: var(--err); }

/* ── Tablas ────────────────────────────────────────────────────────────── */
.table-card {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: 0 2px 14px var(--brand-shadow);
  overflow-x: auto;
}
table { width: 100%; border-collapse: collapse; font-size: 13px; }
table th, table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
table th {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--sub);
  white-space: nowrap;
}
/* Columna numérica: cifras alineadas a la derecha y de ancho fijo, para que
   se puedan comparar de un vistazo en vertical (§6, tabla densa). */
table th.num, table td.num { text-align: right; font-variant-numeric: tabular-nums; }

table tbody tr:hover { background: var(--row-hover); }
table tbody tr:last-child td { border-bottom: none; }

.table-card thead th { background: #fbf9f5; padding: 12px 16px; border-bottom: 1px solid var(--line-soft); }

/* Cabecera ordenable: un clic ordena por esa columna, el siguiente invierte
   el sentido. La flecha tenue sólo aparece al pasar el cursor; la de la
   columna activa se queda fija. */
th.th-sort { padding: 0 !important; }
th.th-sort > a {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 12px 16px;
  color: inherit;
  white-space: nowrap;
}
th.th-sort > a:hover { color: var(--navy); text-decoration: none; }
th.th-sort .sort-ic { font-size: 9px; color: var(--slate); opacity: 0; transition: opacity .15s; }
th.th-sort:hover .sort-ic { opacity: .6; }
th.th-sort.is-on > a { color: var(--navy); }
th.th-sort.is-on .sort-ic { color: var(--gold); opacity: 1; }
.table-card th.th-sort:first-child > a { padding-left: 18px; }
.table-card th.th-sort:last-child > a { padding-right: 18px; }
.table-card td { padding: 13px 16px; font-size: 13.5px; }
.table-card th:first-child, .table-card td:first-child { padding-left: 18px; }
.table-card th:last-child, .table-card td:last-child { padding-right: 18px; }

/* Acento de color a la izquierda de la fila, según el estado del registro. */
tr.accent-ok    > td:first-child { box-shadow: inset 4px 0 0 var(--ok); }
tr.accent-warn  > td:first-child { box-shadow: inset 4px 0 0 var(--warn); }
tr.accent-crit  > td:first-child { box-shadow: inset 4px 0 0 var(--crit); }
tr.accent-slate > td:first-child { box-shadow: inset 4px 0 0 var(--slate); }
tr.accent-err   > td:first-child { box-shadow: inset 4px 0 0 var(--err); }

.cell-name { font-weight: 700; color: var(--navy); font-size: 13.5px; }
a.cell-name:hover { color: var(--gold); text-decoration: none; }
.cell-num { text-align: right; }
/* Fechas y contadores monoespaciados: una sola línea, aunque la columna
   quede angosta (la tarjeta ya hace scroll horizontal si no entra). */
td.mono { white-space: nowrap; }
.actions { display: flex; align-items: center; gap: 0.5rem; }
.actions form { display: inline; }
/* Dentro de una tabla, `display:flex` sacaría la celda del layout de tabla
   (Chrome le genera una celda anónima y descuadra la fila): en un <td> los
   botones se alinean a la derecha en línea, no con flexbox. */
td.actions { display: table-cell; text-align: right; white-space: nowrap; }
td.actions form { display: inline-block; }
td.actions > * { vertical-align: middle; }
td.actions > * + * { margin-left: 0.5rem; }

/* Estado como texto con punto: ● ACTIVE */
.state { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; color: var(--sub); }
.state::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.state.is-ok    { color: var(--ok); }
.state.is-warn  { color: var(--warn); }
.state.is-crit  { color: var(--crit); }
.state.is-slate { color: var(--slate); }
.state.is-err   { color: var(--err); }

/* Chip con borde (clasificación, severidad, categoría) */
.chip {
  display: inline-block;
  padding: 3px 9px;
  border: 1px solid currentColor;
  border-radius: var(--r);
  background: var(--white);
  color: var(--slate);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .7px;
  text-transform: uppercase;
  white-space: nowrap;
}
.chip.is-ok    { color: var(--ok); }
.chip.is-warn  { color: var(--warn); }
.chip.is-crit  { color: var(--crit); }
.chip.is-slate { color: var(--slate); }
.chip.is-err   { color: var(--err); }

/* Chip monoespaciado gris para códigos (CONSENT, CTRL-01, …) */
.chip-code {
  display: inline-block;
  padding: 4px 9px;
  border-radius: var(--r);
  background: var(--code-bg);
  color: var(--code-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .3px;
  white-space: nowrap;
}

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 20px;
  background: var(--brand-tint);
  color: var(--navy-mid);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
}

.link-go { color: var(--gold); font-weight: 700; font-size: 12.5px; white-space: nowrap; }
.link-go:hover { color: var(--gold-light); text-decoration: none; }
.link-primary { color: var(--navy-mid); font-weight: 700; }
.link-primary:hover { color: var(--navy); text-decoration: none; }
.link-back { display: inline-block; margin-bottom: 0.5rem; font-size: 12.5px; color: var(--sub); font-weight: 600; }
.link-back:hover { color: var(--gold); text-decoration: none; }

.toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; gap: 1rem; flex-wrap: wrap; }

/* Paginación */
.pager { display: flex; justify-content: center; gap: 0.4rem; margin-top: 1.25rem; flex-wrap: wrap; }
.pager a {
  min-width: 34px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--white);
  color: var(--sub);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
}
.pager a:hover { border-color: var(--navy-light); color: var(--navy); text-decoration: none; }
.pager a.is-on { background: var(--brand-surface); border-color: var(--brand-surface); color: var(--on-brand); }
.pager-gap { align-self: center; color: var(--sub); padding: 0 0.15rem; }

/* Lista de detalle clave/valor (páginas show) */
.deflist { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.1rem 1.5rem; margin: 0; }
.deflist > div { min-width: 0; }
.deflist dt { font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--sub); margin-bottom: 0.3rem; }
.deflist dd { margin: 0; font-size: 13.5px; color: var(--text); word-break: break-word; }

/* ── Dashboard (M10) ───────────────────────────────────────────────────── */
.dash-toolbar { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.25rem; }
.dash-toolbar h1 { margin: 0 0 0.25rem; }
.dash-subtitle { margin: 0; color: var(--sub); font-size: 14px; }
.dash-attention-count { color: var(--warn); font-weight: 600; }
.dash-meta { color: var(--sub); font-size: 13px; white-space: nowrap; }

.dash-grid-top { display: grid; grid-template-columns: minmax(260px, 340px) 1fr; gap: 1rem; margin-bottom: 1rem; align-items: stretch; }
@media (max-width: 760px) { .dash-grid-top { grid-template-columns: 1fr; } }

.score-card { display: flex; flex-direction: column; }
.score-value { font-size: 2.6rem; font-weight: 700; color: var(--navy); line-height: 1; }
.score-sub { color: var(--sub); font-size: 13px; margin: 0.25rem 0 0; }
.score-divider { border: none; border-top: 1px solid var(--line-soft); margin: 1rem 0; }
.score-footer { display: flex; justify-content: space-between; align-items: center; font-size: 13px; color: var(--sub); margin-top: auto; }
/* El recuento de pendientes lleva al catálogo filtrado por ese estado. */
.score-footer > a:not(.link-primary) { color: inherit; text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 3px; }
.score-footer > a:not(.link-primary):hover { color: var(--navy); text-decoration-color: var(--gold); }

.attention-card { display: flex; flex-direction: column; }
.attention-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 0.75rem; gap: 0.5rem; }
.attention-header h2 { margin: 0; }
.attention-sort { font-size: 12px; color: var(--sub); white-space: nowrap; }
.attention-list { display: flex; flex-direction: column; gap: 0.5rem; }
.attention-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 0.9rem; border-radius: var(--r-btn); background: var(--row-hover); text-decoration: none; color: inherit; transition: background .15s; }
.attention-row:hover { background: var(--gray); text-decoration: none; }
.attention-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--sub); }
.attention-row.severity-red { background: rgba(192,57,43,.08); }
.attention-row.severity-red:hover { background: rgba(192,57,43,.14); }
.attention-row.severity-red .attention-dot { background: var(--err-fill); }
.attention-row.severity-red .attention-due strong { color: var(--err); }
.attention-row.severity-orange { background: rgba(209,129,12,.1); }
.attention-row.severity-orange:hover { background: rgba(209,129,12,.16); }
.attention-row.severity-orange .attention-dot { background: var(--warn-fill); }
.attention-row.severity-orange .attention-due strong { color: var(--warn); }
.attention-row.severity-gray .attention-dot { background: var(--sub); }
.attention-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.attention-text strong { font-size: 13.5px; }
.attention-text small { color: var(--sub); font-size: 12px; }
.attention-due { text-align: right; flex-shrink: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.attention-due strong { font-size: 13px; }
.attention-due small { color: var(--sub); font-size: 11px; }
.attention-empty { color: var(--sub); font-size: 13px; padding: 1rem 0; text-align: center; margin: 0; }

.dash-stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px,1fr)); gap: 1rem; margin-bottom: 1rem; }
/* Tarjeta de severidad del dashboard: es un enlace al listado ya filtrado
   por lo que cuenta (mismo comportamiento que .stat-mini). */
.stat-severity { display: block; border-left: 5px solid var(--gray); color: inherit; text-decoration: none; transition: box-shadow .15s; }
a.stat-severity:hover { text-decoration: none; box-shadow: 0 4px 16px var(--brand-shadow-strong); }
.stat-severity .stat-value { font-size: 28px; font-weight: 700; line-height: 1; }
.stat-severity .stat-label { color: var(--sub); font-size: 10px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; margin-top: 0.4rem; }
.stat-severity.red { border-left-color: var(--err); }
.stat-severity.red .stat-value { color: var(--err); }
.stat-severity.orange { border-left-color: var(--warn); }
.stat-severity.orange .stat-value { color: var(--warn); }
.stat-severity.green { border-left-color: var(--ok); }
.stat-severity.green .stat-value { color: var(--ok); }

.stat-tile-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px,1fr)); gap: 1rem; margin-bottom: 1rem; }
.stat-mini { display: block; text-decoration: none; color: inherit; transition: box-shadow .15s; }
.stat-mini:hover { text-decoration: none; box-shadow: 0 4px 16px var(--brand-shadow-strong); }
.stat-mini--accent { border-left: 5px solid var(--gold); }
.stat-mini-value { font-size: 28px; font-weight: 700; color: var(--navy); line-height: 1.05; }
.stat-mini-value--highlight { color: var(--crit); }
.stat-mini-label { margin-top: 0.35rem; font-size: 10px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; color: var(--sub); }

.dash-charts-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; }
.muted-small { color: var(--sub); font-size: 12px; margin: -0.5rem 0 0.75rem; }
.response-value { font-size: 2rem; font-weight: 700; color: var(--navy); }
.response-value span { font-size: 0.85rem; font-weight: 600; color: var(--sub); margin-left: 0.3rem; }
.response-bar-track { height: 8px; border-radius: 4px; background: var(--gray); margin: 0.75rem 0 0.35rem; overflow: hidden; }
.response-bar-fill { height: 100%; border-radius: 4px; background: var(--ok-fill); }
.response-bar-fill.over { background: var(--err-fill); }
.response-bar-labels { display: flex; justify-content: space-between; font-size: 11px; color: var(--sub); }
.response-status { margin: 0.5rem 0 0; font-size: 12px; font-weight: 700; }
.response-status.ok { color: var(--ok); }
.response-status.over { color: var(--err); }

/* Con cabecera pública arriba, el toast baja debajo de ella. */
:root:has(.site-header) { --ux-toast-top: 76px; }

/* ── Feedback ──────────────────────────────────────────────────────────── */
.alert { padding: 0.9rem 1rem; border-radius: var(--r-btn); margin-bottom: 1rem; font-size: 13px; border-left: 4px solid transparent; }
.alert.success { background: rgba(30,132,73,.1); color: var(--ok-text); border-left-color: var(--ok); }
.alert.warn { background: rgba(209,129,12,.1); color: var(--warn-text); border-left-color: var(--warn); }
.alert.info { background: var(--brand-tint-soft); color: var(--navy-mid); border-left-color: var(--navy-light); }

/* ── Aviso de error ────────────────────────────────────────────────────── */
/*
 * Un fallo de escritura no se puede parecer a un aviso informativo más: es
 * la única cosa de la pantalla que obliga al usuario a rehacer algo. Por eso
 * usa el mismo tratamiento que .err-box/.modal-err del resto de la familia
 * de apps — fondo azul marino de marca, filo rojo completo (no sólo a la
 * izquierda como los demás .alert) y el triángulo de alerta a la izquierda —
 * y por eso nunca se desvanece solo: se pinta en el servidor y se queda
 * hasta que el usuario recarga o navega.
 *
 * .err-box es el bloque genérico; .alert.error el flash del layout;
 * .l-error el de las pantallas de login/2FA, que tienen su propio ancho.
 */
.err-box,
.alert.error,
.l-error {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  background: var(--brand-surface);
  /* border-left va explícito porque .alert y .l-error traen "border-left: 4px
     solid transparent" y, sin esta línea, ganaría por ser más específico. */
  border: 1.5px solid var(--err-line);
  border-left: 1.5px solid var(--err-line);
  border-radius: var(--r);
  padding: 11px 14px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--on-brand-soft);
}
.err-box .ic,
.alert.error .ic,
.l-error .ic { width: 16px; height: 16px; margin-top: 1px; color: var(--err-line); stroke-width: 2; }
.err-box strong,
.alert.error strong,
.l-error strong { color: var(--on-brand); font-weight: 700; }
.err-box a,
.alert.error a,
.l-error a { color: var(--on-brand); text-decoration: underline; }

/* Aviso pegado al formulario/modal donde ocurrió el fallo, en vez de arriba
   del todo: el usuario ya está mirando ahí. */
.err-box--form { margin-bottom: 1rem; }

/* ── Página de error (404 / 403 / 419 / 500) ───────────────────────────────
   El chasis de la casa para los estados que salían en text/plain desde los
   69 puntos que llaman a notFound()/forbidden(), y para el 500 de
   bootstrap.php. El código va en grande y en gris: quien lo necesita es
   quien reporta el fallo, no quien lo sufre — arriba manda el título.
   Lleva salida (§7 #15 del estándar): un estado vacío sin acción es un
   callejón. */
.err-page {
  max-width: 560px;
  margin: 2.5rem auto;
  text-align: center;
}

.err-page-code {
  margin: 0;
  font-size: 44px;
  font-weight: 800;
  line-height: 1;
  color: var(--gray-2);
  font-variant-numeric: tabular-nums;
}

.err-page-title {
  margin: 0.6rem 0 0;
  font-size: 24px;
  font-weight: 800;
  color: var(--navy);
}

.err-page-msg {
  margin: 0.6rem 0 1.4rem;
  color: var(--sub);
  font-size: 15px;
}

.err-page .actions { justify-content: center; }

/* ── Botones ───────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .3px;
  padding: 10px 18px;
  border-radius: var(--r-btn);
  border: 1.5px solid var(--line);
  background: #fff;
  color: var(--sub);
  cursor: pointer;
  transition: background-color var(--ux-dur), border-color var(--ux-dur), color var(--ux-dur), box-shadow var(--ux-dur), opacity var(--ux-dur);
}
.btn:hover { border-color: var(--navy-light); color: var(--navy); text-decoration: none; }
.btn.sm { padding: 6px 15px; font-size: 11px; border-radius: 8px; }
.btn.primary {
  background: var(--brand-surface);
  border-color: var(--brand-surface);
  color: var(--on-brand);
  box-shadow: 0 4px 12px var(--brand-glow);
}
.btn.primary:hover { background: var(--navy-mid); border-color: var(--navy-mid); color: var(--on-brand); }
/* Acción principal de la página (arriba a la derecha) y CTA del portal. */
.btn.secondary, .btn.action {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--on-accent);
  box-shadow: 0 4px 12px var(--accent-glow);
}
.btn.secondary:hover, .btn.action:hover { background: var(--gold-light); border-color: var(--gold-light); color: var(--on-accent); }
.btn.action { padding: 11px 20px; font-size: 12.5px; }
.btn.danger { color: var(--err); border-color: var(--line); }
.btn.danger:hover { background: var(--err); border-color: var(--err); color: #fff; }

/* ── Formularios ───────────────────────────────────────────────────────── */
form > div, .fl { margin-bottom: 16px; }
label {
  display: block;
  margin-bottom: 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--sub);
}
/* Kit de campos canónico de la familia (§5 del estándar): borde de 1,5 px,
   radio --r y cuerpo de 14 px. Acá eran 1 px, --r-btn (10) y 13,5 px, que es
   la única parte del login que no coincidía ya al dígito con la referencia —y
   como en esta app el kit no tiene clase propia, la regla vale para los
   formularios de las 50 pantallas, no sólo para el de entrar. */
input, select, textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1.5px solid var(--field-border);
  border-radius: var(--r);
  font-family: inherit;
  font-size: 14px;
  color: var(--text);
  background: var(--field-bg);
  transition: border-color .2s, background .2s;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--field-focus);
  background: #fff;
}

/* ── Foco de teclado ────────────────────────────────────────────────────────
   Hasta acá el único indicador de foco era el borde de 1 px que la regla de
   arriba tiñe de --gold, y --gold es el color SECUNDARIO que elige cada
   empresa: con el dorado de la casa ya daba 2,47:1 contra el blanco, con un
   secundario claro desaparecía, y con un secundario igual al primario dejaba
   de distinguirse del reposo. Un anillo de 2 px separado del control se ve
   aunque el color falle, porque lo que cambia no es sólo el tono: es la forma.

   Va con :focus-visible y no con :focus para que el anillo salga al navegar
   con el teclado y no al hacer clic, que es lo que hacía que estos contornos
   se quitaran en primer lugar. */
:focus-visible {
  outline: 2px solid var(--field-focus);
  outline-offset: 2px;
}
/* El contorno nativo sólo cuando el foco NO viene del teclado. */
:focus:not(:focus-visible) { outline: none; }

/* Los campos de texto llevan el foco en su borde, más un halo suave del mismo
   color. El navegador los marca focus-visible también al hacer clic, y el
   anillo separado encima del borde dorado se veía como un borde doble. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--field-focus) 22%, transparent);
}
input[type=checkbox], input[type=radio] { width: auto; accent-color: var(--gold); }
.field-error { color: var(--err); font-size: 0.8rem; margin-top: 0.25rem; }
.field-hint { color: var(--sub); font-size: 11.5px; margin: 0.3rem 0 0; }
.check { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 12.5px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--text); margin: 0; }

/* Select compacto tipo píldora, para las barras de filtros. */
.select-pill {
  width: auto;
  max-width: 190px;   /* si no, el <select> se estira hasta la opción más larga */
  text-overflow: ellipsis;
  padding: 9px 32px 9px 14px;
  border-radius: var(--r-btn);
  background: var(--white) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a6070' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E") no-repeat right 11px center/12px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--sub);
  appearance: none;
  -webkit-appearance: none;
}
.select-pill:focus { color: var(--navy); }

/* Campo de color: muestra de color + hex monoespaciado */
.color-field { display: flex; align-items: center; gap: 0.65rem; padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--r-btn); background: var(--white); }
.color-field input[type=color] { width: 28px; height: 28px; flex-shrink: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--r); background: none; cursor: pointer; }
.color-field input[type=color]::-webkit-color-swatch-wrapper { padding: 2px; }
.color-field input[type=color]::-webkit-color-swatch { border: none; border-radius: 3px; }
.color-field .hex { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; font-weight: 600; color: var(--text); text-transform: none; }
/* El hex es un input editable, pero se lee como texto dentro del recuadro. */
.color-field input.hex { width: 100%; min-width: 0; margin: 0; padding: 0; border: 0; background: none; box-shadow: none; }
.color-field input.hex:focus { outline: none; box-shadow: none; }
.color-field:focus-within { border-color: var(--field-focus); outline: 2px solid var(--field-focus); outline-offset: 2px; }
/* Letra sobre cada color de marca: una fila de radios bajo su campo. */
.ink-pick { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; margin: 0.6rem 0 0; padding: 0; border: 0; }
.ink-pick legend { float: left; margin-right: 0.2rem; padding: 0; font-size: 10px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--sub); }

/* Zona de carga de archivo con borde punteado */
.dropzone {
  display: block;
  padding: 1.6rem 1rem;
  border: 1.5px dashed #d9d3c6;
  border-radius: 12px;
  background: #fcfbf8;
  text-align: center;
  cursor: pointer;
  transition: border-color .2s, background .2s;
  margin: 0;
  letter-spacing: 0;
  text-transform: none;
}
.dropzone:hover { border-color: var(--field-focus); background: var(--accent-tint); }
.dropzone strong { display: block; font-size: 13px; font-weight: 700; color: var(--navy); letter-spacing: 0; text-transform: none; }
.dropzone small { display: block; margin-top: 0.25rem; font-size: 11.5px; color: var(--sub); }
.dropzone input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; }

/* ── Login / 2FA (layouts/auth.php) ───────────────────────────────────── */
.auth-body { background: var(--brand-surface); }
.login-wrap {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--brand-surface) 0%, var(--navy-mid) 60%, var(--navy-light) 100%);
  padding: 24px;
}
.login-card {
  width: 100%;
  background: #fff;
  border-radius: 16px;
  padding: 34px 30px;
  max-width: 360px;
  box-shadow: 0 22px 60px rgba(0,0,0,.28);
  border: 1px solid var(--brand-tint);
  border-top: 4px solid var(--gold);
}
.l-logo { display: block; max-width: 200px; max-height: 80px; width: auto; object-fit: contain; margin: 0 auto 20px; }
.l-badge {
  display: table;
  margin: 0 auto 20px;
  background: var(--gold);
  color: var(--on-accent);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  border-radius: 2px;
  padding: 5px 11px;
}
.l-title { font-size: 21px; font-weight: 800; color: var(--navy); text-align: center; margin: 0 0 12px; }
.l-title::after {
  content: '';
  display: block;
  width: 36px;
  height: 3px;
  background: var(--gold);
  border-radius: 2px;
  margin: 10px auto 0;
}
.l-sub { font-size: 12px; color: var(--sub); text-align: center; margin: 0 0 22px; line-height: 1.5; }
.login-card form { margin-top: 4px; }
.login-card .btn {
  width: 100%;
  padding: 12px 18px;
  font-size: 13px;
}
/* Campo de contraseña con ojo. El botón va dentro del campo, así que el input
   se reserva el hueco a la derecha y no escribe nunca debajo del icono. Nace
   con [hidden] y lo destapa el script: sin JavaScript no habría nada que
   conmutar, y un mando muerto es peor que no tenerlo. El alto se lo da el
   input, así que el botón se centra sobre él y no sobre la fila entera. */
.pass-wrap { position: relative; }
/* Los dos tipos, y con el atributo puesto: el kit de campos de arriba
   selecciona por elemento y ganaría a un `.pass-wrap input` a secas. `text`
   hace falta porque es lo que pasa a ser el campo al destaparlo. */
.pass-wrap input[type="password"],
.pass-wrap input[type="text"] { padding-right: 40px; }
.pass-toggle {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: none;
  border: 0;
  border-radius: var(--r);
  color: var(--sub);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: color .2s;
}
/* El atributo [hidden] no basta contra el display:flex de arriba. */
.pass-toggle[hidden] { display: none; }
.pass-toggle:hover { color: var(--navy); }

/* También como <button> (el «Cerrar sesión» del cambio de clave forzado),
   que trae fondo, borde y ancho propios. */
button.btn-link { width: 100%; background: none; border: 0; padding: 0; font-family: inherit; cursor: pointer; }
.btn-link {
  display: block;
  text-align: center;
  margin-top: 16px;
  font-size: 12px;
  color: var(--sub);
  text-decoration: underline;
}
/* El aspecto de .l-error lo define el bloque "Aviso de error" de arriba
   (mismo azul marino + filo rojo que el resto); acá sólo el margen propio
   de las pantallas angostas de login/2FA. */
.l-error { margin-bottom: 16px; }
.l-qr {
  display: flex;
  justify-content: center;
  margin: 20px 0;
  padding: 16px;
  border: 2px solid var(--gold);
  border-radius: var(--r-btn);
}
.l-details { margin-bottom: 20px; font-size: 12px; color: var(--sub); }
.l-details summary { cursor: pointer; color: var(--navy-mid); font-weight: 600; }
.l-details summary:hover { color: var(--gold); }
.l-secret { margin-top: 8px; word-break: break-all; }
.l-secret code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background: var(--field-bg); border: 1px solid var(--line); border-radius: 4px; padding: 2px 6px; }

/* ── Landing pública del dominio raíz (layouts/marketing.php) ─────────── */
.hero { text-align: center; padding: 1.5rem 0 2rem; }
.hero h1 { font-size: 2rem; color: var(--navy); margin: 0 0 0.75rem; }
.hero h1::after {
  content: '';
  display: block;
  width: 48px;
  height: 3px;
  background: var(--gold);
  border-radius: 2px;
  margin: 14px auto 0;
}
.hero-sub { max-width: 720px; margin: 0 auto; color: var(--sub); font-size: 1rem; line-height: 1.6; }

.title-accent { position: relative; display: inline-block; padding-bottom: 10px; }
.title-accent::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 56px;
  height: 3px;
  background: var(--gold);
  border-radius: 2px;
}

/* ============================================================================
   FILTRADO SIN RECARGA — esqueleto de carga
   ----------------------------------------------------------------------------
   Al cambiar un filtro no se repinta la página entera: se vuelve a pedir sólo
   el bloque de resultados (#js-results) y, mientras llega, se pinta una
   silueta con la misma forma que tenía el contenido anterior. Ver
   public/js/filters.js.

   La silueta la calca el JS de lo que ya hay en pantalla, así que conserva la
   altura del bloque: el contenido no se encoge y el scroll no da el salto que
   obliga a buscar dónde estabas.

   Ojo con la CSP: los anchos y altos variables los fija el JS por CSSOM
   (el.style.width = …), que la política no intercepta. En el HTML que emite
   PHP no se escribe ningún atributo `style` nuevo.
   ========================================================================= */

/* Contenedor de resultados mientras se está pidiendo el reemplazo. */
.js-loading { position: relative; }

/* El esqueleto ocupa el sitio del contenido real; ninguna de sus piezas es
   interactiva ni la ve un lector de pantalla (el aviso lo da .sk-estado). */
.sk { pointer-events: none; }

.sk-caja {
  border: 1px solid var(--gray);
  border-radius: var(--r);
  background: var(--white);
  padding: 18px 20px;
  overflow: hidden;
}

/* Las líneas grises. El ancho lo pone el JS, para que no salgan todas iguales
   y el bloque no parezca una reja. */
.sk-linea {
  height: 11px;
  border-radius: 4px;
  margin-bottom: 12px;
  background: linear-gradient(90deg, var(--cream-2) 25%, var(--gray) 37%, var(--cream-2) 63%);
  background-size: 400% 100%;
  animation: sk-brillo 1.4s ease-in-out infinite;
}
.sk-linea:last-child { margin-bottom: 0; }

/* La primera línea de cada caja hace de título: más alta y más oscura. */
.sk-linea.es-titulo {
  height: 15px;
  margin-bottom: 18px;
  background: linear-gradient(90deg, var(--gray) 25%, var(--gray-2) 37%, var(--gray) 63%);
  background-size: 400% 100%;
}

@keyframes sk-brillo {
  from { background-position: 100% 50%; }
  to   { background-position: 0 50%; }
}

/* Con el movimiento reducido no se anima, pero tampoco se deja el degradado
   quieto: se vería como líneas a medio pintar. */
@media (prefers-reduced-motion: reduce) {
  .sk-linea, .sk-linea.es-titulo { background: var(--gray); animation: none; }
}

/* Aviso para lectores de pantalla: «Actualizando resultados…» / «Resultados
   actualizados.». Visualmente no ocupa nada; el cambio a la vista es el
   esqueleto. Vive fuera de #js-results, porque si estuviera dentro el propio
   reemplazo se lo llevaría por delante antes de anunciar nada. */
.sk-estado {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* La fila de píldoras de filtro activo se emite siempre (aunque esté vacía)
   para que el motor tenga un nodo estable que reemplazar al filtrar; sin
   filtros puestos no debe ocupar sitio. */
.filter-chips.is-empty { display: none; }

/* Los campos ocultos que arrastran los filtros vigentes (hidden_filters) van
   envueltos para que el motor de filtrado pueda reemplazarlos de una pieza.
   El envoltorio no debe contar como ítem del flex de la barra de filtros. */
.filter-carry { display: none; }

/* Columna de tarjetas apiladas (políticas y formaciones de Accountability).
   Reemplaza al `style="display:flex; …"` que llevaban esos dos bloques: el
   bloque de resultados se anida dentro con la misma regla, y así separarlo del
   panel de alta no cambió nada de lo que se ve. */
.stack-list { display: flex; flex-direction: column; gap: 0.9rem; }

/* ── Editor del ciclo del dato ──────────────────────────────────────────── */
.stage-head { display: flex; align-items: center; gap: .7rem; margin-bottom: .9rem; }

/* El número no es decoración: la posición en el ciclo es información, y es
   justamente lo que los botones ▲▼ modifican. */
.stage-num {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--brand-surface);
  color: var(--on-brand);
  font-size: 12px; font-weight: 700;
}
.stage-move { display: flex; gap: .3rem; }
.stage-move form { margin: 0; }
.stage-move .is-disabled { opacity: .3; cursor: default; }

.stage-card .fdrop { margin-bottom: .6rem; }
.stage-assets-label { display: block; margin: 1rem 0 .4rem; font-size: 12px; font-weight: 600; color: var(--sub); }
.stage-chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .4rem; }
.stage-actions { margin-top: 1rem; }
.stage-delete { margin-top: .8rem; padding-top: .8rem; border-top: 1px solid var(--line-soft); }

/* Plantillas de arranque: la fila entera es la propuesta y el botón la aplica. */
.stage-template {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .85rem 0;
  border-bottom: 1px solid var(--line-soft);
  margin: 0;
}
.stage-template:last-child { border-bottom: none; }
.stage-track { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin-top: .4rem; }
.stage-arrow { color: var(--slate); font-size: 11px; }

/* ── Leyenda del diagrama de flujo de datos ─────────────────────────────── */
.diagram-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin-top: .75rem;
  font-size: .82rem;
  color: var(--sub);
}
/* Cada símbolo dibuja la figura que nombra. Antes todos los span compartían
   el mismo cuadrado gris, de modo que «rectángulo recto», «redondeado»,
   «abierto» y «línea de puntos» se veían idénticos — y el que anunciaba el
   borde naranjo se pintaba gris, contradiciendo su propia etiqueta. */
.diagram-legend span::before {
  content: '';
  display: inline-block;
  width: .8rem;
  height: .7rem;
  margin-right: .4rem;
  border: 1.5px solid var(--slate);
  vertical-align: baseline;
}
.diagram-legend .sym-entity::before   { border-radius: 0; }
.diagram-legend .sym-process::before  { border-radius: 6px; background: var(--brand-soft); border-color: var(--navy); }
.diagram-legend .sym-store::before    { border-right: none; border-left-width: 4px; border-radius: 0; }
.diagram-legend .sym-boundary::before { border-style: dashed; border-radius: 3px; }
.diagram-legend .sym-foreign::before  { border-color: #9a4a12; border-width: 2px; }

/* ── M3 · EIPD: criterios, matriz de riesgo y fichas de riesgo ──────────────
   La matriz es la única figura de la aplicación que no es un diagrama SVG: son
   16 casillas con un color por nivel, y se pinta con la misma familia semántica
   que los chips (ok/warn/crit/err) para que «alto» sea del mismo naranja acá y
   en el listado. */

/* Las diez casillas del test de procedencia llevan explicación debajo, así que
   cada una ocupa su línea y la casilla se alinea con la primera. */
.criteria-grid { display: grid; gap: 0.8rem; margin-top: 0.4rem; }
.criteria-grid .check { align-items: flex-start; }
.criteria-grid .check > input { margin-top: 3px; }

/* Encabezado de cada grupo del test de procedencia. Los dos grupos tienen
   fuerza legal distinta, así que se separan visualmente y no se mezclan. */
.criteria-group {
  margin: 1.4rem 0 0.2rem;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--sub);
}

/* Chequeo del contenido mínimo que exige el artículo: una fila por elemento,
   con el estado a la izquierda alineado con la primera línea. */
.legal-check { margin: 0; padding: 0; list-style: none; }
.legal-check li {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--line-soft);
  font-size: 13.5px;
}
.legal-check li:first-child { border-top: none; }
.legal-check .state { flex-shrink: 0; min-width: 52px; padding-top: 2px; }
.legal-check .muted-small { display: block; }

.criteria-list { margin: 0; padding-left: 1.1rem; }
.criteria-list li { margin-bottom: 0.65rem; font-size: 13.5px; }
.criteria-list .muted-small { display: block; }

.risk-matrix { border-collapse: separate; border-spacing: 4px; }
.risk-matrix th {
  padding: 4px 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--sub);
  text-align: center;
}
.risk-matrix th[scope="row"] { text-align: right; white-space: nowrap; }
.risk-matrix-corner {
  font-size: 10px !important;
  font-weight: 400 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  text-align: right !important;
}
.risk-cell {
  width: 78px;
  height: 46px;
  border-radius: var(--r);
  background: var(--line-soft);
  text-align: center;
  vertical-align: middle;
  font-size: 15px;
  font-weight: 700;
  color: var(--sub);
}
.risk-cell.is-ok   { background: rgba(30,132,73,.12); }
.risk-cell.is-warn { background: rgba(209,129,12,.14); }
.risk-cell.is-crit { background: rgba(192,95,28,.18); }
.risk-cell.is-err  { background: rgba(192,57,43,.20); }
/* Sólo las casillas ocupadas se marcan: la matriz vacía es un fondo, no un dato. */
.risk-cell.has-risks { color: var(--navy); box-shadow: inset 0 0 0 2px var(--brand-ring); }

.risk-legend { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-top: 1rem; }

.risk-head { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.risk-subtitle {
  margin: 1rem 0 0.3rem;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--sub);
}

.risk-edit { margin-top: 1rem; padding-top: 0.8rem; border-top: 1px solid var(--line-soft); }
.risk-edit > summary { cursor: pointer; font-size: 12px; font-weight: 600; color: var(--sub); }
.risk-edit > summary:hover { color: var(--navy); }
.risk-scales { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 0 1.1rem; }


/* ── Barra lateral contraída ────────────────────────────────────────────────
   Hasta acá ningún @media tocaba el chasis fuera de @media print: la barra se
   quedaba con su ancho fijo siempre, y en un teléfono de 375 px se llevaba el
   56 % de la pantalla dejando el contenido operando en el resto.

   A partir del breakpoint de la familia (800 px) se contrae a --sb-w-min y
   quedan sólo los iconos, que siguen siendo enlaces con su mismo destino y su
   mismo marcador de activo. No es un panel deslizante con velo y botón como en
   Control-de-Horas y Seguimiento: acá no hay JavaScript de chasis que mantener
   —el único JS de la app es el filtrado— y una barra de 76 px siempre visible
   no necesita que nadie la abra.

   Las etiquetas no se ocultan con display:none sino con el mismo recorte que
   .visually-hidden: el icono no tiene texto propio, así que si la etiqueta
   desapareciera del árbol de accesibilidad el enlace se quedaría sin nombre.
   Así se va de la pantalla y se queda en el lector. */
@media (max-width: 800px) {
  .sidebar { width: var(--sb-w-min); }

  .sb-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .sidebar-brand,
  .sidebar-brand-block { padding-left: 0; padding-right: 0; text-align: center; }
  .sidebar-brand { font-size: 13px; letter-spacing: .5px; }

  .sidebar-nav a,
  .sidebar-soon { justify-content: center; gap: 0; padding-left: 0; padding-right: 0; }
  .sidebar-nav a .nav-icon,
  .sidebar-soon .nav-icon { font-size: 16px; }

  /* El rótulo de sección y el «pronto» de la consola no caben en 76 px, y
     ninguno de los dos es un mando: son letreros. */
  .sidebar-section,
  .sidebar-soon em,
  .console-badge { display: none; }

  /* En el pie sólo sobrevive el botón de salir, con su icono. El nombre de la
     empresa y el de la persona ya están en la propia pantalla. */
  .sidebar-footer { padding-left: 0.5rem; padding-right: 0.5rem; }
  .sidebar-company,
  .sidebar-user { display: none; }
  .sidebar-footer .btn { padding-left: 0; padding-right: 0; }
}

/* ── Impresión ──────────────────────────────────────────────────────────────
   Lo que se imprime de esta aplicación son fichas y diagramas que terminan
   dentro de un informe o de una carpeta de auditoría. Sin estas reglas salía
   la barra lateral navy de 210 px, la navegación y los botones — y sin
   ninguna referencia de cuándo se generó el documento. */
.print-footer { display: none; }

@media print {
  :root { --white: #fff; }

  body { background: #fff; color: #000; }

  /* Navegación, acciones y controles no existen en papel. */
  .sidebar,
  .app-footer,
  .site-footer,
  /* La cabecera pública sí se queda: lleva el logo de la empresa, que en papel
     es identificación. Lo que sobra es su navegación. */
  .site-nav,
  .actions,
  .filterbar,
  .pager,
  .impersonation-bar,
  form:not(.print-keep),
  details > summary,
  /* Cajas que sólo envuelven acciones: en pantalla son el panel donde se
     opera, en papel dejaban un título con el cuerpo vacío (el formulario ya
     está oculto por la regla de arriba). */
  .no-print { display: none !important; }

  /* El texto alternativo del diagrama sí se imprime: es la versión legible
     de lo que la figura muestra, y no todo el mundo lee un plano. */
  details { display: block !important; }
  details > p { margin-top: 0 !important; }

  .app-shell,
  .app-content,
  .container { display: block; max-width: none; margin: 0; padding: 0; }

  .card, .panel, .table-card {
    box-shadow: none;
    border: 1px solid #ccc;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  h1, h2, h3 { break-after: avoid; page-break-after: avoid; }
  table { break-inside: auto; }
  tr { break-inside: avoid; page-break-inside: avoid; }

  /* El diagrama entra completo en el ancho de la página. */
  [style*="overflow-x"] { overflow: visible !important; }
  [style*="min-width"] { min-width: 0 !important; }
  svg { max-width: 100%; height: auto; }

  .print-footer {
    display: block;
    margin-top: 1rem;
    padding-top: .5rem;
    border-top: 1px solid #ccc;
    font-size: 9pt;
    color: #444;
  }

  a[href^="/"]::after { content: ""; }
}

/* ── Fluidez: entradas breves ─────────────────────────────────────────── */
@keyframes fdrop-entra { from { opacity: 0; transform: translateY(-4px); } }
@keyframes panel-entra { from { opacity: 0; } }
.fdrop[open] > .fdrop-menu { animation: fdrop-entra 120ms var(--ux-ease); }
.panel-add[open] > :not(summary),
details.eval-panel[open] > :not(summary) { animation: panel-entra 150ms var(--ux-ease); }
@media print { .toasts { display: none !important; } }

/* ── «Evaluar» de Cumplimiento como diálogo ─────────────────────────────────
   Sigue siendo un <details>; abierto, su formulario sale centrado sobre un velo
   (en la celda quedaba apretado en 230 px, y una tarjeta flotante la recortaría
   el overflow de la tabla: lo fijo escapa de eso). El velo es el ::before del
   propio <details>, así que un clic en él es un clic en el details y fdrop.js
   lo cierra. Centrado con inset + margin:auto y no con transform, para no pelear
   con la animación de entrada de .eval-panel. */
details.eval-dialogo[open]::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 900;
  background: rgba(25, 47, 80, .55);
  animation: ux-funde var(--ux-dur) var(--ux-ease);
}
details.eval-dialogo > form {
  position: fixed;
  inset: 0;
  z-index: 901;
  margin: auto;
  width: min(460px, calc(100vw - 32px));
  height: fit-content;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  padding: 24px 24px 20px;
  background: var(--white);
  border-radius: var(--r-lg);
  box-shadow: 0 24px 80px rgba(0, 0, 0, .35);
  text-align: left;
  cursor: auto;
}
.eval-dialogo-cab { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 18px; }
.eval-dialogo-cab h3 { margin: 0; font-size: 16px; font-weight: 800; color: var(--navy); line-height: 1.35; }
details.eval-dialogo textarea { resize: vertical; min-height: 110px; }
.eval-dialogo-acciones { display: flex; justify-content: flex-end; gap: 10px; margin: 4px 0 0; }
