/* ===========================================================================
   PerimetroX — Portal de clientes (zona privada)
   EXTENSIÓN de assets/styles.css (cárgalo ANTES). NO redefine el diseño base:
   reutiliza tokens (:root), .shell, .btn*, .sev*, .tag, .glass, .card-hover,
   .icon-badge, .site-header/.nav-inner, .site-footer y el fondo
   (.bg-layers: mesh/grid con parallax sutil por scroll, vía assets/app.js).
   Aquí solo viven los componentes propios del panel (KPIs, tablas, hallazgos…).
   =========================================================================== */

/* ---------- Layout base del portal ----------
   Fondo transparente: lo provee .bg-layers (igual que la landing). */
.px-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: transparent;
}
/* Eleva contenido y footer por encima del fondo fijo (.bg-layers, z-index:0).
   <main> ya recibe z-index:var(--z-base) por la regla global `main{}`. */
.px-main {
  position: relative;
  z-index: var(--z-base);
  flex: 1 0 auto;
  /* deja espacio para el header flotante fijo (.site-header: top 14px + nav-h) */
  padding-top: calc(var(--nav-h) + 46px);
  padding-bottom: clamp(40px, 6vw, 72px);
}
.px-body .site-footer { position: relative; z-index: var(--z-base); }
.px-main > .shell { display: grid; gap: clamp(16px, 2.4vw, 24px); }

/* ---------- Header: usa .site-header de la landing; solo ajustes del portal ---------- */
.site-header .px-head-id {
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.82);
  max-width: 34ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.site-header .px-head-id strong { color: #fff; font-weight: 600; }
@media (max-width: 900px) { .site-header .nav-links { display: none; } }
@media (max-width: 560px) { .site-header .px-head-id { display: none; } .px-hide-sm { display: none; } }

/* Accesos del portal: son enlaces directos, no un menú desplegable. La
   navegación usa una segunda fila antes de que sus enlaces puedan invadir el
   logo, la identidad o las acciones de sesión.
   Escopado a `[data-px-page]` (portal real Y panel admin, que sí imprimen ese
   atributo en <body> con distintos valores) y no a `.px-body` en general:
   /demo-portal.html también usa la clase `.px-body` para reutilizar las
   tarjetas/tablas de este archivo, pero reusa la MISMA navegación pública
   que el resto del sitio (sin .px-head-id ni sesión) y no debe partirse en
   una segunda fila — eso es lo que la hacía "verse fea" ahí y en ningún
   otro lado.
   flex-wrap (2026-09-01, no grid): un grid con número de columnas fijo
   (`repeat(N, ...)`) obliga a que la última fila reparta el ancho completo
   entre SOLO los enlaces que le tocaron, dejando una franja vacía enorme
   cada vez que el conteo real de enlaces no es múltiplo exacto de N — pasa
   siempre en el panel admin (8 enlaces fijos sobre un N pensado para otro
   conteo) y en el portal cada vez que "Recomendaciones" se muestra (el
   enlace se oculta/muestra según si el informe trae recomendaciones, así
   que el conteo visible cambia solo). flex-wrap + justify-content:center
   no tiene ese problema por diseño: cada enlace mide lo que necesita su
   texto y la fila sobrante queda centrada, se vea 5, 6, 7 u 8 enlaces. */
.px-body[data-px-page] .site-header .nav-links { min-width: 0; }
.px-body[data-px-page] .site-header .nav-inner {
  height: auto;
  min-height: var(--nav-h);
  flex-wrap: wrap;
  gap: 0;
  padding: 7px 12px 8px 20px;
  border-radius: 24px;
}
.px-body[data-px-page] .site-header .nav-links {
  order: 3;
  flex: 1 0 100%;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px 6px;
  margin: 5px 0 0;
  padding-top: 5px;
  border-top: 1px solid rgba(255, 255, 255, 0.16);
}
.px-body[data-px-page] .site-header .nav-links > a {
  min-width: 0;
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 8px 12px;
}
.px-body[data-px-page] .px-main { padding-top: calc(var(--nav-h) + 94px); }
.px-body[data-px-page] section[id] { scroll-margin-top: 142px; }
@media (max-width: 1080px) {
  .px-body[data-px-page] .site-header .px-head-id,
  .px-body[data-px-page] .site-header .nav-cta .btn-primary { display: none; }
  .px-body[data-px-page] .site-header .nav-links { margin: 0 4px; gap: 1px 2px; }
  .px-body[data-px-page] .site-header .nav-links > a { padding: 8px 10px; font-size: 13px; }
}
@media (max-width: 900px) {
  .px-body[data-px-page] .site-header .nav-links { display: flex; }
}
@media (max-width: 720px) {
  /* Antes esta franja pasaba a scroll horizontal (overflow-x: auto) sin
     ninguna pista visual de que hubiera más enlaces fuera de pantalla --
     en un teléfono angosto "Inventario", "Exclusiones e Inclusiones" y
     "Comparar" quedaban completamente invisibles y sin ningún indicio de
     que existieran (detectado en revisión mobile, 2026-09-01). Se mantiene
     el flex-wrap heredado de la regla de arriba: todos los enlaces quedan
     siempre visibles, repartidos en 2 filas en vez de ocultos. */
  .px-body[data-px-page] .site-header .nav-links > a { padding: 7px 9px; font-size: 12.5px; }
}

/* ---------- Breadcrumbs ---------- */
.px-crumbs {
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  color: var(--text-dim);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.px-crumbs a { color: var(--text-muted); }
.px-crumbs a:hover { color: var(--cyan); }
.px-crumbs .sep { opacity: 0.5; }

/* ---------- Encabezado de página ---------- */
.px-page-head { display: grid; gap: 8px; }
.px-admin-return { justify-self: start; margin-top: 6px; }
.px-h1 {
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: clamp(26px, 4vw, 38px);
  font-weight: 600;
  line-height: 1.1;
}
.px-h2 {
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: clamp(18px, 2.4vw, 22px);
  font-weight: 600;
}
.px-lead { color: var(--text-muted); max-width: 70ch; }
.px-muted { color: var(--text-muted); }
.px-mono { font-family: "JetBrains Mono", monospace; }
.px-mt { margin-top: 12px; }
.px-mt-lg { margin-top: 16px; }
/* Inventario: control "Mostrar más" (paginacion incremental por seccion). */
.px-inventory-more { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.px-inventory-more-info { font-size: 13px; color: var(--text-dim); }

/* ---------- Tarjetas: el look glass viene de .glass; aquí solo padding/cabecera ---------- */
.px-card { padding: clamp(16px, 2.4vw, 24px); overflow: hidden; }
.px-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  /* Franja de cabecera a sangre completa (tira los márgenes del propio
     padding de .px-card) para separar visualmente cada sección del panel,
     en vez de un simple borde inferior — mismo contenido/ids, solo look. */
  margin: calc(-1 * clamp(16px, 2.4vw, 24px)) calc(-1 * clamp(16px, 2.4vw, 24px)) 14px;
  padding: 14px clamp(16px, 2.4vw, 24px) 12px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--line-soft);
}
.px-card-title { display: flex; align-items: center; gap: 12px; min-width: 0; }
.px-card-title h2, .px-card-title h3, .px-card-head h2, .px-card-head h3 {
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: 16px;
  font-weight: 600;
}
/* badge de icono algo más compacto que en la landing (títulos de 16px) */
.px-card-title .icon-badge { width: 38px; height: 38px; border-radius: 11px; }
.px-card-title .icon-badge svg { width: 19px; height: 19px; }
.px-card-sub { color: var(--text-muted); font-size: 14px; }

/* ---------- Selector de dominio (varios dominios bajo el mismo cliente) ---------- */
.px-domain-switcher { margin-bottom: 14px; }
.px-domain-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--text-muted);
}
.px-domain-select {
  font: inherit;
  color: var(--text-strong, inherit);
  background: var(--surface-2, transparent);
  border: 1px solid var(--border, #ccc);
  border-radius: 8px;
  padding: 4px 8px;
}

/* ---------- Selector de reportes ---------- */
.px-report-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.px-report-tab {
  min-height: 42px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.62);
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  font: 700 13px/1.2 "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  cursor: pointer;
}
.px-report-tab:hover { border-color: var(--line-strong); }
.px-report-tab.is-active {
  border-color: rgba(167, 43, 67, 0.42);
  background: rgba(167, 43, 67, 0.09);
  color: var(--brand-dark);
}
.px-report-tab .meta {
  color: var(--text-dim);
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 600;
}
.px-report-tab.is-hidden { opacity: 0.72; }

/* Agrupa las pestañas por bloque (lanzamiento comercial: país1/país2/merged
   de una misma contratación). Cada bloque ocupa su propia fila dentro del
   contenedor flex-wrap existente (width:100% fuerza el salto de línea). */
.px-report-tab-group {
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.42);
  width: 100%;
  overflow: hidden;
}
.px-report-tab-group-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 14px;
  cursor: pointer;
  color: var(--text);
  font-size: 13px;
  list-style: none;
}
.px-report-tab-group-label::-webkit-details-marker { display: none; }
.px-report-tab-group-label::before {
  content: "+";
  color: var(--brand-dark);
  font: 700 16px/1 "JetBrains Mono", monospace;
}
.px-report-tab-group[open] .px-report-tab-group-label::before { content: "−"; }
.px-report-tab-group-label strong { margin-right: auto; }
.px-report-tab-group-count {
  color: var(--text-dim);
  font: 600 11px/1 "JetBrains Mono", monospace;
  white-space: nowrap;
}
.px-report-tab-group-content {
  display: grid;
  gap: 8px;
  padding: 0 14px 14px;
  border-top: 1px solid var(--line-soft);
}
.px-report-tabs-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* Subdivide cada bloque comercial en "trios" (Unificado + Region1 + Region2
   de un mismo lanzamiento de análisis). Cada trio es su propio grupo visual,
   separado del resto por un borde punteado sutil (no una caja cerrada, para
   no competir visualmente con .px-report-tab-group). */
.px-report-batch {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px 0 2px;
  border-top: 1px dashed var(--line-soft);
}
.px-report-batch:first-child {
  border-top: none;
  padding-top: 8px;
}
.px-report-batch-label {
  margin: 0;
  font-size: 11.5px;
  color: var(--text-muted);
}

/* ---------- Grids ---------- */
.px-grid { display: grid; gap: 16px; }
.px-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.px-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.px-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 860px) {
  .px-grid--3, .px-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .px-grid--2, .px-grid--3, .px-grid--4 { grid-template-columns: 1fr; }
}

/* ---------- Tiles de métrica ---------- */
.px-stat {
  background: var(--panel-solid);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 14px 16px;
  display: grid;
  gap: 4px;
}
.px-stat .num {
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: clamp(22px, 3vw, 30px);
  font-weight: 700;
  line-height: 1;
}
.px-stat .lbl { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.px-stat .num--sm { font-size: 16px; }
.px-stat .num--md { font-size: 18px; }
/* align-items: start (no "end"): con 3 partes angostas ("Dominios activos" /
   "IPs directas" / "Servicios") la etiqueta mas larga envuelve a 2 lineas en
   pantallas chicas/medianas; con "end" eso desalinea los NUMEROS entre si
   (cada parte se ancla por abajo). Con "start" los numeros quedan siempre en
   la fila superior, alineados entre las 3 partes, sea cual sea el largo de
   cada etiqueta debajo. */
.px-stat--split { grid-template-columns: repeat(var(--px-stat-parts, 2), 1fr); align-items: start; }
.px-stat-part { display: grid; gap: 4px; }

/* ---------- Score + nivel de exposición ---------- */
.px-score { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.px-score .val {
  font-family: "Space Grotesk", "Inter", sans-serif;
  font-size: clamp(40px, 7vw, 60px);
  font-weight: 700;
  line-height: 1;
  background: var(--grad-text);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}
.px-score .max { color: var(--text-dim); font-size: 18px; }
.px-exposure {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: "JetBrains Mono", monospace;
  font-size: 12px; font-weight: 600; text-transform: uppercase;
  padding: 5px 12px; border-radius: 999px; border: 1px solid currentColor;
}
.px-exposure .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; }
.px-exposure--critico { color: var(--crit); background: rgba(167, 43, 67, 0.10); }
.px-exposure--alto    { color: var(--high); background: rgba(200, 71, 21, 0.10); }
.px-exposure--medio   { color: var(--med);  background: rgba(159, 119, 1, 0.10); }
.px-exposure--bajo    { color: var(--low);  background: rgba(4, 154, 237, 0.10); }
.px-meter { height: 10px; border-radius: 999px; background: rgba(100, 99, 100, 0.16); overflow: hidden; margin-top: 14px; }
.px-meter > i { display: block; height: 100%; border-radius: 999px; background: var(--grad-brand); }
/* La tarjeta de score responde al nivel real de exposición que ya calcula
   portal.js (clase .px-exposure--* existente, sin lógica nueva): un acento
   superior de color hace que el KPI más importante del panel destaque del
   resto de tarjetas a simple vista, en vez de verse igual que todas. */
.px-card:has(.px-exposure--critico) { border-top: 3px solid var(--crit); }
.px-card:has(.px-exposure--alto) { border-top: 3px solid var(--high); }
.px-card:has(.px-exposure--medio) { border-top: 3px solid var(--med); }
.px-card:has(.px-exposure--bajo) { border-top: 3px solid var(--low); }

/* ---------- Severidad: conteos ---------- */
.px-sevgrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 560px) { .px-sevgrid { grid-template-columns: repeat(2, 1fr); } }
.px-sevtile {
  border: 1px solid var(--line);
  border-top-width: 3px;
  border-radius: var(--r-md);
  padding: 14px 16px;
  display: grid;
  gap: 8px;
  background: var(--panel-solid);
  transition: transform 0.15s var(--ease), box-shadow 0.2s var(--ease);
}
.px-sevtile:hover { transform: translateY(-2px); box-shadow: var(--shadow-card); }
.px-sevtile .count { font-family: "Space Grotesk", "Inter", sans-serif; font-size: 30px; font-weight: 700; line-height: 1; }
.px-sevtile--crit { border-color: var(--line); border-top-color: var(--crit); }
.px-sevtile--crit .count { color: var(--crit); }
.px-sevtile--high { border-color: var(--line); border-top-color: var(--high); }
.px-sevtile--high .count { color: var(--high); }
.px-sevtile--med  { border-color: var(--line); border-top-color: var(--med); }
.px-sevtile--med .count { color: var(--med); }
.px-sevtile--low  { border-color: var(--line); border-top-color: var(--low); }
.px-sevtile--low .count { color: var(--low); }
.sev-info { color: var(--text-dim); background: rgba(100, 99, 100, 0.10); }

/* ---------- Dashboard (#pxDashboardSection) ----------
   Gráficos propios en SVG/CSS, sin librerías externas (mismo criterio que
   .px-trend-card, ver portal.js#buildTrendCard): CSP script-src 'self'. */
.px-dash-grid { display: grid; gap: 16px; margin-top: 16px; }
.px-dash-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 760px) { .px-dash-grid--2 { grid-template-columns: 1fr; } }
.px-dash-panel {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 18px;
  transition: box-shadow 0.18s var(--ease, ease), transform 0.18s var(--ease, ease), border-color 0.18s var(--ease, ease);
}
.px-dash-panel:hover { box-shadow: var(--shadow-card); transform: translateY(-1px); border-color: var(--line-strong); }
.px-dash-panel--wide { margin-top: 16px; }
.px-dash-panel .px-h3 { margin: 0 0 12px; }
.px-dash-panel .px-trend-grid { margin-top: 0; }

/* Medidor de score (#pxDashScoreGauge): pieza "hero" del Dashboard, arco
   semicircular vía path SVG (describeArc/polarToCartesian en portal.js) —
   el color del arco es SIEMPRE el mismo que .px-exposure ya usa para
   report.exposureLevel, nunca un umbral numérico inventado en el frontend. */
.px-dash-hero {
  margin: 16px 0;
  background: linear-gradient(135deg, rgba(167, 43, 67, 0.07), rgba(4, 154, 237, 0.05));
}
.px-gauge-wrap { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.px-gauge-svg { width: 260px; max-width: 100%; height: auto; flex: none; }
.px-gauge-track { stroke: rgba(100, 99, 100, 0.16); }
.px-gauge-value { stroke: currentColor; filter: drop-shadow(0 0 9px currentColor); }
.px-gauge-tip { fill: currentColor; filter: drop-shadow(0 0 7px currentColor); }
.px-gauge-value-text { font: 700 44px "Space Grotesk", "Inter", sans-serif; fill: var(--text); }
.px-gauge-max-text { font: 600 13px "Inter", sans-serif; fill: var(--text-dim); }
.px-gauge--critico { color: var(--crit); }
.px-gauge--alto { color: var(--high); }
.px-gauge--medio { color: var(--med); }
.px-gauge--bajo { color: var(--low); }
.px-gauge-side { display: grid; gap: 9px; flex: 1 1 210px; min-width: 210px; }
.px-gauge-kicker { font: 600 11px "Inter", sans-serif; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-dim); }
.px-gauge-copy { margin: 0; }

/* Donuts (severidad / confianza de verificación): trazo en currentColor
   para poder aplicarle glow por CSS, igual que .px-exposure .dot. */
.px-donut-wrap { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.px-donut-svg { width: 140px; height: 140px; flex: none; filter: drop-shadow(0 2px 5px rgba(38, 38, 38, 0.08)); }
.px-donut-seg { transition: filter 0.15s var(--ease, ease); }
.px-donut-seg:hover { filter: drop-shadow(0 0 7px currentColor); }
.px-donut-center-value { font: 700 26px "Space Grotesk", "Inter", sans-serif; fill: var(--text); }
.px-donut-center-label { font: 500 10px "Inter", sans-serif; fill: var(--text-dim); }
.px-donut-legend { display: grid; gap: 7px; flex: 1 1 175px; min-width: 175px; }
.px-donut-legend-row {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 600;
  padding: 6px 9px;
  border-radius: 9px;
  border-left: 3px solid currentColor;
  background: rgba(100, 99, 100, 0.05);
  transition: background 0.15s var(--ease, ease);
}
.px-donut-legend-row:hover { background: rgba(100, 99, 100, 0.11); }
.px-donut-legend-text { color: currentColor; }
.px-donut-legend-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; box-shadow: 0 0 5px currentColor; }
.px-donut-legend-pct { color: var(--text-dim); font-weight: 500; font-size: 11.5px; width: 34px; text-align: right; }
.px-donut-legend-count { margin-left: auto; font: 700 13px "JetBrains Mono", monospace; color: var(--text); }
.px-donut-empty, .px-hbar-empty { color: var(--text-dim); font-size: 13px; }

/* Barras horizontales (inventario por categoría, activos con más hallazgos,
   cambios vs. análisis anterior) */
.px-hbar-list { display: grid; gap: 9px; }
.px-hbar-row { display: grid; grid-template-columns: 132px 1fr auto; align-items: center; gap: 10px; padding: 3px 0; }
.px-hbar-list.is-ranked .px-hbar-row { grid-template-columns: 22px 150px 1fr auto; }
.px-hbar-rank {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--grad-brand); color: #fff;
  font: 700 11px "Space Grotesk", "Inter", sans-serif;
}
.px-hbar-label { font-size: 12.5px; color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.px-hbar-track { height: 10px; border-radius: 999px; background: rgba(100, 99, 100, 0.13); overflow: hidden; }
.px-hbar-track > i { display: block; height: 100%; border-radius: 999px; background: var(--grad-brand); box-shadow: 0 0 7px rgba(167, 43, 67, 0.32); transition: width 0.5s var(--ease, ease); }
.px-hbar-value {
  font: 700 12px "JetBrains Mono", monospace; color: var(--text); text-align: center;
  background: rgba(100, 99, 100, 0.09); border-radius: 999px; padding: 2px 9px; min-width: 26px;
}
.px-hbar-row.is-new .px-hbar-track > i { background: var(--high); box-shadow: 0 0 7px rgba(200, 71, 21, 0.32); }
.px-hbar-row.is-persisting .px-hbar-track > i { background: var(--brand); box-shadow: 0 0 7px rgba(167, 43, 67, 0.32); }
.px-hbar-row.is-gone .px-hbar-track > i { background: var(--ok); box-shadow: 0 0 7px rgba(22, 138, 91, 0.32); }
@media (max-width: 480px) {
  .px-hbar-row { grid-template-columns: 96px 1fr 34px; }
  .px-hbar-list.is-ranked .px-hbar-row { grid-template-columns: 18px 86px 1fr 34px; }
}

/* Relleno de las tarjetas de tendencia (.px-trend-card, ver
   portal.js#buildTrendCard) — usa currentColor, por eso cada variante de
   color abajo fija `color` sobre el propio SVG, no solo sobre line/dot.
   Puramente decorativo: la polyline con el dato real sigue dibujándose
   encima, sin cambios.
   Geometría (2026-09-02, corregido a pedido del propietario: "el relleno
   que está entre los puntos y la traza que traza el inicio y final" —
   antes el <polygon> cerraba contra una línea base fija en la parte
   inferior de la tarjeta, produciendo una cuña grande sin relación con la
   forma del dato). Ahora el JS arma el `<polygon>` SOLO con los puntos
   reales: un <polygon> siempre cierra en línea recta desde el último
   punto hasta el primero, así que ese cierre automático ES la "traza
   inicio-final" — el área queda angosta donde el dato sigue la tendencia
   recta y más ancha donde se aparta de ella.
   Semitransparente Y en degradado a la vez (2026-09-02, pedido explícito
   final del propietario: "debe de ser semitransparente y degradado el
   color, de todos los de su mismo tipo" — aplica a las 8 variantes de
   color de abajo, no solo a "score"). Un primer intento había aplanado la
   opacidad (mismo valor en los 2 stops) porque el degradado 0.30→0
   original parecía "no funcionar" — pero la causa real era otro bug (ver
   nota debajo de `.px-trend-dot`): la propia línea de tendencia se
   pintaba con relleno opaco encima, tapando cualquier transparencia o
   degradado del área. Corregido ese bug, se restaura un degradado real
   que NUNCA llega a opacidad 0 (para que siga siendo reconociblemente
   translúcido de punta a punta, en vez de desvanecerse a invisible como
   en el primer intento). */
.px-trend-area { pointer-events: none; }
.px-trend-area-stop-a { stop-color: currentColor; stop-opacity: 0.34; }
.px-trend-area-stop-b { stop-color: currentColor; stop-opacity: 0.10; }
/* Traza recta discreta que une el primer punto con el último (el borde de
   cierre del <polygon> de arriba) — sin trazo visible se leería como un
   corte diagonal sin explicación. Punteada y más tenue que la línea real
   de datos para que quede claro cuál es cuál. */
.px-trend-chord { stroke: currentColor; stroke-width: 1; stroke-dasharray: 2.5 3; stroke-opacity: 0.55; fill: none; pointer-events: none; }
/* Degradado del propio trazo (2026-09-01): antes .px-trend-line usaba un
   stroke plano (var(--brand)/var(--crit)/etc. más abajo); ahora esas reglas
   quedan como fallback (por si algún navegador no resuelve el gradiente) y
   buildTrendCard()/demo-portal.js fijan `stroke` inline con
   url(#...Line) — más sutil en el origen, más vívido hacia el punto más
   reciente. Mismo currentColor que ya usa el área, nunca un color nuevo. */
/* Degradado de 2 tonos DENTRO del mismo color (nunca un color distinto: eso
   ya se probó y se veía chocante, ver nota de más abajo) -- color-mix() en
   vez de solo opacidad porque un fade de opacidad contra una línea zigzag
   se notaba demasiado sutil, casi plano. */
.px-trend-line-stop-a { stop-color: color-mix(in srgb, currentColor 55%, black); stop-opacity: 1; }
.px-trend-line-stop-b { stop-color: currentColor; stop-opacity: 1; }
.px-trend-dot.is-last { filter: drop-shadow(0 0 4px currentColor); }
.px-trend-card.is-score .px-trend-card-svg { color: var(--brand); }
.px-trend-card.is-critical .px-trend-card-svg { color: var(--crit); }
.px-trend-card.is-high .px-trend-card-svg { color: var(--high); }
.px-trend-card.is-medium .px-trend-card-svg { color: var(--med); }
.px-trend-card.is-low .px-trend-card-svg { color: var(--low); }
.px-trend-card.is-neutral-subdomains .px-trend-card-svg { color: var(--cyan); }
.px-trend-card.is-neutral-cloud .px-trend-card-svg { color: var(--teal); }
.px-trend-card.is-neutral-cctv .px-trend-card-svg { color: var(--violet); }

/* ---------- Tablas ---------- */
/* Contenedor con scroll horizontal (mouse/trackpad/táctil) sin ocultar
   columnas: min-width en la tabla obliga al navegador a mostrar la
   scrollbar en vez de comprimir cada celda hasta hacerla ilegible.
   tabindex="0" (puesto en el HTML) permite recorrerlo con teclado. */
.px-table-wrap {
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: thin; max-width: 100%;
  min-width: 0;
}
/* min-width:0 en cualquier contenedor grid/flex que pueda envolver una
   .px-table-wrap: sin esto, un item de grid/flex usa min-width:auto (el
   tamaño min-content de su contenido, incluida la tabla ancha) y puede
   ensanchar la tarjeta/columna entera en vez de dejar que la tabla
   desplace horizontalmente DENTRO de su propio contenedor. */
.px-card, .px-grid > *, .form-grid > * { min-width: 0; }
.px-table-wrap:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; }
.px-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.px-table--sticky-actions { min-width: 960px; }
.px-table th, .px-table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.px-table th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-dim); border-bottom: 1px solid var(--line); }
.px-table tbody tr:hover { background: rgba(4, 154, 237, 0.04); }
.px-table .mono { font-family: "JetBrains Mono", monospace; font-size: 13px; }

/* Fila de encabezado de bloque (agrupa reportes por lanzamiento comercial:
   país1/país2/merged de una misma contratación). Nunca recibe :hover ni
   acciones — es puramente informativa. */
.px-table tr.px-block-head td {
  background: var(--panel-2);
  font-size: 12.5px;
  color: var(--text-muted);
  padding-top: 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.px-table tr.px-block-head:hover td { background: var(--panel-2); }
.px-table tr.px-block-head td strong { color: var(--text); }

/* Fila de subgrupo "trio" (Unificado + Region1 + Region2 de un mismo
   lanzamiento) dentro de un bloque comercial. Más discreta que el
   encabezado de bloque: no repite el fondo, solo separa con texto tenue. */
.px-table tr.px-batch-head td {
  font-size: 11.5px;
  color: var(--text-muted);
  padding-top: 8px;
  padding-bottom: 4px;
  border-bottom: none;
}
.px-table tr.px-batch-head:hover td { background: transparent; }

/* Herramienta "Comparar reportes" (elección manual del usuario, distinta de
   la comparación automática de #pxComparisonSection): 2 selects + botón,
   resultado con deltas de score/severidad. */
.px-compare-pickers {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; margin-top: 10px;
}
.px-compare-pickers .field { flex: 1 1 220px; margin: 0; }
.px-compare-pickers .btn { flex: 0 0 auto; }
.px-compare-sevgrid {
  display: flex; flex-direction: column; gap: 6px; margin: 12px 0;
  border: 1px solid var(--line); border-radius: 10px; padding: 10px 14px;
}
.px-compare-sevrow {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 13.5px;
}
.px-compare-sevrow-label { color: var(--text-dim); }
.px-compare-sevrow-count { font-family: "JetBrains Mono", monospace; color: var(--text); }
.px-compare-sevrow-arrow { font-weight: 700; font-family: "JetBrains Mono", monospace; min-width: 2.5em; text-align: right; }
.px-compare-sevrow-arrow--empeoro { color: var(--high); }
.px-compare-sevrow-arrow--mejoro { color: var(--ok); }
.px-compare-sevrow-arrow--sin_cambio { color: var(--text-dim); }

/* Comparaciones: el resultado se organiza por decisiones (riesgo, hallazgos,
   severidad e inventario), no como una lista de texto técnico. */
#pxComparison, #pxCompareResult { display: grid; gap: 16px; }
.px-compare-result-heading {
  margin: 0; color: var(--text-dim); font: 600 12px/1.45 "JetBrains Mono", monospace;
}
.px-comparison-overview { display: grid; gap: 12px; }
.px-comparison-risk {
  display: grid; gap: 4px; padding: 16px; border: 1px solid var(--line-strong);
  border-radius: 12px; background: linear-gradient(135deg, rgba(37, 99, 235, 0.08), rgba(255, 255, 255, 0.74));
}
.px-comparison-risk.is-empeoro { border-color: rgba(185, 45, 50, 0.35); background: linear-gradient(135deg, rgba(185, 45, 50, 0.10), rgba(255, 255, 255, 0.74)); }
.px-comparison-risk.is-mejoro { border-color: rgba(22, 138, 91, 0.34); background: linear-gradient(135deg, rgba(22, 138, 91, 0.10), rgba(255, 255, 255, 0.74)); }
.px-comparison-kicker, .px-comparison-inventory-label {
  color: var(--text-dim); font: 700 10px/1.2 "JetBrains Mono", monospace;
  letter-spacing: 0.07em; text-transform: uppercase;
}
.px-comparison-risk-score { color: var(--brand-dark); font: 700 28px/1 "Space Grotesk", "Inter", sans-serif; }
.px-comparison-risk-copy { color: var(--text); font-size: 13.5px; }
.px-comparison-impact { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
.px-comparison-impact-card {
  display: grid; gap: 3px; min-width: 0; padding: 12px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
}
.px-comparison-impact-card.is-new { border-top: 3px solid var(--high); }
.px-comparison-impact-card.is-persisting { border-top: 3px solid var(--brand); }
.px-comparison-impact-card.is-gone { border-top: 3px solid var(--ok); }
.px-comparison-impact-number { color: var(--brand-dark); font: 700 23px/1 "Space Grotesk", "Inter", sans-serif; }
.px-comparison-impact-label { color: var(--text); font-size: 13px; font-weight: 700; }
.px-comparison-impact-copy { color: var(--text-dim); font-size: 11.5px; line-height: 1.35; }
/* padding-block: 0 es necesario porque hay una regla global `section {
   padding-block: clamp(64px, 9vw, 120px); }` (styles.css, pensada para las
   secciones grandes de la landing) que por especificidad de selector de
   tipo (no de clase) se cuela en este <section> del portal si no se anula
   explícitamente, dejando ~115px de hueco vacío arriba y abajo de cada
   grupo de comparación. */
.px-comparison-group { display: grid; gap: 7px; padding-block: 0; }
.px-comparison-group > .px-h3, .px-comparison-group > .px-muted { margin: 0; }
.px-comparison-severity { margin: 0; background: var(--panel-2); }
.px-comparison-inventory { display: grid; grid-template-columns: repeat(auto-fit, minmax(145px, 1fr)); gap: 9px; }
.px-comparison-inventory-card {
  display: grid; gap: 5px; padding: 11px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--panel-2);
}
.px-comparison-inventory-card.is-aumento { border-left: 3px solid var(--brand); }
.px-comparison-inventory-card.is-disminuyo { border-left: 3px solid var(--ok); }
.px-comparison-inventory-card.is-sin_cambio { border-left: 3px solid var(--text-dim); }
.px-comparison-inventory-values { color: var(--text); font: 700 16px/1.15 "JetBrains Mono", monospace; }
.px-comparison-inventory-delta { color: var(--text-dim); font-size: 11.5px; }
.px-comparison-detail {
  border: 1px solid var(--line); border-radius: 10px; padding: 0 13px; background: var(--panel-2);
}
.px-comparison-detail > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  cursor: pointer; list-style: none; padding: 12px 0; color: var(--text);
}
.px-comparison-detail > summary::-webkit-details-marker { display: none; }
.px-comparison-detail > summary::before { content: "▸"; color: var(--text-dim); margin-right: 7px; transition: transform 0.15s var(--ease, ease); }
.px-comparison-detail[open] > summary::before { transform: rotate(90deg); }
.px-comparison-detail-count {
  margin-left: auto; color: var(--text-dim); font: 700 10px/1.2 "JetBrains Mono", monospace;
  text-transform: uppercase; white-space: nowrap;
}
.px-comparison-detail > .px-muted { margin: 0 0 9px; }
.px-comparison-finding-list { margin: 0 0 13px; }
@media (max-width: 600px) { .px-comparison-impact { grid-template-columns: 1fr; } }

/* Columna de acciones ("Ver") fija a la derecha: siempre visible sin tener
   que desplazar hasta el final de la tabla. */
.px-table--sticky-actions .px-table-action-col {
  position: sticky; right: 0; background: var(--panel-solid);
  box-shadow: -6px 0 8px -6px rgba(0, 0, 0, 0.35);
  white-space: nowrap;
}
.px-table--sticky-actions tbody tr:hover .px-table-action-col { background: var(--panel-solid); }

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

/* ---------- Filtros plegables ---------- */
.px-filters { margin-bottom: 4px; }
.px-filters-summary {
  cursor: pointer; list-style: none; user-select: none;
  font-weight: 600; font-size: 14px; color: var(--text);
  padding: 8px 0; display: flex; align-items: center; gap: 8px;
}
.px-filters-summary::-webkit-details-marker { display: none; }
.px-filters-summary::before {
  content: "▸"; display: inline-block; transition: transform 0.15s var(--ease, ease);
  color: var(--text-dim);
}
.px-filters[open] > .px-filters-summary::before { transform: rotate(90deg); }
/* Grid de filtros: auto-fit para aprovechar el ancho disponible sin
   forzar columnas fijas que se compriman en pantallas medianas. */
.px-filter-grid { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

/* ---------- Acordeón de detalle ---------- */
.px-detail-section {
  border: 1px solid var(--line-soft); border-radius: var(--r-sm, 10px);
  margin-top: 12px; padding: 0 14px;
}
.px-detail-section > summary {
  cursor: pointer; list-style: none; user-select: none;
  font: 700 15px/1.3 "Space Grotesk", "Inter", sans-serif; color: var(--text);
  padding: 12px 0; display: flex; align-items: center; gap: 8px;
}
.px-detail-section > summary::-webkit-details-marker { display: none; }
.px-detail-section > summary::before {
  content: "▸"; display: inline-block; transition: transform 0.15s var(--ease, ease);
  color: var(--text-dim); flex: none;
}
.px-detail-section[open] > summary::before { transform: rotate(90deg); }
.px-detail-section > summary:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.px-detail-section-body { padding-bottom: 14px; }

/* Accesos del detalle de contratación: se mantienen a la vista en escritorio
   y abren el acordeón elegido antes de desplazarlo a la posición correcta. */
.px-detail-workspace {
  display: grid;
  grid-template-columns: minmax(190px, 220px) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  margin-top: 14px;
}
.px-detail-content { min-width: 0; }
.px-detail-quicknav {
  position: sticky;
  top: calc(var(--nav-h) + 22px);
  display: grid;
  gap: 7px;
  padding: 14px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md, 12px);
  background: rgba(255, 255, 255, 0.68);
  box-shadow: 0 12px 28px -24px rgba(18, 28, 44, 0.38);
}
.px-detail-quicknav-title {
  margin: 0 0 2px;
  color: var(--text-muted);
  font: 700 11px/1.2 "JetBrains Mono", monospace;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.px-detail-quicknav-link {
  width: 100%;
  border: 1px solid transparent;
  border-radius: 9px;
  padding: 9px 10px;
  color: var(--text);
  background: transparent;
  text-align: left;
  font: 600 13px/1.25 "Inter", system-ui, sans-serif;
  cursor: pointer;
}
.px-detail-quicknav-link:hover,
.px-detail-quicknav-link:focus-visible {
  color: var(--brand-dark);
  background: rgba(167, 43, 67, 0.08);
  border-color: rgba(167, 43, 67, 0.2);
  outline: none;
}
@media (max-width: 960px) {
  .px-detail-workspace { grid-template-columns: 1fr; }
  .px-detail-quicknav {
    position: static;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .px-detail-quicknav-title { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .px-detail-quicknav { grid-template-columns: 1fr; }
}

/* ---------- Inventario completo ---------- */
.px-inventory-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.px-inventory-tab {
  min-height: 36px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.64);
  color: var(--text);
  padding: 7px 10px;
  font: 700 12px/1.2 "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  cursor: pointer;
}
.px-inventory-tab.is-active {
  border-color: rgba(4, 154, 237, 0.38);
  background: rgba(4, 154, 237, 0.08);
  color: var(--brand-dark);
}
.px-inventory-search {
  display: grid;
  gap: 6px;
  max-width: 420px;
  margin-bottom: 12px;
}
.px-inventory-search span {
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
}
.px-inventory-search input {
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.88);
  color: var(--text);
  font: 500 14px/1.3 "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  padding: 8px 10px;
}
.px-inventory-search input:focus {
  outline: 0;
  border-color: rgba(4, 154, 237, 0.34);
  box-shadow: 0 0 0 4px rgba(4, 154, 237, 0.08);
}
.px-inventory-panel { display: grid; gap: 10px; }
.px-inventory-panel .px-table td { max-width: 380px; overflow-wrap: anywhere; }

/* Vistas agrupadas (puertos confirmados vs no reconocibles, directorios por status) */
.px-grouped { display: grid; gap: 14px; }
.px-group-head {
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-dim); padding-bottom: 2px; border-bottom: 1px solid var(--line);
}
/* Grupos colapsables del inventario (agrupado genérico + Información sensible
   agrupada): reusa el acordeón .px-detail-section, sin el margin-top propio
   (el gap de .px-grouped / .px-findings-list ya separa los <details> entre sí). */
.px-inv-group.px-detail-section { margin-top: 0; }
/* VHosts con sus directorios */
.px-vhosts { display: grid; gap: 12px; }
.px-vhost-card { border: 1px solid var(--line-soft); border-radius: 12px; padding: 12px 14px; }
.px-vhost-head { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; }
.px-vhost-sub {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-dim); margin: 10px 0 4px;
}
.px-route-list { margin: 0; padding-left: 18px; display: grid; gap: 2px; }
.px-route-list li {
  font-family: "JetBrains Mono", monospace; font-size: 13px; overflow-wrap: anywhere;
}
.px-route-list--restr li { color: var(--text-muted); }

/* ---------- Banner de identidad / avisos ---------- */
.px-banner {
  display: flex; gap: 12px; align-items: flex-start;
  border-radius: var(--r-md); padding: 14px 16px;
  border: 1px solid var(--line); background: var(--panel-solid);
}
.px-banner .ic { flex: none; width: 20px; height: 20px; margin-top: 2px; }

/* Descargas del reporte (artifacts en R2) */
.px-downloads { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.px-downloads-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; font-weight: 600; color: var(--text); }
.px-downloads-head .ic { flex: none; width: 18px; height: 18px; }
.px-downloads-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.px-downloads-actions .btn { gap: 6px; }
.px-downloads-actions .ic { flex: none; width: 16px; height: 16px; }

/* Hint del panel de monitoreo (admin) */
.px-mon-hint { font-size: 0.85rem; margin: 0.25rem 0 0.7rem; }
.px-mon-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.px-banner .bd { display: grid; gap: 2px; color: var(--text); }
.px-banner .bd strong { font-weight: 600; }
.px-banner--warn { color: var(--high); border-color: rgba(200, 71, 21, 0.35); background: rgba(200, 71, 21, 0.07); }
.px-banner--ok   { color: var(--ok);   border-color: rgba(22, 138, 91, 0.35); background: rgba(22, 138, 91, 0.07); }
.px-banner--info { color: var(--cyan); border-color: rgba(4, 154, 237, 0.32); background: rgba(4, 154, 237, 0.06); }
.px-banner .bd .t { color: inherit; }

/* ---------- Aviso de datos ficticios ---------- */
.px-notice {
  font-size: 13px; color: var(--text-muted);
  border: 1px dashed var(--line-strong); border-radius: var(--r-md);
  padding: 10px 14px; background: rgba(159, 119, 1, 0.06);
}

/* ---------- Hallazgos ---------- */
.px-findings { display: grid; gap: 12px; }
.px-findings-list { display: grid; gap: 12px; }
.px-finding-toolbar {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: 12px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, 0.48);
}
.px-filter {
  display: grid;
  gap: 6px;
  min-width: min(100%, 210px);
}
/* Varios <select> de filtro/agrupado lado a lado (p.ej. Información sensible:
   Estado + Tipo + Confianza + Agrupar por), ver renderInventory() en portal.js. */
.px-inventory-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 12px;
  margin-bottom: 4px;
}
.px-filter span {
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
}
.px-filter select {
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.88);
  color: var(--text);
  font: 500 14px/1.3 "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  padding: 8px 10px;
}
.px-filter select:focus {
  outline: 0;
  border-color: rgba(167, 43, 67, 0.34);
  box-shadow: 0 0 0 4px rgba(167, 43, 67, 0.08);
}
.px-finding-count {
  margin-left: auto;
  color: var(--text-dim);
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
  padding-bottom: 11px;
}
.px-finding {
  border: 1px solid var(--line); border-left-width: 3px; border-radius: var(--r-md);
  padding: 14px 16px; background: var(--panel-solid);
  display: grid; gap: 8px;
}
.px-finding > summary {
  cursor: pointer;
  list-style: none;
}
.px-finding > summary::-webkit-details-marker { display: none; }
.px-finding--critical { border-left-color: var(--crit); }
.px-finding--high { border-left-color: var(--high); }
.px-finding--medium { border-left-color: var(--med); }
.px-finding--low { border-left-color: var(--low); }
.px-finding .fh { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.px-finding .fid { font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--text-dim); }
.px-finding .ft { flex: 1 1 260px; min-width: 0; font-weight: 600; font-family: "Space Grotesk", "Inter", sans-serif; }
.px-finding .fasset { font-family: "JetBrains Mono", monospace; font-size: 13px; color: var(--text-muted); }
.px-finding .frec { font-size: 14px; }
.px-finding .frec b { color: var(--text); font-weight: 600; }
.px-finding .fev {
  font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--text-dim);
  background: var(--bg-2); border-radius: var(--r-sm); padding: 6px 10px; overflow-x: auto;
}
.px-detail-cta {
  color: var(--brand);
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
}
.px-verification {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 600;
}
.px-verification--confirmed { color: var(--ok); background: rgba(22, 138, 91, 0.10); }
.px-verification--probable { color: var(--med); background: rgba(159, 119, 1, 0.10); }
.px-verification--potential { color: var(--high); background: rgba(200, 71, 21, 0.10); }
.px-verification--unknown { color: var(--text-dim); background: rgba(100, 99, 100, 0.10); }
.px-validation-note {
  border: 1px solid rgba(159, 119, 1, 0.28);
  border-radius: var(--r-sm);
  background: rgba(159, 119, 1, 0.08);
  color: var(--text);
  font-size: 13px;
  padding: 8px 10px;
}
/* Hallazgo sobre un servidor de hosting compartido de terceros (no propiedad
   del cliente) -- 2026-09-15. Color distinto (cyan/info) a proposito: no es
   una severidad ni una alerta de validacion pendiente, es una aclaracion de
   a quien le corresponde corregirlo. */
.px-third-party {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border: 1px solid var(--cyan);
  border-radius: 999px;
  color: var(--cyan);
  background: rgba(4, 154, 237, 0.10);
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
.px-third-party-note {
  border: 1px solid rgba(4, 154, 237, 0.28);
  border-radius: var(--r-sm);
  background: rgba(4, 154, 237, 0.08);
  color: var(--text);
  font-size: 13px;
  padding: 8px 10px;
  margin-top: 6px;
}
.px-finding-detail {
  border-top: 1px solid var(--line-soft);
  margin-top: 4px;
  padding-top: 12px;
}
.px-detail-grid {
  display: grid;
  gap: 8px;
  margin: 0;
}
.px-detail-row {
  display: grid;
  grid-template-columns: minmax(130px, 0.28fr) 1fr;
  gap: 12px;
}
.px-detail-row dt {
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 700;
}
.px-detail-row dd {
  min-width: 0;
  margin: 0;
  color: var(--text);
  overflow-wrap: anywhere;
}
.px-detail-row.mono dd,
.px-detail-row.evidence dd {
  font-family: "JetBrains Mono", monospace;
  font-size: 12px;
}
.px-detail-row.evidence dd {
  background: var(--bg-2);
  border-radius: var(--r-sm);
  color: var(--text-dim);
  padding: 8px 10px;
}
@media (max-width: 680px) {
  .px-finding-count { width: 100%; margin-left: 0; padding-bottom: 0; }
  .px-filter { flex: 1 1 100%; }
  .px-detail-row { grid-template-columns: 1fr; gap: 3px; }
  .px-detail-cta { width: 100%; }
}

/* ---------- Listas ---------- */
.px-list { display: grid; gap: 10px; }
.px-list li { display: flex; gap: 10px; align-items: flex-start; }
.px-list li::before {
  content: ""; flex: none; width: 7px; height: 7px; margin-top: 8px;
  border-radius: 50%; background: var(--cyan); box-shadow: 0 0 8px rgba(4, 154, 237, 0.5);
}

/* ---------- Recomendaciones priorizadas ---------- */
.px-recommendations {
  display: grid;
  gap: 10px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}
.px-recommendations-toggle { margin-top: 14px; }
.px-recommendations-open { width: 100%; justify-content: center; }
.px-recommendation {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: start;
  padding: 16px;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  background: linear-gradient(135deg, rgba(4, 154, 237, 0.08), rgba(122, 88, 237, 0.05));
  box-shadow: 0 8px 24px rgba(20, 41, 66, 0.04);
}
.px-recommendation-number {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  color: var(--brand-dark);
  background: rgba(4, 154, 237, 0.12);
  border: 1px solid rgba(4, 154, 237, 0.25);
  font: 700 12px/1 "JetBrains Mono", monospace;
}
.px-recommendation-body { min-width: 0; }
.px-recommendation-text { margin: 0; color: var(--text); font-size: 14px; line-height: 1.55; }
.px-recommendation-text strong { color: var(--brand-dark); font-weight: 750; }
.px-recommendation-meta {
  display: grid;
  grid-template-columns: 126px minmax(0, 1fr);
  gap: 8px;
  margin-top: 10px;
  font-size: 12px;
  line-height: 1.45;
}
.px-recommendation-meta-label {
  color: var(--text-dim);
  font: 700 10px/1.45 "JetBrains Mono", monospace;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.px-recommendation-reason { color: var(--text-dim); }
.px-recommendation-assets { display: flex; flex-wrap: wrap; gap: 5px; }
.px-recommendation-asset {
  padding: 3px 6px;
  border: 1px solid rgba(4, 154, 237, 0.18);
  border-radius: 5px;
  background: rgba(4, 154, 237, 0.07);
  color: var(--brand-dark);
  font: 500 11px/1.25 "JetBrains Mono", monospace;
  overflow-wrap: anywhere;
}
.px-recommendation-code {
  padding: 1px 4px;
  border-radius: 4px;
  background: rgba(4, 154, 237, 0.10);
  color: var(--brand-dark);
  font: 500 0.9em/1.35 "JetBrains Mono", monospace;
}
.px-recommendation-origin {
  display: block;
  margin-top: 8px;
  color: var(--text-dim);
  font-size: 12px;
}
@media (max-width: 520px) {
  .px-recommendation { gap: 10px; padding: 12px; }
  .px-recommendation-number { width: 30px; height: 30px; border-radius: 9px; }
  .px-recommendation-meta { grid-template-columns: 1fr; gap: 3px; }
}

/* ---------- Acciones / botones placeholder ---------- */
.px-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.px-soon { position: relative; opacity: 0.62; cursor: not-allowed; }
.px-soon::after {
  content: "Próximamente"; font-family: "JetBrains Mono", monospace; font-size: 9px;
  text-transform: uppercase; letter-spacing: 0.04em;
  background: var(--med); color: #fff; border-radius: 999px; padding: 1px 6px; margin-left: 8px;
}

/* ---------- Tarjeta de cliente (portal index) ---------- */
.px-client-card { display: grid; gap: 12px; }
.px-client-card .row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.px-status {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: "JetBrains Mono", monospace; font-size: 11px; text-transform: uppercase; font-weight: 600;
  padding: 4px 11px; border-radius: 999px;
  color: var(--ok); background: rgba(22, 138, 91, 0.10); border: 1px solid currentColor;
}
.px-status .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.px-selected-report {
  display: grid; gap: 10px; padding: 14px;
  border: 1px solid var(--line-strong); border-radius: 12px;
  background: linear-gradient(135deg, rgba(167, 43, 67, 0.09), rgba(255, 255, 255, 0.72));
  box-shadow: 0 8px 22px rgba(47, 24, 29, 0.06);
}
.px-selected-report-kicker {
  color: var(--brand); font: 700 10px/1.2 "JetBrains Mono", monospace;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.px-selected-report-ref {
  color: var(--brand-dark); font: 700 16px/1.35 "JetBrains Mono", monospace;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}
.px-selected-report-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.px-selected-report-meta-item {
  display: grid; gap: 3px; min-width: 0; padding: 8px 9px;
  border: 1px solid rgba(47, 24, 29, 0.10); border-radius: 8px;
  background: rgba(255, 255, 255, 0.66);
}
.px-selected-report-meta-label {
  color: var(--text-dim); font: 700 9px/1.2 "JetBrains Mono", monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
}
.px-selected-report-meta-value { color: var(--text); font-size: 12px; font-weight: 650; overflow-wrap: anywhere; }
@media (max-width: 440px) { .px-selected-report-meta { grid-template-columns: 1fr; } }

/* ---------- Router visual de Access ---------- */
.px-auth { display: grid; place-items: center; min-height: calc(100vh - var(--nav-h) - 120px); }
.px-authcard { width: 100%; max-width: 440px; }
.px-auth-head { display: grid; gap: 6px; margin-bottom: 18px; text-align: center; }
.px-auth-badge {
  justify-self: center;
  display: inline-flex; align-items: center; gap: 7px;
  font-family: "JetBrains Mono", monospace; font-size: 11px; text-transform: uppercase; font-weight: 600;
  color: var(--brand-dark); background: rgba(167, 43, 67, 0.10);
  border: 1px solid var(--line-strong); padding: 4px 11px; border-radius: 999px;
}
.px-auth-badge svg { width: 14px; height: 14px; }
.px-form { display: grid; gap: 14px; }
.px-form .btn { width: 100%; margin-top: 4px; }
.px-form .btn[disabled] { cursor: progress; opacity: 0.72; transform: none; }
.px-form-status {
  margin: 0; min-height: 1.3em; font-size: 13.5px; text-align: center; color: var(--text-dim);
}
.px-form-status.is-sending { color: var(--brand); }
.px-form-status.is-error { color: var(--high); }
.px-form-status.is-success { color: var(--ok); }
/* Avisos/aclaraciones que exigen una decisión del usuario (p.ej. "escribe la
   referencia para confirmar", "solo puedes elegir una opción"): diferenciados
   del resto del texto con color de marca + negrita + subrayado, nunca solo
   color (igual de legibles sin percepción de color). */
.px-form-status.is-notice {
  color: var(--cyan); font-weight: 700; text-decoration: underline; text-align: left;
}

.px-bulk-bar {
  display: flex; align-items: center; gap: 12px; margin: 10px 0;
  padding: 10px 14px; border-radius: 10px;
  background: rgba(167, 43, 67, 0.08); border: 1px solid rgba(167, 43, 67, 0.24);
  font-weight: 600; font-size: 13.5px;
}

.px-modal-overlay {
  position: fixed; inset: 0; z-index: 200; display: grid; place-items: center;
  background: rgba(10, 8, 9, 0.62); padding: 20px;
}
.px-modal { width: 100%; max-width: 520px; display: grid; gap: 14px; }
.px-modal .form-grid { gap: 12px; }
.px-launch-fallback { width: 100%; min-height: 88px; resize: vertical; }
.px-launch-commands { display: grid; gap: 8px; margin-top: 10px; }
.px-launch-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.px-launch-row .px-launch-country { font-weight: 600; min-width: 2.5em; }
.px-center { text-align: center; }
.px-link { color: var(--brand); font-weight: 600; border-bottom: 1px solid rgba(167, 43, 67, 0.26); }
.px-link:hover { color: var(--brand-dark); border-color: currentColor; }
.px-access-router { display: grid; gap: 16px; }
.px-auth-actions { display: grid; gap: 10px; }
.px-auth-actions .btn { width: 100%; }
.px-denied-shell { display: grid; place-items: center; min-height: calc(100vh - var(--nav-h) - 160px); }
.px-denied-card { width: 100%; max-width: 520px; text-align: center; }
.px-denied-card .px-auth-actions { margin-top: 18px; }

/* ---------- Utilidades ---------- */
.px-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.px-spread { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; justify-content: space-between; }
[hidden] { display: none !important; }
.px-skel { color: var(--text-dim); font-family: "JetBrains Mono", monospace; font-size: 13px; }

/* ---------- Clickwrap legal: modal BLOQUEANTE (Términos + Privacidad) ---------- */
.px-legal-locked { overflow: hidden; }
.px-legal-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(8, 10, 14, 0.72);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.px-legal-card {
  width: 100%;
  max-width: 460px;
  padding: clamp(22px, 3vw, 30px);
  background: var(--panel-solid);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.px-legal-title { margin: 0 0 8px; font-size: 20px; color: var(--text); }
.px-legal-text { margin: 0 0 16px; color: var(--text-muted); }
.px-legal-links { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; }
.px-legal-links a {
  color: var(--brand);
  font-weight: 700;
  border-bottom: 1px solid rgba(167, 43, 67, 0.26);
}
.px-legal-links a:hover { color: var(--brand-dark); border-color: currentColor; }
.px-legal-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}
.px-legal-check input[type="checkbox"] {
  margin-top: 2px;
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  accent-color: var(--brand);
  cursor: pointer;
}
.px-legal-error { margin: 12px 0 0; color: var(--brand-dark); font-size: 13px; }
.px-legal-actions { margin-top: 20px; display: flex; justify-content: flex-end; }
.px-legal-actions .btn[disabled] { opacity: 0.55; cursor: not-allowed; }

/* ---------- Portal: "Exclusiones e Inclusiones" (autoservicio, NO bloqueante) --- */
.px-scope-adjust-trigger { margin-top: 10px; }
.px-scope-text { margin: 12px 0 8px; color: var(--text-muted); font-size: 14px; }
.px-scope-quota {
  margin: 0 0 16px;
  font-family: "JetBrains Mono", monospace;
  font-size: 13px;
  color: var(--text);
}
.px-scope-section-title { margin: 18px 0 8px; font-size: 14px; color: var(--text); }
.px-scope-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 4px; }
.px-scope-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.px-scope-row input[type="checkbox"] {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  accent-color: var(--brand);
  cursor: pointer;
}
.px-scope-row-fixed { flex: 0 0 auto; }
.px-scope-row-tag {
  margin-left: auto;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}
.px-scope-add-row { display: flex; gap: 8px; align-items: center; }
.px-scope-add-row input[type="text"] {
  flex: 1 1 auto;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 13px;
}
.px-scope-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.px-scope-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--line);
  font-size: 12px;
  color: var(--text);
}
.px-scope-chip-remove {
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0;
}
.px-scope-chip-remove:hover { color: var(--brand-dark); }
.px-scope-annexes .px-scope-row { cursor: default; }
.px-scope-annexes .px-scope-row button { margin-left: auto; }
.px-scope-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
  margin-top: 18px;
}
.px-scope-check input[type="checkbox"] {
  margin-top: 2px;
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  accent-color: var(--brand);
  cursor: pointer;
}
.px-scope-error { margin: 12px 0 0; color: var(--brand-dark); font-size: 13px; }
.px-scope-ok { margin: 12px 0 0; color: #16a34a; font-size: 13px; }
.px-scope-actions { margin-top: 16px; display: flex; justify-content: flex-end; }
.px-scope-actions .btn[disabled] { opacity: 0.55; cursor: not-allowed; }
.px-scope-faq-link {
  display: inline-block;
  margin: 2px 0 10px;
  padding: 0;
  background: none;
  border: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--brand-dark);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.px-scope-faq-link:hover { color: var(--brand); }

/* --- Encuesta de satisfacción (estrellas 1-5): tarjeta sugerida tras cada
   análisis nuevo (#pxSurveySection) y pestaña "Calificar el servicio" del
   widget de ayuda (Fase 7). Reusa px-scope-text/px-scope-actions de arriba
   para el texto y los botones -- solo estrellas y comentario son nuevos. */
.px-survey-stars { display: flex; gap: 8px; margin: 4px 0 6px; }
.px-survey-star {
  background: none;
  border: none;
  padding: 2px;
  font-size: 34px;
  line-height: 1;
  color: var(--line-strong);
  cursor: pointer;
  transition: color 0.18s ease, transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1),
    filter 0.18s ease;
  filter: drop-shadow(0 0 0 rgba(232, 163, 61, 0));
}
.px-survey-star:hover,
.px-survey-star:focus-visible { transform: scale(1.18); }
.px-survey-star:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
.px-survey-star.is-active {
  color: #e8a33d;
  filter: drop-shadow(0 3px 8px rgba(232, 163, 61, 0.55));
}
.px-survey-rating-label {
  min-height: 18px;
  margin: 0 0 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--brand-dark);
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.px-survey-rating-label.is-visible { opacity: 1; transform: translateY(0); }
.px-survey-comment {
  width: 100%;
  min-height: 72px;
  resize: vertical;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
  color: inherit;
  background: var(--panel-solid);
}

/* --- Widget de ayuda (Fase 7): botón flotante fijo + panel de 3 pestañas.
   Por encima de --z-menu (70) para no quedar tapado por la nav. */
.px-help-widget { position: fixed; right: 20px; bottom: 20px; z-index: 80; }
.px-help-fab {
  width: 56px; height: 56px; border-radius: 50%; border: none;
  display: grid; place-items: center; cursor: pointer;
  background: var(--brand); color: #fff; box-shadow: var(--shadow-card);
  transition: transform 0.15s ease;
}
.px-help-fab:hover { transform: scale(1.06); }
.px-help-fab svg { width: 26px; height: 26px; }
.px-help-panel {
  position: absolute; right: 0; bottom: calc(100% + 12px);
  width: min(380px, calc(100vw - 40px));
  max-height: min(600px, calc(100vh - 120px));
  overflow-y: auto;
  background: var(--panel-solid); border: 1px solid var(--line-strong);
  border-radius: 16px; box-shadow: var(--shadow-card); padding: 18px;
}
.px-help-panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.px-help-panel-head h2 { margin: 0; font-size: 16px; }
.px-help-close {
  background: none; border: none; cursor: pointer; font-size: 20px; line-height: 1;
  color: var(--text-dim); padding: 4px 6px;
}
.px-help-close:hover { color: var(--text); }
.px-help-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.px-help-tab {
  flex: 1; background: none; border: none; border-bottom: 2px solid transparent;
  padding: 8px 4px; font-size: 12.5px; font-weight: 600; color: var(--text-dim); cursor: pointer;
}
.px-help-tab:hover { color: var(--text); }
.px-help-tab.is-active { color: var(--brand-dark); border-bottom-color: var(--brand); }
.px-help-form { display: grid; gap: 12px; }
.px-help-form textarea { min-height: 90px; resize: vertical; }
.px-help-ticket-row {
  width: 100%; display: flex; align-items: center; gap: 8px; text-align: left;
  background: none; border: none; border-bottom: 1px solid var(--line); padding: 10px 4px; cursor: pointer;
}
.px-help-ticket-row:hover { background: rgba(167, 43, 67, 0.06); }
.px-help-ticket-number { font: 700 12px/1.2 "JetBrains Mono", monospace; color: var(--text); flex: 0 0 auto; }
.px-help-ticket-desc {
  flex: 1; font-size: 12.5px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.px-help-ticket-status {
  flex: 0 0 auto; font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px; letter-spacing: 0.03em;
  background: var(--bg-2); color: var(--text-dim);
}
.px-help-ticket-status--open { background: rgba(200, 71, 21, 0.14); color: var(--high); }
.px-help-ticket-status--in_progress { background: rgba(4, 154, 237, 0.14); color: #0a7fc2; }
.px-help-ticket-status--resolved,
.px-help-ticket-status--closed { background: rgba(22, 138, 91, 0.14); color: var(--ok); }
.px-help-ticket-head { display: flex; align-items: center; gap: 10px; margin: 10px 0 6px; }
.px-help-thread { display: grid; gap: 8px; margin: 12px 0; }
.px-help-message { padding: 8px 12px; border-radius: 10px; font-size: 13px; }
.px-help-message p { margin: 0; overflow-wrap: anywhere; }
.px-help-message--client { background: var(--bg-2); }
.px-help-message--admin { background: rgba(167, 43, 67, 0.10); }
.px-help-reply-form { display: grid; gap: 8px; margin-top: 8px; }
.px-help-reply-form textarea {
  width: 100%; min-height: 60px; resize: vertical; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px; font: inherit; color: inherit; background: var(--panel-solid);
}
@media (max-width: 480px) {
  .px-help-widget { right: 14px; bottom: 14px; }
  .px-help-panel { right: -6px; }
}

/* --- Calendario de escaneos: tarjetas de cadencia + vista previa editable
   (mi-calendario-de-escaneos.html). Antes usaban clases (px-review-grid,
   px-review-block, px-purchase-mode-option) que ninguna hoja de este sitio
   definía, así que se veían como texto plano sin agrupar; estas reglas les
   dan forma real. ------------------------------------------------------- */
.px-review-grid { display: grid; gap: 14px; margin-top: 10px; }
@media (min-width: 640px) {
  .px-review-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.px-review-block {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 14px 16px;
}
.px-purchase-mode-option {
  display: flex;
  flex-direction: column;
  gap: 6px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.px-purchase-mode-option:hover { border-color: var(--line-strong); }
.px-purchase-mode-option:has(input:checked) {
  border-color: var(--brand);
  background: rgba(167, 43, 67, 0.06);
}
.px-purchase-mode-option input[type="radio"] {
  margin: 0;
  accent-color: var(--brand);
  width: 17px;
  height: 17px;
}

.px-scan-dates-preview { margin-top: 18px; }
.px-scan-dates-preview > .px-muted { margin: 0 0 10px; }
.px-scan-dates-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
}
.px-scan-dates-grid .field { margin: 0; }
.px-scan-dates-grid .field span {
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-dim);
}

/* Evolución en los últimos análisis: grilla de tarjetas de tendencia
   compactas (una por métrica — score, cada severidad, cada categoría de
   inventario), cada una con su propia mini línea de tiempo con TODOS los
   períodos del historial (d.history en el portal real / DATA.history en la
   demo pública — ver buildTrendCard en portal.js y en demo-portal.js), no
   solo "antes/ahora". Compactas a propósito: al ser muchas tarjetas juntas,
   una por una con leyenda y ejes grandes se vería saturado — acá el
   valor+variación va en el encabezado de la tarjeta y la línea solo aporta
   la forma de la tendencia. Compartido entre el portal real (clientes/) y
   la demo pública (demo-portal.html) para que se vean idénticas. */
.px-trend-history-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 14px;
  font-size: 13px;
  color: var(--text-muted);
}
.px-trend-history-controls input[type="number"] {
  width: 72px;
  padding: 6px 8px;
  border-radius: 8px;
  border: 1px solid var(--line-soft);
  background: var(--panel-solid);
  color: var(--text);
  font: 600 13px "JetBrains Mono", monospace;
}
.px-trend-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px 14px;
  margin: 4px 0 6px;
}
@media (max-width: 900px) { .px-trend-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .px-trend-grid { grid-template-columns: 1fr; } }
.px-trend-card {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel-solid);
  padding: 10px 12px 8px;
}
.px-trend-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.px-trend-card-title { font-size: 12.5px; font-weight: 600; color: var(--text-muted); }
.px-trend-card-value { font: 700 15px "JetBrains Mono", monospace; color: var(--text); white-space: nowrap; }
.px-trend-card-delta { display: inline-block; margin-left: 6px; font-size: 11px; font-weight: 700; }
.px-trend-card-delta.is-mejoro { color: var(--ok); }
.px-trend-card-delta.is-empeoro { color: var(--crit); }
.px-trend-card-delta.is-sin_cambio { color: var(--text-dim); }
.px-trend-card-delta.is-neutral { color: var(--text-dim); }
.px-trend-card-svg { width: 100%; height: 44px; display: block; margin-top: 4px; }
/* Variante "hero" (opts.tall en buildTrendCard, 2026-09-01, corregida el
   mismo día): tarjetas anchas como "Evolución del score de exposición" en
   el Dashboard usan un viewBox propio más ancho (640x170, ver
   buildTrendCard) en vez de estirar el angosto -- por eso acá NO se fija un
   height en px (eso exigiría preserveAspectRatio="none", que deforma línea
   y puntos al escalar X e Y distinto). `height: auto` deja que el navegador
   escale el SVG completo y de forma UNIFORME: el alto real sale de
   width-real × (170/640), sin distorsión, cualquiera sea el ancho del panel. */
.px-trend-card.is-tall .px-trend-card-svg { height: auto; }
.px-trend-card.is-tall .px-trend-card-value { font-size: 20px; }
.px-trend-card.is-tall .px-trend-card-title { font-size: 14px; }
.px-trend-card.is-tall .px-trend-line { stroke-width: 3; }
.px-trend-baseline { stroke: var(--line-soft); stroke-width: 1; }
.px-trend-line { fill: none; stroke-width: 2.25; stroke-linecap: round; stroke-linejoin: round; opacity: 0.95; stroke: var(--brand); }
.px-trend-dot { fill: var(--brand); stroke: var(--panel-solid); stroke-width: 1.5; }
.px-trend-dot.is-last { stroke-width: 2; }
.px-trend-card-foot { display: flex; justify-content: space-between; font-size: 10px; color: var(--text-dim); margin-top: 2px; }
/* Bug corregido el 2026-09-02 (reportado por el propietario: el relleno
   semitransparente del área de tendencia se veía como un rojo sólido sin
   matices): estas reglas ponían `fill` a `.px-trend-line` además de a
   `.px-trend-dot`. Un <polyline> con `fill` distinto de `none` se cierra
   solo (último punto → primer punto, igual que un <polygon>) y queda
   pintado con ese color a opacidad TOTAL -- desde que el área semitransp.
   de abajo pasó a cerrar exactamente con esa misma forma (la "traza
   inicio-fin"), este relleno accidental de la línea quedaba pintado justo
   encima, tapando por completo cualquier transparencia o degradado del
   área. Fix: `.px-trend-line` nunca lleva `fill` (ya hereda `fill: none`
   de la regla general de la línea 1622); solo `.px-trend-dot` lo necesita. */
.px-trend-card.is-score .px-trend-line { stroke: var(--brand); }
.px-trend-card.is-score .px-trend-dot { fill: var(--brand); }
.px-trend-card.is-critical .px-trend-line { stroke: var(--crit); }
.px-trend-card.is-critical .px-trend-dot { fill: var(--crit); }
.px-trend-card.is-high .px-trend-line { stroke: var(--high); }
.px-trend-card.is-high .px-trend-dot { fill: var(--high); }
.px-trend-card.is-medium .px-trend-line { stroke: var(--med); }
.px-trend-card.is-medium .px-trend-dot { fill: var(--med); }
.px-trend-card.is-low .px-trend-line { stroke: var(--low); }
.px-trend-card.is-low .px-trend-dot { fill: var(--low); }
.px-trend-card.is-neutral-subdomains .px-trend-line { stroke: var(--cyan); }
.px-trend-card.is-neutral-subdomains .px-trend-dot { fill: var(--cyan); }
.px-trend-card.is-neutral-cloud .px-trend-line { stroke: var(--teal); }
.px-trend-card.is-neutral-cloud .px-trend-dot { fill: var(--teal); }
.px-trend-card.is-neutral-cctv .px-trend-line { stroke: var(--violet); }
.px-trend-card.is-neutral-cctv .px-trend-dot { fill: var(--violet); }
.px-trend-caption { margin-top: 2px; }
