/* Consola lilapro — sistema visual V1 (docs/diseno_plataforma_web.md §5.6).
   Sin framework, sin build de Node: hoja propia, JS vanilla, SVG en el servidor.
   Móvil primero, claro/oscuro por `prefers-color-scheme` con conmutador manual
   (`data-tema` en <html>, recordado en localStorage). La restricción -- pocos
   tamaños, color que solo comunica estado, densidad -- es la regla de §5.6.5:
   es lo que separa una interfaz profesional de una "pobre". */

/* ─── Tipografía: Inter, AUTOALOJADA (22-sep-2026) ───────────────────────
   El dueño señaló la tipografía como el cambio con más impacto visual por
   kilobyte y pidió que se hiciera de verdad — la política de contenido ya
   se había relajado para Google Fonts (ver nucleo_web.py) y nunca se llegó
   a usar. Se autoaloja en vez de tirar de la CDN de Google: carga del
   mismo origen (sin resolver otro DNS ni abrir otra conexión), no depende
   de que ese tercero esté arriba, no le cuenta a nadie ajeno quién entra a
   la consola, y permite REVERTIR la relajación de la CSP en vez de usarla.

   `inter.woff2` es la fuente VARIABLE de Google Fonts (v20), recorte
   `latin` únicamente — cubre ASCII + Latin-1 (ñ, á-ú, «», €), que es todo
   lo que usa una consola en español — en UN SOLO fichero que cubre el eje
   completo de grosor 400..700 (regular, semi-negrita para KPIs/th, negrita
   para .codigo-grande): 47,3 KiB comprimidos, nada de traer 3-4 ficheros
   estáticos por separado. Se descartó el subset `latin-ext` (glifos que la
   consola no usa) y la variante itálica (un solo `<em>` en toda la consola,
   `tareas.html`; el navegador la sintetiza en oblicua, no vale otros ~47 KiB).
   `font-display: swap` — el texto se ve con la fuente de sistema desde el
   primer instante, sin parpadeo en blanco, y cambia a Inter en cuanto carga. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/estaticos/inter.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;
}

:root {
  /* ─── Marca (GalapagosTech, skill reporte-estilo-galapagostech, §5.6.1) ─── */
  --marca:        #2098af;   /* 3.40:1 sobre blanco — relleno, bordes, barras, títulos grandes */
  --marca-fuerte: #1a7a8a;   /* 5.01:1 sobre blanco — enlaces y texto pequeño en teal */
  --marca-suave:  #e8f4f7;   /* fondo de realce, pastillas */
  --marca-texto:  #ffffff;   /* texto sobre un relleno de marca */

  /* Relleno de BOTÓN, separado de `--marca` (22-sep-2026, el dueño mirando
     la consola en oscuro: el botón «Entrar» se leía deshabilitado). En claro
     es el mismo teal de siempre — ahí funciona bien, 3.40:1 con blanco. En
     oscuro `--marca` se aclaró a propósito para servir como TEXTO legible
     sobre fondo oscuro (8.89:1) — pero ese mismo tono pastel, puesto de
     RELLENO, lee como "apagado/inactivo" en vez de como acción principal.
     Un botón necesita su propio token: mismo family teal, calibrado como
     relleno solamente (ver el porqué medido junto al bloque oscuro). */
  --boton-primario-fondo: var(--marca);
  --boton-primario-texto: var(--marca-texto);

  /* ─── Superficie y texto (light) ─── */
  --fondo:        #f5f5f4;
  --fondo-2:      #f3f4f6;   /* caja secundaria / resumen (skill reporte-estilo-galapagostech) */
  --superficie:   #ffffff;
  --borde:        #d1d5db;
  --borde-tenue:  #eef0f2;
  --campo-borde:  var(--borde);   /* borde de campo de formulario — alias en claro, valor propio en oscuro */
  --texto:        #1a1a1a;
  --texto-fuerte: #111827;
  --texto-suave:  #6b7280;
  --sombra-1:     0 1px 2px rgba(17, 24, 39, 0.06), 0 1px 1px rgba(17, 24, 39, 0.04);
  --sombra-2:     0 4px 12px rgba(17, 24, 39, 0.10), 0 2px 4px rgba(17, 24, 39, 0.06);

  /* ─── Los cuatro estados, único vocabulario en toda la consola (§5.4.1) ─── */
  --exito:        #2f6b3a;
  --exito-fondo:  #e6f2e8;
  --aviso:        #8a5a00;
  --aviso-fondo:  #fbf1dd;
  --error:        #9a3324;
  --error-fondo:  #fbeae6;
  --inactivo:     #6b7280;
  --inactivo-fondo: #eef0f2;

  /* ─── Serie categórica de gráficos (§5.6.4) ─── */
  --serie-1: #2098af;
  --serie-2: #1a5b7a;
  --serie-3: #6ab8a0;
  --serie-4: #2d3f6b;
  --serie-5: #8fa8b5;

  /* ─── Tipografía: cinco tamaños, ni uno más (§5.6.5) ─── */
  --texto-xs:  clamp(0.75rem,  0.70rem + 0.25vw,  0.875rem);
  --texto-sm:  clamp(0.875rem, 0.80rem + 0.375vw, 1rem);
  --texto-base:clamp(1rem,     0.90rem + 0.5vw,   1.125rem);
  --texto-lg:  clamp(1.125rem, 1.00rem + 0.625vw, 1.25rem);
  --texto-xl:  clamp(1.25rem,  1.10rem + 0.75vw,  1.5rem);
  --texto-2xl: clamp(1.5rem,   1.20rem + 1.5vw,   2rem);
  --texto-3xl: clamp(1.875rem, 1.40rem + 2.375vw, 2.5rem);
  --texto-4xl: clamp(2.25rem,  1.50rem + 3.75vw,  3.5rem);   /* solo el titular de "/" */

  /* ─── Espaciado fluido (skill responsive-design) ─── */
  --espacio-xs: clamp(0.5rem,  0.4rem + 0.5vw,  0.75rem);
  --espacio-sm: clamp(0.75rem, 0.6rem + 0.75vw, 1rem);
  --espacio-md: clamp(1rem,    0.8rem + 1vw,    1.5rem);
  --espacio-lg: clamp(1.5rem,  1.2rem + 1.5vw,  2rem);
  --espacio-xl: clamp(2rem,    1.5rem + 2.5vw,  3rem);
  --espacio-2xl:clamp(3rem,    2.0rem + 5vw,    5rem);

  --ancho-prosa: min(100% - 2rem, 45rem);
  --ancho-app:   min(100% - 2rem, 68rem);

  --radio: 8px;
  --radio-pill: 999px;
}

/* ─── Oscuro: `prefers-color-scheme` y conmutador manual, los dos caminos ─── */
@media (prefers-color-scheme: dark) {
  :root:not([data-tema="claro"]) {
    --marca:        #5bc6d8;   /* 8.89:1 sobre #17181a */
    --marca-fuerte: #7ad3e3;
    --marca-suave:  #10333a;
    --marca-texto:  #0c1620;

    /* Medido (22-sep-2026): `--marca` de relleno en un botón, con
       `--marca-texto` encima, da 3.40:1 — pasa como elemento gráfico pero
       el ojo lo lee "apagado" junto a un fondo casi negro (1.6:1 de por sí).
       #1d8090 es la MISMA familia (H188 S66%, entre `--marca` y
       `--marca-fuerte`) con más peso: 4.6:1 con blanco (AA de texto normal,
       no solo "grande"), y ≥3.4:1 contra la tarjeta y la página — se
       distingue como elemento, no se funde. */
    --boton-primario-fondo: #1d8090;
    --boton-primario-texto: #ffffff;

    --fondo:        #17181a;
    --fondo-2:      #1d1f22;
    --superficie:   #212226;
    --borde:        #3a3c40;
    --borde-tenue:  #2a2c30;
    /* El borde normal (#3a3c40) da 1.4-1.6:1 contra el campo y la tarjeta —
       invisible (el mínimo WCAG 1.4.11 para límites de componente es 3:1).
       Gris neutro más claro, sin tocar `--borde` general (tablas, tarjetas):
       el problema medido era SOLO en los campos de formulario. */
    --campo-borde:  #7a7a7e;
    --texto:        #e7e6e3;
    --texto-fuerte: #f3f2ef;
    --texto-suave:  #a9a8a4;
    --sombra-1:     0 1px 2px rgba(0, 0, 0, 0.4);
    --sombra-2:     0 4px 16px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.35);

    --exito:        #7fbf8c;
    --exito-fondo:  #16261a;
    --aviso:        #e0b45a;
    --aviso-fondo:  #2a2110;
    --error:        #e2897a;
    --error-fondo:  #2b1714;
    --inactivo:     #a9a8a4;
    --inactivo-fondo: #2a2c30;
  }
}
:root[data-tema="oscuro"] {
  --marca:        #5bc6d8;
  --marca-fuerte: #7ad3e3;
  --marca-suave:  #10333a;
  --marca-texto:  #0c1620;
  --boton-primario-fondo: #1d8090;
  --boton-primario-texto: #ffffff;

  --fondo:        #17181a;
  --fondo-2:      #1d1f22;
  --superficie:   #212226;
  --borde:        #3a3c40;
  --borde-tenue:  #2a2c30;
  --campo-borde:  #7a7a7e;
  --texto:        #e7e6e3;
  --texto-fuerte: #f3f2ef;
  --texto-suave:  #a9a8a4;
  --sombra-1:     0 1px 2px rgba(0, 0, 0, 0.4);
  --sombra-2:     0 4px 16px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.35);

  --exito:        #7fbf8c;
  --exito-fondo:  #16261a;
  --aviso:        #e0b45a;
  --aviso-fondo:  #2a2110;
  --error:        #e2897a;
  --error-fondo:  #2b1714;
  --inactivo:     #a9a8a4;
  --inactivo-fondo: #2a2c30;
}

/* ─── Rejilla base ─── */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--fondo);
  color: var(--texto);
  font: var(--texto-base)/1.5 'Inter', 'Helvetica Neue', Helvetica, Arial, -apple-system,
        BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  overflow-x: hidden;
}

a { color: var(--marca-fuerte); text-decoration: none; transition: color 0.15s ease; }
a:hover { text-decoration: underline; }

/* ─── Movimiento con cuidado: transición corta y sobria, nunca decorativa,
   y del todo apagada si la persona pidió menos movimiento (§5.6.6) ─── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

.envoltorio {
  max-width: 1088px;
  width: var(--ancho-app);
  margin: 0 auto;
  padding: 0 0 var(--espacio-2xl);
  padding-inline: 0;
}

.prosa { width: var(--ancho-prosa); margin-inline: auto; }

/* ─── Cabecera ─── */
header.cabecera {
  border-bottom: 1px solid var(--borde);
  background: var(--superficie);
  padding: var(--espacio-sm) var(--espacio-md);
  padding-top: calc(var(--espacio-sm) + env(safe-area-inset-top, 0px));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espacio-xs) var(--espacio-md);
  position: sticky;
  top: 0;
  z-index: 10;
}

header.cabecera strong { font-size: var(--texto-lg); font-weight: 600; color: var(--texto-fuerte); }

nav.principal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--espacio-xs) var(--espacio-md);
  margin-inline-start: auto;
}

nav.principal a, header.cabecera form { font-size: var(--texto-sm); }
nav.principal a {
  padding: 0.35em 0.6em;
  border-radius: var(--radio);
  transition: background-color 0.15s ease, color 0.15s ease;
}
nav.principal a:hover { background: var(--fondo-2); text-decoration: none; }
nav.principal a.activo { background: var(--marca-suave); color: var(--texto-fuerte); font-weight: 600; }

/* ─── Tipografía de página: cinco usos, cinco tokens (§5.6.5) ─── */
h1 { font-size: var(--texto-2xl); font-weight: 600; margin: 0 0 var(--espacio-md); color: var(--texto-fuerte); }
h2 { font-size: var(--texto-lg); font-weight: 600; margin: var(--espacio-lg) 0 var(--espacio-sm); color: var(--texto-fuerte); }
p, li { font-size: var(--texto-base); }
.secundario, .metadato { font-size: var(--texto-sm); color: var(--texto-suave); }
.etiqueta-xs { font-size: var(--texto-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; }

main { padding-top: var(--espacio-lg); }
main.sin-cabecera { padding-top: 0; }

/* ─── Tarjeta ─── */
.tarjeta {
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  box-shadow: var(--sombra-1);
  padding: var(--espacio-md);
  margin-bottom: var(--espacio-md);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.tarjeta > h2:first-child { margin-top: 0; }

/* `<details class="tarjeta">` es la única tarjeta que de verdad se toca (el
   acordeón de preguntas de la portada): la elevación en hover/foco confirma
   que responde, sin tocar las que solo muestran datos. */
details.tarjeta > summary { cursor: pointer; }
details.tarjeta:hover, details.tarjeta:focus-within { box-shadow: var(--sombra-2); }

/* Tarjeta de KPI: vive en tres anchos distintos (tablero, selector de empresas,
   panel del operador) — `container query`, no media query (§5.6.3). */
.tarjeta-kpi {
  container: kpi / inline-size;
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: var(--espacio-sm) var(--espacio-md);
}
.tarjeta-kpi .kpi-etiqueta { font-size: var(--texto-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.03em; color: var(--texto-suave); }
.tarjeta-kpi .kpi-numero { display: block; font-size: var(--texto-xl); font-weight: 600;
  color: var(--texto-fuerte); font-variant-numeric: tabular-nums; margin: 0.15em 0; }
.tarjeta-kpi .kpi-comparacion { font-size: var(--texto-xs); color: var(--texto-suave); }
.tarjeta-kpi .kpi-comparacion.sube { color: var(--exito); }
.tarjeta-kpi .kpi-comparacion.baja { color: var(--error); }
@container kpi (min-width: 13rem) {
  .tarjeta-kpi .kpi-numero { font-size: var(--texto-3xl); }
}

.numero-grande { font-size: var(--texto-3xl); font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--texto-fuerte); }

/* ─── Rejilla `auto-fit`, sin media queries (§5.6.3) ─── */
.rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--espacio-md);
}
.rejilla-kpi {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: var(--espacio-sm);
}

/* ─── Formularios ─── */
label { display: block; margin: var(--espacio-sm) 0 0.25rem; font-weight: 600; font-size: var(--texto-sm); }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=search], input[type=url], select, textarea {
  width: 100%;
  padding: 0.6rem 0.7rem;
  min-height: 44px;
  border: 1px solid var(--campo-borde);
  border-radius: var(--radio);
  background: var(--fondo);
  color: var(--texto);
  font-size: var(--texto-base);
  font-family: inherit;
}
input:focus-visible, select:focus-visible, textarea:focus-visible, a:focus-visible,
button:focus-visible, .boton:focus-visible {
  outline: 2px solid var(--marca);
  outline-offset: 2px;
}

button, .boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4em;
  min-height: 44px;
  min-width: 44px;
  padding: 0.5rem 1.1rem;
  border-radius: var(--radio);
  border: 1px solid var(--boton-primario-fondo);
  background: var(--boton-primario-fondo);
  color: var(--boton-primario-texto);
  font-size: var(--texto-base);
  font-family: inherit;
  cursor: pointer;
  transition: filter 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
button.secundario, .boton.secundario { background: transparent; color: var(--marca-fuerte); border-color: var(--borde); }
button.peligro, .boton.peligro { background: var(--error); border-color: var(--error); color: #fff; }
button.enlace, .boton.enlace { background: none; border: none; color: var(--marca-fuerte); padding: 0.25rem 0.4rem; min-width: 0; }
button:disabled, .boton:disabled { opacity: 0.55; cursor: default; }

/* Que responder al pulgar/al cursor se NOTE — filled se oscurece, outline se
   rellena tenue, ninguno cambia de tamaño ni tiembla (§5.6.6, movimiento sobrio) */
button:not(:disabled):hover, .boton:not(.deshabilitado):hover { filter: brightness(0.94); }
button.secundario:not(:disabled):hover, .boton.secundario:not(.deshabilitado):hover,
button.enlace:not(:disabled):hover, .boton.enlace:not(.deshabilitado):hover { background: var(--fondo-2); filter: none; }
button:not(:disabled):active, .boton:not(.deshabilitado):active { transform: translateY(1px); }
.boton-primario, a.boton, a.boton-primario { transition: filter 0.15s ease, background-color 0.15s ease, transform 0.05s ease; }
.boton-primario:hover, a.boton:hover, a.boton-primario:hover { filter: brightness(0.94); text-decoration: none; }
.boton.secundario:hover, .boton.enlace:hover { text-decoration: none; }
.boton-primario:active, a.boton:active, a.boton-primario:active { transform: translateY(1px); }

/* ─── Mensajes (nunca solo color: color + icono + palabra, §5.6.6) ─── */
.mensaje { display: flex; align-items: flex-start; gap: 0.5em; padding: var(--espacio-sm) var(--espacio-md);
  border-radius: var(--radio); margin-bottom: var(--espacio-md); font-size: var(--texto-sm); }
.mensaje.exito { background: var(--exito-fondo); color: var(--exito); }
.mensaje.error { background: var(--error-fondo); color: var(--error); }
.mensaje.aviso { background: var(--aviso-fondo); color: var(--aviso); }
.mensaje .icono { flex: none; width: 1.2em; height: 1.2em; margin-top: 0.1em; }

.codigo-grande {
  font-size: var(--texto-2xl);
  letter-spacing: 0.08em;
  font-weight: 700;
  padding: var(--espacio-sm) var(--espacio-md);
  background: var(--fondo-2);
  border: 1px dashed var(--marca);
  border-radius: var(--radio);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ─── Pastilla de estado — vocabulario único de las cuatro listas (§5.4.1) ───
   Estado + icono + palabra, nunca color solo. */
.pastilla {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.15rem 0.6rem;
  border-radius: var(--radio-pill);
  font-size: var(--texto-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.pastilla .icono { width: 0.85em; height: 0.85em; flex: none; }
.pastilla.etiqueta { background: var(--fondo-2); color: var(--texto-suave); text-transform: none; font-weight: 500; }

.estado-hecho       { background: var(--exito-fondo);    color: var(--exito); }
.estado-esperando    { background: var(--aviso-fondo);    color: var(--aviso); }
.estado-error        { background: var(--error-fondo);    color: var(--error); }
.estado-no-hecho     { background: var(--inactivo-fondo); color: var(--inactivo); }

.etiqueta {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: var(--radio-pill);
  font-size: var(--texto-xs);
  background: var(--fondo-2);
  border: 1px solid var(--borde);
  color: var(--texto-suave);
}

/* ─── Tablas de datos: densas, filas escaneables (§5.6.5, regla 4) ───
   `tabular-nums` en TODA celda, no solo en las que hoy tienen montos: Inter
   trae cifras de ancho fijo, así que no cuesta nada aplicarlo aquí una vez
   y que ninguna columna de dinero futura tenga que acordarse de pedirlo. */
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--borde-tenue);
  font-size: var(--texto-sm); font-variant-numeric: tabular-nums; }
th { color: var(--texto-suave); font-weight: 600; font-size: var(--texto-xs); text-transform: uppercase; letter-spacing: 0.02em; }
.tabla-datos tbody tr { transition: background-color 0.15s ease; }
.tabla-datos tbody tr:hover { background: var(--fondo-2); }
.tabla-datos td { max-height: 72px; }

/* Envoltura con scroll horizontal contenido, nunca desbordamiento de página */
.tabla-envoltorio { overflow-x: auto; }
.tabla-envoltorio table { min-width: 32rem; }

/* Tablas -> tarjeta en pantallas angostas (patrón ya existente, extendido) */
@media (max-width: 640px) {
  table.responsiva, table.responsiva thead, table.responsiva tbody,
  table.responsiva th, table.responsiva td, table.responsiva tr,
  .tabla-datos, .tabla-datos thead, .tabla-datos tbody,
  .tabla-datos th, .tabla-datos td, .tabla-datos tr { display: block; }
  table.responsiva thead, .tabla-datos thead { display: none; }
  table.responsiva tr, .tabla-datos tr {
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    margin-bottom: var(--espacio-sm);
    padding: 0.4rem 0.6rem;
  }
  table.responsiva td, .tabla-datos td {
    border: none;
    padding: 0.35rem 0;
    display: flex;
    justify-content: space-between;
    gap: var(--espacio-md);
  }
  table.responsiva td::before, .tabla-datos td::before {
    content: attr(data-etiqueta);
    font-weight: 600;
    color: var(--texto-suave);
  }
}

/* ─── Actividad y listas: fila = frase legible (§5.4.2) ─── */
.lista-filas { display: flex; flex-direction: column; }
.fila {
  padding: var(--espacio-sm) 0;
  border-bottom: 1px solid var(--borde-tenue);
  display: flex;
  flex-direction: column;
  gap: 0.3em;
}
.fila:last-child { border-bottom: none; }
.fila { transition: background-color 0.15s ease; }
.fila:hover { background: var(--fondo-2); }
.fila-cabecera { display: flex; align-items: baseline; gap: 0.5em; flex-wrap: wrap; font-size: var(--texto-sm); color: var(--texto-suave); }
.fila-cabecera .icono { width: 1em; height: 1em; }
.fila-frase { font-size: var(--texto-base); color: var(--texto); }
.fila-acciones { display: flex; gap: var(--espacio-sm); margin-top: 0.2em; flex-wrap: wrap; }
.fila-detalle { margin-top: 0.4em; }
.fila-detalle pre {
  background: var(--fondo-2);
  border-radius: var(--radio);
  padding: var(--espacio-sm);
  overflow-x: auto;
  font-size: var(--texto-xs);
  white-space: pre-wrap;
  word-break: break-word;
}

/* ─── Filtros ─── */
.filtros { display: flex; flex-wrap: wrap; gap: var(--espacio-sm); align-items: center; margin-bottom: var(--espacio-md); }
.filtros select, .filtros input { width: auto; min-width: 8rem; }
.filtros .buscador { flex: 1 1 12rem; }

/* ─── Paginación ─── */
.paginacion { display: flex; gap: var(--espacio-sm); align-items: center; justify-content: center;
  margin-top: var(--espacio-md); font-size: var(--texto-sm); color: var(--texto-suave); }

/* ─── Avisos (franja bajo el tablero, §5.3) ─── */
.avisos { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: var(--espacio-md); }
.aviso-fila {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5rem var(--espacio-md);
  border-radius: var(--radio);
  font-size: var(--texto-sm);
}
.aviso-fila.critico { background: var(--error-fondo); color: var(--error); }
.aviso-fila.atencion { background: var(--aviso-fondo); color: var(--aviso); }
.aviso-fila a { margin-inline-start: auto; white-space: nowrap; }

/* ─── Estado vacío: enseña, no se disculpa (§5.3, §5.6.5) ─── */
.vacio {
  text-align: center;
  padding: var(--espacio-xl) var(--espacio-md);
  color: var(--texto-suave);
}
.vacio .icono { width: 2.5rem; height: 2.5rem; color: var(--marca); margin-bottom: var(--espacio-sm); }
.vacio h3 { font-size: var(--texto-lg); color: var(--texto-fuerte); margin: 0 0 0.5rem; }
.vacio ol { text-align: start; max-width: 28rem; margin: var(--espacio-sm) auto; }
.vacio-banda {
  position: relative;
}
.vacio-banda::after {
  content: "EJEMPLO";
  position: absolute;
  top: 0.4rem;
  inset-inline-end: 0.4rem;
  background: var(--aviso-fondo);
  color: var(--aviso);
  font-size: var(--texto-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 0.1rem 0.5rem;
  border-radius: var(--radio-pill);
}

/* ─── Gráficos SVG (heredan currentColor: el oscuro sale gratis) ─── */
.grafico { width: 100%; height: auto; color: var(--texto-suave); }
.grafico text { fill: currentColor; font-size: var(--texto-xs); font-family: inherit; }
/* El «sin datos» de un gráfico vacío: legible, pero sin gritar más que las
   cifras de al lado, que sí tienen algo que contar. */
.grafico .grafico-vacio { font-size: var(--texto-sm); fill: var(--texto-suave); }
.grafico .serie-1 { fill: var(--serie-1); stroke: var(--serie-1); }
.grafico .serie-2 { fill: var(--serie-2); stroke: var(--serie-2); }
.grafico .serie-3 { fill: var(--serie-3); stroke: var(--serie-3); }
.grafico .serie-4 { fill: var(--serie-4); stroke: var(--serie-4); }
.grafico .serie-5 { fill: var(--serie-5); stroke: var(--serie-5); }
.grafico .eje { stroke: var(--borde); }

/* ─── Pasos (asistente de alta) ─── */
.pasos { display: flex; gap: var(--espacio-sm); margin-bottom: var(--espacio-lg); flex-wrap: wrap; }
.pasos .paso { font-size: var(--texto-sm); color: var(--texto-suave); display: flex; align-items: center; gap: 0.4em; }
.pasos .paso.activo { color: var(--marca-fuerte); font-weight: 600; }
.pasos .paso.hecho { color: var(--exito); }

/* ─── Iconos ─── */
.icono { width: 1em; height: 1em; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; flex: none; vertical-align: -0.125em; }
.icono.relleno { fill: currentColor; stroke: none; }

/* ─── Conmutador de tema — el botón ya tenía CSS y JS (`app.js`,
   `[data-conmutador-tema]`) pero ninguna plantilla lo pintaba: el modo
   oscuro solo se veía si el sistema operativo ya estaba en oscuro, sin
   forma de elegirlo aparte. El ícono muestra el destino del clic, no el
   estado actual (convención GitHub/Vercel): sol cuando está oscuro
   ofreciendo claro, luna cuando está claro ofreciendo oscuro. ─── */
.conmutador-tema { background: none; border: 1px solid var(--borde); color: var(--texto-suave); padding: 0.4rem; }
.conmutador-tema:hover { background: var(--fondo-2); filter: none; }
.conmutador-tema .icono-sol { display: none; }
.conmutador-tema .icono-luna { display: inline; }
@media (prefers-color-scheme: dark) {
  :root:not([data-tema="claro"]) .conmutador-tema .icono-sol { display: inline; }
  :root:not([data-tema="claro"]) .conmutador-tema .icono-luna { display: none; }
}
:root[data-tema="oscuro"] .conmutador-tema .icono-sol { display: inline; }
:root[data-tema="oscuro"] .conmutador-tema .icono-luna { display: none; }
:root[data-tema="claro"] .conmutador-tema .icono-sol { display: none; }
:root[data-tema="claro"] .conmutador-tema .icono-luna { display: inline; }

/* ─── Objetivo táctil, ancho contenido (skill responsive-design) ─── */
/* El botón del menú SOLO existe en pantallas estrechas: en ancho, la
   navegación ya está a la vista y un botón «Menú» sobraría. */
.boton-menu { display: none; }

@media (max-width: 640px) {
  nav.principal { display: none; }
  nav.principal.abierta { display: flex; flex-direction: column; width: 100%; }
  .boton-menu { display: inline-flex; align-items: center; min-height: 44px; }
}

@media (min-width: 1024px) {
  nav.principal { display: flex; }
}

/* ─── Utilidades — para no escribir `style=` en ninguna plantilla (§5.6, C10) ─── */
.caja-angosta { max-width: 26rem; margin-inline: auto; }
/* 22-sep-2026 — mismo bug que el de las tarjetas de la portada (línea ~683),
   encontrado por auditoría explícita: las cuatro pantallas de cuenta
   (`registro`, `ingresar`, `recuperar`, `clave_nueva`) llevaban
   `tw:rounded-2xl tw:border-border/60 tw:shadow-xl tw:shadow-black/5 tw:p-8`
   en su tarjeta principal — INERTES las tres propiedades, medido con
   `getComputedStyle` en las cuatro pantallas reales (no leyendo el HTML):
   `borderRadius` daba 8px (el de `.tarjeta` a secas, nunca los 16px
   pedidos), `padding` daba 17.8px (nunca los 32px pedidos) y `boxShadow`
   daba `--sombra-1` (nunca la sombra pedida) — la regla sin capa de
   `.tarjeta` le sigue ganando a la utilidad de Tailwind, esté en la
   plantilla que esté. Se quitan esas clases inertes del HTML y se arregla
   aquí, en una hoja sin capa, donde sí puede ganar. `--sombra-2` en vez de
   un valor fijo porque ya está calibrada para los dos temas (ver su
   definición) — un rgba nuevo habría que auditarlo aparte en oscuro. */
.tarjeta.caja-angosta {
  border-radius: 16px;
  padding: 2rem;
  box-shadow: var(--sombra-2);
}
.forma-angosta { margin-top: var(--espacio-sm); max-width: 24rem; }
.mt-1 { margin-top: var(--espacio-sm); }
.mb-1 { margin-bottom: var(--espacio-md); }
.sin-margen { margin: 0; }
.etiqueta-en-linea { margin: 0; font-weight: 400; }
.en-linea-bloque { display: inline-block; }
.en-linea-bloque-arriba { display: inline-block; vertical-align: top; }
.sin-subrayado { text-decoration: none; }
.con-puntero { cursor: pointer; }
.texto-critico { color: var(--error); font-weight: 600; }
.pre-envuelto { white-space: pre-wrap; word-break: break-word; }
.casilla-en-linea { display: flex; align-items: center; gap: 0.35em; margin: 0; font-weight: 400; }

/* ─── Portada (§5.2) — el resplandor sale de un `radial-gradient` con el
   mismo `--marca-suave` que ya existía para las pastillas: cero peso extra
   (ningún archivo nuevo) y el oscuro sale gratis porque el token ya tiene
   su variante. Es la única sección que se permite decoración sin ser
   estado ni acción (§5.6.5.2): es la fachada, no una pantalla de trabajo. */
.portada-seccion {
  text-align: center;
  padding-block: var(--espacio-2xl);
  background: radial-gradient(ellipse 60% 100% at 50% 0%, var(--marca-suave), transparent 70%);
}
.portada-seccion-final { text-align: center; padding-block: var(--espacio-xl); }
/* `text-wrap: balance` (22-sep-2026, el team-lead: el corte dejaba la
   segunda línea casi tan larga como la primera) — el navegador reparte las
   palabras entre líneas para que queden parejas, en vez de rellenar la
   primera hasta el límite y tirar el resto a la segunda. Soportado en todo
   navegador con el que se prueba esta consola; donde no lo esté, cae al
   corte normal — ningún fallback hace falta. */
.titular-portada { font-size: var(--texto-4xl); line-height: 1.15; letter-spacing: -0.02em; font-weight: 700; margin: 0; text-wrap: balance; }
/* MISMA causa raíz que las tarjetas (ver más abajo): `h1 { color: ... }`,
   sin capa, le ganaba SIEMPRE al `tw:text-transparent` (con capa) que el
   degradado necesita para pintarse — el titular se veía sólido, nunca el
   degradado que el HTML pedía (`tw:bg-gradient-to-br ... tw:bg-clip-text
   tw:text-transparent`). Comprobado: `color` calculaba el tono sólido de
   `--texto-fuerte`, nunca `transparent`, tapando el degradado entero. */
.titular-portada { color: transparent; }
.subtitulo-portada { font-size: var(--texto-lg); }

/* Los botones secundarios de la portada (`.boton.secundario` con
   `tw:rounded-full` en el HTML) tenían el MISMO problema: `button, .boton {
   border-radius: var(--radio); }` es una regla sin capa y siempre gana.
   Alcance a propósito: solo dentro de la portada — el resto de la consola
   sigue con el radio de `--radio` de siempre en sus botones secundarios. */
.barra-publica .boton.secundario,
.portada-seccion .boton.secundario,
.portada-seccion ~ section .boton.secundario {
  border-radius: var(--radio-pill);
}

/* Más aire entre bloques que el `.mb-1` genérico de la consola (§5.6.5,
   "aire entre bloques"): la portada es una fachada que se recorre con
   scroll, no una pantalla de trabajo densa — cada sección necesita
   separarse de la siguiente para leerse como un bloque propio. Selector
   de hermano general, sin clase nueva: solo afecta a lo que va DESPUÉS
   del hero de la portada.

   22-sep-2026 (el dueño, otra vez: "las secciones están pegadas"): subido
   de `--espacio-xl` a `--espacio-2xl` — el MISMO token que ya usa
   `.portada-seccion` para el aire del propio hero, así que el ritmo
   vertical de la portada es consistente de punta a punta, no dos escalas
   distintas. */
.portada-seccion ~ section { margin-bottom: var(--espacio-2xl); }

/* Las tres tarjetas de "Cómo funciona" son pasos, no datos sueltos: el
   trazo de marca arriba las agrupa como una secuencia, sin tocar el HTML
   ni la clase `.tarjeta` que comparten con el resto de la consola. */
#como-funciona.rejilla .tarjeta { border-top: 3px solid var(--marca); }

/* 22-sep-2026 — presencia de tarjeta a la par del front nuevo (React,
   `frontend_consola/src/components/ui/card.tsx`): mismo radio (12px, el
   `rounded-xl` de ahí) y una elevación real al pasar el cursor.

   🔴 CAUSA RAÍZ de "las tarjetas son lo más pobre de la pantalla": el HTML
   de `publico/inicio.html` YA pedía esto (`tw:rounded-2xl
   tw:border-border/60 tw:shadow-sm tw:hover:shadow-lg
   tw:hover:-translate-y-0.5`) pero NUNCA se aplicaba — comprobado en
   pantalla, no supuesto. Tailwind 4 mete sus utilidades dentro de `@layer
   utilities`; por especificación CSS, una regla SIN capa (como CUALQUIERA
   de esta hoja, `estilos.css`, que no declara `@layer`) le gana SIEMPRE a
   una regla con capa, sin importar especificidad ni orden de carga — así
   que el `border-radius: 8px` de `.tarjeta` (abajo) ganaba siempre contra
   el `tw:rounded-2xl` (16px) que el HTML pedía. El radio medido en pantalla
   era 8px, nunca 16px — "pieza escrita, nunca conectada", esta vez en CSS.
   Se quitaron esas clases inertes del HTML (ya no engañan a quien lea la
   plantilla) y se arregla AQUÍ, en una hoja sin capa, donde sí puede
   ganar. Alcance a propósito: solo las tarjetas DESPUÉS del hero de la
   portada (`.portada-seccion ~ section`) — el resto de la consola sigue
   con el radio de `--radio` de siempre, sin tocar. */
.portada-seccion ~ section .tarjeta,
.portada-seccion ~ section.tarjeta {
  border-radius: 12px;
  transition: box-shadow 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.portada-seccion ~ section .tarjeta:hover,
.portada-seccion ~ section .tarjeta:focus-within,
.portada-seccion ~ section.tarjeta:hover {
  box-shadow: var(--sombra-2);
  transform: translateY(-2px);
}
/* `<details>` abierto: la elevación de host quedaría rara con el contenido
   ya desplegado debajo — se queda en el resto de `--sombra-1`, sin levantar. */
.portada-seccion ~ section details.tarjeta[open]:hover,
.portada-seccion ~ section details.tarjeta[open]:focus-within {
  transform: none;
}

/* 22-sep-2026 — el dueño, mirando los DOS temas (encargo posterior, con
   hallazgos concretos): "en oscuro las tarjetas casi desaparecen — el
   fondo es casi el mismo negro de la página". Causa: una sombra OSCURA
   sobre una página ya casi negra no separa nada — es una técnica de tema
   CLARO (`--sombra-1`/`--sombra-2` son negro con alfa; sobre #17181a el ojo
   no distingue "negro con alfa 0.4" de "negro"). En oscuro la tarjeta se
   distingue por el BORDE, no por la sombra: se usa `--campo-borde`
   (#7a7a7e), el MISMO tono que ya se calibró para que los campos de
   formulario se separen del fondo en oscuro (ver su comentario, línea
   ~133) — reutilizado, no un tono nuevo que auditar aparte. En claro no
   hace falta: `--borde` (#d1d5db) ya separa bien sobre blanco. */
@media (prefers-color-scheme: dark) {
  :root:not([data-tema="claro"]) .portada-seccion ~ section .tarjeta,
  :root:not([data-tema="claro"]) .portada-seccion ~ section.tarjeta {
    border-color: var(--campo-borde);
  }
}
:root[data-tema="oscuro"] .portada-seccion ~ section .tarjeta,
:root[data-tema="oscuro"] .portada-seccion ~ section.tarjeta {
  border-color: var(--campo-borde);
}

/* Título de cada bloque de tres tarjetas ("Cómo funciona" / "Qué te
   garantizamos", texto nuevo autorizado para este hallazgo): antes las seis
   tarjetas de los dos bloques se leían como una lista suelta de seis cosas,
   sin nada que las agrupe en "pasos" vs. "promesas". `h2` ya trae el tamaño
   y el peso del resto de la consola (§5.6.5) — solo hace falta centrarlo,
   a la par del resto de la portada. */
.titulo-bloque-portada { text-align: center; }
/* El título de cada TARJETA baja a `<h3>` (antes `<h2>`) porque ahora hay un
   `<h2>` de bloque por encima — jerarquía correcta, no decoración. Sin una
   regla propia caería al tamaño de párrafo del navegador por omisión (no
   hay `h3` general en esta hoja, a propósito: "cinco tamaños, ni uno más",
   §5.6.5) — se mantiene VISIBLE pero un escalón por debajo del título de
   bloque, alcance acotado a la tarjeta de la portada, no un `h3` global que
   habría que auditar en toda la consola. */
.portada-seccion ~ section .tarjeta h3 {
  font-size: var(--texto-base);
  font-weight: 600;
  color: var(--texto-fuerte);
  margin: 0;
}

/* La prueba social ("N empresas conectadas · N acciones") es el dato MÁS
   persuasivo de la página (skill landing-page: "specificity beats
   cleverness") — con `.secundario` (texto tenue, pensado para metadatos que
   NO hace falta leer) se perdía. Clase propia: no se toca `.secundario` en
   ningún otro sitio de la consola. */
.prueba-social-portada { color: var(--texto-fuerte); font-weight: 600; font-size: var(--texto-base); }

/* El CTA del hero es la ÚNICA acción que importa en toda la pantalla y
   tenía el mismo tamaño que el botón secundario de al lado — sin jerarquía
   visual entre "la acción" y "leer más". Se escala por SELECTOR (nunca
   añadiendo una clase al `<a class="boton-primario">`: `test_publico_vista.
   py::test_portada_tiene_un_solo_cta_primario` cuenta el literal
   `class="boton-primario"` — una clase de más lo haría desaparecer del
   conteo). Alcance: solo el CTA dentro del hero de la portada; el de la
   sección final (`.portada-seccion-final`) y el resto de la consola
   siguen con el tamaño de siempre. */
.portada-seccion .boton-primario {
  min-height: 52px;
  padding: 0.85rem 2rem;
  font-size: var(--texto-lg);
}

/* El triángulo nativo de `<details>` se ve distinto en cada navegador y no
   dice "clic aquí": un "+" que gira a "×" al abrir, con `::marker` en vez de
   una imagen, es la misma información con la fricción de un ícono menos. */
details.tarjeta > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--espacio-sm);
}
details.tarjeta > summary::-webkit-details-marker { display: none; }
details.tarjeta > summary::after {
  content: "+";
  flex: none;
  font-size: var(--texto-lg);
  font-weight: 400;
  color: var(--marca-fuerte);
  transition: transform 0.15s ease;
}
details.tarjeta[open] > summary::after { transform: rotate(45deg); }

.boton-primario {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0.6rem 1.4rem;
  border-radius: var(--radio);
  border: 1px solid var(--boton-primario-fondo);
  background: var(--boton-primario-fondo);
  color: var(--boton-primario-texto);
  font-size: var(--texto-base);
  font-weight: 600;
  cursor: pointer;
}

/* ─── Página de error (`plantillas/error.html`, agente app.py): los botones
   de salida centrados, igual que el resto de `.vacio` ─── */
.vacio .fila-acciones { justify-content: center; }

/* ─── Cabecera de las pantallas sin sesión ───
   21-sep/25-sep-2026: nace para la familia "entrar a tu cuenta"
   (`ingresar`/`recuperar`/`clave_nueva`) — un enlace de vuelta a la
   izquierda, el conmutador a la derecha.

   22-sep-2026 (el team-lead, mirando la portada real a 1470px): "la
   cabecera está desordenada" — la portada y `registro`/`seguridad` NO
   usaban esta clase, pintaban `nav.principal` y el conmutador SUELTOS,
   hermanos sin envoltorio flex común. Resultado medido en pantalla: el nav
   se estira al 100% dentro de `<main>` (que no es flex, así que el
   `margin-inline-start: auto` de `nav.principal` no tenía contra qué
   empujar) y queda pegado arriba y corrido a la izquierda; el conmutador,
   sin fila que compartir, cae en la línea de abajo, suelto; y en NINGUNA
   de las tres pantallas hay marca — quien llega de un enlace no sabe dónde
   está.

   Una sola clase para las seis pantallas públicas con encabezado propio
   (`inicio`, `registro`, `seguridad`, `ingresar`, `recuperar`,
   `clave_nueva`): `.marca-cabecera` siempre primero (identidad, sin
   `href` — mismo `<strong>lilapro</strong>` que `header.cabecera`, no es
   una cuarta opción de navegación), luego el contenido propio de cada
   pantalla (`nav.principal`, que YA trae `margin-inline-start: auto` —
   línea 242 — o el enlace único `.volver-inicio`, que lo toma prestado
   abajo), y el conmutador siempre al final. Sin `justify-content:
   space-between`: con dos o tres elementos ese reparto los separa a partes
   iguales por toda la fila — vacío en el medio otra vez, el mismo defecto
   que se está arreglando —, el auto-margin del elemento penúltimo agrupa
   todo lo demás contra el borde derecho, que es lo que pide una cabecera:
   marca a un lado, el resto junto al otro. */
.barra-publica {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--espacio-xs) var(--espacio-md);
  padding-block: var(--espacio-sm);
}
.barra-publica .marca-cabecera {
  font-size: var(--texto-lg);
  font-weight: 600;
  color: var(--texto-fuerte);
}
.barra-publica .volver-inicio { margin-inline-start: auto; }

/* Centrado vertical real: la tarjeta ya no queda pegada arriba con media
   pantalla vacía debajo.

   22-sep-2026 (el team-lead, mirando la pantalla real en 1470px de ancho:
   «la pantalla está casi toda vacía», tarjeta perdida en un fondo plano).
   La corrección del 21-sep decía "sin gradiente, la jerarquía la da el
   espacio" — cierto en móvil, falso en un monitor ancho: `.envoltorio` ya
   limita el contenido a 68rem, y dentro de eso la tarjeta de 26rem deja
   todo alrededor sin nada. Se reutiliza la MISMA excepción que ya existe para
   `.portada-seccion` (§5.6.5.2: decoración permitida en una fachada, no en
   una pantalla de trabajo) — esta pantalla es tan fachada como la portada,
   así que el mismo resplandor con `--marca-suave` (cero peso extra, el
   oscuro ya sale del token) le da profundidad sin romper "un solo
   objetivo": sigue siendo una tarjeta angosta, centrada, con una acción. */
.pantalla-ingreso {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--espacio-xl);
  padding-block: var(--espacio-2xl);
  text-align: center;
  background: radial-gradient(ellipse 65% 75% at 50% 15%, var(--marca-suave), transparent 70%);
}
.marca-ingreso { display: flex; flex-direction: column; align-items: center; gap: 0.3em; }
.marca-ingreso .marca-nombre {
  /* `--texto-4xl`, la misma escala que el titular de la portada: esta
     pantalla es fachada, no tabla de datos — se permite el tamaño grande
     que en el resto de la consola está reservado para "/" (§5.6.5). */
  font-size: var(--texto-4xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--texto-fuerte);
}
.tarjeta-ingreso { width: 100%; text-align: left; }
