:root {
  /* Paleta Evolia (agosto 2026) — reemplaza la paleta institucional anterior
     que había antes. Los tonos salen directo del logo (icono + wordmark). */
  --evolia-azul: #1976d4;        /* Azul del ícono */
  --evolia-azul-oscuro: #0c255c; /* Azul marino del wordmark */
  --evolia-morado: #7c3aed;      /* Morado de acento (barras del ícono) */
  --evolia-grad: linear-gradient(120deg, #0c255c 0%, #1976d4 55%, #7c3aed 100%);

  /* Se conservan estos nombres internos, ahora con los colores de Evolia */
  --azul: #1976d4;            /* (color principal -> azul Evolia) */
  --azul-claro: #e8f0fd;      /* azul muy claro para fondos suaves */
  --verde: #1e8449;
  --amarillo: #b9770e;
  --rojo: #c0392b;
  --gris: #566573;
  --gris-claro: #f4f6f7;
  --borde: #d5dbdb;
  --radio: 10px;
}

* { box-sizing: border-box; }

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--gris-claro);
  color: #1b2631;
  margin: 0;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}

.contenedor {
  max-width: 720px;
  margin: 0 auto;
  padding: 20px 16px 60px;
}

.contenedor-ancho {
  max-width: 1100px;
  margin: 0 auto;
  padding: 20px 16px 60px;
}

header.top {
  background: var(--evolia-grad);
  color: white;
  padding: 14px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 3px solid var(--evolia-morado);
}

header.top a { color: white; text-decoration: none; font-weight: 600; }
header.top a.marca, header.top span.marca { display: inline-flex; align-items: center; gap: 8px; }
header.top .marca img { height: 24px; width: auto; border-radius: 4px; display: block; }
header.top .rol { font-size: 13px; opacity: 0.85; }

/* Campanita de avisos por inasistencia (se inserta desde api.js) */
header.top .campana {
  position: relative; display: inline-block; margin-right: 14px;
  font-size: 17px; line-height: 1; text-decoration: none; opacity: 0.9;
}
header.top .campana:hover { opacity: 1; }
header.top .campana .globo {
  position: absolute; top: -7px; right: -10px;
  background: white; color: var(--evolia-azul-oscuro);
  font-size: 10px; font-weight: 800; line-height: 1;
  padding: 3px 5px; border-radius: 999px; min-width: 8px; text-align: center;
}
header.top .campana.urgente .globo { background: #e74c3c; color: white; }

h1 { font-size: 22px; margin: 0 0 6px; }
h2 { font-size: 18px; margin: 24px 0 10px; }
p.subtitulo { color: var(--gris); margin-top: 0; }

.tarjeta {
  background: white;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: 18px;
  margin-bottom: 16px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}

label { display: block; font-size: 13px; font-weight: 600; margin: 12px 0 4px; color: var(--gris); }
input, select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--borde);
  border-radius: 8px;
  font-size: 15px;
}
input:focus, select:focus { outline: 2px solid var(--azul); border-color: var(--azul); }

/* Campo de contraseña con botón "ojito" para mostrar/ocultar */
.campo-clave { position: relative; }
.campo-clave input { padding-right: 46px; }
.campo-clave .ojo {
  position: absolute;
  right: 6px;
  top: 6px;
  bottom: 6px;
  margin: 0;
  padding: 0 10px;
  background: none;
  border: none;
  color: var(--gris);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.campo-clave .ojo:hover { opacity: 1; color: var(--azul); }

button, .boton {
  display: inline-block;
  background: var(--azul);
  color: white;
  border: none;
  padding: 11px 18px;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  margin-top: 14px;
  text-decoration: none;
  text-align: center;
}
button:hover, .boton:hover { opacity: 0.92; }
button.secundario { background: white; color: var(--azul); border: 1px solid var(--azul); }
button.peligro { background: var(--rojo); }
button:disabled { opacity: 0.5; cursor: not-allowed; }

.tabs { display: flex; gap: 8px; margin-bottom: 16px; }
.tabs button { flex: 1; margin-top: 0; background: white; color: var(--gris); border: 1px solid var(--borde); }
.tabs button.activo { background: var(--azul); color: white; border-color: var(--azul); }

.error { background: #fdedec; color: var(--rojo); border: 1px solid #f5b7b1; padding: 10px 12px; border-radius: 8px; margin-top: 12px; font-size: 14px; }
.exito { background: #eafaf1; color: var(--verde); border: 1px solid #a9dfbf; padding: 10px 12px; border-radius: 8px; margin-top: 12px; font-size: 14px; }
.info { background: var(--azul-claro); color: var(--azul); border: 1px solid #aed6f1; padding: 10px 12px; border-radius: 8px; margin-top: 12px; font-size: 14px; }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--borde); }
th { background: var(--azul-claro); color: var(--azul); font-weight: 600; position: sticky; top: 0; }
tr:hover td { background: #fbfcfc; }

.pill { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; }
.pill.ok { background: #eafaf1; color: var(--verde); }
.pill.medio { background: #fef5e7; color: var(--amarillo); }
.pill.mal { background: #fdedec; color: var(--rojo); }

.barra { background: var(--borde); border-radius: 6px; height: 8px; width: 100%; overflow: hidden; }
.barra > div { height: 100%; border-radius: 6px; }

.qr-caja { text-align: center; padding: 10px; }
.qr-caja img { width: 220px; height: 220px; border: 8px solid white; box-shadow: 0 2px 10px rgba(0,0,0,0.12); border-radius: 8px; }
.cuenta-regresiva { font-size: 13px; color: var(--gris); margin-top: 8px; }

.lista-fichas a { display: block; padding: 12px 14px; border: 1px solid var(--borde); border-radius: 8px; margin-bottom: 8px; text-decoration: none; color: #1b2631; background: white; }
.lista-fichas a:hover { border-color: var(--azul); }
.lista-fichas .codigo { font-weight: 700; color: var(--azul); font-size: 13px; }

.fila-stats { display: flex; gap: 10px; flex-wrap: wrap; margin: 14px 0; }
.stat { flex: 1; min-width: 100px; background: white; border: 1px solid var(--borde); border-radius: 8px; padding: 12px; text-align: center; }
.stat .num { font-size: 22px; font-weight: 700; color: var(--azul); }
.stat .lbl { font-size: 12px; color: var(--gris); }

#lector-qr { width: 100%; border-radius: 8px; overflow: hidden; }

footer.nota { text-align: center; color: var(--gris); font-size: 12px; margin-top: 30px; }
.pie-evolia { margin-top: 10px; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; opacity: 0.85; }
.pie-evolia img { height: 15px; width: auto; border-radius: 3px; }
.pie-evolia span { font-size: 12px; }
.pie-evolia a { color: var(--gris); font-size: 12px; text-decoration: none; border: 1px solid var(--borde); padding: 3px 10px; border-radius: 999px; white-space: nowrap; }
.pie-evolia a:hover { color: var(--evolia-azul); border-color: var(--evolia-azul); }

.login-marca { text-align: center; margin-bottom: 14px; }
.login-marca img { height: 54px; width: auto; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.12); background: white; }

/* =====================================================================
   PORTADA (login.html / login_docente.html) — rediseño oscuro y futurista,
   agosto 2026.

   TODO va scoped bajo body.pagina-portada / .portada / .tarjeta-cristal.
   Es a propósito: así el dashboard, los reportes y las pantallas del
   aprendiz siguen intactas con el tema claro mientras se rediseñan una
   por una. Cuando le toque el turno a cada una, se le pone su clase de
   página y hereda este mismo lenguaje visual. Nada de restilar `button`,
   `input` o `.tarjeta` a secas: eso reventaría los colores de estado
   (verde/amarillo/rojo de presente/medio/ausente), que NO son colores de
   marca y no se tocan nunca.
   ===================================================================== */

/* ---------- 1. El fondo ----------------------------------------------
   El color va en el body (plano y oscuro) y los degradados van en un DIV
   aparte, .fondo, fijo a la pantalla.

   ¿Por qué no todo en el body con background-attachment: fixed? Porque
   así el navegador solo pinta el alto de la ventana y, en cuanto la
   página crece un poco (el móvil con el formulario de registro abierto),
   lo de más abajo se queda BLANCO. Además Safari en iPhone lleva años
   con ese atributo medio roto. Una capa fija de verdad no tiene ninguno
   de los dos problemas.
   --------------------------------------------------------------------- */
body.pagina-portada {
  margin: 0;
  min-height: 100vh;
  color: #e6ecfa;
  overflow-x: hidden;
  /* Base que acompaña al scroll. .fondo (fijo) va encima y es lo que se
     ve siempre; esto es la red de seguridad para que, pase lo que pase,
     por debajo no aparezca ni un pixel blanco. */
  background: linear-gradient(135deg, #0a1642 0%, #0d1a4a 45%, #1b0b45 100%);
  background-color: #0a1642;
}

/* El fondo de portada.
   --------------------
   Es la imagen "Ondas de datos neón futuristas". Va en dos formatos y dos
   tamaños a propósito:

     * WebP primero (130 KB) y JPG de respaldo (195 KB) para el navegador
       viejo que no entienda WebP. El PNG original pesa 1.9 MB, y el fondo es
       literalmente lo primero que se descarga: en un celular con datos, esos
       1.9 MB son la diferencia entre que la página "aparezca" y que "cargue".
     * Una versión de 900 px para pantallas chicas — en un teléfono no se nota
       la diferencia y son 52 KB en vez de 130.

   Debajo queda el degradado de siempre: si la imagen no cargara, no aparece
   ni un pixel en blanco. */
.fondo {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    image-set(url("/static/img/fondo-evolia.webp?v=11") type("image/webp"),
              url("/static/img/fondo-evolia.jpg?v=11")  type("image/jpeg"))
      center / cover no-repeat,
    linear-gradient(135deg, #0a1642 0%, #0d1a4a 45%, #1b0b45 100%);
  background-color: #0a1642;
}

@media (max-width: 820px) {
  .fondo {
    background:
      image-set(url("/static/img/fondo-evolia-movil.webp?v=11") type("image/webp"),
                url("/static/img/fondo-evolia-movil.jpg?v=11")  type("image/jpeg"))
        center / cover no-repeat,
      linear-gradient(135deg, #0a1642 0%, #0d1a4a 45%, #1b0b45 100%);
    background-color: #0a1642;
  }
}

/* Rejilla sutil de 50px que se desvanece hacia abajo. Es lo que le da la
   sensación de "plano técnico" sin que se note el truco. */
.fondo::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(255,255,255,0.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.025) 1px, transparent 1px);
  background-size: 50px 50px;
  -webkit-mask-image: linear-gradient(to bottom, black, transparent);
  mask-image: linear-gradient(to bottom, black, transparent);
  opacity: 0.35;
}

/* Segunda capa de iluminación, arriba a la derecha. */
.fondo::after {
  content: "";
  position: absolute;
  width: 600px;
  height: 600px;
  right: -200px;
  top: -150px;
  background: radial-gradient(circle, rgba(25,118,212,0.25), transparent 70%);
  filter: blur(80px);
}

/* Partículas flotantes. Va en su propio div para que la animación no
   arrastre el degradado. */
.particulas {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(circle, #2ba7ff 1px, transparent 1px),
    radial-gradient(circle, #7c3aed 1px, transparent 1px);
  background-size: 180px 180px;
  background-position: 0 0, 90px 90px;
  opacity: 0.18;
  animation: flotando 25s linear infinite;
}
@keyframes flotando {
  from { transform: translateY(0); }
  to   { transform: translateY(-180px); }
}

/* Quien tenga activado "reducir movimiento" en su equipo no ve nada
   moverse. Es accesibilidad básica y cuesta tres líneas. */
@media (prefers-reduced-motion: reduce) {
  .particulas { animation: none; }
  .portada-marca,
  .portada-hero h1,
  .portada-hero p.portada-subtitulo,
  .portada-beneficios,
  .tarjeta-cristal,
  .portada-estado-entrando { animation: none !important; }
}

/* ---------- 2. Estructura: contenido centrado, pie abajo -------------- */
.portada {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center; /* centra verticalmente el panel (.portada-estados) cuando es más bajo que la ventana; si es más alto (registro+NDA), min-height deja crecer y no recorta nada */
  padding: 36px 20px 24px;
}

/* DOS COLUMNAS: a la izquierda el discurso (marca, titular y los tres
   beneficios), a la derecha el formulario. Es la que eligió Kely después
   de ver las dos — "me gusta mas esta presentacion".

   Se probó también una versión de una sola columna centrada y se
   descartó: se veía más limpia, pero la de dos columnas le da a quien
   llega por primera vez el "¿qué es esto?" al lado del "entra aquí", y
   esta pantalla también sirve de carta de presentación del sistema.

   flex:1 + align-content:center = el bloque se centra verticalmente en la
   ventana y el pie se va solo al borde de abajo, sin el hueco raro que
   quedaba al centrar los dos juntos. */
.portada-grid {
  flex: 1;
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  grid-template-areas:
    "hero       tarjeta"
    "beneficios tarjeta";
  column-gap: 56px;
  row-gap: 32px;
  align-content: center;
}
.portada-hero       { grid-area: hero; align-self: end; }
.portada-beneficios { grid-area: beneficios; align-self: start; }
.tarjeta-cristal    { grid-area: tarjeta; align-self: center; }

/* En el móvil el orden cambia a propósito: titular, FORMULARIO, y los
   beneficios debajo. Quien abre esto en el celular viene a entrar, no a
   que le vendan el sistema; el formulario tiene que caer de una vez. */
@media (max-width: 900px) {
  .portada { padding: 24px 18px 20px; }
  .portada-grid {
    grid-template-columns: 1fr;
    grid-template-areas: "hero" "tarjeta" "beneficios";
    row-gap: 26px;
    max-width: 470px;
    align-content: start;
  }
  .portada-hero, .portada-beneficios, .tarjeta-cristal { align-self: auto; }
}

/* Entrada suave al cargar: primero la marca, luego el texto, luego la
   tarjeta. Son 0.8s en total: no se siente lento, pero sí se siente
   "hecho a propósito". */
@keyframes entrar {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}
.portada-marca { animation: entrar 0.6s ease both; }
.portada-hero h1,
.portada-hero p.portada-subtitulo { animation: entrar 0.6s ease 0.08s both; }
.tarjeta-cristal { animation: entrar 0.6s ease 0.16s both; }
.portada-beneficios { animation: entrar 0.6s ease 0.24s both; }

/* ---------- 3. El logo ------------------------------------------------
   Se usa el lockup de marca en versión clara (letras blancas), así que no
   hace falta la placa blanca detrás: el resplandor azul basta y se ve
   mucho más limpio sobre el fondo oscuro.
   --------------------------------------------------------------------- */
.portada-marca {
  display: flex;
  align-items: center;
  margin-bottom: 16px; /* ajuste de proporción (v4): antes 24px, panel más compacto */
}
.portada-marca img {
  height: 84px;
  width: auto;
  filter: drop-shadow(0 0 34px rgba(25,118,212,0.45));
  /* Escala (recomposición septiembre 2026, v3): el boceto aprobado le da al
     logo un peso mucho más protagonista que el que tenía aquí (antes
     64px/50px) frente al eyebrow ("Asistente Académico" / "Espacio
     Académico Seguro"). Se sube a 84px/64px — el archivo en sí no cambia
     (mismo PNG, mismo recorte, sin deformar ni filtrar), solo la altura a
     la que se pinta.
     Corrección de alineación (se mantiene igual que antes): el archivo del
     logo trae el ícono y el wordmark "EVOL-IA" apilados, y el ícono es más
     alto que el wordmark — así que el CENTRO GEOMÉTRICO del PNG (lo que
     align-items: center de .portada-marca usa para alinear) cae más arriba
     que el centro real del texto "EVOL-IA". Se sube el PNG un 18% de su
     propio alto (medido sobre el archivo: el wordmark queda centrado en
     ~68.5% de la altura, no en el 50%) para que el wordmark, no el ícono,
     quede a la misma altura que el eyebrow. Al ser un porcentaje, sigue
     escalando igual sin importar la altura del PNG. */
  transform: translateY(-18%);
}
@media (max-width: 900px) {
  .portada-marca { margin-bottom: 12px; }
  .portada-marca img { height: 64px; }
}

/* ---------- 4. Titular y subtítulo ------------------------------------
   El max-width del subtítulo no es decorativo: pasadas unas 70 letras por
   renglón el ojo pierde el salto de línea.
   --------------------------------------------------------------------- */
.portada-hero h1 {
  font-size: 40px;
  line-height: 1.16;
  font-weight: 800;
  letter-spacing: -1px;
  margin: 0 0 10px; /* ajuste de proporción (v4): antes 16px */
  color: #ffffff;
}
/* Palabra de acento (septiembre 2026), referencia aprobada: "Académica" en
   Portada 1 y "de nuevo" en Portada 2 llevan el degradado azul→morado de
   marca; el resto del titular queda en blanco sólido. Un solo mecanismo
   para las dos portadas — mismo lenguaje gráfico, sin duplicar reglas. */
.portada-hero h1 .titulo-acento {
  background: linear-gradient(120deg, #3aa8ff, #7c3aed);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* Línea decorativa bajo el titular — solo Portada 1 (presentación), como
   en la referencia aprobada. */
#estado-presentacion .portada-hero h1::after {
  content: "";
  display: block;
  width: 72px;
  height: 4px;
  margin: 10px auto 0; /* v5: centrada bajo el título, como la referencia nueva */
  border-radius: 999px;
  background: linear-gradient(90deg, #3aa8ff, #7c3aed);
}
.portada-hero p.portada-subtitulo {
  color: #b8c7e5;
  font-size: 16.5px;
  line-height: 1.55;
  margin: 0;
  max-width: 450px;
}
@media (max-width: 900px) {
  .portada-hero h1 { font-size: 29px; letter-spacing: -0.6px; margin-bottom: 8px; }
  #estado-presentacion .portada-hero h1::after { margin-top: 8px; }
  .portada-hero p.portada-subtitulo { font-size: 14.5px; }
}

/* ---------- 5. Los tres beneficios ------------------------------------ */
/* Lista vertical debajo del titular, con el icono a la izquierda. Van en
   la columna del texto, no en la del formulario. */
.portada-beneficios {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px; /* ajuste de proporción (v4): antes 18px */
  max-width: 440px;
}
.portada-beneficios li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}
.portada-beneficios strong {
  display: block;
  color: #ffffff;
  font-size: 15px;
  margin-bottom: 3px;
  font-weight: 700;
}
.portada-beneficios .beneficio-detalle {
  display: block;
  color: #93a6c8;
  font-size: 13.5px;
  line-height: 1.45;
}
.portada-beneficios .icono-beneficio {
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: 13px;
  background: linear-gradient(140deg, rgba(25,118,212,0.22), rgba(124,58,237,0.22));
  border: 1px solid rgba(142,160,255,0.30);
  box-shadow: 0 8px 22px rgba(0,0,0,0.30), inset 0 1px 0 rgba(255,255,255,0.10);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #93c5fd;
  transition: 0.3s;
}
.portada-beneficios li:hover .icono-beneficio {
  color: #ffffff;
  border-color: rgba(142,160,255,0.55);
  box-shadow: 0 10px 28px rgba(25,118,212,0.28), inset 0 1px 0 rgba(255,255,255,0.16);
}

/* Un color propio por beneficio (septiembre 2026, referencia aprobada) —
   antes los cuatro compartían el mismo azul claro. El :hover de arriba
   sigue ganando (más selectores = más especificidad) y los pone blancos
   a los cuatro por igual al pasar el mouse. */
.icono-beneficio.i-qr       { color: #22d3ee; background: linear-gradient(140deg, rgba(34,211,238,0.24), rgba(34,211,238,0.06)); border-color: rgba(34,211,238,0.35); }
.icono-beneficio.i-personas { color: #a78bfa; background: linear-gradient(140deg, rgba(167,139,250,0.26), rgba(124,58,237,0.10)); border-color: rgba(167,139,250,0.38); }
.icono-beneficio.i-doc      { color: #38bdf8; background: linear-gradient(140deg, rgba(56,189,248,0.24), rgba(25,118,212,0.08)); border-color: rgba(56,189,248,0.35); }
.icono-beneficio.i-avisos   { color: #5b8cff; background: linear-gradient(140deg, rgba(91,140,255,0.24), rgba(25,118,212,0.08)); border-color: rgba(91,140,255,0.35); }

/* ---------- 6. La tarjeta de cristal ---------------------------------- */
/* Ajuste septiembre 2026 (v2) — panel 100% sólido, sin cristal:
   la ronda anterior dejaba a propósito 4% de transparencia + blur(26px)
   ("sigue habiendo cristal/blur real en el borde y el resto de fondo
   visible"), pero contra un fondo tan brillante ese 4% más el blur
   alcanzaban a mezclarse con las ondas, y el recuadro dejaba de leerse
   sólido — no coincidía con la referencia aprobada. Ahora el relleno es
   #0E1841 sin ningún canal de transparencia y sin backdrop-filter, igual
   que el panel principal (.portada-estado). La tarjeta se sigue
   diferenciando del panel por su borde claro propio y por su radio
   (24px vs. 40px del panel), no por transparencia. No cambia tamaño,
   posición, radio ni el hover. */
.tarjeta-cristal {
  position: relative;
  background: #0e1841; /* color de recuadro que dio Kely, 100% sólido */
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 24px;
  padding: 30px;
  box-shadow: 0 30px 70px rgba(0,0,0,0.60), 0 0 80px rgba(25,118,212,0.12), inset 0 1px 0 rgba(255,255,255,0.08);
  transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.tarjeta-cristal:hover {
  transform: translateY(-5px);
  box-shadow: 0 40px 90px rgba(0,0,0,0.45), 0 0 100px rgba(25,118,212,0.18);
}
@media (max-width: 900px) {
  .tarjeta-cristal { padding: 22px 18px; border-radius: 20px; }
  /* En el celular no hay ratón: levantar la tarjeta solo estorba. */
  .tarjeta-cristal:hover { transform: none; }
}

.tarjeta-cristal > p.subtitulo:first-child {
  color: #cbd8f0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.2px;
}
.tarjeta-cristal .subtitulo { color: #93a6c8; font-size: 13.5px; line-height: 1.5; }
.tarjeta-cristal label {
  color: #c8d4ec;
  font-size: 13px;
  font-weight: 600;
  margin: 14px 0 6px;
}

/* ---------- 7. Campos ------------------------------------------------- */
.tarjeta-cristal input,
.tarjeta-cristal select {
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.15);
  color: #ffffff;
  padding: 14px;
  border-radius: 14px;
  font-size: 15px;
  transition: 0.3s;
}
.tarjeta-cristal input::placeholder { color: #93a6c8; }
.tarjeta-cristal input:focus,
.tarjeta-cristal select:focus {
  outline: none;
  border-color: #32b7ff;
  box-shadow: 0 0 25px rgba(50,183,255,0.25);
  background: rgba(255,255,255,0.08);
}
.tarjeta-cristal .campo-clave input { padding-right: 50px; }
.tarjeta-cristal .ojo { color: #93a6c8; }
.tarjeta-cristal .ojo:hover { color: #ffffff; }

/* Icono a la izquierda en Correo/Contraseña (septiembre 2026, referencia
   aprobada). Puramente decorativo (aria-hidden en el HTML): el campo
   sigue siendo el mismo <input>, con el mismo id — solo cambia lo que hay
   alrededor. Compone con .campo-clave (el botón del ojito) sin chocar:
   una es padding-left, la otra padding-right. */
.tarjeta-cristal .campo-icono { position: relative; }
.tarjeta-cristal .campo-icono input { padding-left: 44px; }
.tarjeta-cristal .campo-icono-svg {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  color: #7fa0d6;
  pointer-events: none;
  display: flex;
}

/* Autocompletar de Chrome: por defecto pinta el campo de amarillo y se
   carga el diseño. Este truco lo deja en el mismo tono del formulario. */
.tarjeta-cristal input:-webkit-autofill,
.tarjeta-cristal input:-webkit-autofill:hover,
.tarjeta-cristal input:-webkit-autofill:focus {
  -webkit-text-fill-color: #ffffff;
  -webkit-box-shadow: 0 0 0 1000px #10203c inset;
  caret-color: #ffffff;
  transition: background-color 9999s ease-in-out 0s;
}

/* ---------- 8. Botones ------------------------------------------------ */
.tarjeta-cristal button:not(.ojo) {
  width: 100%;
  padding: 15px;
  background: linear-gradient(135deg, #1976d4, #3aa8ff, #7c3aed);
  border: none;
  border-radius: 14px;
  font-size: 16px;
  font-weight: 600;
  color: #ffffff;
  cursor: pointer;
  transition: transform 0.35s ease, box-shadow 0.35s ease;
  box-shadow: 0 20px 40px rgba(25,118,212,0.30);
}
.tarjeta-cristal button:not(.ojo):hover {
  transform: translateY(-2px);
  opacity: 1;
  box-shadow: 0 25px 55px rgba(25,118,212,0.45);
}
.tarjeta-cristal button:not(.ojo):active { transform: translateY(0); }

/* Las dos pestañas (Iniciar sesión / Registrarme) son secundarias: si
   llevaran el mismo degradado que el botón principal, competirían con él
   y la pantalla perdería el punto de entrada claro. */
.tarjeta-cristal .tabs { gap: 8px; }
.tarjeta-cristal .tabs button {
  padding: 11px;
  font-size: 14.5px;
  background: rgba(255,255,255,0.05);
  color: #a9b7d4;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: none;
  border-radius: 12px;
}
.tarjeta-cristal .tabs button:hover {
  transform: none;
  color: #ffffff;
  background: rgba(255,255,255,0.09);
  box-shadow: none;
}
.tarjeta-cristal .tabs button.activo {
  background: linear-gradient(135deg, #1976d4, #3aa8ff, #7c3aed);
  color: #ffffff;
  border-color: transparent;
  box-shadow: 0 10px 26px rgba(25,118,212,0.28);
}

/* ---------- 9. Avisos dentro de la tarjeta ---------------------------- */
.aviso-enlace {
  margin-top: 20px;
  padding: 14px 16px;
  border-radius: 14px;
  background: rgba(25,118,212,0.10);
  border: 1px solid rgba(25,118,212,0.28);
}
.aviso-enlace p.subtitulo { color: #b9d3f7; font-size: 13px; line-height: 1.5; }
.aviso-enlace .aviso-icono { color: #60a5fa; vertical-align: -3px; margin-right: 6px; }

.tarjeta-cristal .error { background: rgba(231,76,60,0.16); color: #ff9086; border: 1px solid rgba(231,76,60,0.40); border-radius: 12px; }
.tarjeta-cristal .exito { background: rgba(30,132,73,0.20); color: #7be3a8; border: 1px solid rgba(30,132,73,0.45); border-radius: 12px; }
.tarjeta-cristal .info  { background: rgba(25,118,212,0.18); color: #8fc1ff; border: 1px solid rgba(25,118,212,0.45); border-radius: 12px; }

/* ---------- 10. Pie ---------------------------------------------------- */
.portada footer.nota {
  color: #6f7fa4;
  margin-top: 34px;
  position: relative;
  z-index: 1;
}
.portada .pie-evolia a { color: #b8c7e5; border-color: rgba(255,255,255,0.18); }
.portada .pie-evolia a:hover { color: #ffffff; border-color: #ffffff; background: rgba(255,255,255,0.06); }

/* =====================================================================
   EL FONDO EN TODAS LAS PANTALLAS (agosto 2026)

   Antes la imagen solo salía en la portada. Kely la quería en todas las
   hojas, y eso obliga a algo más que pegarla de fondo: las pantallas de
   adentro (panel del docente, reportes, consolidado, admin) tienen títulos
   y subtítulos en gris oscuro, pensados para el fondo claro de siempre.
   Sobre la imagen oscura, ese texto se vuelve ilegible.

   Cómo queda resuelto:
     * la imagen va en una capa fija por DEBAJO de todo (body::before), así
       no se mueve al bajar y no estorba ningún clic;
     * las tarjetas blancas se quedan blancas — ahí viven las tablas, los
       formularios y los números, y es donde la legibilidad manda sobre lo
       bonito;
     * SOLO el texto que está suelto (título y subtítulo directamente
       dentro del contenedor, nunca el de adentro de una tarjeta) se aclara.
       De ahí el selector de hijo directo `>`: un `.subtitulo` dentro de una
       tarjeta blanca tiene que seguir gris.
   ===================================================================== */

body:not(.pagina-portada)::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(rgba(6,14,40,0.62), rgba(6,14,40,0.62)),
    image-set(url("/static/img/fondo-evolia.webp?v=11") type("image/webp"),
              url("/static/img/fondo-evolia.jpg?v=11")  type("image/jpeg"))
      center / cover no-repeat,
    linear-gradient(135deg, #0a1642 0%, #0d1a4a 45%, #1b0b45 100%);
  background-color: #0a1642;
}

@media (max-width: 820px) {
  body:not(.pagina-portada)::before {
    background:
      linear-gradient(rgba(6,14,40,0.62), rgba(6,14,40,0.62)),
    image-set(url("/static/img/fondo-evolia-movil.webp?v=11") type("image/webp"),
                url("/static/img/fondo-evolia-movil.jpg?v=11")  type("image/jpeg"))
        center / cover no-repeat,
      linear-gradient(135deg, #0a1642 0%, #0d1a4a 45%, #1b0b45 100%);
    background-color: #0a1642;
  }
}

body:not(.pagina-portada) {
  background: transparent;
  background-color: #0a1642;
}

/* Texto suelto: el que va sobre la imagen. Solo hijos directos. */
body:not(.pagina-portada) .contenedor > h1,
body:not(.pagina-portada) .contenedor > h2,
body:not(.pagina-portada) .contenedor-ancho > h1,
body:not(.pagina-portada) .contenedor-ancho > h2 {
  color: #eaf1ff;
  text-shadow: 0 1px 3px rgba(0,0,0,0.45);
}

body:not(.pagina-portada) .contenedor > p.subtitulo,
body:not(.pagina-portada) .contenedor-ancho > p.subtitulo,
body:not(.pagina-portada) .contenedor > .subtitulo,
body:not(.pagina-portada) .contenedor-ancho > .subtitulo {
  color: #c3d1ee;
  text-shadow: 0 1px 3px rgba(0,0,0,0.4);
}

body:not(.pagina-portada) .contenedor > p.subtitulo strong,
body:not(.pagina-portada) .contenedor-ancho > p.subtitulo strong {
  color: #ffffff;
}

/* Enlaces sueltos (volver, ver más) sobre el fondo. */
body:not(.pagina-portada) .contenedor > a,
body:not(.pagina-portada) .contenedor-ancho > a {
  color: #9fc6ff;
}

/* Las tarjetas se despegan del fondo oscuro con un borde y una sombra algo
   más marcados; sobre gris claro no hacían falta. */
body:not(.pagina-portada) .tarjeta {
  border-color: rgba(255,255,255,0.14);
  box-shadow: 0 10px 30px rgba(0,0,0,0.35);
}

/* La lista de fichas son enlaces sueltos con fondo blanco: igual trato. */
body:not(.pagina-portada) .lista-fichas a {
  box-shadow: 0 6px 18px rgba(0,0,0,0.28);
  border-color: rgba(255,255,255,0.14);
}

body:not(.pagina-portada) .stat {
  box-shadow: 0 6px 18px rgba(0,0,0,0.28);
  border-color: rgba(255,255,255,0.14);
}

/* Pie de página. */
body:not(.pagina-portada) footer.nota { color: #a9b8dc; }
body:not(.pagina-portada) .pie-evolia a {
  color: #c3d1ee;
  border-color: rgba(255,255,255,0.22);
}
body:not(.pagina-portada) .pie-evolia a:hover {
  color: #ffffff;
  border-color: #ffffff;
  background: rgba(255,255,255,0.08);
}

/* El check-in del estudiante centra una sola tarjeta: se ve mejor con algo
   de aire arriba para que la imagen respire. */
body:not(.pagina-portada) .contenedor { padding-top: 28px; }

/* =====================================================================
   BARRAS FLOTANTES — pantallas internas (agosto 2026)

   El problema que resuelve: las pantallas de adentro se veían como un
   formulario administrativo — etiqueta, caja blanca, etiqueta, caja blanca —
   y eso hacía sentir el sistema como una hoja de cuaderno, no como una
   plataforma. La lógica estaba bien; lo que fallaba era la presentación.

   Qué cambia, y solo esto:
     * cada control pasa a ser una BARRA horizontal traslúcida sobre el
       fondo, en vez de una caja blanca dentro de una tarjeta;
     * la tarjeta deja de ser un recuadro blanco y pasa a ser solo un
       agrupador — el aire lo dan los espacios, no los bordes;
     * el texto principal va en blanco puro; los niveles secundarios se
       resuelven con opacidad, no con gris;
     * las advertencias que NO son errores (la ubicación que no llegó, por
       ejemplo — se puede seguir sin ella) van en ámbar, no en rojo. El rojo
       queda para lo que de verdad está roto.

   NO se tocó una sola línea de JavaScript, ni un identificador, ni un
   endpoint, ni una validación. Todo esto es presentación.

   Se aplica bajo `body:not(.pagina-portada)` para no alterar la portada,
   que ya tiene su propio diseño.
   ===================================================================== */

/* Los controles nativos (desplegables, selector de archivo, calendario)
   se pintan claros por defecto y quedaban como parches blancos sobre el
   fondo oscuro. Esto le dice al navegador que la interfaz es oscura. */
body:not(.pagina-portada) { color-scheme: dark; }

/* ---------- 1. Jerarquía tipográfica ---------------------------------- */
body:not(.pagina-portada) .contenedor > h1,
body:not(.pagina-portada) .contenedor-ancho > h1 {
  color: #ffffff;
  font-size: 27px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 6px 0 8px;
  text-shadow: 0 2px 14px rgba(0,0,0,0.45);
}

body:not(.pagina-portada) .contenedor > h2,
body:not(.pagina-portada) .contenedor-ancho > h2 {
  color: #ffffff;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  margin: 46px 0 14px;
  text-shadow: 0 2px 14px rgba(0,0,0,0.45);
}

body:not(.pagina-portada) .contenedor > p.subtitulo,
body:not(.pagina-portada) .contenedor-ancho > p.subtitulo,
body:not(.pagina-portada) .contenedor > .subtitulo,
body:not(.pagina-portada) .contenedor-ancho > .subtitulo {
  color: rgba(255,255,255,0.72);
  font-size: 14.5px;
  line-height: 1.65;
  max-width: 60ch;
  margin-bottom: 22px;
  text-shadow: 0 1px 8px rgba(0,0,0,0.4);
}
body:not(.pagina-portada) .contenedor > p.subtitulo strong,
body:not(.pagina-portada) .contenedor-ancho > p.subtitulo strong { color: #ffffff; }

/* ---------- 2. La tarjeta deja de ser una tarjeta --------------------- */
/* Se vuelve un agrupador sin fondo ni borde: lo que se ve son las barras. */
body:not(.pagina-portada) .tarjeta {
  background: none;
  border: none;
  box-shadow: none;
  padding: 0;
  margin-bottom: 30px;
}

/* Salvo cuando lo que agrupa es una tabla o una lista: ahí sí hace falta
   una superficie que la contenga, o las filas flotan sobre la imagen. */
body:not(.pagina-portada) .tarjeta:has(table),
body:not(.pagina-portada) .tarjeta[style*="overflow"] {
  background: rgba(10, 22, 55, 0.55);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid rgba(255,255,255,0.09);
  border-radius: 16px;
  padding: 6px 4px;
  box-shadow: 0 18px 40px rgba(0,0,0,0.32);
}

/* ---------- 3. Las barras --------------------------------------------- */
body:not(.pagina-portada) label {
  color: rgba(255,255,255,0.66);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  margin: 26px 0 8px;
}

body:not(.pagina-portada) input,
body:not(.pagina-portada) select {
  background: rgba(12, 26, 62, 0.62);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.11);
  border-radius: 14px;
  color: #ffffff;
  font-size: 15.5px;
  padding: 15px 18px;
  box-shadow: 0 10px 26px rgba(0,0,0,0.22), inset 0 1px 0 rgba(255,255,255,0.05);
  transition: border-color .16s ease, box-shadow .16s ease, background .16s ease;
}

body:not(.pagina-portada) input::placeholder {
  color: rgba(255,255,255,0.38);
}

/* Al enfocar: un resplandor azul discreto. Tecnológico, no gamer. */
body:not(.pagina-portada) input:focus,
body:not(.pagina-portada) select:focus {
  outline: none;
  background: rgba(16, 34, 78, 0.78);
  border-color: rgba(96, 165, 255, 0.65);
  box-shadow: 0 0 0 3px rgba(56, 132, 255, 0.16),
              0 0 26px rgba(56, 132, 255, 0.20),
              inset 0 1px 0 rgba(255,255,255,0.07);
}

/* El desplegable abierto lo pinta el sistema operativo: hay que decirle
   explícitamente los colores o salen opciones blancas sobre blanco. */
body:not(.pagina-portada) select option {
  background: #0d1b3e;
  color: #ffffff;
}

/* El selector de archivo trae su propio botón, que venía gris de sistema. */
body:not(.pagina-portada) input[type="file"] {
  padding: 12px 14px;
  color: rgba(255,255,255,0.72);
  font-size: 14px;
}
body:not(.pagina-portada) input[type="file"]::file-selector-button {
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 10px;
  color: #ffffff;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  margin-right: 14px;
  padding: 9px 16px;
  cursor: pointer;
  transition: background .16s ease, border-color .16s ease;
}
body:not(.pagina-portada) input[type="file"]::file-selector-button:hover {
  background: rgba(96, 165, 255, 0.20);
  border-color: rgba(96, 165, 255, 0.45);
}

/* ---------- 4. Los botones -------------------------------------------- */
/* La acción principal manda: más luminosa que todo lo demás. */
body:not(.pagina-portada) button,
body:not(.pagina-portada) .boton {
  background: linear-gradient(118deg, #2b7fff 0%, #4f6dff 52%, #8b5cf6 100%);
  border: none;
  border-radius: 14px;
  color: #ffffff;
  font-size: 15.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 15px 24px;
  margin-top: 24px;
  box-shadow: 0 14px 32px rgba(43, 127, 255, 0.30);
  transition: transform .14s ease, box-shadow .16s ease, filter .16s ease;
}
body:not(.pagina-portada) button:hover:not(:disabled),
body:not(.pagina-portada) .boton:hover {
  opacity: 1;
  filter: brightness(1.08);
  box-shadow: 0 18px 40px rgba(43, 127, 255, 0.42);
  transform: translateY(-1px);
}
body:not(.pagina-portada) button:active:not(:disabled) { transform: translateY(0); }
body:not(.pagina-portada) button:disabled {
  background: rgba(255,255,255,0.07);
  color: rgba(255,255,255,0.40);
  box-shadow: none;
  opacity: 1;
}

/* La acción secundaria acompaña, no compite: misma barra, sin relleno. */
body:not(.pagina-portada) button.secundario,
body:not(.pagina-portada) .boton.secundario {
  background: rgba(12, 26, 62, 0.55);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.14);
  color: #ffffff;
  box-shadow: 0 8px 22px rgba(0,0,0,0.22);
}
body:not(.pagina-portada) button.secundario:hover:not(:disabled),
body:not(.pagina-portada) .boton.secundario:hover {
  background: rgba(43, 127, 255, 0.20);
  border-color: rgba(96, 165, 255, 0.50);
  filter: none;
}
body:not(.pagina-portada) button.peligro {
  background: linear-gradient(118deg, #e0524a 0%, #c0392b 100%);
  box-shadow: 0 14px 32px rgba(192, 57, 43, 0.28);
}

body:not(.pagina-portada) .tabs { gap: 10px; margin-bottom: 22px; }
body:not(.pagina-portada) .tabs button {
  background: rgba(12, 26, 62, 0.55);
  border: 1px solid rgba(255,255,255,0.12);
  color: rgba(255,255,255,0.72);
  box-shadow: none;
  margin-top: 0;
}
body:not(.pagina-portada) .tabs button.activo {
  background: linear-gradient(118deg, #2b7fff 0%, #6d5cf6 100%);
  border-color: transparent;
  color: #ffffff;
  box-shadow: 0 10px 26px rgba(43,127,255,0.30);
}

/* ---------- 5. Mensajes ------------------------------------------------ */
/* Un aviso NO es un error. La ubicación que no llegó se puede continuar
   sin ella, así que va en ámbar: llama la atención sin alarmar. El rojo se
   reserva para lo que de verdad está roto. */
body:not(.pagina-portada) .info,
body:not(.pagina-portada) #ubicacion-estado.error {
  background: rgba(255, 213, 79, 0.09);
  border: 1px solid rgba(255, 213, 79, 0.30);
  border-radius: 14px;
  color: #ffd54f;
  padding: 14px 16px 14px 44px;
  position: relative;
  font-size: 14px;
  line-height: 1.55;
}
body:not(.pagina-portada) .info::before,
body:not(.pagina-portada) #ubicacion-estado.error::before {
  content: "⚠";
  position: absolute;
  left: 16px;
  top: 13px;
  font-size: 16px;
  line-height: 1.4;
}

body:not(.pagina-portada) .error {
  background: rgba(224, 82, 74, 0.12);
  border: 1px solid rgba(224, 82, 74, 0.34);
  border-radius: 14px;
  color: #ff9a90;
  padding: 14px 16px;
  font-size: 14px;
  line-height: 1.55;
}

body:not(.pagina-portada) .exito {
  background: rgba(52, 199, 123, 0.12);
  border: 1px solid rgba(52, 199, 123, 0.34);
  border-radius: 14px;
  color: #7be3a8;
  padding: 14px 16px;
  font-size: 14px;
  line-height: 1.55;
}

/* ---------- 6. Tablas, listas y cifras -------------------------------- */
body:not(.pagina-portada) table { color: rgba(255,255,255,0.88); }
body:not(.pagina-portada) th {
  background: rgba(255,255,255,0.05);
  color: rgba(255,255,255,0.62);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid rgba(255,255,255,0.10);
}
body:not(.pagina-portada) td {
  border-bottom: 1px solid rgba(255,255,255,0.07);
  padding: 13px 12px;
}
body:not(.pagina-portada) td strong { color: #ffffff; }
body:not(.pagina-portada) tr:hover td { background: rgba(255,255,255,0.04); }

body:not(.pagina-portada) .lista-fichas a {
  background: rgba(12, 26, 62, 0.58);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.11);
  border-radius: 14px;
  color: #ffffff;
  padding: 15px 18px;
  margin-bottom: 10px;
  box-shadow: 0 10px 26px rgba(0,0,0,0.22);
  transition: border-color .16s ease, background .16s ease, transform .14s ease;
}
body:not(.pagina-portada) .lista-fichas a:hover {
  background: rgba(43, 127, 255, 0.16);
  border-color: rgba(96, 165, 255, 0.45);
  transform: translateY(-1px);
}
body:not(.pagina-portada) .lista-fichas .codigo { color: #8fc1ff; }

body:not(.pagina-portada) .stat {
  background: rgba(12, 26, 62, 0.58);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.11);
  border-radius: 16px;
  padding: 18px 14px;
  box-shadow: 0 10px 26px rgba(0,0,0,0.22);
}
body:not(.pagina-portada) .stat .num { color: #ffffff; font-size: 26px; }
body:not(.pagina-portada) .stat .lbl {
  color: rgba(255,255,255,0.60);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: 11px;
}

body:not(.pagina-portada) .pill.ok    { background: rgba(52,199,123,0.16);  color: #7be3a8; }
body:not(.pagina-portada) .pill.medio { background: rgba(255,213,79,0.16);  color: #ffd54f; }
body:not(.pagina-portada) .pill.mal   { background: rgba(224,82,74,0.16);   color: #ff9a90; }
body:not(.pagina-portada) .barra { background: rgba(255,255,255,0.10); }

body:not(.pagina-portada) .cuenta-regresiva { color: rgba(255,255,255,0.62); }
body:not(.pagina-portada) .contenedor > a,
body:not(.pagina-portada) .contenedor-ancho > a { color: rgba(255,255,255,0.62); }
body:not(.pagina-portada) .contenedor-ancho > a:hover { color: #ffffff; }

/* ---------- 7. Aire ---------------------------------------------------- */
body:not(.pagina-portada) .contenedor,
body:not(.pagina-portada) .contenedor-ancho { padding: 34px 20px 80px; }

/* En pantallas chicas las barras siguen siendo barras: se estrechan, no se
   encogen de alto. El dedo necesita el mismo blanco para acertar. */
@media (max-width: 620px) {
  body:not(.pagina-portada) .contenedor,
  body:not(.pagina-portada) .contenedor-ancho { padding: 24px 14px 70px; }
  body:not(.pagina-portada) .contenedor > h1,
  body:not(.pagina-portada) .contenedor-ancho > h1 { font-size: 23px; }
  body:not(.pagina-portada) .contenedor > h2,
  body:not(.pagina-portada) .contenedor-ancho > h2 { margin-top: 38px; }
  body:not(.pagina-portada) input,
  body:not(.pagina-portada) select { padding: 14px 15px; font-size: 16px; }
  body:not(.pagina-portada) button,
  body:not(.pagina-portada) .boton { padding: 15px 18px; width: 100%; }
}

/* Corrección: al volver transparentes las tarjetas, ya no queda NINGUNA
   superficie blanca en las pantallas internas. Los títulos y subtítulos que
   viven dentro de una tarjeta seguían en gris oscuro —pensados para el fondo
   blanco de antes— y quedaban ilegibles. Ahora todo el texto de estas
   pantallas se trata como texto sobre fondo oscuro. */
body:not(.pagina-portada) .contenedor h1,
body:not(.pagina-portada) .contenedor h2,
body:not(.pagina-portada) .contenedor h3,
body:not(.pagina-portada) .contenedor-ancho h1,
body:not(.pagina-portada) .contenedor-ancho h2,
body:not(.pagina-portada) .contenedor-ancho h3 {
  color: #ffffff;
  text-shadow: 0 2px 14px rgba(0,0,0,0.45);
}

/* Un título dentro de una tarjeta es un subtítulo de sección: no compite con
   el título de la pantalla, así que va más discreto que los de primer nivel. */
body:not(.pagina-portada) .tarjeta h2,
body:not(.pagina-portada) .tarjeta h3 {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: none;
  margin: 0 0 6px;
}

body:not(.pagina-portada) .subtitulo,
body:not(.pagina-portada) .tarjeta p,
body:not(.pagina-portada) .tarjeta > div:not([class]) {
  color: rgba(255,255,255,0.70);
}
body:not(.pagina-portada) .subtitulo strong { color: #ffffff; }

/* El enlace de volver estaba casi invisible sobre el fondo. */
body:not(.pagina-portada) .contenedor > a[href],
body:not(.pagina-portada) .contenedor-ancho > a[href] {
  color: rgba(255,255,255,0.70);
  text-decoration: none;
  font-weight: 600;
}
body:not(.pagina-portada) .contenedor > a[href]:hover,
body:not(.pagina-portada) .contenedor-ancho > a[href]:hover { color: #ffffff; }

/* La cabecera de la tabla se salía de las esquinas redondeadas. */
body:not(.pagina-portada) .tarjeta:has(table) { overflow: hidden; }
body:not(.pagina-portada) .tarjeta:has(table) table { border-collapse: collapse; }

/* Texto suelto dentro de una tarjeta (mensajes de "Cargando…", listas
   vacías) — también sobre fondo oscuro ahora. */
body:not(.pagina-portada) .tarjeta { color: rgba(255,255,255,0.88); }

/* En el celular la barra superior partía "Asistencia Académica" en dos
   líneas y empujaba "Salir" abajo. Se ajusta el tamaño para que quepa de
   una sola línea, sin quitarle nada. */
@media (max-width: 620px) {
  header.top { padding: 12px 14px; gap: 8px; }
  header.top .marca { font-size: 14.5px; }
  header.top .marca img { height: 20px; }
  header.top .rol { font-size: 11.5px; }
  header.top a[onclick] { font-size: 14px; }
}

/* =====================================================================
   DOS PORTADAS INDEPENDIENTES (septiembre 2026)

   Corrección de arquitectura sobre la primera versión: esto NO es una
   portada con un panel que muestra/oculta otro panel por dentro. Son DOS
   COMPOSICIONES COMPLETAS — PORTADA 1, presentación del producto
   (#estado-presentacion) y PORTADA 2, acceso al sistema (#estado-login) —
   cada una con su PROPIO panel grande y autocontenido: logo, eyebrow,
   título, contenido y pie de página cada uno dentro de SU recuadro,
   siguiendo la composición de EVOL-IA Contracts. Por eso footer.nota está
   duplicado en las dos secciones de login.html más abajo en el HTML: son
   dos portadas, cada una con su propio pie, no un pie compartido.

   Técnicamente se sigue siendo la misma URL / el mismo <body>, y pasar de
   una a otra sigue siendo mostrarEstadoLogin() en portada.js (oculta un
   <section>, muestra el otro) — pero visualmente cada
   <section class="portada-estado"> ES una portada independiente: al pulsar
   el CTA desaparece el panel completo de la Portada 1 (con su pie) y
   aparece el panel completo de la Portada 2 (con el suyo).

   login_docente.html no tiene el toggle (no existe #estado-presentacion):
   como se llega siempre por invitación, entra directo a la Portada 2, con
   el mismo tratamiento de panel.

   A propósito reutiliza tal cual .portada-hero, .portada-marca,
   .portada-beneficios y .tarjeta-cristal — con sus mismas reglas de más
   arriba (incluida la animación de entrada y su guard de
   prefers-reduced-motion). Nada de esto toca button, input, h1 ni
   .tarjeta a secas: mismo criterio que el resto del archivo.
   ===================================================================== */
.portada-estados {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.portada-estado[hidden] { display: none; }

/* Cada .portada-estado ES el panel grande de su propia portada. */
.portada-estado {
  position: relative;
  width: 100%;
  max-width: 580px; /* v5: antes 760px — recuadro más angosto, como la referencia nueva */
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px; /* ajuste de proporción (v4): antes 28px — panel más compacto verticalmente, misma estructura */
  /* Recomposición septiembre 2026 (v3, fidelidad al boceto aprobado): el
     eje de lectura del panel es IZQUIERDO, no centrado. El boceto muestra
     el logo, el título y el subtítulo arrancando en el mismo margen que
     los beneficios y la tarjeta de abajo — antes el bloque hero (logo +
     título + subtítulo) estaba centrado de forma independiente, mientras
     beneficios/tarjeta ya eran left. Ese desfase de ejes es justo lo que
     Kely pidió corregir. Solo el pie (footer.nota, más abajo) se queda
     centrado a propósito: así se ve en el boceto en las dos portadas. */
  text-align: left;
  /* Borde con degradado azul→morado (septiembre 2026, referencia aprobada):
     técnica de doble capa — "padding-box" es el relleno sólido de siempre
     y "border-box" es el degradado, que solo asoma en el grosor del borde.
     Ajuste septiembre 2026 (v2): se quita el backdrop-filter que había
     acá — con el relleno ya 100% sólido (dos paradas iguales de
     #0e1841, sin canal alfa) no aportaba nada visible, y sí arriesgaba
     dejar asomar el fondo animado en las esquinas redondeadas. Kely
     pidió el panel como un bloque #0E1841 uniforme, sin ningún grado de
     transparencia; el fondo tecnológico debe quedar visible solo AFUERA
     del panel. */
  background:
    linear-gradient(#0e1841, #0e1841) padding-box,
    linear-gradient(135deg, #3aa8ff 0%, #7c3aed 100%) border-box;
  border: 1px solid transparent;
  border-radius: 40px;
  padding: 40px 40px 26px; /* v5: panel más angosto, márgenes internos acordes */
  box-shadow: 0 40px 100px rgba(0,0,0,0.55), 0 0 120px rgba(25,118,212,0.12), inset 0 1px 0 rgba(255,255,255,0.07);
}

/* v5 (referencia nueva de Kely): el ENCABEZADO va centrado — logo, eyebrow,
   título, línea decorativa y descripción — y solo los beneficios y la tarjeta
   se quedan alineados a la izquierda. Antes (v3) todo el hero era left. */
.portada-estado .portada-marca { justify-content: center; margin-bottom: 0; }
.portada-estado .portada-hero { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 12px; width: 100%; }
.portada-estado .portada-hero p.portada-subtitulo { max-width: 430px; margin: 0 auto; text-align: center; }

/* Los beneficios y la tarjeta se leen de izquierda a derecha (íconos +
   texto, o etiquetas + campos): el centrado es del PANEL, no de su
   contenido interno. Los dos llenan el ancho útil del panel — ya no
   tienen su propio max-width, ahora el que manda es el del panel. */
.portada-estado .portada-beneficios { text-align: left; width: 100%; }
.portada-estado .tarjeta-cristal { width: 100%; text-align: left; }

/* El pie queda DENTRO de cada panel: es el pie de ESA portada, no uno
   compartido entre las dos. La línea tenue arriba lo separa del
   contenido, como en la referencia de Contracts. (.portada footer.nota,
   más arriba en el archivo, sigue aplicando el color — esto solo agrega
   el espaciado y el divisor dentro del panel.) */
.portada-estado footer.nota {
  width: 100%;
  margin-top: 8px;
  padding-top: 24px;
  border-top: 1px solid rgba(255,255,255,0.08);
  /* El resto del panel pasó a alinearse a la izquierda (recomposición
     septiembre 2026, v3), pero el pie se queda centrado a propósito: así
     aparece en el boceto aprobado en las dos portadas. */
  text-align: center;
}

@media (max-width: 900px) {
  .portada-estado { gap: 16px; padding: 32px 24px 24px; border-radius: 30px; } /* ajuste de proporción (v4): antes gap 22px, padding 40px 26px 30px */
  .portada-estado .portada-hero { gap: 10px; } /* ajuste de proporción (v4) */
  .portada-beneficios { gap: 12px; } /* ajuste de proporción (v4): antes 18px (heredado) */
}
@media (max-width: 480px) {
  .portada-estado { padding: 26px 18px 20px; border-radius: 24px; } /* ajuste de proporción (v4): antes 32px 18px 24px */
}

/* El pequeño rótulo junto al logo ("Asistente Académico" / "Espacio
   Académico Seguro" según el estado). */
.portada-marca-eyebrow {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #93c5fd;
  padding-left: 16px;
  border-left: 1px solid rgba(147,197,253,0.35);
  /* v5: en la referencia nueva el rótulo cae en dos renglones junto al logo,
     no en uno solo muy largo. Se le deja partir y se le da un ancho máximo
     para que el corte sea siempre "ASISTENTE / ACADÉMICO". */
  white-space: normal;
  /* 13em ≈ 17 caracteres: parte "ASISTENTE / ACADÉMICO" en Portada 1 y
     "ESPACIO ACADÉMICO / SEGURO" en Portada 2, las dos en dos renglones. */
  max-width: 13em;
  line-height: 1.45;
  text-align: left;
}
@media (max-width: 480px) {
  .portada-marca-eyebrow { font-size: 11px; padding-left: 10px; white-space: normal; }
}

/* El botón "Ingresar al sistema": mismo lenguaje visual que los botones
   de .tarjeta-cristal, pero como clase propia porque vive fuera de ella.
   Ancho completo del panel (antes tenía max-width:320px, se quita: con el
   panel ahora tan ancho, un botón angosto se veía perdido — en la
   referencia de Contracts el CTA ocupa todo el ancho útil). */
.cta-ingresar {
  display: inline-block;
  width: 100%;
  padding: 16px 28px;
  background: linear-gradient(135deg, #1976d4, #3aa8ff, #7c3aed);
  border: none;
  border-radius: 18px; /* v5: esquinas más redondeadas, como la referencia nueva */
  color: #ffffff;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 20px 40px rgba(25,118,212,0.30);
  transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.cta-ingresar:hover {
  transform: translateY(-2px);
  box-shadow: 0 25px 55px rgba(25,118,212,0.45);
}
.cta-ingresar:active { transform: translateY(0); }
.cta-ingresar .cta-flecha {
  display: inline-block;
  margin-left: 6px;
  transition: transform 0.25s ease;
}
.cta-ingresar:hover .cta-flecha { transform: translateX(4px); }

/* Entrada de la tarjeta de login al aparecer (clic en el CTA). Reutiliza
   la misma animación "entrar" que ya usan .tarjeta-cristal, .portada-marca,
   etc. al cargar la página — por eso el guard de prefers-reduced-motion de
   más arriba también cubre esta clase. */
.portada-estado-entrando { animation: entrar 0.5s ease both; }

/* El video de fondo: solo se inserta por JavaScript (app/static/js/
   portada.js), solo en escritorio y solo sin prefers-reduced-motion. Va
   dentro de .fondo, cubriendo exactamente lo mismo que la imagen que ya
   pinta ese div por CSS — si el video no llega a cargar o el navegador
   bloquea el autoplay, la imagen de siempre se sigue viendo debajo. */
.fondo-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* =====================================================================
   PORTADA — CONTRASTE DEL BLOQUE NDA (septiembre 2026)

   Mismo motivo que la corrección de .tarjeta-cristal de más arriba: el
   cuadro del Acuerdo de Confidencialidad y su checkbox viven dentro de
   app/templates/_acuerdo_confidencialidad.html, que trae su propio
   <style> (.acuerdo-caja / .acuerdo-check). Ese archivo es, a propósito,
   la ÚNICA copia del texto del NDA (lo usan login.html y login_docente.html
   por igual) y no se toca aquí — en vez de eso se sobreescribe desde acá,
   con más especificidad (body.pagina-portada + la clase), para que el
   NDA quede TODAVÍA más sólido que la tarjeta que lo contiene: es el
   bloque legal, tiene que leerse sin esfuerzo y sin que las ondas del
   fondo interfieran. No cambia el texto, la estructura ni el checkbox en
   sí — solo su color de fondo, borde y el tono del texto del checkbox. */
body.pagina-portada .acuerdo-caja {
  background: #0e1841; /* mismo color de recuadro, sólido: el NDA va aún más firme que la tarjeta */
  border-color: rgba(255,255,255,0.18);
}
body.pagina-portada .acuerdo-check {
  color: #d7deee;
}
/* Bug real, no solo de contraste: la regla global "input, select { width:
   100%; }" (la de más arriba, para los formularios de toda la app) también
   le llegaba a este <input type="checkbox">. Con flex-shrink:0 puesto en el
   propio _acuerdo_confidencialidad.html, ese 100% lo dejaba ocupando TODO
   el ancho del renglón flex y el texto del label salía empujado fuera de
   la tarjeta — por eso se veía sobre el fondo, sin caja detrás. Se le fija
   un tamaño de casilla normal (16x16) para que la regla global ya no
   aplique y el texto recupere el espacio y quede dentro de la tarjeta. */
body.pagina-portada .acuerdo-check input {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  accent-color: #3aa8ff;
}

/* =====================================================================
   ICONO DEL ENCABEZADO DEL NDA (septiembre 2026, referencia aprobada)

   _acuerdo_confidencialidad.html es la única copia del texto del NDA y no
   se toca (mismo criterio que el bloque de arriba): el icono se agrega
   por CSS puro, con un ::before sobre el <strong> del encabezado. Es un
   SVG embebido como data-URI (mismo lenguaje visual que los demás iconos
   nuevos), no una imagen aparte que haya que gestionar.
   ===================================================================== */
body.pagina-portada .acuerdo-caja p:first-child strong::before {
  content: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2215%22%20height%3D%2215%22%20fill%3D%22none%22%20stroke%3D%22%2360a5fa%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M14%203H7a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h10a2%202%200%200%200%202-2V8z%22/%3E%3Cpath%20d%3D%22M14%203v5h5%22/%3E%3Cline%20x1%3D%229%22%20y1%3D%2213%22%20x2%3D%2215%22%20y2%3D%2213%22/%3E%3Cline%20x1%3D%229%22%20y1%3D%2217%22%20x2%3D%2215%22%20y2%3D%2217%22/%3E%3C/svg%3E");
  display: inline-block;
  vertical-align: -3px;
  margin-right: 7px;
}
