/* ==========================================================================
   UTPLabs · Sistema de diseño
   --------------------------------------------------------------------------
   Dos referencias, y cada una aporta una cosa distinta:

   1. La PALETA y la TIPOGRAFÍA salen de utp.edu.pe. El rojo institucional
      medido en su sitio es #D3052D, sobre negro (#050505 / #262626) y blanco.
      Nada de azules: el prototipo viejo era azul y eso quedó atrás. La letra
      es Libre Franklin, la que usa la universidad, y es la única del sistema:
      cuerpo y titulares, igual que en su web.

   2. El ESTILO DE LOS ELEMENTOS sale de prensalink.com. No la estructura de
      sus páginas, sino cómo están hechas sus piezas:
        · bordes capilares de 0.8px en gris muy claro, nunca marcos gruesos;
        · radios cortos: 6px en botones, 12px en tarjetas, 18px en paneles;
        · sombras anchas y casi invisibles (0.03–0.08 de opacidad), no el
          típico box-shadow oscuro;
        · el marcador de color detrás de las palabras del titular;
        · barra negra arriba + cabecera blanca pegajosa;
        · botón píldora con contorno para la acción secundaria.

   Regla de oro del proyecto: ningún estado se comunica SOLO con color.
   Siempre color + texto (y muchas veces + punto o ícono), porque el
   documento del rol 1 lo pide y porque el jurado lo va a mirar.
   ========================================================================== */

/* -------------------------------------------------------------------------
   1. Fichas de diseño (tokens)
   ------------------------------------------------------------------------- */
:root {
  /* --- Rojos UTP --- */
  --rojo: #d3052d;            /* el institucional, medido en utp.edu.pe */
  --rojo-vivo: #e5163f;       /* hover */
  --rojo-hondo: #9d0322;      /* activo / texto sobre claro */
  --carmin: #d01a49;          /* acento secundario de la UTP */
  --rojo-velo: rgba(211, 5, 45, 0.08);
  --rojo-velo-2: rgba(211, 5, 45, 0.16);

  /* --- Negros y grises --- */
  --tinta: #050505;           /* negro de titular */
  --tinta-2: #161616;         /* superficies oscuras */
  --tinta-3: #262626;         /* gris muy oscuro UTP */
  --gris-texto: #444444;      /* párrafo sobre blanco */
  --gris-medio: #6b6b6b;      /* texto secundario */
  --gris-suave: #8f8f8f;      /* texto terciario, marcas de agua */
  --linea: #e2e2e2;           /* capilar sobre claro */
  --linea-firme: #d0d0d0;     /* capilar con más presencia */
  --linea-oscura: #272727;    /* capilar sobre oscuro */

  /* --- Papeles --- */
  --papel: #ffffff;
  --papel-2: #f7f7f7;
  --papel-3: #f1efec;         /* hueso: bandas de sección */

  /* --- Semáforo (siempre acompañado de texto) --- */
  --ok: #10703c;      --ok-velo: #e9f4ee;
  --espera: #8a5a00;  --espera-velo: #fbf3e2;
  --alto: var(--rojo); --alto-velo: #fdeaed;
  --frio: #1f4f73;    --frio-velo: #eaf1f7;   /* informativo, nada más */

  /* --- Tipografía ---
     Una sola familia para todo, que es como está hecha utp.edu.pe: ahí el
     cuerpo y los titulares son Libre Franklin, con los pesos de 400 a 900, y
     no hay ninguna serif en la página. Antes los titulares iban en Lora y
     eso era una decisión nuestra, no de la marca.

     `--titular` sustituye a la vieja `--serif`. El nombre cambió porque el
     valor ya no describe una serif y dejarlo llamándose así hacía leer mal
     cada regla que lo usa. */
  --titular: "Libre Franklin", -apple-system, "Segoe UI", Roboto, sans-serif;
  --palo: "Libre Franklin", -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "IBM Plex Mono", "Cascadia Mono", Consolas, monospace;

  /* --- Trazo y forma --- */
  --capilar: 0.8px;           /* el grosor de borde de prensalink */
  --r-boton: 6px;
  --r-tarjeta: 12px;
  --r-panel: 18px;
  --r-pildora: 999px;

  /* --- Sombras: anchas, bajísimas de opacidad --- */
  --sombra-1: 0 10px 26px rgba(0, 0, 0, 0.03);
  --sombra-2: 0 28px 70px rgba(0, 0, 0, 0.08);
  --sombra-3: 0 28px 60px rgba(0, 0, 0, 0.22);
  --anillo: 0 0 0 1px var(--tinta);

  /* --- Ritmo --- */
  --e1: 4px;  --e2: 8px;  --e3: 12px; --e4: 16px;
  --e5: 24px; --e6: 32px; --e7: 48px; --e8: 72px;

  --transicion: 160ms cubic-bezier(0.2, 0, 0.2, 1);
}

/* -------------------------------------------------------------------------
   2. Reset y base
   ------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; padding: 0; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--palo);
  font-size: 16px;
  line-height: 1.55;
  color: var(--gris-texto);
  background: var(--papel);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

main { flex: 1 0 auto; }

img, svg, video { display: block; max-width: 100%; }

/* `hidden` tiene que ganarle a cualquier clase con display propio. */
[hidden] { display: none !important; }

/* En palo seco un titular necesita más peso y menos interletra que en serif
   para pesar lo mismo en la página: los grandes van en 800 —el 900 que usa
   la UTP en sus portadas aplasta los titulares largos de una interfaz— y del
   h3 hacia abajo alcanza con 700. */
h1, h2, h3, h4, h5 {
  font-family: var(--titular);
  font-weight: 700;
  color: var(--tinta);
  line-height: 1.12;
  letter-spacing: -0.02em;
}

h1 { font-size: clamp(2.1rem, 5vw, 3.6rem); font-weight: 800; }
h2 { font-size: clamp(1.6rem, 3.4vw, 2.5rem); font-weight: 800; }
h3 { font-size: clamp(1.1rem, 1.9vw, 1.45rem); line-height: 1.2; letter-spacing: -0.015em; }
h4 { font-size: 1.05rem; line-height: 1.3; letter-spacing: -0.01em; }
h5 { font-size: 0.95rem; font-family: var(--palo); font-weight: 700; letter-spacing: -0.005em; }

p { max-width: 68ch; }

a { color: inherit; text-decoration-color: var(--linea-firme); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--rojo); }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }

code, kbd, samp, .mono {
  font-family: var(--mono);
  font-size: 0.86em;
  letter-spacing: -0.01em;
}

::selection { background: var(--rojo); color: #fff; }

:focus-visible {
  outline: 2px solid var(--rojo);
  outline-offset: 2px;
  border-radius: 2px;
}

hr, .regla {
  border: none;
  border-top: var(--capilar) solid var(--linea);
  margin: var(--e5) 0;
}

/* Saltar al contenido: lo primero que encuentra el teclado. */
.salto {
  position: absolute; left: var(--e4); top: -60px; z-index: 3000;
  background: var(--tinta); color: #fff; padding: 10px 18px;
  border-radius: var(--r-boton); font-size: 0.9rem; font-weight: 600;
  transition: top var(--transicion);
}
.salto:focus { top: var(--e3); }

.sr-solo {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* -------------------------------------------------------------------------
   3. Rejilla y secciones
   ------------------------------------------------------------------------- */
.contenedor { width: min(100% - 32px, 1200px); margin-inline: auto; }
.contenedor-angosto { width: min(100% - 32px, 760px); margin-inline: auto; }

.seccion { padding-block: clamp(var(--e6), 6vw, var(--e8)); }
.seccion-chica { padding-block: var(--e6); }

.banda-hueso { background: var(--papel-3); }
.banda-gris { background: var(--papel-2); }
.banda-tinta { background: var(--tinta); color: #cfcfcf; }
.banda-tinta h1, .banda-tinta h2, .banda-tinta h3, .banda-tinta h4 { color: #fff; }
.banda-tinta a { color: #fff; }

.rejilla { display: grid; gap: var(--e4); }
.rejilla-auto { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.rejilla-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.rejilla-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.rejilla-4 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.rejilla-lateral { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 980px) {
  .rejilla-lateral { grid-template-columns: minmax(0, 1fr) 340px; gap: var(--e5); }
  .rejilla-lateral-izq { grid-template-columns: 300px minmax(0, 1fr); gap: var(--e5); }
}

.fila { display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap; }
.fila-apretada { display: flex; align-items: center; gap: var(--e2); flex-wrap: wrap; }
.entre { display: flex; align-items: center; justify-content: space-between; gap: var(--e3); flex-wrap: wrap; }
.pila { display: flex; flex-direction: column; gap: var(--e3); }
.crece { flex: 1 1 auto; min-width: 0; }

/* -------------------------------------------------------------------------
   4. Tipografía de interfaz
   ------------------------------------------------------------------------- */

/* Antetítulo: versalitas rojas con una rayita delante. Es la firma
   tipográfica del sistema; aparece arriba de casi toda sección. */
.antetitulo {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--palo); font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--rojo);
}
.antetitulo::before {
  content: ""; width: 26px; height: 2px; background: var(--rojo); flex: none;
}
.banda-tinta .antetitulo { color: #ff7a93; }
.banda-tinta .antetitulo::before { background: #ff7a93; }

/* El marcador del titular: bloque rojo detrás de las palabras que importan. */
.marca {
  background: var(--rojo); color: #fff;
  padding: 0.04em 0.16em 0.1em;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
.marca-tinta { background: var(--tinta); color: #fff; padding: 0.04em 0.16em 0.1em; }

.bajada {
  font-size: clamp(1rem, 1.6vw, 1.22rem);
  line-height: 1.5; color: var(--gris-texto); max-width: 62ch;
}
.sutil { font-size: 0.85rem; color: var(--gris-medio); }
.mini { font-size: 0.78rem; color: var(--gris-suave); }
.fuerte { font-weight: 700; color: var(--tinta); }
.rojo { color: var(--rojo); }
.centrado { text-align: center; }
.derecha { text-align: right; }
.nowrap { white-space: nowrap; }

/* Cifra grande en serif: métricas del tablero, contadores, montos. */
.cifra {
  font-family: var(--titular); font-weight: 700; color: var(--tinta);
  font-size: clamp(1.9rem, 3.4vw, 2.6rem); line-height: 1; letter-spacing: -0.02em;
}
.cifra-chica { font-family: var(--titular); font-weight: 700; font-size: 1.5rem; color: var(--tinta); line-height: 1; }

/* Código de reserva, de aula, de material, de error. */
.codigo {
  font-family: var(--mono); font-size: 0.82rem; font-weight: 500;
  background: var(--papel-2); border: var(--capilar) solid var(--linea);
  border-radius: 4px; padding: 2px 6px; color: var(--tinta-3);
  white-space: nowrap;
}

.lista-marcada { list-style: none; display: grid; gap: var(--e2); }
.lista-marcada li { position: relative; padding-left: 22px; }
.lista-marcada li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 8px; height: 2px; background: var(--rojo);
}

/* -------------------------------------------------------------------------
   5. Barra negra + cabecera pública
   ------------------------------------------------------------------------- */
.barra-tope {
  background: var(--tinta); color: #b9b9b9;
  font-size: 0.78rem; letter-spacing: 0.01em;
}
.barra-tope .contenedor {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3); min-height: 38px; flex-wrap: wrap;
}
.barra-tope a { color: #e8e8e8; text-decoration: none; }
.barra-tope a:hover { color: #fff; text-decoration: underline; text-decoration-color: var(--rojo); }
.barra-tope-enlaces { display: flex; gap: var(--e4); flex-wrap: wrap; }

.cabecera {
  position: sticky; top: 0; z-index: 900;
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: saturate(140%) blur(8px);
  border-bottom: var(--capilar) solid var(--linea);
}
.cabecera .contenedor {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e4); min-height: 68px;
}

/* -------------------------------------------------------------------------
   El logotipo: UTP+Labs
   -------------------------------------------------------------------------
   Es el archivo oficial de la marca: las tres letras en sus cajas, el signo
   en rosa UTP y «Labs» al lado. Antes se dibujaba con nodos y CSS; ahora son
   dos PNG, y por eso hay dos y no uno:

     utp-labs.png           cajas negras, letras blancas, «Labs» negro
     utp-labs-negativo.png  cajas blancas, letras negras, «Labs» blanco

   Van como imagen de fondo y no como `<img>` porque así la ruta la resuelve
   esta hoja —vale igual desde `/index.html` y desde `/alumno/index.html`— y
   porque el negativo entra con un selector, sin tocar el HTML. `aspect-ratio`
   saca el ancho de la altura, que es lo único que se fija.

   La altura sale del contexto: 22px en la barra lateral y en la portada, más
   grande en el acceso, donde el logo es la cabecera del formulario.
   ------------------------------------------------------------------------- */
.logo { display: inline-flex; align-items: center; text-decoration: none; line-height: 1; }
.logo-img {
  display: block; height: 22px; aspect-ratio: 955 / 159;
  background: url("img/utp-labs.png") left center / contain no-repeat;
}

/* Sobre fondo oscuro entra el negativo. */
.barra-tope .logo-img, .banda-tinta .logo-img, .pie .logo-img,
.acceso-relato .logo-img, .lateral .logo-img {
  background-image: url("img/utp-labs-negativo.png");
}

/* En el acceso el logotipo ocupa el lugar del titular que había antes, así
   que pesa como un titular. */
.acceso-forma .logo-img { height: 34px; }
@media (max-width: 480px) { .acceso-forma .logo-img { height: 28px; } }

.nav { display: flex; align-items: center; gap: var(--e5); }
.nav a {
  position: relative; text-decoration: none; font-size: 0.93rem;
  font-weight: 500; color: var(--tinta-3); padding-block: 6px;
}
.nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--rojo); transform: scaleX(0); transform-origin: left;
  transition: transform var(--transicion);
}
.nav a:hover::after, .nav a[aria-current="page"]::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: var(--tinta); font-weight: 600; }

.nav-movil { display: none; }
@media (max-width: 900px) {
  .nav { display: none; }
  .nav.abierta {
    display: flex; position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--papel); border-bottom: var(--capilar) solid var(--linea);
    padding: var(--e3) 16px var(--e4); box-shadow: var(--sombra-1);
  }
  .nav.abierta a { padding: 12px 0; border-bottom: var(--capilar) solid var(--linea); }
  .nav-movil {
    display: inline-grid; place-items: center; width: 40px; height: 40px;
    border: var(--capilar) solid var(--linea-firme); border-radius: var(--r-boton);
  }
}

/* -------------------------------------------------------------------------
   6. Botones
   ------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 20px; border-radius: var(--r-boton);
  border: var(--capilar) solid transparent;
  font-size: 0.93rem; font-weight: 600; line-height: 1.2;
  text-decoration: none; white-space: nowrap;
  transition: background var(--transicion), color var(--transicion),
              border-color var(--transicion), transform var(--transicion),
              box-shadow var(--transicion);
}
.btn:active { transform: translateY(1px); }

.btn-primario { background: var(--rojo); border-color: var(--rojo); color: #fff; }
.btn-primario:hover { background: var(--rojo-vivo); border-color: var(--rojo-vivo); }

.btn-tinta { background: var(--tinta); border-color: var(--tinta); color: #fff; }
.btn-tinta:hover { background: var(--tinta-3); border-color: var(--tinta-3); }

.btn-contorno { background: var(--papel); border-color: var(--tinta); color: var(--tinta); }
.btn-contorno:hover { background: var(--tinta); color: #fff; }

.btn-linea { background: var(--papel); border-color: var(--linea-firme); color: var(--tinta-3); }
.btn-linea:hover { border-color: var(--tinta); color: var(--tinta); }

.btn-fantasma { background: transparent; color: var(--tinta-3); padding-inline: 10px; }
.btn-fantasma:hover { background: var(--papel-2); color: var(--tinta); }

.btn-peligro { background: var(--papel); border-color: var(--rojo); color: var(--rojo-hondo); }
.btn-peligro:hover { background: var(--rojo); color: #fff; }

/* Píldora con contorno: la de "Iniciar sesión", tal cual prensalink. */
.btn-pildora { border-radius: var(--r-pildora); padding-inline: 22px; }

.btn-chico { padding: 7px 13px; font-size: 0.83rem; }
.btn-grande { padding: 14px 26px; font-size: 1rem; }
.btn-bloque { width: 100%; }

.btn[disabled], .btn[aria-disabled="true"] {
  opacity: 0.45; cursor: not-allowed; transform: none; pointer-events: none;
}

.btn-icono {
  display: inline-grid; place-items: center; width: 38px; height: 38px;
  border-radius: var(--r-boton); border: var(--capilar) solid var(--linea);
  background: var(--papel); color: var(--tinta-3);
}
.btn-icono:hover { border-color: var(--tinta); color: var(--tinta); }

/* -------------------------------------------------------------------------
   7. Formularios
   ------------------------------------------------------------------------- */
.campo { display: grid; gap: 6px; margin-bottom: var(--e4); }
.campo > label, .etiqueta-campo {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--tinta-3);
}

input[type="text"], input[type="password"], input[type="email"], input[type="number"],
input[type="search"], input[type="date"], input[type="time"], input[type="tel"],
select, textarea {
  width: 100%; padding: 11px 13px;
  background: var(--papel);
  border: var(--capilar) solid var(--linea-firme);
  border-radius: var(--r-boton);
  font-size: 0.95rem; color: var(--tinta);
  transition: border-color var(--transicion), box-shadow var(--transicion);
}
input:hover, select:hover, textarea:hover { border-color: var(--gris-suave); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--tinta);
  box-shadow: 0 0 0 3px var(--rojo-velo);
}
/* Con el teclado, el velo del 8 % no alcanza: quien llega tabulando necesita
   ver dónde está parado sin tener que buscarlo. Se le devuelve el mismo
   contorno que a todo lo demás. Al hacer clic con el ratón se queda el
   tratamiento suave de arriba, que es el que no molesta al escribir. */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--rojo); outline-offset: 2px;
}
input[disabled], select[disabled], textarea[disabled] {
  background: var(--papel-2); color: var(--gris-medio); cursor: not-allowed;
}
input::placeholder, textarea::placeholder { color: var(--gris-suave); }
textarea { min-height: 96px; resize: vertical; line-height: 1.5; }
select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--tinta-3) 50%),
                    linear-gradient(135deg, var(--tinta-3) 50%, transparent 50%);
  background-position: calc(100% - 18px) 52%, calc(100% - 13px) 52%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
  padding-right: 34px;
}

.campo-ayuda { font-size: 0.8rem; color: var(--gris-medio); }
/* Un radio o una casilla dentro de un grupo de campo no es una etiqueta de
   campo: va en texto normal, no en versalitas. */
.campo > label.radio, .campo > label.check {
  font-size: 0.93rem; font-weight: 400; letter-spacing: normal; text-transform: none; color: var(--tinta-3);
}

/* Enlace de texto dentro de un formulario: el "Restablecer contraseña" del
   login de la UTP. Va como <button> cuando no navega a ninguna parte, para
   que el teclado y el lector de pantalla sepan que es una acción. */
.enlace {
  background: none; border: 0; padding: 0; font: inherit;
  font-size: 0.85rem; font-weight: 600; color: var(--rojo-hondo);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.enlace:hover { color: var(--rojo); }
.enlace:focus-visible { outline: 2px solid var(--rojo); outline-offset: 3px; border-radius: 3px; }
.acceso-enlace { margin: -8px 0 var(--e4); text-align: right; }
/* Sobre fondo negro el rojo hondo no contrasta: en el pie va en gris claro. */
.pie .enlace, .banda-tinta .enlace { color: #d4d4d4; font-weight: 500; }
.pie .enlace:hover, .banda-tinta .enlace:hover { color: #fff; }
.campo-error { font-size: 0.82rem; color: var(--rojo-hondo); font-weight: 600; }
.campo.con-error input, .campo.con-error select, .campo.con-error textarea {
  border-color: var(--rojo);
  box-shadow: 0 0 0 3px var(--rojo-velo);
}

/* Casilla y radio propios: el check en rojo UTP. */
.check, .radio {
  display: inline-flex; align-items: flex-start; gap: 10px;
  cursor: pointer; font-size: 0.93rem; color: var(--tinta-3);
}
.check input[type="checkbox"], .radio input[type="radio"] {
  appearance: none; width: 19px; height: 19px; flex: none; margin-top: 2px;
  border: var(--capilar) solid var(--linea-firme); background: var(--papel);
  border-radius: 4px; display: grid; place-items: center;
  transition: var(--transicion);
}
.radio input[type="radio"] { border-radius: 50%; }
.check input[type="checkbox"]:checked, .radio input[type="radio"]:checked {
  background: var(--rojo); border-color: var(--rojo);
}
.check input[type="checkbox"]:checked::after {
  content: ""; width: 5px; height: 9px; margin-top: -2px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(42deg);
}
.radio input[type="radio"]:checked::after {
  content: ""; width: 7px; height: 7px; border-radius: 50%; background: #fff;
}
.check input:disabled, .radio input:disabled { opacity: 0.45; cursor: not-allowed; }
/* Con appearance: none el navegador no dibuja el foco: se dibuja acá, porque
   la lista de asistencia se tiene que poder pasar solo con el teclado. */
.check input:focus-visible, .radio input:focus-visible { outline: 2px solid var(--rojo); outline-offset: 2px; }

.buscador { position: relative; }
.buscador input { padding-left: 38px; }
.buscador i, .buscador svg {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  color: var(--gris-suave); pointer-events: none;
}

.campos-2 { display: grid; gap: 0 var(--e4); grid-template-columns: 1fr; }
@media (min-width: 700px) { .campos-2 { grid-template-columns: 1fr 1fr; } }

/* Interruptor (tareas del bot, reglas activas). */
.interruptor { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; }
.interruptor input { appearance: none; width: 42px; height: 24px; flex: none;
  background: var(--linea-firme); border-radius: var(--r-pildora);
  position: relative; transition: background var(--transicion); }
.interruptor input::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  background: #fff; border-radius: 50%; transition: transform var(--transicion);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
}
.interruptor input:checked { background: var(--rojo); }
.interruptor input:checked::after { transform: translateX(18px); }
.interruptor input:disabled { opacity: 0.5; cursor: not-allowed; }

/* -------------------------------------------------------------------------
   8. Tarjetas y paneles
   ------------------------------------------------------------------------- */
.tarjeta {
  background: var(--papel);
  border: var(--capilar) solid var(--linea);
  border-radius: var(--r-tarjeta);
  padding: var(--e4);
  transition: border-color var(--transicion), box-shadow var(--transicion),
              transform var(--transicion);
}
.tarjeta-enlace { text-decoration: none; display: block; color: inherit; }
.tarjeta-enlace:hover, .tarjeta-viva:hover {
  border-color: var(--linea-firme);
  box-shadow: var(--sombra-1);
  transform: translateY(-2px);
}
/* La cabecera de una tarjeta lleva el título a la izquierda y el estado a la
   derecha. El estado se centra en el eje Y: pegado arriba —como estaba— se
   veía levantado y suelto frente a un título de dos líneas, que es el caso
   normal (el código encima y el aula debajo). */
.tarjeta-cabeza {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3); margin-bottom: var(--e3);
}
.tarjeta-pie {
  margin-top: var(--e4); padding-top: var(--e3);
  border-top: var(--capilar) solid var(--linea);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3); flex-wrap: wrap;
}
.tarjeta-plana { box-shadow: none; }

/* Tarjeta con foto (laboratorios). La foto entra desaturada y toma color
   al pasar el cursor: el color de la página lo pone el rojo, no la foto. */
.tarjeta-foto { padding: 0; overflow: hidden; }
.tarjeta-foto img {
  width: 100%; aspect-ratio: 16 / 10; object-fit: cover;
  filter: saturate(0.55) contrast(1.05);
  transition: filter 300ms ease, transform 300ms ease;
}
.tarjeta-foto:hover img { filter: saturate(1); transform: scale(1.02); }
.tarjeta-foto-cuerpo { padding: var(--e4); }

.panel {
  background: var(--papel);
  border: var(--capilar) solid var(--linea);
  border-radius: var(--r-panel);
  box-shadow: var(--sombra-1);
  padding: var(--e5);
}
.panel-tinta {
  background: var(--tinta); color: #cfcfcf;
  border-color: var(--linea-oscura); box-shadow: none;
}
.panel-tinta h2, .panel-tinta h3, .panel-tinta h4, .panel-tinta .cifra { color: #fff; }
.panel-tinta .sutil { color: #9a9a9a; }

/* Bloque con filo rojo a la izquierda: avisos, citas, reglas del negocio. */
.filo {
  border-left: 3px solid var(--rojo);
  padding: var(--e2) 0 var(--e2) var(--e4);
  background: linear-gradient(90deg, var(--rojo-velo), transparent 60%);
}

/* Métricas del tablero. */
.metricas { display: grid; gap: 1px; background: var(--linea);
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta);
  overflow: hidden; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.metrica { background: var(--papel); padding: var(--e4) var(--e4) var(--e3); }
.metrica-pie { font-size: 0.8rem; color: var(--gris-medio); margin-top: 6px; }
.banda-tinta .metricas, .panel-tinta .metricas { background: var(--linea-oscura); border-color: var(--linea-oscura); }
.banda-tinta .metrica, .panel-tinta .metrica { background: var(--tinta); }
.banda-tinta .metrica .cifra, .panel-tinta .metrica .cifra { color: #fff; }

/* -------------------------------------------------------------------------
   9. Estados y etiquetas — nunca solo color
   ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------
   Estados: barra de color y texto
   -------------------------------------------------------------------------
   Sin píldora y sin fondo de color. Queda una barra vertical de 3 px a la
   izquierda y el texto en negrita, que es más sobrio y se lleva mejor con el
   resto —bordes capilares, tipografía editorial— que una etiqueta de color
   saturado.

   La regla 2 del sistema no cambia: el color nunca va solo. La barra es el
   acento, pero lo que dice el estado es la palabra, y por eso el texto va en
   tinta y no en el color del estado: sobre blanco, «Rechazada» en rojo claro
   no llegaba al contraste que hace falta para texto pequeño.
   ------------------------------------------------------------------------- */
.estado {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 1px 0 1px 9px; border-left: 3px solid var(--linea-firme);
  font-size: 0.8rem; font-weight: 600; letter-spacing: 0.01em;
  color: var(--tinta); white-space: nowrap;
}
.estado::before { content: none; }

.estado-ok     { border-left-color: var(--ok); }
.estado-espera { border-left-color: var(--espera); }
.estado-alto   { border-left-color: var(--rojo); }
.estado-frio   { border-left-color: var(--frio); }
.estado-neutro { border-left-color: var(--linea-firme); color: var(--gris-medio); }

/* «En curso» es el único que además late: es el que dice que algo está
   pasando ahora mismo, y a eso se le perdona el movimiento. */
.estado-curso { border-left-color: var(--tinta); }
.estado-curso::after {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--tinta); flex: none; animation: latido 1.6s ease-in-out infinite;
}

@keyframes latido { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* Sobre fondo oscuro el texto en tinta no se lee. */
.banda-tinta .estado, .panel-tinta .estado, .burbuja-caja-cabeza .estado { color: #fff; }
.banda-tinta .estado-neutro, .panel-tinta .estado-neutro { color: #c8c8c8; }
.panel-tinta .estado-curso { border-left-color: #fff; }
.panel-tinta .estado-curso::after { background: #fff; }

/* Etiqueta cuadrada: tipo de laboratorio, sede, "Comprar", "Automático". */
.etiqueta {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; border-radius: 4px;
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  background: var(--papel-2); color: var(--tinta-3);
  border: var(--capilar) solid var(--linea);
}
.etiqueta-rojo { background: var(--rojo); color: #fff; border-color: var(--rojo); }
.etiqueta-tinta { background: var(--tinta); color: #fff; border-color: var(--tinta); }
.etiqueta-contorno { background: transparent; border-color: var(--linea-firme); color: var(--gris-medio); }
/* Lo que escribió el bot se firma para que nadie crea que contestó una persona. */
.etiqueta-bot { background: var(--tinta-3); color: #fff; border-color: var(--tinta-3); }
.etiqueta-critica { background: var(--rojo-velo); color: var(--rojo-hondo); border-color: var(--rojo-velo-2); }

.punto-aviso {
  display: inline-grid; place-items: center; min-width: 19px; height: 19px;
  padding-inline: 5px; border-radius: var(--r-pildora);
  background: var(--rojo); color: #fff; font-size: 0.7rem; font-weight: 700;
}

/* -------------------------------------------------------------------------
   10. Tablas
   ------------------------------------------------------------------------- */
.tabla-caja {
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta);
  overflow: hidden; background: var(--papel);
}
.tabla-scroll { overflow-x: auto; }
table.tabla { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.tabla thead th {
  text-align: left; padding: 11px var(--e4);
  background: var(--papel-2); color: var(--tinta-3);
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  border-bottom: var(--capilar) solid var(--linea); white-space: nowrap;
}
.tabla tbody td { padding: 12px var(--e4); border-bottom: var(--capilar) solid var(--linea); vertical-align: middle; }
.tabla tbody tr:last-child td { border-bottom: none; }
.tabla tbody tr:hover { background: var(--papel-2); }
.tabla tbody tr.fila-marcada { background: var(--rojo-velo); }
.tabla td .codigo { font-size: 0.78rem; }
.tabla-compacta tbody td, .tabla-compacta thead th { padding: 8px var(--e3); }

/* En celular la tabla se apila: cada celda muestra su encabezado. */
@media (max-width: 760px) {
  .tabla-apilable thead { display: none; }
  .tabla-apilable tbody tr {
    display: block; padding: var(--e3) var(--e4);
    border-bottom: var(--capilar) solid var(--linea);
  }
  .tabla-apilable tbody td {
    display: flex; justify-content: space-between; gap: var(--e3);
    padding: 5px 0; border: none; text-align: right;
  }
  .tabla-apilable tbody td::before {
    content: attr(data-etiqueta); text-align: left; flex: none;
    font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--gris-medio);
  }
}

/* -------------------------------------------------------------------------
   11. Armazón de portal (cabecera propia + pestañas)
   ------------------------------------------------------------------------- */
.portal-tope {
  background: var(--tinta); color: #b9b9b9; font-size: 0.78rem;
}
.portal-tope .contenedor {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3); min-height: 34px; flex-wrap: wrap;
}
.portal-tope .dominio { font-family: var(--mono); color: #fff; letter-spacing: -0.01em; }
.portal-tope .dominio::before { content: "●"; color: var(--rojo); margin-right: 7px; font-size: 0.7em; vertical-align: 2px; }

.portal-cabecera {
  position: sticky; top: 0; z-index: 800;
  background: var(--papel); border-bottom: var(--capilar) solid var(--linea);
}
.portal-cabecera .contenedor {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e4); min-height: 62px;
}
.portal-nombre {
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--gris-medio); padding-left: var(--e3); margin-left: var(--e3);
  border-left: var(--capilar) solid var(--linea-firme);
}
.portal-usuario { display: flex; align-items: center; gap: var(--e3); min-width: 0; }
/* En celular la barra no da para acciones, avatar, nombre y salir: el nombre
   se va (el avatar lleva las iniciales y el nombre completo de título), el
   portal pierde su rótulo y las acciones se quedan con el ícono. */
@media (max-width: 520px) {
  .portal-cabecera .contenedor { gap: var(--e2); }
  .portal-usuario { gap: var(--e2); }
  .portal-usuario > .sutil, .portal-cabecera .portal-nombre { display: none; }
  .portal-usuario .btn-chico { padding-inline: 10px; }
  .portal-usuario .accion-texto { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
}
/* -------------------------------------------------------------------------
   10 bis. Armazón con navegación lateral
   -------------------------------------------------------------------------
   Los apartados pasaron de pestañas horizontales a una columna fija a la
   izquierda. Con ocho apartados —la consola del bot— las pestañas ya se
   deslizaban de lado y había que adivinar que existían más; en vertical
   entran todos a la vez.

   La columna va en negro, no en rojo: el rojo es el acento y marca cuál está
   abierto. En pantalla chica no hay columna que valga, así que se convierte
   en un cajón que entra desde la izquierda y oscurece el fondo.
   ------------------------------------------------------------------------- */
.armazon { display: flex; min-height: 100vh; align-items: stretch; }

.lateral {
  position: sticky; top: 0; align-self: flex-start;
  width: 236px; flex: none; height: 100vh;
  background: var(--tinta); color: #cfcfcf;
  display: flex; flex-direction: column; z-index: 900;
}
.lateral-marca {
  flex: none; padding: var(--e4) var(--e4) var(--e3);
  border-bottom: var(--capilar) solid var(--linea-oscura);
}
.lateral-nav { flex: 1; overflow-y: auto; padding: var(--e3) 0; scrollbar-width: thin; }
.lateral-item {
  position: relative; width: 100%;
  display: flex; align-items: center; gap: var(--e3);
  padding: 11px var(--e4); border: none; background: none; text-align: left;
  font: 500 0.9rem/1.3 var(--palo); color: #cfcfcf; cursor: pointer;
  transition: background var(--transicion), color var(--transicion);
}
.lateral-item i { width: 18px; text-align: center; font-size: 0.95rem; flex: none; }
.lateral-item span.crece { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.lateral-item:hover { background: rgba(255, 255, 255, 0.06); color: #fff; }
.lateral-item.activa { background: rgba(255, 255, 255, 0.09); color: #fff; font-weight: 700; }
.lateral-item.activa::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  background: var(--rojo);
}
.lateral-item .punto-aviso { margin-left: auto; }
.lateral-pie {
  flex: none; padding: var(--e3) var(--e4) var(--e4);
  border-top: var(--capilar) solid var(--linea-oscura);
  font-size: 0.7rem; color: var(--gris-suave);
}
.lateral-pie .dominio { font-family: var(--mono); color: #9a9a9a; display: block; }
.lateral-pie .dominio::before { content: "●"; color: var(--rojo); margin-right: 6px; font-size: 0.75em; vertical-align: 1px; }

/* La columna de contenido. `min-width: 0` para que una tabla ancha no
   estire el grid entero y saque scroll horizontal a la página. */
.armazon-cuerpo { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* La barra de arriba del contenido: nombre del apartado y el usuario. */
.cabecera-app {
  position: sticky; top: 0; z-index: 800;
  background: var(--papel); border-bottom: var(--capilar) solid var(--linea);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e4); padding: 0 var(--e5); min-height: 62px;
}
.cabecera-app .portal-nombre { padding-left: 0; margin-left: 0; border-left: none; }
.abrir-cajon { display: none; }

/* -------------------------------------------------------------------------
   El menú del usuario
   ------------------------------------------------------------------------- */
.usuario-caja { position: relative; }
.usuario-boton {
  display: flex; align-items: center; gap: var(--e3);
  padding: 5px 8px 5px 5px; border-radius: var(--r-pildora);
  border: var(--capilar) solid var(--linea); background: var(--papel);
  cursor: pointer; text-align: left; transition: border-color var(--transicion);
}
.usuario-boton:hover { border-color: var(--linea-firme); }
.usuario-datos { display: grid; gap: 1px; min-width: 0; }
.usuario-hola { font-size: 0.86rem; color: var(--gris-texto); line-height: 1.2; }
.usuario-hola strong { font-weight: 700; color: var(--tinta); }
.usuario-codigo { font-family: var(--mono); font-size: 0.7rem; color: var(--gris-suave); line-height: 1.2; }
.usuario-flecha { color: var(--gris-suave); font-size: 0.75rem; }

.usuario-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 1000;
  min-width: 232px; padding: 6px;
  background: var(--papel); border: var(--capilar) solid var(--linea);
  border-radius: var(--r-tarjeta); box-shadow: var(--sombra-2);
}
.usuario-menu a, .usuario-menu button {
  display: flex; align-items: center; gap: var(--e3); width: 100%;
  padding: 10px var(--e3); border: none; background: none; border-radius: var(--r-boton);
  font: 500 0.88rem/1.3 var(--palo); color: var(--gris-texto);
  text-align: left; text-decoration: none; cursor: pointer;
}
.usuario-menu a:hover, .usuario-menu button:hover { background: var(--papel-2); color: var(--tinta); }
.usuario-menu i { width: 16px; text-align: center; color: var(--gris-suave); }
.usuario-menu hr { border: none; border-top: var(--capilar) solid var(--linea); margin: 5px 4px; }
.usuario-menu .externo { margin-left: auto; font-size: 0.68rem; color: var(--gris-suave); }

/* -------------------------------------------------------------------------
   Tableta: la columna se queda en un riel de iconos con su rótulo debajo.
   ------------------------------------------------------------------------- */
@media (max-width: 1080px) and (min-width: 781px) {
  .lateral { width: 84px; }
  .lateral-marca { padding: var(--e3) var(--e2); text-align: center; }
  .lateral-marca .logo { justify-content: center; }
  .lateral-pie { display: none; }
  .lateral-item {
    flex-direction: column; gap: 5px; padding: 11px 4px;
    font-size: 0.64rem; text-align: center; line-height: 1.2;
  }
  .lateral-item i { width: auto; font-size: 1.05rem; }
  .lateral-item .punto-aviso { position: absolute; top: 6px; right: 14px; margin: 0; }
}

/* -------------------------------------------------------------------------
   Celular: cajón. Se abre con el botón de la barra y se cierra al elegir.
   ------------------------------------------------------------------------- */
@media (max-width: 780px) {
  .lateral {
    position: fixed; inset: 0 auto 0 0; height: 100%; width: 270px;
    transform: translateX(-100%); transition: transform var(--transicion);
    box-shadow: var(--sombra-3);
  }
  .lateral.abierto { transform: none; }
  .cajon-fondo {
    position: fixed; inset: 0; z-index: 890; background: rgba(5, 5, 5, 0.5);
    backdrop-filter: blur(2px);
  }
  .abrir-cajon { display: inline-flex; }
  .cabecera-app { padding: 0 var(--e4); gap: var(--e2); }
  .cabecera-app .portal-nombre { display: none; }
  .usuario-datos { display: none; }
  .usuario-boton { border-color: transparent; padding: 3px; }
  .usuario-menu { min-width: 216px; }
}

/* El contenido ya no necesita el contenedor centrado de la portada: dentro
   del armazón manda el ancho de la columna. */
.armazon-cuerpo .vista > .contenedor { max-width: 1180px; }

.avatar {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: grid; place-items: center; background: var(--tinta); color: #fff;
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.02em;
}
.avatar-rojo { background: var(--rojo); }

/* Pestañas de apartado: subrayado rojo grueso en la activa. */
.pestanas {
  display: flex; gap: var(--e5);
  overflow-x: auto; overflow-y: hidden;      /* en celular las pestañas se deslizan */
  border-bottom: var(--capilar) solid var(--linea);
  background: var(--papel);
  scrollbar-width: none;                      /* sin barra a la vista: se arrastra */
}
.pestanas::-webkit-scrollbar { display: none; }
.pestanas.pegajosa { position: sticky; top: 62px; z-index: 700; }
.pestana {
  position: relative; padding: 14px 2px; white-space: nowrap;
  font-size: 0.9rem; font-weight: 600; color: var(--gris-medio);
  background: none; border: none; text-decoration: none;
  transition: color var(--transicion);
}
.pestana:hover { color: var(--tinta); }
.pestana[aria-selected="true"], .pestana.activa { color: var(--tinta); }
.pestana[aria-selected="true"]::after, .pestana.activa::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px;
  background: var(--rojo);
}
.pestana .punto-aviso { margin-left: 6px; }

/* Segundo nivel: píldoras (bandejas del SAE, filtros de logística). */
.sub-pestanas { display: flex; gap: var(--e2); flex-wrap: wrap; }
.sub-pestana {
  padding: 7px 14px; border-radius: var(--r-pildora);
  border: var(--capilar) solid var(--linea-firme);
  font-size: 0.85rem; font-weight: 600; color: var(--gris-medio); background: var(--papel);
}
.sub-pestana:hover { border-color: var(--tinta); color: var(--tinta); }
.sub-pestana.activa { background: var(--tinta); border-color: var(--tinta); color: #fff; }

/* -------------------------------------------------------------------------
   Barra de aulas del panel del laboratorio
   -------------------------------------------------------------------------
   El recuento y las pestañas de aula a la izquierda; el estado del aula
   elegida a la derecha y en el mismo renglón, centrado contra las pestañas,
   porque es de ellas que habla. En celular el estado pasa debajo: antes que
   apretarlo contra la última pestaña, mejor que baje.
   ------------------------------------------------------------------------- */
.aulas-barra {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3) var(--e4); flex-wrap: wrap;
  padding-bottom: var(--e3); margin-bottom: var(--e3);
  border-bottom: var(--capilar) solid var(--linea);
}
.aulas-barra-lista { display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap; }

/* -------------------------------------------------------------------------
   Desglose: una sección que se abre y se cierra
   -------------------------------------------------------------------------
   El equipamiento del aula y la lista de lo que se vende son dos listas
   largas, y ninguna es lo primero que se viene a mirar al panel de un
   laboratorio. Van dentro de un `details` cerrado, con el rótulo diciendo
   cuántos objetos hay dentro. La flecha es un ícono de verdad en el HTML y
   no un `::after` con una familia tipográfica adivinada, así que gira sin
   depender de cómo se llame la versión de Font Awesome que esté cargada.
   ------------------------------------------------------------------------- */
.desglose {
  border: var(--capilar) solid var(--linea);
  border-radius: var(--r-tarjeta);
  background: var(--papel);
}
.desglose + .desglose { margin-top: var(--e2); }
.desglose > summary {
  display: flex; align-items: center; gap: var(--e3);
  padding: var(--e3) var(--e4); cursor: pointer; list-style: none;
  font-size: 0.86rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--tinta-3);
  border-radius: var(--r-tarjeta);
}
.desglose > summary::-webkit-details-marker { display: none; }
.desglose > summary:hover { background: var(--papel-2); }
.desglose > summary .mini { text-transform: none; letter-spacing: 0; font-weight: 500; flex: none; }
.desglose-flecha {
  flex: none; font-size: 0.72rem; color: var(--gris-medio);
  transition: transform var(--transicion);
}
.desglose[open] > summary { border-bottom: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta) var(--r-tarjeta) 0 0; }
.desglose[open] .desglose-flecha { transform: rotate(180deg); }
.desglose-cuerpo { padding: var(--e3) var(--e4) var(--e4); }

.vista { padding-block: var(--e5) var(--e7); }
.vista-titulo { margin-bottom: var(--e2); }
.vista-intro { color: var(--gris-medio); max-width: 70ch; margin-bottom: var(--e5); }
.bloque { margin-bottom: var(--e6); }
.bloque > h3 { margin-bottom: var(--e3); }

/* Barra de filtros combinables. */
/* Los campos se alinean por arriba, no por abajo. Con `align-items: end` el
   que no tenía texto de ayuda quedaba empujado hacia abajo: su etiqueta y su
   control se alineaban contra la ayuda del vecino en vez de contra el control
   del vecino, y «Sección» aparecía más bajo que «Buscar». Alineando por
   arriba las etiquetas quedan a la misma altura, los controles también, y la
   ayuda cuelga debajo de quien la tenga. */
.filtros {
  display: grid; gap: var(--e3) var(--e4); align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  padding: var(--e4); background: var(--papel-2);
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta);
  margin-bottom: var(--e5);
}
.filtros .campo { margin-bottom: 0; }

/* -------------------------------------------------------------------------
   12. Minicalendario y bloques de horario
   ------------------------------------------------------------------------- */
.minicalendario { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.dia-cabeza {
  text-align: center; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--gris-medio);
  padding-bottom: 4px;
}
.dia {
  border: var(--capilar) solid var(--linea); border-radius: 8px;
  padding: 6px; min-height: 76px; background: var(--papel);
}
.dia-numero { font-family: var(--titular); font-weight: 700; font-size: 0.95rem; color: var(--tinta); }
.dia-hoy { border-color: var(--tinta); box-shadow: inset 0 0 0 1px var(--tinta); }

/* Verde, rojo y blanco del documento, pero cada uno con su símbolo:
   el color solo no basta y hay gente que no lo distingue. */
.bloque-hora {
  display: flex; align-items: center; gap: 5px; width: 100%;
  margin-top: 4px; padding: 5px 7px; border-radius: 5px;
  font-size: 0.76rem; font-weight: 600; text-align: left;
  border: var(--capilar) solid transparent;
}
.bloque-hora::before { font-size: 0.85em; font-weight: 700; }
.bloque-libre { background: var(--ok-velo); color: var(--ok); border-color: rgba(16, 112, 60, 0.3); }
.bloque-libre::before { content: "✓"; }
.bloque-libre:hover { background: var(--ok); color: #fff; }
.bloque-ocupado {
  color: var(--rojo-hondo); border-color: rgba(211, 5, 45, 0.3); cursor: not-allowed;
  background: repeating-linear-gradient(135deg, var(--alto-velo), var(--alto-velo) 5px,
              rgba(211, 5, 45, 0.14) 5px, rgba(211, 5, 45, 0.14) 10px);
}
.bloque-ocupado::before { content: "×"; }
.bloque-cerrado {
  background: var(--papel); color: var(--gris-suave);
  border: var(--capilar) dashed var(--linea-firme); cursor: not-allowed;
}
.bloque-cerrado::before { content: "–"; }
.bloque-elegido { background: var(--tinta); color: #fff; border-color: var(--tinta); }
.bloque-elegido::before { content: "◉"; }

/* Los bloques apagados llevan `aria-disabled` y no `disabled`, así que se
   pueden enfocar y pulsar para que digan por qué lo están. El cursor avisa
   que no se van a reservar, pero el foco tiene que verse igual: si no se ve,
   quien navega con el teclado se pierde dentro de la cuadrícula. */
.bloque-hora[aria-disabled="true"] { cursor: help; }
.bloque-hora[aria-disabled="true"]:hover { border-style: solid; border-color: var(--tinta); }

/* El motivo que explica un día entero, dentro de su propia celda. */
.dia-motivo {
  margin-top: 5px; font-size: 0.68rem; line-height: 1.25;
  color: var(--gris-medio);
  border-top: var(--capilar) solid var(--linea); padding-top: 4px;
}

/* La línea que aparece al pulsar un bloque apagado. Vacía no ocupa lugar. */
.calendario-aclaracion {
  display: none; align-items: flex-start; gap: 9px;
  border-left: 3px solid var(--tinta); padding: var(--e2) var(--e3);
  background: var(--papel-2); border-radius: var(--r-boton);
  font-size: 0.86rem; color: var(--tinta-3); max-width: none;
}
.calendario-aclaracion.visible { display: flex; }
.calendario-aclaracion i { margin-top: 3px; color: var(--rojo); flex: none; }

/* Ayuda a pedido: un ícono de información con una línea que dice qué hay
   detrás. Para lo que conviene saber pero no hace falta leer siempre, como
   los motivos de los bloques apagados del calendario. Toda la fila es el
   botón, así que tocar el texto también lo abre. */
.ayuda-info {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 0; border: 0; background: none; text-align: left; cursor: pointer;
  font-size: 0.86rem; color: var(--gris-texto);
}
.ayuda-info-icono {
  display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: var(--r-pildora);
  border: var(--capilar) solid var(--linea-firme); background: var(--papel);
  color: var(--tinta); font-size: 0.95rem;
  transition: background var(--transicion), color var(--transicion), border-color var(--transicion);
}
.ayuda-info:hover .ayuda-info-icono { background: var(--tinta); border-color: var(--tinta); color: #fff; }
.ayuda-info:hover .ayuda-info-texto { color: var(--tinta); }
.ayuda-info:focus-visible { outline: 2px solid var(--rojo); outline-offset: 3px; border-radius: var(--r-boton); }

/* La lista de motivos: el motivo y los días que toca. Va dentro del modal
   que abre `.ayuda-info`, no suelta debajo del calendario. */
.lista-motivos { list-style: none; display: grid; gap: 1px; background: var(--linea);
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta); overflow: hidden; }
.lista-motivos li {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--e4);
  background: var(--papel); padding: 9px var(--e3); font-size: 0.86rem;
}
.lista-motivos .mini { flex: none; color: var(--gris-medio); }

/* Catorce días por siete columnas no entran en un teléfono sin quedar
   ilegibles. El calendario se desliza dentro de su caja, como una tabla:
   es la única excepción al "nada se desborda" y es a propósito. */
.minicalendario-caja { overflow-x: auto; padding-bottom: var(--e2); }
@media (max-width: 820px) { .minicalendario { min-width: 700px; } }

.leyenda { display: flex; gap: var(--e4); flex-wrap: wrap; font-size: 0.82rem; color: var(--gris-medio); }

/* -------------------------------------------------------------------------
   12 bis-a. Horario del aula en etiquetas (portal del alumno)
   -------------------------------------------------------------------------
   La cuadrícula de `.horario` son seis columnas por catorce filas y se
   desborda en un teléfono. Para el alumno, que solo quiere saber qué horas
   están tomadas, va un renglón por día con una etiqueta por tramo ocupado:
   las etiquetas envuelven solas y no hay nada que deslizar. En pantalla
   angosta el nombre del día pasa a su propia línea.
   ------------------------------------------------------------------------- */
.horario-simple {
  list-style: none; display: grid; gap: 1px; background: var(--linea);
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta); overflow: hidden;
}
.horario-simple > li {
  display: flex; gap: var(--e2) var(--e4); flex-wrap: wrap; align-items: baseline;
  background: var(--papel); padding: 10px var(--e3);
}
.horario-simple-dia { flex: 0 0 8rem; display: flex; align-items: baseline; gap: 8px; }
.horario-simple-dia strong { font-size: 0.88rem; color: var(--tinta); text-transform: capitalize; }
.horario-simple-tramos { flex: 1 1 11rem; display: flex; gap: 6px; flex-wrap: wrap; }

/* La etiqueta de un tramo lleva una hora y un nombre propio, así que no va
   en versalitas: «07:00–09:00 · QUÍMICA GENERAL» se lee peor que en caja
   baja, y el espaciado de letra le rompe los dos puntos de la hora. */
.etiqueta-tramo {
  text-transform: none; letter-spacing: 0; font-weight: 500;
  font-size: 0.76rem; white-space: nowrap;
}

@media (max-width: 560px) {
  .horario-simple-dia { flex-basis: 100%; }
}

/* -------------------------------------------------------------------------
   12 bis. Horario semanal del aula (coordinación)
   -------------------------------------------------------------------------
   Qué horas ya están tomadas: las clases fijas del ciclo y las reservas
   aprobadas de otros grupos. Lunes a sábado en columnas y las horas de
   atención del aula en filas. Cada celda ocupada lleva texto, no solo color.
   ------------------------------------------------------------------------- */
.horario-caja { overflow-x: auto; padding-bottom: var(--e2); }
.horario {
  display: grid; grid-template-columns: 54px repeat(6, minmax(86px, 1fr));
  gap: 3px; min-width: 580px; font-size: 0.72rem;
}
.horario-cabeza {
  text-align: center; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--gris-medio); padding-bottom: 5px;
}
.horario-hora {
  font-family: var(--mono); color: var(--gris-suave);
  text-align: right; padding: 7px 6px 0 0; white-space: nowrap;
}
.horario-celda {
  border: var(--capilar) solid var(--linea); border-radius: 4px;
  min-height: 36px; padding: 4px 6px; display: grid; align-content: center; gap: 1px;
  overflow: hidden;
}
.horario-celda strong { font-weight: 700; line-height: 1.25; }
.horario-celda span { font-weight: 400; opacity: 0.85; line-height: 1.25; }
.horario-libre { background: var(--papel); color: var(--gris-suave); }
.horario-clase {
  color: var(--rojo-hondo); border-color: rgba(211, 5, 45, 0.3);
  background: repeating-linear-gradient(135deg, var(--alto-velo), var(--alto-velo) 5px,
              rgba(211, 5, 45, 0.14) 5px, rgba(211, 5, 45, 0.14) 10px);
}
.horario-reserva { background: var(--frio-velo); border-color: rgba(31, 79, 115, 0.22); color: var(--frio); }
.horario-espera { background: var(--espera-velo); border-color: rgba(138, 90, 0, 0.3); color: var(--espera); border-style: dashed; }
.horario-cerrado { background: var(--papel-2); border: var(--capilar) dashed var(--linea-firme); color: var(--gris-medio); }
/* El mantenimiento diario: gris rayado, para no confundirlo con una clase
   (rojo rayado) ni con un cierre del laboratorio (gris punteado). */
.horario-mantenimiento {
  color: var(--tinta-3); border-color: var(--linea-firme);
  background: repeating-linear-gradient(135deg, var(--papel-2), var(--papel-2) 5px,
              var(--linea) 5px, var(--linea) 10px);
}

/* -------------------------------------------------------------------------
   12 ter. Barra de avance
   -------------------------------------------------------------------------
   El cierre de ciclo no se deja completar hasta el 100 %: la barra dice
   cuánto falta con número, no solo con largo. */
.avance { display: grid; gap: 6px; }
.avance-cabeza { display: flex; justify-content: space-between; gap: var(--e3); font-size: 0.85rem; }
.avance-barra {
  height: 10px; border-radius: var(--r-pildora); overflow: hidden;
  background: var(--papel-2); border: var(--capilar) solid var(--linea);
}
.avance-relleno { height: 100%; background: var(--rojo); transition: width 240ms ease; }
.avance-completo .avance-relleno { background: var(--ok); }
.leyenda span { display: inline-flex; align-items: center; gap: 6px; }
.leyenda i { width: 14px; height: 14px; border-radius: 4px; border: var(--capilar) solid var(--linea-firme); }

/* Contador de la retención: mono, grande, y se pone rojo al final. */
.contador {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 1.1rem; font-weight: 600;
  padding: 7px 13px; border-radius: var(--r-boton);
  background: var(--papel-2); border: var(--capilar) solid var(--linea-firme);
  color: var(--tinta); font-variant-numeric: tabular-nums;
}
.contador-urgente { background: var(--alto-velo); border-color: var(--rojo); color: var(--rojo-hondo); }
/* La tolerancia de asistencia: el mismo contador, en grande, porque se mira
   desde lejos mientras el grupo entra al aula. */
.contador-grande { font-size: clamp(1.8rem, 5vw, 2.6rem); padding: 10px 18px; gap: 12px; }

/* Tramos de la reserva: apertura · uso · supervisión final. */
.tramos { display: flex; gap: 2px; border-radius: var(--r-boton); overflow: hidden; }
.tramo {
  flex: 1; padding: 7px 9px; font-size: 0.75rem; font-weight: 600; text-align: center;
  background: var(--papel-2); color: var(--tinta-3); border: var(--capilar) solid var(--linea);
}
.tramo-uso { background: var(--tinta); color: #fff; border-color: var(--tinta); flex: 2.4; }
.tramo span { display: block; font-weight: 400; color: inherit; opacity: 0.75; font-size: 0.7rem; }

/* El tramo en el que está el bloque ahora, calculado contra la hora real.
   Lleva filo rojo y la palabra "Ahora": el color solo no alcanza. */
.tramo-actual { box-shadow: inset 0 0 0 2px var(--rojo); }
.tramo-ahora {
  display: block; margin-bottom: 2px; font-style: normal; font-size: 0.6rem;
  font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--rojo-hondo);
}
.tramo-uso .tramo-ahora { color: #ff7a93; }

/* Línea de tiempo del día del encargado. */
.linea-tiempo { position: relative; padding-left: var(--e5); }
.linea-tiempo::before {
  content: ""; position: absolute; left: 7px; top: 6px; bottom: 6px;
  width: var(--capilar); background: var(--linea-firme);
}
.hito { position: relative; padding-bottom: var(--e4); }
.hito::before {
  content: ""; position: absolute; left: calc(-1 * var(--e5) + 3px); top: 5px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--papel); border: 2px solid var(--linea-firme);
}
.hito-activo::before { background: var(--rojo); border-color: var(--rojo); }
.hito-hecho::before { background: var(--tinta); border-color: var(--tinta); }
/* La marca de "ahora" en la línea de tiempo: hueca, con halo rojo. */
.hito-ahora {
  padding-bottom: var(--e3); font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--rojo-hondo);
}
.hito-ahora::before { background: var(--papel); border-color: var(--rojo); box-shadow: 0 0 0 4px var(--rojo-velo); }

/* Tarjeta gris que se despliega: las reservas de las próximas horas del
   encargado. Es un <details>, así que abre con teclado sin JavaScript. */
.desplegable { background: var(--papel-2); padding: 0; overflow: hidden; }
.desplegable + .desplegable { margin-top: var(--e3); }
.desplegable > summary {
  list-style: none; cursor: pointer; padding: var(--e3) var(--e4);
  display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap;
}
.desplegable > summary::-webkit-details-marker { display: none; }
.desplegable > summary::after {
  content: ""; width: 8px; height: 8px; margin-left: auto; flex: none;
  border-right: 2px solid var(--tinta-3); border-bottom: 2px solid var(--tinta-3);
  transform: rotate(45deg); transition: transform var(--transicion);
}
.desplegable[open] > summary::after { transform: rotate(-135deg); }
.desplegable > summary:focus-visible { outline: 2px solid var(--rojo); outline-offset: -2px; }
.desplegable-cuerpo { padding: var(--e4); background: var(--papel); border-top: var(--capilar) solid var(--linea); }

/* -------------------------------------------------------------------------
   13. Mensajería y chat
   ------------------------------------------------------------------------- */
.mensajeria { display: grid; gap: 0; grid-template-columns: 1fr;
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta); overflow: hidden; }
@media (min-width: 900px) { .mensajeria { grid-template-columns: 320px minmax(0, 1fr); } }
.mensajeria-lista { border-right: var(--capilar) solid var(--linea); background: var(--papel-2); max-height: 560px; overflow-y: auto; }
.hilo {
  width: 100%; text-align: left; padding: var(--e3) var(--e4);
  border-bottom: var(--capilar) solid var(--linea); background: none;
  display: grid; gap: 3px;
}
.hilo:hover { background: var(--papel); }
.hilo.activo { background: var(--papel); box-shadow: inset 3px 0 0 var(--rojo); }
.hilo-titulo { font-weight: 600; color: var(--tinta); font-size: 0.92rem; }
.hilo-resumen {
  font-size: 0.82rem; color: var(--gris-medio);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hilo-cerrado .hilo-titulo { color: var(--gris-medio); }

.conversacion { display: flex; flex-direction: column; min-height: 420px; }
.conversacion-cabeza { padding: var(--e3) var(--e4); border-bottom: var(--capilar) solid var(--linea); }
.conversacion-cuerpo { flex: 1; overflow-y: auto; padding: var(--e4); display: grid; gap: var(--e3); align-content: start; background: var(--papel-2); }
.conversacion-pie { padding: var(--e3) var(--e4); border-top: var(--capilar) solid var(--linea); display: flex; gap: var(--e2); align-items: flex-end; }

.mensaje { max-width: 78%; padding: 10px 13px; border-radius: 12px; background: var(--papel);
  border: var(--capilar) solid var(--linea); font-size: 0.92rem; color: var(--tinta-3); }
.mensaje-mio { margin-left: auto; background: var(--tinta); border-color: var(--tinta); color: #fff; }
.mensaje-sistema {
  margin-inline: auto; max-width: 92%; background: var(--papel);
  border-left: 3px solid var(--rojo); border-radius: 8px; font-size: 0.86rem;
}
.mensaje-firma { font-size: 0.72rem; color: var(--gris-suave); margin-top: 5px; }
.mensaje-mio .mensaje-firma { color: rgba(255, 255, 255, 0.6); }

/* ---- Mensajería: lo que se agregó en el bloque 4 ---- */

/* El texto del mensaje respeta los saltos de línea y no desborda con un
   código largo pegado sin espacios. */
.mensaje-texto { white-space: pre-wrap; overflow-wrap: anywhere; }
.mensaje-cabeza { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 5px; }

/* La lista de hilos, partida en grupos: cobros, abiertos y cerrados. */
.hilo-grupo {
  padding: 10px var(--e4) 6px; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--gris-medio);
  border-bottom: var(--capilar) solid var(--linea); background: var(--papel-3);
}
.hilo-linea { display: flex; align-items: center; justify-content: space-between; gap: var(--e2); }
.hilo .mini { color: var(--gris-medio); }
.mensajeria .conversacion-cuerpo { max-height: 460px; }
.mensajeria .conversacion { min-width: 0; }

/* En celular la lista y el hilo no entran lado a lado: se ve uno a la vez
   y el hilo trae su botón de volver. */
@media (max-width: 899px) {
  .mensajeria-lista { border-right: none; max-height: none; }
  .mensajeria.viendo-hilo > .mensajeria-lista { display: none; }
  .mensajeria:not(.viendo-hilo) > .conversacion,
  .mensajeria:not(.viendo-hilo) > .vacio { display: none; }
}
@media (min-width: 900px) { .solo-movil { display: none !important; } }

/* Mensajería del personal: cada fila es una persona, con su avatar, su rol
   y el último mensaje. El panel de la derecha envuelve la conversación. */
.hilo-persona { display: flex; align-items: flex-start; gap: var(--e3); }
.hilo-texto { display: grid; gap: 3px; min-width: 0; flex: 1; }
.mensajeria-panel { min-width: 0; display: flex; flex-direction: column; }
.mensajeria-panel > .conversacion { flex: 1; }
.mensajeria-panel > .vacio { margin: auto; }
@media (max-width: 899px) {
  .mensajeria:not(.viendo-hilo) > .mensajeria-panel { display: none; }
  .mensajeria.viendo-hilo > .mensajeria-lista { display: none; }
}

/* Adjuntos: miniaturas en el mensaje y en el formulario antes de enviar. */
.mensaje-adjuntos, .adjuntos-previa { display: flex; flex-wrap: wrap; gap: 6px; }
.mensaje-adjuntos { margin-top: 8px; }
.adjunto-miniatura {
  position: relative; width: 72px; height: 72px; padding: 0; flex: none;
  border-radius: 8px; overflow: hidden; background: var(--papel-2);
  border: var(--capilar) solid var(--linea);
}
.adjunto-miniatura img { display: block; width: 100%; height: 100%; object-fit: cover; }
.adjunto-quitar {
  position: absolute; top: 3px; right: 3px; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: 0.7rem;
  background: rgba(5, 5, 5, 0.75); color: #fff;
}
/* El input de archivo va oculto y lo representa su etiqueta con forma de
   botón; el foco del teclado se dibuja en la etiqueta. */
.adjuntar-entrada:focus-visible + .btn { outline: 2px solid var(--rojo); outline-offset: 2px; }

fieldset.campo { border: 0; padding: 0; min-width: 0; }
fieldset.campo legend { margin-bottom: 6px; }

/* Burbuja flotante: encargado, coordinación, SAE y administración. */
.burbuja { position: fixed; right: 20px; bottom: 20px; z-index: 950; display: grid; justify-items: end; gap: var(--e3); }
.burbuja-boton {
  width: 56px; height: 56px; border-radius: 50%; background: var(--rojo); color: #fff;
  display: grid; place-items: center; font-size: 1.25rem;
  box-shadow: var(--sombra-3); position: relative;
}
.burbuja-boton:hover { background: var(--rojo-vivo); }
.burbuja-boton .punto-aviso {
  position: absolute; top: -3px; right: -3px; border: 2px solid var(--papel);
}
.burbuja-caja {
  width: min(360px, calc(100vw - 40px)); max-height: min(560px, calc(100vh - 140px));
  background: var(--papel); border: var(--capilar) solid var(--linea);
  border-radius: var(--r-panel); box-shadow: var(--sombra-2); overflow: hidden;
  display: flex; flex-direction: column;
}
.burbuja-caja-cabeza {
  padding: var(--e3) var(--e4); background: var(--tinta); color: #fff;
  display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
}

/* El chat del personal dentro de la burbuja: alto fijo, pestañas chicas y la
   conversación ocupando lo que queda, con los mensajes deslizándose adentro. */
.burbuja-chat { height: min(580px, calc(100vh - 110px)); width: min(380px, calc(100vw - 40px)); }
.burbuja-pestanas {
  display: flex; gap: 4px; padding: var(--e2) var(--e3); overflow-x: auto; flex: none;
  background: var(--papel-2); border-bottom: var(--capilar) solid var(--linea);
}
.burbuja-pestana {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 6px 11px; border-radius: var(--r-pildora); font-size: 0.8rem; font-weight: 600; color: var(--tinta-3);
}
.burbuja-pestana:hover { background: var(--papel); }
.burbuja-pestana.activa { background: var(--tinta); color: #fff; }
.burbuja-cuerpo { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; }
.burbuja-cuerpo .mensajeria-lista { max-height: none; border-right: none; background: var(--papel); }
.burbuja-cuerpo .conversacion { flex: 1; min-height: 0; }
.burbuja-cuerpo .conversacion-cuerpo { min-height: 120px; max-height: none; }
.burbuja-cuerpo .conversacion-cabeza h3 { font-size: 1rem; }
.burbuja-cuerpo .vacio { padding: var(--e4); }
.burbuja-volver { padding: var(--e2) var(--e4) 0; text-align: left; font-size: 0.8rem; }
.burbuja-nuevo { padding: var(--e3) var(--e4) var(--e4); }
.burbuja-cuerpo textarea { min-height: 56px; }

/* Campana del alumno. */
.campana { position: relative; }
.campana .punto-aviso { position: absolute; top: -4px; right: -6px; }
.campana-panel {
  position: absolute; right: 0; top: calc(100% + 10px); width: min(360px, 88vw);
  background: var(--papel); border: var(--capilar) solid var(--linea);
  border-radius: var(--r-tarjeta); box-shadow: var(--sombra-2); z-index: 950;
  max-height: 420px; overflow-y: auto;
}
.campana-item { padding: var(--e3) var(--e4); border-bottom: var(--capilar) solid var(--linea); }
.campana-item:last-child { border-bottom: none; }
.campana-item.sin-leer { background: var(--rojo-velo); }
.campana-item { display: flex; gap: var(--e3); align-items: flex-start; }
.campana-item > i { color: var(--rojo); margin-top: 3px; width: 16px; text-align: center; }
.campana-cabeza {
  position: sticky; top: 0; z-index: 1; background: var(--papel);
  padding: var(--e3) var(--e4); border-bottom: var(--capilar) solid var(--linea);
  display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
}
/* Un aviso que lleva a algún sitio es un botón, y tiene que parecerlo: se
   ilumina al pasar por encima y se puede alcanzar con Tab. */
.campana-item-enlace {
  width: 100%; text-align: left; border: none; background: none;
  cursor: pointer; font: inherit; color: inherit;
}
.campana-item-enlace:hover { background: var(--papel-2); }

.campana-nota {
  padding: var(--e2) var(--e4); font-size: 0.78rem; color: var(--gris-medio);
  background: var(--papel-2); border-bottom: var(--capilar) solid var(--linea);
}
/* En celular la campana no está en la esquina de la barra, así que el panel
   anclado a ella se saldría por la izquierda: se fija al ancho de la pantalla. */
@media (max-width: 600px) {
  .campana-panel { position: fixed; left: 16px; right: 16px; top: 72px; width: auto; }
}

/* -------------------------------------------------------------------------
   14. Modal, tostada, cinta fija
   ------------------------------------------------------------------------- */
.modal-fondo {
  position: fixed; inset: 0; z-index: 1000; background: rgba(5, 5, 5, 0.55);
  backdrop-filter: blur(3px); display: grid; place-items: center; padding: var(--e4);
  animation: aparecer 140ms ease-out;
}
.modal {
  width: min(520px, 100%); max-height: 90vh; overflow-y: auto;
  background: var(--papel); border-radius: var(--r-panel);
  box-shadow: var(--sombra-3); border-top: 4px solid var(--rojo);
  padding: var(--e5);
}
.modal-ancho { width: min(820px, 100%); }
.modal-cabeza { margin-bottom: var(--e4); }
.modal-pie { margin-top: var(--e5); display: flex; gap: var(--e2); justify-content: flex-end; flex-wrap: wrap; }

/* Panel que sube desde abajo: el reporte de daño. Oscurece el fondo igual
   que el modal, pero se pega al borde inferior. La cabecera y el pie quedan
   fijos y el formulario se desliza entre los dos. */
.hoja-fondo {
  position: fixed; inset: 0; z-index: 1000; background: rgba(5, 5, 5, 0.55);
  backdrop-filter: blur(3px); display: flex; align-items: flex-end; justify-content: center;
  padding-top: var(--e4); animation: aparecer 140ms ease-out;
}
.hoja {
  width: min(760px, 100%); max-height: min(88vh, 920px);
  background: var(--papel); border-radius: var(--r-panel) var(--r-panel) 0 0;
  box-shadow: var(--sombra-3); border-top: 4px solid var(--rojo);
  display: flex; flex-direction: column;
  animation: desde-abajo 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.hoja-cabeza { flex: none; padding: var(--e3) var(--e5) var(--e4); border-bottom: var(--capilar) solid var(--linea); }
.hoja-asa {
  display: block; width: 44px; height: 4px; margin: 0 auto var(--e3);
  border-radius: var(--r-pildora); background: var(--linea-firme);
}
.hoja-cuerpo {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--e4) var(--e5) var(--e5); display: grid; gap: var(--e5); align-content: start;
}
.hoja-pie {
  flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--e3); flex-wrap: wrap;
  padding: var(--e3) var(--e5) calc(var(--e3) + env(safe-area-inset-bottom, 0px));
  border-top: var(--capilar) solid var(--linea); background: var(--papel-2);
}
.hoja-cuerpo h4 { font-size: 1rem; }
.hoja-cabeza .entre { flex-wrap: nowrap; }
@media (max-width: 600px) {
  .hoja { max-height: 94vh; }
  .hoja-cabeza, .hoja-cuerpo, .hoja-pie { padding-left: var(--e4); padding-right: var(--e4); }
  .hoja-pie > .fila-apretada { width: 100%; }
  .hoja-pie > .fila-apretada .btn { flex: 1; justify-content: center; }
}
@keyframes desde-abajo { from { transform: translateY(100%); } to { transform: none; } }

/* Un material dentro del reporte de daño: código, tipo, monto y comentario
   en una caja numerada que se puede quitar. En escritorio van de a dos. */
.dano-item {
  display: grid; gap: var(--e3); padding: var(--e4);
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta); background: var(--papel);
}
.dano-item-cabeza { display: flex; align-items: center; justify-content: space-between; gap: var(--e3); }
.dano-item .campo { margin-bottom: 0; }
.dano-rejilla { display: grid; gap: var(--e4); grid-template-columns: minmax(0, 1fr); }
.dano-ancho { grid-column: 1 / -1; }
.dano-hueco { display: none; }
@media (min-width: 640px) {
  .dano-rejilla { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .dano-hueco { display: block; }
}
.dano-ficha {
  margin-top: var(--e2); padding: 8px 12px; border-radius: 8px;
  background: var(--papel-2); font-size: 0.84rem; color: var(--tinta-3);
}
.opciones-fila { display: flex; flex-wrap: wrap; gap: var(--e2) var(--e4); }

/* Datos de una ficha: nombre del dato a la izquierda y valor a la derecha;
   en celular, uno debajo del otro. */
.ficha-datos { display: grid; grid-template-columns: minmax(130px, max-content) minmax(0, 1fr); gap: 10px var(--e4); margin: 0; }
.ficha-datos dt {
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--gris-medio); padding-top: 3px;
}
.ficha-datos dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 520px) {
  .ficha-datos { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .ficha-datos dd { margin-bottom: var(--e2); }
}
/* El nombre que abre una ficha dentro de una tabla. */
.tabla .enlace { text-align: left; }
input[readonly] { background: var(--papel-2); color: var(--tinta-3); }

@keyframes aparecer { from { opacity: 0; } to { opacity: 1; } }
@keyframes subir { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

.tostada {
  position: fixed; right: 20px; bottom: 20px; z-index: 1100;
  background: var(--tinta); color: #fff; padding: 13px 18px;
  border-radius: var(--r-boton); box-shadow: var(--sombra-3);
  border-left: 3px solid var(--rojo); font-size: 0.9rem; max-width: 380px;
  animation: subir 200ms ease-out;
}
.tostada-ok { border-left-color: #2fbb6e; }
.tostada-mal { border-left-color: var(--rojo); }

/* Franja fija que no se cierra: el bot lleva más de una hora pausado. */
.cinta-fija {
  position: sticky; top: 0; z-index: 1200;
  background: var(--rojo); color: #fff; padding: 9px 16px;
  font-size: 0.88rem; font-weight: 600; text-align: center;
}
.cinta-fija .codigo { background: rgba(255, 255, 255, 0.16); border-color: rgba(255, 255, 255, 0.3); color: #fff; }

/* Avisos dentro de la página. */
.aviso {
  display: flex; gap: var(--e3); align-items: flex-start;
  padding: var(--e3) var(--e4); border-radius: var(--r-tarjeta);
  border: var(--capilar) solid var(--linea); background: var(--papel-2);
  font-size: 0.9rem; color: var(--tinta-3);
}
/* El ícono va arriba, con la primera línea del texto, pero centrado en
   ella: Font Awesome le pone `line-height: 1` y así quedaba cuatro píxeles
   más alto que las letras. Con la altura de línea del texto, calza. */
.aviso > i { flex: none; line-height: inherit; }
.aviso-alto { background: var(--alto-velo); border-color: rgba(211, 5, 45, 0.25); color: var(--rojo-hondo); }
.aviso-espera { background: var(--espera-velo); border-color: rgba(138, 90, 0, 0.25); color: var(--espera); }
.aviso-ok { background: var(--ok-velo); border-color: rgba(16, 112, 60, 0.25); color: var(--ok); }

/* -------------------------------------------------------------------------
   15. Carga, vacío y error — las tres pantallas que siempre se olvidan
   ------------------------------------------------------------------------- */
.esqueleto {
  background: linear-gradient(90deg, var(--papel-2) 25%, #ececec 37%, var(--papel-2) 63%);
  background-size: 400% 100%; animation: brillo 1.3s ease infinite;
  border-radius: 6px; height: 14px;
}
.esqueleto-titulo { height: 24px; width: 45%; margin-bottom: var(--e3); }
.esqueleto-linea { margin-bottom: 9px; }
.esqueleto-linea:nth-child(odd) { width: 92%; }
.esqueleto-linea:nth-child(even) { width: 76%; }
@keyframes brillo { from { background-position: 100% 50%; } to { background-position: 0 50%; } }

.vacio {
  text-align: center; padding: var(--e7) var(--e4);
  border: var(--capilar) dashed var(--linea-firme); border-radius: var(--r-tarjeta);
  color: var(--gris-medio); background: var(--papel);
}
.vacio-icono { font-size: 1.7rem; color: var(--linea-firme); margin-bottom: var(--e3); }
.vacio h4 { color: var(--tinta); margin-bottom: 6px; }
.vacio p { margin-inline: auto; }

.cargando { display: inline-flex; align-items: center; gap: 9px; color: var(--gris-medio); font-size: 0.88rem; }
.girador {
  width: 15px; height: 15px; border-radius: 50%; flex: none;
  border: 2px solid var(--linea-firme); border-top-color: var(--rojo);
  animation: girar 700ms linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }

/* -------------------------------------------------------------------------
   16. Pie de página
   ------------------------------------------------------------------------- */
.pie { background: var(--tinta); color: #9a9a9a; padding-block: var(--e7) var(--e5); margin-top: auto; }
.pie h4 {
  color: #fff; font-family: var(--palo); font-size: 0.74rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; margin-bottom: var(--e3);
}
.pie a { color: #d4d4d4; text-decoration: none; font-size: 0.9rem; }
.pie a:hover { color: #fff; text-decoration: underline; text-decoration-color: var(--rojo); }
.pie-rejilla { display: grid; gap: var(--e5); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.pie-columna { display: grid; gap: 9px; align-content: start; }
.pie-fin {
  margin-top: var(--e6); padding-top: var(--e4);
  border-top: var(--capilar) solid var(--linea-oscura);
  display: flex; justify-content: space-between; gap: var(--e3); flex-wrap: wrap;
  font-size: 0.82rem; color: #7c7c7c;
}

/* -------------------------------------------------------------------------
   17. Utilidades
   ------------------------------------------------------------------------- */
.mt-1 { margin-top: var(--e2); }  .mt-2 { margin-top: var(--e3); }
.mt-3 { margin-top: var(--e4); }  .mt-4 { margin-top: var(--e5); }
.mt-5 { margin-top: var(--e6); }
.mb-1 { margin-bottom: var(--e2); } .mb-2 { margin-bottom: var(--e3); }
.mb-3 { margin-bottom: var(--e4); } .mb-4 { margin-bottom: var(--e5); }
/* `mb-5` faltaba, y siete pantallas la venían pidiendo sin saber que no
   existía: el inventario del encargado dejaba sus dos tablas pegadas una a
   la otra, sin un milímetro entre ellas, porque la clase que las tenía que
   separar no estaba declarada. Es la pareja de `mt-5`. */
.mb-5 { margin-bottom: var(--e6); }
.sin-lista { list-style: none; }

/* Lista de filas con capilar: los materiales de un aula, los integrantes de
   un grupo, los productos de una boleta. Dato a la izquierda, estado o monto
   a la derecha, y en celular la derecha baja sola. */
.lista-filas { list-style: none; display: grid; }
.lista-filas > li {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e3); flex-wrap: wrap; font-size: 0.9rem;
  padding: 9px 0; border-bottom: var(--capilar) solid var(--linea);
}
.lista-filas > li:last-child { border-bottom: none; }
.lista-filas .crece { flex: 1 1 auto; min-width: 0; }

/* La boleta de una compra, como la abre el alumno desde su notificación
   para mostrársela al encargado: papel de ticket, con el corte punteado
   arriba y abajo, y el código grande para leerlo de un vistazo. */
.boleta {
  background: var(--papel-2); border: var(--capilar) solid var(--linea);
  border-top: 2px dashed var(--linea-firme); border-bottom: 2px dashed var(--linea-firme);
  border-radius: var(--r-tarjeta); padding: var(--e4);
}
.boleta .codigo { font-size: 1.1rem; font-weight: 600; }
.boleta .lista-filas { margin-top: var(--e3); border-top: var(--capilar) solid var(--linea); }
.solo-lectura { opacity: 0.72; pointer-events: none; }
.tachado { text-decoration: line-through; color: var(--gris-suave); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important; scroll-behavior: auto !important;
  }
}

/* -------------------------------------------------------------------------
   18. Acceso — la pantalla de login que comparten los seis portales
   -------------------------------------------------------------------------
   Dos columnas: a la izquierda una banda negra que dice quién entra por acá
   y qué se hace adentro; a la derecha el formulario sobre blanco. En celular
   la banda negra se encoge y queda arriba como encabezado. */
.acceso { display: grid; grid-template-columns: 1fr; min-height: 100vh; }
@media (min-width: 900px) { .acceso { grid-template-columns: 1.05fr 1fr; } }

.acceso-relato {
  background: var(--tinta); color: #b5b5b5;
  padding: var(--e6) 24px; display: flex; align-items: center;
  position: relative; overflow: hidden;
}
/* Trama diagonal roja apenas visible, para que el negro no sea plano. */
.acceso-relato::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(135deg, transparent, transparent 22px,
              rgba(211, 5, 45, 0.07) 22px, rgba(211, 5, 45, 0.07) 23px);
}
.acceso-relato-caja { position: relative; z-index: 1; width: min(100%, 520px); margin-inline: auto; }
.acceso-relato h1 { color: #fff; font-size: clamp(2rem, 3.6vw, 3rem); }
.acceso-relato-texto { color: #c5c5c5; font-size: 1.02rem; max-width: 46ch; }
.acceso-nota {
  display: flex; gap: 11px; align-items: flex-start;
  border: var(--capilar) solid var(--linea-oscura); border-left: 3px solid var(--rojo);
  border-radius: var(--r-boton); padding: var(--e3) var(--e4);
  font-size: 0.86rem; color: #a8a8a8; background: rgba(255, 255, 255, 0.02);
}
.acceso-nota i { color: var(--rojo); margin-top: 3px; }

.acceso-forma { display: flex; align-items: center; padding: var(--e6) 24px; background: var(--papel); }
.acceso-forma-caja { width: min(100%, 420px); margin-inline: auto; }
.acceso-forma .btn-bloque { margin-top: var(--e2); }

.acceso-demo {
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta);
  padding: var(--e3) var(--e4); background: var(--papel-2); font-size: 0.85rem;
}
.acceso-demo summary { cursor: pointer; font-weight: 600; color: var(--tinta-3); }
.acceso-demo li { padding: 4px 0; border-bottom: var(--capilar) solid var(--linea); }
.acceso-demo li:last-child { border-bottom: none; }

@media (max-width: 899px) {
  .acceso { min-height: auto; }
  .acceso-relato { padding-block: var(--e6); }
  .acceso-relato h1 { font-size: 1.9rem; }
}

/* -------------------------------------------------------------------------
   19. Portada pública
   ------------------------------------------------------------------------- */
.hero { padding-block: clamp(var(--e6), 7vw, var(--e8)) clamp(var(--e6), 5vw, var(--e7)); }
.hero h1 { max-width: 16ch; }
.hero .bajada { margin-top: var(--e4); }
.hero-acciones { display: flex; gap: var(--e3); flex-wrap: wrap; margin-top: var(--e5); }
.hero-nota { margin-top: var(--e4); font-size: 0.86rem; color: var(--gris-medio); display: flex; align-items: center; gap: 8px; }
.hero-nota i { color: var(--rojo); }

/* Franja de cifras debajo del hero, separadas por capilares. */
.cifras {
  display: grid; gap: var(--e4) var(--e5);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  border-top: var(--capilar) solid var(--linea); padding-top: var(--e5);
}
.cifra-bloque { border-left: var(--capilar) solid var(--linea); padding-left: var(--e4); }
.cifra-bloque:first-child { border-left: none; padding-left: 0; }
@media (max-width: 700px) { .cifra-bloque { border-left: none; padding-left: 0; } }

/* Hero de la portada: texto a la izquierda, foto a la derecha. La foto se
   va al final en celular, porque lo primero tiene que ser el titular. */
.hero-doble { display: grid; gap: var(--e5); align-items: center; }
@media (min-width: 980px) { .hero-doble { grid-template-columns: 1.05fr 0.95fr; gap: var(--e6); } }
.hero-foto {
  border-radius: var(--r-panel); overflow: hidden;
  border: var(--capilar) solid var(--linea); box-shadow: var(--sombra-2);
}
.hero-foto img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
@media (max-width: 979px) { .hero-foto { order: -1; } .hero-foto img { aspect-ratio: 16 / 9; } }

/* Rejilla de fichas con foto: la portada y los resultados de Laboratorios.
   Tres columnas en escritorio. Con `rejilla-2` salen cuatro y las tarjetas
   quedan demasiado angostas para los tramos y las listas de materiales. */
.rejilla-fichas { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }
/* Tipo de laboratorio en la portada: foto arriba, nombre y estado abajo. */
.tipo-lab .tarjeta-foto-cuerpo { display: grid; gap: 6px; }
.tipo-lab h3 { font-size: 1.05rem; }
.tipo-lab .mini { color: var(--gris-medio); }
/* La tarjeta se quedó con dos piezas —la cabecera y el enlace del pie— y los
   márgenes estaban calculados para tres: entre las dos abría un hueco de casi
   50px. Acá se cierra, y el enlace se queda a la derecha, donde estaba cuando
   compartía el renglón con la modalidad. */
.tipo-lab .tarjeta-cabeza { margin-bottom: 0; }
.tipo-lab .tarjeta-pie { margin-top: var(--e2); justify-content: flex-end; }

/* Tarjeta de portal en el índice. */
.portal-tarjeta { display: grid; gap: 10px; align-content: start; height: 100%; }
.portal-tarjeta .codigo { justify-self: start; }
.portal-tarjeta h3 { display: flex; align-items: center; gap: 10px; }
.portal-tarjeta h3 i { color: var(--rojo); font-size: 0.9em; }
.portal-tarjeta p { font-size: 0.9rem; color: var(--gris-medio); }
.portal-tarjeta .credencial {
  margin-top: auto; padding-top: var(--e3); border-top: var(--capilar) solid var(--linea);
  font-size: 0.8rem; color: var(--gris-suave);
}

/* Paso numerado (cómo funciona). */
.paso { display: grid; gap: 8px; }
.paso-numero {
  font-family: var(--titular); font-size: 2.1rem; font-weight: 700; line-height: 1;
  color: var(--rojo); border-bottom: 3px solid var(--rojo); padding-bottom: 6px;
  width: fit-content; min-width: 44px;
}


/* -------------------------------------------------------------------------
   20. Diagrama de estado del sistema
   -------------------------------------------------------------------------
   El mapa del administrador: los portales arriba, el backend en el medio y
   las bases y servicios abajo, con una línea que une las capas. Es HTML y
   CSS, sin librerías de diagramas: son tres filas de cajas y dos líneas.

   Ningún nodo dice su estado solo con el color. El punto de la izquierda va
   siempre acompañado del texto ("Operativo", "Degradado", "Apagado"), que es
   la regla 3 del sistema de diseño.
   ------------------------------------------------------------------------- */
.diagrama { display: flex; flex-direction: column; align-items: stretch; }
.diagrama-capa { border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta);
  background: var(--papel); padding: var(--e4); }
.diagrama-capa-titulo { display: flex; align-items: baseline; gap: var(--e2);
  font: 600 0.72rem/1 var(--palo); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--gris-suave); margin-bottom: var(--e3); }
.diagrama-capa-titulo span { letter-spacing: 0; text-transform: none; font-weight: 400;
  font-size: 0.78rem; color: var(--gris-medio); }
.diagrama-nodos { display: grid; gap: var(--e2);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

/* El enlace entre capas: una línea vertical corta y centrada. */
.diagrama-enlace { height: var(--e5); display: flex; align-items: center; justify-content: center; }
.diagrama-enlace::before { content: ""; width: var(--capilar); height: 100%;
  background: var(--linea-firme); }

.nodo { display: flex; gap: var(--e2); align-items: flex-start; text-align: left;
  border: var(--capilar) solid var(--linea); border-left: 3px solid var(--linea-firme);
  border-radius: var(--r-boton); background: var(--papel-2); padding: var(--e3); }
.nodo-cuerpo { flex: 1; min-width: 0; }
.nodo-nombre { font: 600 0.9rem/1.2 var(--palo); color: var(--tinta); }
.nodo-detalle { font-size: 0.74rem; color: var(--gris-medio); margin-top: 2px;
  overflow-wrap: anywhere; }
.nodo-estado { display: inline-flex; align-items: center; gap: 6px; margin-top: var(--e2);
  font: 500 0.72rem/1 var(--palo); }
.nodo-estado::before { content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: currentColor; }
.nodo-ok { border-left-color: var(--ok); }
.nodo-ok .nodo-estado { color: var(--ok); }
.nodo-tibio { border-left-color: var(--espera); background: var(--espera-velo); }
.nodo-tibio .nodo-estado { color: var(--espera); }
.nodo-mal { border-left-color: var(--alto); background: var(--alto-velo); }
.nodo-mal .nodo-estado { color: var(--rojo-hondo); }
.nodo-frio { border-left-color: var(--gris-suave); }
.nodo-frio .nodo-estado { color: var(--gris-medio); }

/* -------------------------------------------------------------------------
   21. Reglas de la contraseña
   -------------------------------------------------------------------------
   La lista que acompaña al campo cuando alguien crea su contraseña. Se lee
   antes de escribir y cada regla se va marcando sola: enterarse de la regla
   recién en el mensaje de error es enterarse tarde.

   El estado no se dice solo con el color ni solo con el icono. Delante de
   cada línea va la palabra —«Cumplida», «Falta»— en `.sr-solo`, para quien
   no ve ninguno de los dos.
   ------------------------------------------------------------------------- */
.reglas-clave { list-style: none; display: grid; gap: 6px; margin-top: var(--e2); }
.regla-clave {
  display: flex; gap: var(--e2); align-items: flex-start;
  font-size: 0.8rem; line-height: 1.45; color: var(--gris-medio);
}
.regla-clave i { margin-top: 3px; font-size: 0.72rem; color: var(--linea-firme); flex: none; }
.regla-cumplida { color: var(--ok); }
.regla-cumplida i { color: var(--ok); }
.regla-rota { color: var(--rojo-hondo); }
.regla-rota i { color: var(--rojo); }

/* Guía de estilo. */
.muestra {
  border: var(--capilar) solid var(--linea); border-radius: var(--r-tarjeta);
  padding: var(--e4); background: var(--papel); margin-bottom: var(--e4);
}
.muestra > h4 { margin-bottom: var(--e3); }
.muestra-fila { display: flex; flex-wrap: wrap; gap: var(--e3); align-items: center; }
.ficha-color {
  width: 100%; height: 56px; border-radius: 8px;
  border: var(--capilar) solid var(--linea); margin-bottom: 7px;
}

/* El logotipo sobre fondo negro: la palabra va en blanco, la marca sigue roja. */
.acceso-relato .logo-texto, .banda-tinta .logo-texto, .pie .logo-texto { color: #fff; }
.acceso-relato .antetitulo { color: #ff7a93; }
.acceso-relato .antetitulo::before { background: #ff7a93; }
