/*
Theme Name: GTA Becas
Description: Tema ligero del Portal de Becados GTA — "Becas G&G: Futuro Digital". Design tokens y componentes según DESIGN.md. Sin frameworks (presupuesto §8).
Version: 0.2.11
Author: GTA
Text Domain: gta-becas
*/

/* ===== Tipografía — Nunito autoalojada (DESIGN.md §2 y §8) =====
   Se sirve desde el tema y no desde fonts.gstatic.com por dos razones que no
   admiten atajo: la cabecera Content-Security-Policy de ops/nginx-becas.conf
   declara `default-src 'self'` y no abre ningún `font-src`, así que una petición
   al CDN se bloquearía y el portal se quedaría en el system-ui de respaldo; y
   DESIGN.md §2 lo prohíbe por privacidad, porque el CDN vería la IP de cada
   becario menor de edad en cada visita.

   Un único archivo variable en lugar de tres estáticos porque sale más barato
   por los dos lados: 38,2 KB en una descarga frente a 47,9 KB en tres
   (16,0 + 15,8 + 16,1 KB medidos sobre los mismos subsets), y el tema sólo
   necesita 400 cuerpo, 700 subtítulos y 800 títulos/cifras.

   El rango 200-1000 no es una elección de diseño: es el eje `wght` real que
   trae el archivo (leído de su tabla fvar). Declarar menos obligaría al
   navegador a recortar pesos que la fuente sí sabe dibujar.

   El `unicode-range` es el subset «latin» de Google, el mismo que cubre el
   archivo (verificado: 230 puntos de código, con todas las acentuadas, la ñ y
   los signos de apertura del español). Está declarado para que un carácter
   fuera de ese rango vaya directo a la familia de respaldo en vez de salir como
   cuadrito vacío dibujado por Nunito. */
@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-weight: 200 1000;
  /* swap y no block: en internet lento se lee antes con system-ui que esperando. */
  font-display: swap;
  src: url('assets/fuentes/nunito-variable-latino.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ===== Design tokens — DESIGN.md §2 (copiados tal cual) ===== */
:root {
  --teal-700: #0A4540;
  --teal-600: #0E5B55;
  --teal-500: #14766E;
  --teal-100: #DDEBE9;
  --teal-50:  #EEF4F3;

  --sol-400:  #FFC24B;
  --sol-100:  #FFF3D9;
  --coral-600:#C74532;
  --coral-400:#E85D4A;

  --tinta:      #1E2B29;
  --secundario: #52625F;
  --fondo:      #F6F8F7;
  --superficie: #FFFFFF;
  --borde:      #E3E8E6;

  /* TANDA 19-SEP-W · W6 (contraste medido) · --error bajó de #C4402F a #BA3C2C: medido contra
     su propio fondo tintado (`.gta-alerta--error`, #FCEBE8) daba 4.41:1, bajo el 4.5:1 de
     texto normal AA. Sobre blanco/fondo el margen era amplio (5.10/5.53), así que el token se
     movió, no el fondo: sigue por encima de 4.5:1 en los tres sitios donde el CSS lo usa como
     color de texto (ver `ops/prueba-contraste-w6.php`). */
  --exito: #2E7D32;  --error: #BA3C2C;  --info: #2A6FB0;

  --font: 'Nunito', system-ui, -apple-system, sans-serif;
  --fs-900: clamp(1.75rem, 4vw, 2.5rem);
  --fs-700: clamp(1.25rem, 2.5vw, 1.5rem);
  --fs-500: 1.0625rem;
  --fs-400: 0.9375rem;
  --fs-300: 0.8125rem;

  --r-lg: 20px;  --r-md: 14px;  --r-sm: 10px;  --r-pill: 999px;
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px; --sp-7: 48px;
  --sombra-card: 0 1px 3px rgb(14 91 85 / .08), 0 4px 16px rgb(14 91 85 / .06);
  --sombra-flotante: 0 8px 28px rgb(14 91 85 / .18);
  --touch-min: 44px;

  /* ===== Mobiliario flotante del móvil (D10) =====
     Tres piezas se pegan al borde inferior de la ventana y TAPAN lo que hay debajo: la tabbar
     (`.gta-tabbar`), la burbuja de Beki (`.gta-chat-burbuja`, que vive POR ENCIMA de la tabbar)
     y, cuando se abre, el panel del chat. Todo lo que termine cerca del fondo del documento
     —hoy el pie— tiene que reservarles sitio, y esa reserva se calcula A PARTIR DE ESTOS
     NÚMEROS, no a ojo.

     Por qué existen estas tres variables y no una constante escrita en cada regla: la reserva
     del pie era `calc(var(--sp-7) + 56px)` = 104 px, donde ese `56px` era el alto que alguien
     SUPUSO para la tabbar. Dos cosas lo desmintieron al medirlo a 390 px: la tabbar mide 65 px
     (44 de mínimo táctil + 8 y 10 de relleno + 1 de borde), y sobre todo la burbuja se añadió
     DESPUÉS, a 72 px del fondo y con 56 de diámetro, o sea llegando a 128 px — muy por encima
     de los 104 reservados. Resultado medido: los últimos 27 px del enlace «Verifica aquí si un
     certificado es válido» quedaban debajo de la burbuja y no se podían pulsar, en las cuatro
     pantallas del guion que llevan tabbar. `elementFromPoint` devolvía la burbuja, no el enlace.

     A ≥641 px pasaba lo mismo por la misma causa (la burbuja baja a `--sp-5` del fondo y el pie
     sólo reservaba `--sp-5`); a 1280 px el enlace se salva por casualidad, porque el pie va
     centrado y a esa anchura su texto termina lejos del rincón donde está la burbuja. Que un
     defecto desaparezca al ensanchar la ventana no es que esté arreglado.

     `ops/prueba-movil-guion.php` comprueba la ARITMÉTICA de esta reserva contra estos tokens,
     que es justo lo que nadie rehízo cuando llegó la burbuja. */
  /* Y ARRIBA PASABA LO MISMO, medido en N506 con navegador: la navbar se declara en DOS
     alturas —56 px y 64 desde 1025— y el `scroll-margin-top` que la esquiva en `.gta-hilo__nuevo`
     llevaba UNA sola cifra escrita a mano (56). Resultado en 1366x768: el separador «Nuevo desde
     aquí» aterrizaba a 4 px del borde de la barra donde su propio comentario promete 12, y que no
     llegara a taparse era aritmética de casualidad (68 > 64 por cuatro). El alto de la barra es
     ahora un token y quien lo esquiva lo CALCULA. */
  --navbar-h: 56px;        /* alto real de .gta-navbar; a >=1025 px lo sube el @media de abajo */
  --tabbar-h: 65px;        /* alto real de .gta-tabbar, medido a 390 px y declarado abajo */
  --burbuja-d: 56px;       /* diámetro de la burbuja de Beki */
  --burbuja-hueco: var(--sp-2);  /* separación burbuja↔tabbar (DESIGN §8 pide ≥8 px) */
  --gta-offset-superior: 0px;  /* alto de la barra de admin de WP cuando está presente (P0.2) */
}

/* P0.2 (OBS-11a) · la barra de admin de WP es `position:fixed` a `top:0` (32 px de escritorio,
   46 bajo 783 px — `wp-includes/css/admin-bar.css`) y sólo la ve docencia/dirección/admin
   (`GTA_Acceso::sin_admin_bar()` se la quita a becario, supervisor y apoderado). Sin esto,
   `.gta-navbar` (también sticky a `top:0`) quedaría tapada por ella para quien SÍ la ve, y
   la barra de pestañas del curso (abajo) heredaría un `top` corto. */
body.admin-bar { --gta-offset-superior: 32px; }
@media screen and (max-width: 782px) {
  body.admin-bar { --gta-offset-superior: 46px; }
}

/* TANDA 19-SEP-W · W6 · A+ de /perfil/ (`gta_fuente_grande`, persistente por usuario). Se
   redefinen los TOKENS de tamaño, no un zoom de `html`: todo el CSS ya lee `var(--fs-*)`
   (h1-h3, `.texto-sec`, el body), así que subir el token sube la letra en todo el aula sin
   tocar cada regla, y no toca `--sp-*`/`--touch-min` (px), que son espaciado y tamaño de
   controles, no letra. */
body.gta-fuente-grande {
  --fs-900: clamp(2.05rem, 4.6vw, 2.9rem);
  --fs-700: clamp(1.45rem, 2.9vw, 1.75rem);
  --fs-500: 1.25rem;
  --fs-400: 1.1rem;
  --fs-300: 0.95rem;
}

/* ===== Base ===== */
*, *::before, *::after { box-sizing: border-box; }

/*
 * `hidden` tiene que ocultar, siempre. La regla del navegador es `[hidden]{display:none}` con
 * especificidad mínima, así que cualquier `display` de este archivo la anula sin avisar. Ya
 * había roto cuatro cosas a la vez, todas silenciosas porque el JavaScript sí ponía
 * `elemento.hidden = true` y nadie veía que en pantalla no pasaba nada: los chips de filtro de
 * /cursos/ (Todos, En progreso, Completados, Bonus), el buscador de /guias/, las cards fantasma
 * y el panel del chat. Es decir, todos los filtros y buscadores del portal eran decorativos.
 *
 * El `!important` es deliberado y es lo que cierra la familia entera: sin él, cada `display`
 * nuevo que alguien escriba mañana vuelve a abrir el mismo agujero. Un elemento que deba
 * mostrarse no lleva `hidden`, así que no hay caso legítimo que este `!important` estorbe.
 */
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-500);
  line-height: 1.55;
  color: var(--tinta);
  background: var(--fondo);
}
img, svg { max-width: 100%; height: auto; }
a { color: var(--teal-600); }
h1 { font-size: var(--fs-900); font-weight: 800; line-height: 1.15; margin: 0 0 var(--sp-4); }
h2 { font-size: var(--fs-700); font-weight: 800; margin: 0 0 var(--sp-3); }
h3 { font-size: var(--fs-500); font-weight: 700; margin: 0 0 var(--sp-2); }
p { margin: 0 0 var(--sp-3); }
.texto-sec { color: var(--secundario); font-size: var(--fs-400); }
.texto-urgente { color: var(--coral-600); font-weight: 800; }
code { background: var(--teal-50); border-radius: 6px; padding: 1px 6px; font-size: .9em; }
:focus-visible { outline: 3px solid rgb(14 91 85 / .35); outline-offset: 2px; border-radius: 4px; }
.screen-reader-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* Q2 chunk 3/3 (TANDA 24-SEP-P23) · «Saltar al contenido»: oculto igual que .screen-reader-text
   hasta que recibe el foco (primer Tab de la página), donde se planta encima de la navbar con
   el mismo anillo que :focus-visible de arriba. */
.gta-skip-link {
  position: absolute; top: -999px; left: 0; z-index: 1000;
  background: var(--teal-700); color: #fff; font-weight: 700;
  padding: var(--sp-3) var(--sp-4); border-radius: 0 0 8px 0; text-decoration: none;
}
.gta-skip-link:focus-visible { top: 0; outline: 3px solid #fff; outline-offset: -3px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ===== Layout ===== */
/*
 * `overflow-wrap: anywhere` GLOBAL, y es el punto de estrangulamiento del ancho: lo que el
 * trozo de las 16:44 dejó apuntado y NO medido, medido aquí.
 *
 * Aquél arregló CINCO cajas una por una —las cinco que hoy pintan texto que teclea una
 * persona— y se negó a poner esta línea con una razón escrita: `anywhere` cambia el ancho
 * MÍNIMO DE CONTENIDO de todo lo que toca, o sea el reparto de columnas de cada tabla y de
 * cada flex del portal, empezando por la tabla de once columnas de «Mi grupo». Meterla de paso
 * obligaría a volver a medir todas esas pantallas.
 *
 * Se volvieron a medir. CATORCE pantallas por CINCO anchos (320, 360, 390, 768 y 1366),
 * comparando el rectángulo de CADA elemento bajo `.gta-main` antes y después de la regla:
 * **7.516 cajas y delta de layout CERO**, «Mi grupo» incluida —3.838 elementos, ni uno se
 * movió a ningún ancho—. El miedo estaba bien fundado pero mal situado: el riesgo no eran las
 * tablas (sólo hay UNA en el portal, y vive en `.gta-mg-scroll`, que se desplaza sola), sino
 * los pares `dt`/`dd` de un flex donde UN lado ya llevaba `anywhere` — ver la excepción abajo.
 *
 * Lo que compra, medido metiendo 200 caracteres sin espacios en CADA caja de texto del portal
 * y mirando si la página se desplaza de lado: **1.591 cajas desbordaban y quedan 105**. No es
 * que hoy haya 1.591 defectos —casi todas pintan texto que escribe el portal, con sus
 * espacios—: es que dejan de ser un defecto el día que su contenido pase a teclearlo alguien.
 * Eso es exactamente lo que hace un punto de estrangulamiento.
 *
 * Las 105 que quedan están CONTADAS y son las dos que no debe arreglar esta regla:
 * 13 son los `dt` de `/mi-beca/` (la excepción de abajo) y 8 son `.gta-mg-serie__titulo`,
 * que lleva `white-space: nowrap` a propósito y gana a cualquier `overflow-wrap`; su texto lo
 * arma el portal («0-25 %», «15 Jul – 21 Jul»), no una persona.
 *
 * Las cinco reglas por caja de las 16:44 SE QUEDAN y no son redundantes: llevan además
 * `min-width: 0`, sin el cual un hijo de flex no encoge por debajo de su ancho mínimo.
 */
.gta-main { max-width: 1080px; margin: 0 auto; padding: var(--sp-5) var(--sp-4) 96px; overflow-wrap: anywhere; }
/*
 * P14.5 (24-sep): a 1440 el prototipo mide 1360 de contenido útil (`main.wrap` sin tope,
 * `padding:34px 40px 48px`). Se aplica SOLO desde 1025px: por debajo sigue el ancho/padding
 * medido por `ops/prueba-wrap-global.php`, que no toca esta regla.
 */
@media (min-width: 1025px) { .gta-main { max-width: 1440px; padding: 34px 40px 48px; } }

/* ===== Navbar — DESIGN §3 =====
   MÓVIL PRIMERO (11-ago). Medido a 390 px: la barra declara `height:56px`, pero el
   logo salía 111×55 —«🦉 Becas» / «G&G» en dos líneas— y «Mi beca» 72×63 empezando en
   `top:-3`, o sea SOBRESALIENDO de su propia barra por arriba y por abajo. La causa es
   aritmética: con `gap:16` y `padding:0 16` quedan 358 px para logo (125) + separador +
   racha (67) + campana (44) + «Mi beca» (74) más CUATRO huecos de 16 = 374. Faltaban
   16 px, así que flexbox encogió los dos extremos y el texto se partió.

   Por qué no lo cazó nada: las suites miden desbordamiento HORIZONTAL de página y los
   44 px de los controles, y esto no es ninguna de las dos cosas —un botón que se sale
   por arriba de su barra sigue midiendo 44 y no ensancha el documento—. Se ve mirando,
   no midiendo lo de siempre; por eso la suite nueva mide el alto de cada hijo contra el
   de la barra. */
.gta-navbar {
  position: sticky; top: var(--gta-offset-superior); z-index: 50;
  background: var(--teal-600); color: #fff;
  height: var(--navbar-h); display: flex; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-3);
}
/* Desde tablet sobra sitio de sobra: el aire vuelve a ser el de DESIGN §3. */
@media (min-width: 641px) { .gta-navbar { gap: var(--sp-4); padding: 0 var(--sp-4); } }
/* Y a 360 px seguía sin caber. Esto NO lo trajo la pantalla de mensajes —a ese ancho la lista de
   enlaces está oculta y no pinta nada—: la barra desbordaba 12 px en TODAS las páginas del portal
   (medido en /, /cursos/, /logros/ y /guias/), y 360 es el ancho de Android más repartido del
   mundo. El arreglo del 11-ago hizo la misma cuenta para 390 y se quedó ahí; a 360 sale
   logo 139 + racha 71 + campana 44 + «Mi beca» 74 = 328, más cuatro huecos de 8 y 24 de padding
   = 384 en 360 de pantalla. Se recorta AIRE —hueco, padding de la barra y el de la racha—, nunca
   el tamaño de un control: 32 px, que es lo que faltaba.
   Por qué no lo cazó nada antes: las suites que miden 320 y 360 recorren el AULA, y en el aula
   no hay navbar del portal; las que recorren el portal miden 390, 768 y 1366. Lo destapó la
   suite 28 al ser la primera que cruza las dos cosas. */
/* N226 · el padding lateral baja de 8 a 4 en TODO teléfono, no sólo en el más pequeño.
   Los ocho píxeles que se recuperan aquí son la mitad de lo que le faltaba a la barra para
   soportar el reflujo de la fuente de respaldo a 390 (medido: +23 px de crecimiento contra
   11 px de holgura). Sigue siendo AIRE lo que se recorta, nunca un control. */
@media (max-width: 640px) {
  .gta-navbar { gap: var(--sp-1); padding: 0 var(--sp-1); }
  .gta-navbar__racha { padding: 6px 8px; }
}
/* La segunda altura de la barra va en el TOKEN y no en la regla: así la sube todo el que
   dependa de ella (hoy el `scroll-margin-top` de `.gta-hilo__nuevo`) y no sólo la barra. */
@media (min-width: 1025px) { :root { --navbar-h: 64px; } }
/* El logo es el «volver a inicio» de todo el portal: es un control, no un rótulo, y en
   móvil se toca con el pulgar. Medía 27 px de alto (DESIGN §2 pide --touch-min).
   `nowrap` + `flex-shrink:0`: la marca del programa no se parte por la mitad ni se
   encoge para hacerle sitio a nada. Si algún día no cupiera, quien sobra es el
   separador elástico, no el nombre. */
/* N226 · `flex-shrink: 0` era una promesa que la barra ya no podía cumplir. La regla escrita
   arriba dice «si algún día no cupiera, quien sobra es el separador elástico», y a 375 px el
   separador ya vale CERO: por debajo de ese ancho no quedaba nadie a quien pedirle sitio y la
   barra ensanchaba el DOCUMENTO (medido: 372 en una ventana de 360, 339 en una de 320, en las
   seis pantallas del guion que llevan barra). Así que la regla se continúa donde se quedó: tras
   el separador, el siguiente que cede es el NOMBRE —nunca Beki, que es la marca dibujada, y
   nunca un destino táctil—, y cede recortándose con puntos suspensivos, no partiéndose ni
   desapareciendo. Con esto el desbordamiento deja de ser una cuenta que sale por poco y pasa a
   ser IMPOSIBLE: haya la letra que haya y diga la racha lo que diga, siempre queda algo que dar.
   El nombre sigue entero en el DOM, así que el lector de pantalla lo lee completo. */
.gta-navbar__logo { color: #fff; text-decoration: none; font-weight: 800; font-size: 1.1rem; display: flex; align-items: center; gap: 8px; min-height: var(--touch-min); white-space: nowrap; min-width: 0; flex-shrink: 1; }
.gta-navbar__logo > span { flex: 0 0 auto; }
.gta-navbar__logo > .gta-navbar__marca { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.gta-navbar__links { display: none; gap: var(--sp-2); margin-left: var(--sp-4); }
@media (min-width: 641px) { .gta-navbar__links { display: flex; } }
.gta-navbar__links a {
  color: #fff; text-decoration: none; font-weight: 700; font-size: var(--fs-400);
  padding: 8px 14px; border-radius: var(--r-pill); min-height: var(--touch-min); display: inline-flex; align-items: center;
}
.gta-navbar__links a:hover, .gta-navbar__links a.activo { background: var(--teal-700); }
/* La cuarta entrada («Mensajes», 11-ago) rompe la barra a 768: medido, 19 px de desbordamiento
   de PÁGINA, con «Mi beca» saliéndose por la derecha. La aritmética es la misma de arriba y el
   aire de los enlaces es lo único que sobra —el logo no se parte por decisión escrita, y la
   racha y la campana son controles—, así que entre tablet y PC los enlaces van más juntos y
   recuperan su aire a partir de 1025. Lo cazó la suite 28 midiendo a los cinco anchos: a 390 la
   lista está oculta y a 1366 sobra sitio, o sea que el único ancho que falla es el de en medio. */
@media (min-width: 641px) and (max-width: 1024px) {
  .gta-navbar__links { gap: 2px; margin-left: var(--sp-2); }
  .gta-navbar__links a { padding: 8px 8px; font-size: var(--fs-300); }
}
.gta-navbar__spacer { flex: 1; }
/* N186 · Dentro del chip ya no va un emoji sino el cofre de D4 (SVG). `inline-flex` para que
   el dibujo y la cifra compartan línea base óptica, y `gap` en vez del espacio de texto que
   dejaba el 🔥. El cofre se pide a 20 px: con los 6+6 de padding el chip sigue midiendo lo
   mismo que antes y la barra de 56 px no cambia de alto. */
.gta-navbar__racha {
  background: var(--teal-700); border-radius: var(--r-pill); padding: 6px 12px;
  font-weight: 800; font-variant-numeric: tabular-nums; font-size: var(--fs-400); white-space: nowrap;
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 6px;
}
.gta-navbar__racha .gta-cofre { display: block; flex-shrink: 0; }
/* «Mi beca» / «Entrar»: es el otro extremo del pulgar en la barra y medía 39 px.
   El `padding` lateral baja a 8 en móvil (12 desde tablet) y el texto no se parte: dos
   líneas dentro de un control de 44 px de mínimo lo empujaban a 63 px, fuera de la
   barra de 56. */
.gta-navbar__salir {
  /* N226 · el padding lateral de teléfono baja de 8 a 4 —la otra mitad de los 16 px que le
     faltaban a la barra a 390—. Es aire: el control sigue midiendo 94x44 con «Mi beca» y su
     avatar, muy por encima del mínimo táctil. Desde tablet vuelve a 12, como estaba. */
  color: #fff; opacity: .85; text-decoration: none; font-size: var(--fs-400); padding: 8px var(--sp-1);
  min-height: var(--touch-min); display: inline-flex; align-items: center;
  white-space: nowrap; flex-shrink: 0;
}
@media (min-width: 641px) { .gta-navbar__salir { padding: 8px 12px; } }

/* P0.1 (TANDA 22-SEP-P0, OBS-02) · menú de cuenta: botón avatar+nombre+chevron en la barra que
   abre un panel con las rutas del perfil y, siempre al final, «Cerrar sesión» en rojo. Mismo
   patrón que .gta-campana__panel (posición absoluta anclada al control, borde+sombra flotante,
   fijo al ancho de ventana bajo 480 px) para no inventar un segundo lenguaje de panel flotante. */
.gta-navbar__cuenta { position: relative; flex-shrink: 0; }
.gta-navbar__cuenta-boton {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--touch-min); padding: 6px var(--sp-1);
  background: transparent; border: 0; border-radius: var(--r-pill);
  color: #fff; font: inherit; font-weight: 700; font-size: var(--fs-400);
  cursor: pointer; white-space: nowrap;
}
@media (min-width: 641px) { .gta-navbar__cuenta-boton { padding: 6px 12px; } }
.gta-navbar__cuenta-boton:hover, .gta-navbar__cuenta-boton[aria-expanded="true"] { background: var(--teal-700); }
.gta-navbar__cuenta-boton .gta-avatar-dib { border-radius: 50%; flex: 0 0 auto; }
.gta-navbar__cuenta-nombre { max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 480px) { .gta-navbar__cuenta-nombre { display: none; } }
.gta-navbar__cuenta-chevron {
  width: 0; height: 0; flex: 0 0 auto;
  border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 5px solid currentColor;
  opacity: .85;
}
.gta-navbar__cuenta-panel {
  position: absolute; top: calc(100% + var(--sp-1)); right: 0; z-index: 60;
  width: min(260px, calc(100vw - var(--sp-4) * 2));
  background: var(--superficie); color: var(--tinta);
  border: 1px solid var(--borde); border-radius: var(--r-md); box-shadow: var(--sombra-flotante);
  padding: var(--sp-1);
}
@media (max-width: 480px) {
  .gta-navbar__cuenta-panel {
    position: fixed; top: calc(var(--navbar-h) + var(--sp-1));
    right: var(--sp-4); left: var(--sp-4); width: auto;
  }
}
.gta-navbar__cuenta-item {
  display: flex; align-items: center; min-height: var(--touch-min);
  padding: 8px var(--sp-2); border-radius: var(--r-sm);
  color: var(--tinta); text-decoration: none; font-weight: 700; font-size: var(--fs-400);
}
.gta-navbar__cuenta-item:hover { background: var(--teal-50); }
.gta-navbar__cuenta-item--peligro { color: var(--error); }
.gta-navbar__cuenta-item--peligro:hover { background: var(--sol-100); }
.gta-navbar__cuenta-sep { height: 1px; background: var(--borde); margin: var(--sp-1) var(--sp-1); }

/* N1 (TANDA 14-SEP-N · D0) · el conmutador «Mi aula / Mi colegio(-grupo)», estilo v4-J («Tu
   panel / Tu empresa») — dos pestañas dentro de una píldora, la activa en blanco sobre teal.
   SIN media query en la regla base a propósito: para el cargo SIN beca (sin tabbar en el pie)
   tiene que verse en cualquier ancho. El modificador --escritorio es la ÚNICA pieza que se
   esconde bajo 641 px, y sólo la usa el docente becado —ver header.php—, porque esa barra ya
   está en su presupuesto de píxeles justo a 390 (comentario de N226, arriba): a ese ancho el
   director-becado llega a /colegio/ por la tabbar, no por aquí. */
.gta-navbar__conmutador {
  display: flex; gap: 4px; align-items: center;
  background: var(--teal-700); border-radius: var(--r-pill); padding: 3px;
}
.gta-navbar__conmutador a {
  color: #fff; text-decoration: none; font-weight: 700; font-size: var(--fs-300);
  padding: 6px 10px; border-radius: var(--r-pill); min-height: var(--touch-min);
  display: inline-flex; align-items: center; white-space: nowrap;
}
.gta-navbar__conmutador a.activo { background: #fff; color: var(--teal-700); }
@media (min-width: 641px) {
  .gta-navbar__conmutador a { padding: 8px 16px; font-size: var(--fs-400); }
}
.gta-navbar__conmutador--escritorio { display: none; margin-left: var(--sp-2); }
@media (min-width: 641px) { .gta-navbar__conmutador--escritorio { display: flex; margin-left: var(--sp-4); } }

/* El suelo real de celular. A 320 px la fila pide 349 px y hay 320: sin esto la barra
   deja de partirse pero empieza a desbordar de lado, que es cambiar un defecto por otro.
   Se recorta AIRE y TAMAÑO DE LETRA —nunca el mínimo táctil de 44 px, que no se toca—.
   Los cuatro elementos siguen ahí: en la barra vive la racha, que es media motivación
   del programa, y esconderla en el celular más pequeño sería quitársela justo a quien
   peor teléfono tiene.

   VA AQUÍ Y NO ARRIBA a propósito: una media query no gana especificidad por serlo, así
   que puesta antes de `.gta-navbar__logo` perdía contra ella por orden y sólo se aplicaba
   el `gap` (medido: el logo seguía en 122 px). Las reglas de ancho máximo van DESPUÉS de
   las que pisan. */
/* N226 · ESTE BLOQUE EMPEZABA EN 359 Y AHÍ NO VIVE NINGÚN TELÉFONO. El Android más repartido
   mide 360 y el iPhone SE 375: los dos caían en tierra de nadie —fuera del suelo de celular por
   un píxel, y con la barra ya sin separador que dar—, y por eso desbordaban 12 y 4 px. La causa
   de que nadie lo viera: `ruta-movil-d10.mjs` recorre el guion a 390 por defecto, que es el
   único ancho de teléfono donde la cuenta salía. Corrido a 360, seis de sus diez pantallas
   estaban en rojo. El corte sube a 389 —justo por debajo del ancho de la demo, que no cambia de
   aspecto— y el `padding: 8px 4px` de la salida se va porque ya lo pone la regla de arriba para
   todo teléfono. */
@media (max-width: 389px) {
  .gta-navbar { gap: var(--sp-1); }
  .gta-navbar__logo { font-size: 1rem; }
  .gta-navbar__racha { padding: 6px 8px; font-size: var(--fs-300); }
  .gta-navbar__salir { font-size: var(--fs-300); }
}

/* Barra inferior móvil */
.gta-tabbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
  display: flex; background: var(--superficie); border-top: 1px solid var(--borde);
  padding-bottom: env(safe-area-inset-bottom);
  /* Declarado, no supuesto: quien reserva sitio debajo (el pie) lee este mismo token. El alto
     lo sigue poniendo el contenido —44 de mínimo táctil más relleno—; esto sólo fija el suelo
     para que el número del token no pueda quedarse corto sin que se note. */
  min-height: var(--tabbar-h);
}
@media (min-width: 641px) { .gta-tabbar { display: none; } }
.gta-tabbar a {
  flex: 1; text-align: center; text-decoration: none; color: var(--secundario);
  font-size: var(--fs-300); font-weight: 700; padding: 8px 0 10px; min-height: var(--touch-min);
}
.gta-tabbar a.activo { color: var(--teal-600); }
.gta-tabbar .icono { display: block; font-size: 1.35rem; line-height: 1.2; }

/* ===== Botones — DESIGN §5.1 ===== */
.btn-pri, .btn-sec, .btn-sol, .ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font); font-weight: 800; font-size: var(--fs-500);
  border-radius: var(--r-pill); min-height: 48px; padding: 10px 24px;
  cursor: pointer; text-decoration: none; transition: transform .12s, background .12s, box-shadow .12s;
  border: 0;
}
.btn-pri { background: var(--teal-600); color: #fff; }
.btn-pri:hover { background: var(--teal-700); transform: translateY(-1px); }
.btn-sec { background: transparent; color: var(--teal-600); border: 2px solid var(--teal-600); }
.btn-sec:hover { background: var(--teal-50); }
.btn-sol { background: var(--sol-400); color: var(--tinta); }
.btn-sol:hover { filter: brightness(1.05); transform: translateY(-1px); }
.ghost { background: transparent; color: var(--teal-600); min-height: var(--touch-min); padding: 8px 12px; border: 0; }
.btn-block { width: 100%; }
button:disabled { opacity: .4; cursor: not-allowed; transform: none !important; }

/* ===== Cards ===== */
.card {
  background: var(--superficie); border-radius: var(--r-lg);
  box-shadow: var(--sombra-card); padding: var(--sp-5); margin-bottom: var(--sp-4);
}
.card--suave { background: var(--teal-50); box-shadow: none; }

/* Los desplegables (<summary>) del aviso de privacidad en P05 y de «¿qué cuenta como día
   de racha?» en P17 son el control que abre el texto: medían 23 px de alto. */
.gta-main summary, .gta-activar summary { min-height: var(--touch-min); display: flex; align-items: center; cursor: pointer; }

/* ===== Chips y badges ===== */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--teal-50); color: var(--teal-600); font-weight: 700; font-size: var(--fs-400);
  border: 1px solid var(--borde); border-radius: var(--r-pill); padding: 6px 14px; cursor: pointer; min-height: 36px;
}
/* Los chips que SE PULSAN (filtros de P12, selección de intereses de P22) son controles
   táctiles y el checklist de DESIGN §8 les exige 44 px. Los chips decorativos —el de la
   herramienta del curso, el de estado— se quedan en 36 px: no se tocan, y subirlos a 44
   engordaría cada tarjeta sin que nadie gane nada. */
button.chip, a.chip, .chip--check, .chip[role="tab"], .chip[role="button"] { min-height: var(--touch-min); }
.chip.activo { background: var(--teal-600); color: #fff; border-color: var(--teal-600); }
.chip--check input { position: absolute; opacity: 0; }
.chip--check:has(input:checked) { background: var(--teal-600); color: #fff; border-color: var(--teal-600); }
.gta-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
/* P2R R7 (TANDA 22-SEP-P2R) · subtítulo de «Mis cursos», pegado al h1 como en `png/MisCursos.png`. */
.gta-cursos-pagina h1 { margin-bottom: var(--sp-1); }
.gta-cursos-pagina__subtitulo { margin: 0 0 var(--sp-3); }
/* P2R R7 chunk 5 (TANDA 22-SEP-P2R) · cabecera de «Mis cursos» como `png/MisCursos.png`: título
   y subtítulo a la izquierda, filtros como grupo segmentado a la derecha, alineados por abajo.
   En celular (mismo ancho que el resto de la página) caen en fila aparte, con scroll horizontal
   si no caben: son botones, no hay nada que recortar. */
.gta-cursos-pagina__cabecera { margin-bottom: var(--sp-3); }
.gta-cursos-pagina__titulos { min-width: 0; }
.gta-cursos-pagina__cabecera .gta-chips {
  margin: var(--sp-3) 0 0; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
}
@media (min-width: 641px) {
  .gta-cursos-pagina__cabecera { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4); }
  .gta-cursos-pagina__cabecera .gta-chips { margin-top: 0; flex: none; overflow: visible; }
}
/* El riel de fondo del grupo segmentado (el gris claro tras las pastillas en el prototipo) y su
   pastilla activa oscura, en vez del botón teal suelto que usa el resto del sitio: aquí el chip
   pulsado ES la pestaña puesta, así que se lee como un solo control de varios estados. */
.gta-cursos-pagina__cabecera .gta-chips {
  background: var(--fondo); border-radius: var(--r-pill); padding: 4px; gap: 2px;
}
.gta-cursos-pagina__cabecera .chip {
  background: transparent; border-color: transparent; color: var(--tinta); font-size: var(--fs-300, 13px); padding: 6px 12px; white-space: nowrap;
}
.gta-cursos-pagina__cabecera .chip.activo { background: var(--teal-700); color: #fff; }
/* P2.2 chunk 2 (TANDA 22-SEP-P2) · el conteo real de cada chip-filtro, como en `png/MisCursos.png`. */
.chip__conteo { background: rgba(0, 0, 0, .08); border-radius: var(--r-pill); padding: 1px 7px; font-size: var(--fs-300, 13px); }
.chip.activo .chip__conteo { background: rgba(255, 255, 255, .25); }
/* P2.2 chunk 1 (TANDA 22-SEP-P2) · el chip del examen de la tarjeta de «Mis cursos»: decorativo
   (no se pulsa), así que cursor normal y sin el estado :hover de los chips-filtro de arriba. */
.gta-card-curso__examen { cursor: default; align-self: flex-start; }
.gta-card-curso__examen[data-estado="certificado"] { background: var(--gold-50, #FBF1D6); color: var(--gold-700, #8a6527); border-color: var(--gold-100, #F1C04E); }
.gta-card-curso__examen[data-estado="aprobado"] { background: var(--exito-fondo, #E6F4EA); color: var(--exito, #1E7B4F); border-color: var(--exito, #1E7B4F); }
.gta-card-curso__modulo { font-weight: 700; }
.badge-exito { color: var(--exito); font-weight: 800; font-size: var(--fs-400); }
.badge-gris { color: var(--secundario); font-weight: 700; font-size: var(--fs-400); }

/* ===== Progreso — DESIGN §5.3 ===== */
.gta-progreso {
  height: 8px; background: var(--teal-100); border-radius: var(--r-pill); overflow: hidden; margin: var(--sp-2) 0;
}
.gta-progreso__fill { height: 100%; background: var(--teal-500); border-radius: var(--r-pill); transition: width .4s; }
.gta-progreso__fill--done { background: var(--sol-400); }

/* ===== Alertas / banners — DESIGN §5.4 ===== */
.gta-alerta {
  background: var(--sol-100); border: 1px solid var(--sol-400);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-4);
}
.gta-alerta--error { background: #FCEBE8; border-color: var(--coral-400); color: var(--error); }
.gta-alerta--exito { background: #E8F4E9; border-color: var(--exito); color: var(--exito); }
.gta-alerta--info { background: #E9F1FA; border-color: var(--info); color: var(--info); }
/* Error de un campo de formulario, junto al campo — sin caja, para no repetir el banner. P23 Q3. */
.gta-campo-error { color: var(--error); font-size: var(--fs-300); margin: calc(-1 * var(--sp-2)) 0 var(--sp-3); }
.gta-banner {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  background: var(--sol-100); border: 1.5px solid var(--coral-400);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-4); font-weight: 700;
}
.gta-banner--vencida { border-color: var(--secundario); background: var(--teal-50); }

/* ===== Formularios — DESIGN §5.5 ===== */
label { display: block; font-weight: 700; margin-bottom: 6px; }
input[type=text], input[type=password], input[type=email], input[type=tel],
input[type=date], input[type=number], input[type=search], select, textarea {
  width: 100%; min-height: 48px; padding: 10px 14px;
  font-family: var(--font); font-size: var(--fs-500); color: var(--tinta);
  background: var(--superficie); border: 1.5px solid var(--borde); border-radius: var(--r-sm);
}
/* Opacidad del anillo igual a la de :focus-visible global (arriba, .35): con .15 el campo de
   texto se veía menos enfocado que un botón o un enlace, y quien navega por teclado perdía el
   rastro justo en los formularios, que es donde más lo necesita. */
input:focus, select:focus, textarea:focus { border-color: var(--teal-500); outline: none; box-shadow: 0 0 0 3px rgb(14 91 85 / .35); }
input[readonly] { background: var(--teal-50); color: var(--secundario); }
.gta-form-grid { display: grid; gap: var(--sp-2) var(--sp-4); }
@media (min-width: 641px) { .gta-form-grid { grid-template-columns: 1fr 1fr; } }
.gta-campo-clave { position: relative; }
/* El ojo de «ver contraseña» es un botón de verdad y medía 36×36: por debajo del mínimo táctil
   y, encima, pegado al borde derecho del campo, que es donde peor se acierta con el pulgar. Va
   a 44×44 centrado dentro del campo (el campo mide 48 de alto, así que cabe sin deformarlo). */
.gta-ver-clave {
  position: absolute; right: var(--sp-1); bottom: 2px;
  background: none; border: 0; font-size: 1.1rem; cursor: pointer;
  min-width: var(--touch-min); min-height: var(--touch-min);
  display: inline-flex; align-items: center; justify-content: center;
}
.gta-check { display: flex; gap: 10px; align-items: flex-start; font-weight: 400; margin: var(--sp-3) 0; min-height: var(--touch-min); }
.gta-check input, .gta-checks input { width: 20px; height: 20px; min-height: 0; accent-color: var(--teal-600); flex-shrink: 0; }
.gta-checks { border: 0; padding: 0; margin: var(--sp-4) 0; }
.gta-checks legend { font-weight: 800; margin-bottom: var(--sp-2); }
.gta-checks label { display: flex; gap: 10px; align-items: flex-start; font-weight: 400; margin-bottom: var(--sp-2); min-height: var(--touch-min); }
.gta-medidor { font-size: var(--fs-400); font-weight: 700; min-height: 22px; margin: -6px 0 var(--sp-2); }
.nivel-rojo { color: var(--error); }
.nivel-ambar { color: #9a6b00; }
.nivel-verde { color: var(--exito); }
.gta-form-estado { margin-left: var(--sp-3); font-weight: 700; color: var(--secundario); }

/* Campo de archivo — el input nativo pinta «Choose File / No file chosen» en el idioma del
   navegador (D2). El input real queda oculto pero enfocable (técnica «visualmente oculto», no
   display:none) y una etiqueta hace de botón en español. */
.gta-campo-archivo { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.gta-campo-archivo-input {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.gta-campo-archivo-fila { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.gta-campo-archivo-boton {
  margin: 0; display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px;
  background: var(--superficie); color: var(--secundario); border: 1.5px solid var(--borde);
  border-radius: var(--r-sm); font-weight: 700; font-size: var(--fs-400); cursor: pointer;
}
.gta-campo-archivo-input:focus-visible + .gta-campo-archivo-fila .gta-campo-archivo-boton,
.gta-campo-archivo-boton:hover { border-color: var(--teal-500); }
.gta-campo-archivo-nombre { font-size: var(--fs-400); color: var(--tinta); }
/* Q1 chunk 4/4 (TANDA 25-SEP-P23) · texto de ayuda del campo de archivo: se lee como cuerpo
   (explica qué formato sube el alumno), no como etiqueta — sube de 13 a >=14 px. */
.gta-campo-archivo-ayuda { font-size: var(--fs-400); color: var(--ink-500, #667085); font-weight: 400; }

/* ===== Login P01 ===== */
.gta-login { display: grid; gap: var(--sp-4); max-width: 960px; margin: 0 auto; }
@media (min-width: 1025px) { .gta-login { grid-template-columns: 1fr 1.2fr; align-items: stretch; } }
.gta-login__panel {
  background: var(--teal-600); color: #fff; border-radius: var(--r-lg);
  padding: var(--sp-6); display: none; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: var(--sp-4);
}
@media (min-width: 1025px) { .gta-login__panel { display: flex; } }
.gta-login__frase { font-size: var(--fs-700); font-weight: 800; margin: 0; }
.gta-login__ayuda, .gta-login__verificar { text-align: center; font-size: var(--fs-400); }
/* «Entrar con mi DNI», «¿No puedes entrar?», «Actívalo aquí» y la verificación pública: cada uno
   es el ÚNICO contenido pulsable de su párrafo —o sea un control, no un enlace dentro de una
   frase— y medían entre 18 y 23 px de alto en la pantalla por la que ENTRA el becario. */
.gta-login__ayuda a, .gta-login__verificar a, .gta-login__activar a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--touch-min); padding: 0 var(--sp-2);
}
.gta-login__activar { text-align: center; margin: var(--sp-4) 0 var(--sp-2); }

/* ===== Wizard P05/P11 ===== */
.gta-pasos { display: flex; gap: var(--sp-2); list-style: none; padding: 0; margin: var(--sp-4) 0; flex-wrap: wrap; }
.gta-pasos li {
  font-size: var(--fs-300); font-weight: 800; color: var(--secundario);
  background: var(--superficie); border: 1.5px solid var(--borde); border-radius: var(--r-pill); padding: 6px 14px;
}
.gta-pasos li.activo { background: var(--teal-600); border-color: var(--teal-600); color: #fff; }
/* N519 · «dónde estoy», que `.activo` no dice: marca los pasos <= n, así que el actual se
   deduce de la frontera oscuro/claro y en el ÚLTIMO paso no hay frontera. El aro cuelga del
   MISMO atributo que lleva el estado al árbol de accesibilidad, para que no puedan separarse.
   Contraste medido del aro: 5,1:1 contra la píldora que rodea (#FFC24B sobre #0E5B55). */
.gta-pasos li[aria-current="step"] { box-shadow: 0 0 0 3px var(--sol-400); }
.gta-activar, .gta-bienvenida { max-width: 640px; margin: 0 auto; }
.gta-activar__head { text-align: center; }
.gta-salida { margin: var(--sp-4) 0 0; text-align: center; font-size: var(--fs-400); color: var(--secundario); }
.gta-privacidad { margin: var(--sp-3) 0; font-size: var(--fs-400); color: var(--secundario); }
.gta-privacidad summary { font-weight: 700; cursor: pointer; color: var(--teal-600); }
.gta-bienvenida-final { text-align: center; }

/* ===== Dashboard P10 ===== */
.gta-saludo { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.gta-saludo h1 { margin: 0; }

/*
 * TANDA 19-SEP-W · W1 · MODO 8-11 — el inicio infantil son 3 tarjetas grandes y nada más
 * (D-065, encargo §W1): el resto del panel (misión, cofre, stats de racha…) sigue en el HTML
 * sin tocar su PHP, y se oculta aquí por `body.gta-modo-infantil` en vez de duplicar su lógica.
 * El saludo y los banners de beca (vencida / esperando apoderado) SIGUEN visibles: son avisos,
 * no gamificación.
 */
body.gta-modo-infantil .gta-dashboard > *:not(.gta-saludo):not(.gta-banner):not(.gta-inicio-infantil) {
  display: none;
}

/*
 * TANDA 19-SEP-W · W6 · «lectura fácil» 8-11 — Nunito no trae interlineado propio (hereda el
 * 1.55 de `body`, DESIGN.md §2 no pide 1.6 para el aula general); en 8-11 el encargo pide 1.6,
 * así que se declara aparte, scoped a `body.gta-modo-infantil`, sin tocar el 1.55 del resto de
 * bandas. `p`/`.texto-sec` cubren consignas de actividad, resumen de lección y anuncios del muro.
 */
body.gta-modo-infantil { line-height: 1.6; }
body.gta-modo-infantil p,
body.gta-modo-infantil .texto-sec { line-height: 1.6; }
.gta-inicio-infantil { display: grid; gap: var(--sp-3); grid-template-columns: 1fr; margin-bottom: var(--sp-4); }
@media (min-width: 641px) { .gta-inicio-infantil { grid-template-columns: repeat(3, 1fr); } }
.gta-tarjeta-grande {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 140px; padding: var(--sp-4); border-radius: var(--r-lg); text-align: center;
  background: var(--teal-50); color: var(--teal-600); text-decoration: none; font-weight: 800;
  font-size: var(--fs-500); line-height: 1.25; box-shadow: 0 1px 3px rgba(0,0,0,.08);
}
.gta-tarjeta-grande--pri { background: var(--teal-600); color: #fff; }
.gta-tarjeta-grande--vacia { opacity: .7; }
.gta-tarjeta-grande__icono { font-size: 2.25rem; line-height: 1; }

/*
 * TANDA 19-SEP-W · W1 chunk 2 — el botón 🔊 (`gta-voz.js`) y la tarjeta de descanso
 * (`gta-descanso.js`). El botón se pinta SIEMPRE que el script corre (`gtaAula.voz`), así que
 * su tamaño va por la misma vara de 8-11 que el resto del modo infantil: ≥ 44px de lado.
 */
.gta-voz-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin-bottom: var(--sp-2);
  border: none; border-radius: var(--r-pill); background: var(--teal-50);
  color: var(--teal-600); font-size: 1.25rem; cursor: pointer;
}
.gta-voz-btn--activo { background: var(--teal-600); color: #fff; }
/*
 * TANDA 19-SEP-Z · Z2 — lectura guiada 8-11: una pregunta por pantalla (`gta-lg-paginado.js`
 * las esconde con esta clase; sin JS, todas quedan visibles y el alumno las responde de corrido).
 */
.gta-lg-preguntas[data-gta-lg-paginado="1"] .gta-lg-pregunta.gta-lg-pregunta--oculta { display: none; }
.gta-lg-preguntas__nav { display: flex; justify-content: space-between; gap: var(--sp-2); margin-top: var(--sp-2); }
.gta-lg-preguntas__paso { text-align: center; color: var(--secundario); }
.gta-descanso-card {
  position: fixed; left: var(--sp-3); right: var(--sp-3); bottom: var(--sp-3); z-index: 40;
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  background: var(--sol-50, #fff8e1); border-radius: var(--r-lg); box-shadow: 0 4px 14px rgba(0,0,0,.18);
  font-weight: 700; font-size: var(--fs-500);
}
.gta-descanso-card__icono { font-size: 1.75rem; line-height: 1; }
.gta-descanso-card__texto { flex: 1; }
.gta-descanso-card__cerrar {
  min-height: 44px; padding: 0 var(--sp-4); border: none; border-radius: var(--r-pill);
  background: var(--teal-600); color: #fff; font-weight: 800; cursor: pointer;
}
/*
 * El «¡Tienes un premio! 🎁» del saludo. SE LLAMABA `.gta-burbuja`, igual que la burbuja de un
 * mensaje del hilo —dos componentes distintos con el mismo nombre—, y como el bloque de la
 * burbuja del hilo va DESPUÉS en el fichero, era el que ganaba: medido en Chromium a 390 px,
 * este aviso salía BLANCO con borde gris y esquina de 14 px, o sea con la pinta de una tarjeta
 * cualquiera, en vez del amarillo sol en forma de píldora que declara aquí. Justo el elemento
 * cuyo único trabajo es que se vea que hay un premio esperando.
 *
 * Apareció al escribir el guardián de esta tanda: el aserto buscaba la regla de la burbuja del
 * hilo, encontró ésta y se cayó. Es la lección de las 16:31 por el lado del CSS — antes de tocar
 * algo con nombre propio, cuenta cuántos hermanos tiene ese nombre.
 */
.gta-saludo__premio {
  display: inline-block; background: var(--sol-400); color: var(--tinta);
  font-weight: 800; border-radius: var(--r-pill); padding: 6px 16px; text-decoration: none;
}
/*
 * N85 · «Ya está dentro» — el panel del primer día. Sin navbar ni tabbar (gta_sin_navbar), así
 * que la tarjeta se centra sola y no se estira a todo lo ancho de un escritorio: una sola cosa
 * que hacer se lee mejor en una columna que en una pancarta.
 */
.gta-primer-dia { max-width: 30rem; margin: var(--sp-6) auto; }
.gta-primer-dia__card { text-align: center; padding: var(--sp-6); }
.gta-primer-dia__empezar { display: inline-block; margin-top: var(--sp-4); }
.gta-primer-dia__pie { margin-top: var(--sp-4); }
/*
 * N86 · «Instalar la app» — los tres pasos de iPhone con su dibujo (GTA_Instalacion::pasos_ios).
 *
 * El número lo pone un contador y no el marcador nativo del <ol>: con un dibujo de 40 px dentro
 * del <li>, el «1.» de serie se alinea con el borde de la caja y acaba leyéndose en diagonal
 * respecto al texto. Un paso mal numerado en un gesto de tres es un gesto que no se completa.
 *
 * La fila es flex y no grid porque el dibujo mide lo que mide y el texto es el que se envuelve:
 * `flex: none` en las dos piezas de los lados, y el <span> con `min-width: 0` para que pueda
 * partirse en un teléfono estrecho en vez de estirar la tarjeta y sacarla de la pantalla.
 */
.gta-instalar__pasos {
  list-style: none; margin: var(--sp-4) 0; padding: 0;
  display: grid; gap: var(--sp-3); counter-reset: gta-paso;
}
.gta-instalar__pasos li { display: flex; align-items: center; gap: var(--sp-3); counter-increment: gta-paso; }
.gta-instalar__pasos li::before {
  content: counter(gta-paso); flex: none;
  width: 1.5rem; height: 1.5rem; border-radius: var(--r-pill);
  background: var(--teal-100); color: var(--teal-700);
  font-weight: 800; font-size: 0.8rem;
  display: flex; align-items: center; justify-content: center;
}
/* currentColor: el dibujo hereda de aquí, y de ningún sitio más. */
.gta-instalar__dibujo { flex: none; color: var(--teal-600); }
.gta-instalar__pasos li span { min-width: 0; }
.gta-instalar__botones { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-4); }
.gta-continuar { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; }
.gta-continuar__info { flex: 1; min-width: 220px; }
.gta-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); margin-bottom: var(--sp-4); }
.gta-stat {
  background: var(--superficie); border-radius: var(--r-md); box-shadow: var(--sombra-card);
  padding: var(--sp-3); text-align: center; text-decoration: none; color: var(--tinta);
  display: flex; flex-direction: column; gap: 2px; min-height: var(--touch-min);
}
.gta-stat strong { font-variant-numeric: tabular-nums; font-size: var(--fs-700); }
.gta-stat--urgente strong { color: var(--coral-600); }
.gta-stat__icono { font-size: 1.3rem; }
/* K2.7 (TANDA 14-SEP-K) · el nombre de la siguiente insignia no cabe en el tamaño grande de un
   número («Constancia de acero»): baja a fs-500, y el «N/16» de antes no desaparece, se muda
   debajo en pequeño — sigue siendo la misma cuenta del esfuerzo, ya no es lo primero que se lee. */
.gta-stat--insignia strong { font-size: var(--fs-500); line-height: 1.2; }
.gta-stat__marcador { font-size: var(--fs-300); color: var(--secundario); font-variant-numeric: tabular-nums; }
/* E2.3 (TANDA 13-SEP-E) · la fecha larga («hasta el 14 de marzo de 2027») no cabe en una de
   las tres columnas estrechas a 390 px con el tamaño grande de las otras dos cifras: a móvil
   la tarjeta Beca se estira a lo ancho y baja el tamaño para que la fecha quede en una línea;
   a partir de 641 px ya hay hueco de sobra en las tres columnas iguales. */
@media (max-width: 640px) {
  .gta-stats { grid-template-columns: repeat(2, 1fr); }
  .gta-stat--beca { grid-column: 1 / -1; }
  .gta-stat--beca strong { font-size: var(--fs-500); white-space: nowrap; }
}
.gta-seccion { margin: var(--sp-5) 0; }
.gta-fila-cards { display: grid; gap: var(--sp-3); grid-template-columns: 1fr; }
/* E2.2 (TANDA 13-SEP-E) · eran 2 columnas para 3 tarjetas fijas: 2 arriba y 1 huérfana sola
   en su fila. Con exactamente 3 columnas no sobra ninguna, en vez de acotar el caso a mano
   como con `.gta-grid-cursos--dos`. */
@media (min-width: 641px) { .gta-fila-cards { grid-template-columns: repeat(3, 1fr); } }
.gta-card-enlace { text-decoration: none; color: var(--tinta); display: block; }
.gta-card-enlace:hover { box-shadow: var(--sombra-flotante); }
/* J2.5 (TANDA 13-SEP-J) · la señal de «esto se toca» que le faltaba a las tres tarjetas de
   esta fila (antes solo el hover lo delataba, y eso no existe en pantalla táctil). */
.gta-card-enlace__ir {
  display: inline-flex; align-items: center; gap: 4px; margin-top: var(--sp-2);
  font-weight: 700; color: var(--teal-600);
}

/* ===== Cards de curso — DESIGN §5.2 ===== */
.gta-grid-cursos { display: grid; gap: var(--sp-3); }
/* P2R · R4 — `.card` trae `margin-bottom: var(--sp-4)` (16px) para cuando vive suelta, pero
   dentro de esta rejilla el `gap` de arriba YA separa las tarjetas: las dos sumadas dejaban 28px
   entre la última tarjeta de curso y la fantasma de abajo en vez de los 12px del gap, empujando
   la fantasma más cerca de la burbuja fija de Beki de lo necesario. */
.gta-grid-cursos > .card { margin-bottom: 0; }
@media (min-width: 641px) { .gta-grid-cursos { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1025px) { .gta-grid-cursos { grid-template-columns: repeat(3, 1fr); } }
/* D2.3 (TANDA 13-SEP-D) · con 4 tarjetas, 3 columnas dejan una huérfana en la segunda fila:
   se pinta a 2 (2+2, fila completa). A 641-1024 ya es 2 columnas y no hace falta el modificador. */
@media (min-width: 1025px) { .gta-grid-cursos--dos { grid-template-columns: repeat(2, 1fr); } }
.gta-card-curso { position: relative; text-decoration: none; color: var(--tinta); display: block; transition: box-shadow .15s, transform .15s; }
.gta-card-curso:hover { box-shadow: var(--sombra-flotante); transform: scale(1.01); }
.gta-cinta {
  position: absolute; top: 12px; right: 12px; background: var(--sol-400); color: var(--tinta);
  font-size: var(--fs-300); font-weight: 800; border-radius: var(--r-pill); padding: 3px 10px;
  display: inline-flex; align-items: center; gap: 4px;
}
/* TANDA 25-SEP-P28 · A2 — la etiqueta del curso abierto va a la izquierda: nunca se pisa con la
   cinta de Bonus (derecha) cuando un curso trae las dos. */
.gta-cinta--abierto {
  left: 12px; right: auto; background: var(--superficie); color: var(--tinta);
  border: 1px solid var(--borde); font-weight: 700;
}
/* P2R R7 chunk 2 (TANDA 22-SEP-P2R) · «Tu racha abre premios» (`png/MisCursos.png`): la tarjeta
   fantasma de la rejilla se retiró (D2.4 la puso ahí) y esto la reemplaza como caja aparte,
   a todo el ancho, bajo la rejilla de cursos. En escritorio el cuerpo y los hitos van lado a
   lado; en celular se apilan. */
.gta-racha-premios { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); }
.gta-racha-premios__cuerpo { display: flex; align-items: flex-start; gap: var(--sp-3); flex: 1 1 320px; min-width: 0; }
.gta-racha-premios__icono { font-size: 32px; line-height: 1; flex: none; }
.gta-racha-premios__texto { min-width: 0; }
.gta-racha-premios__texto h2 { margin: 0 0 var(--sp-1); }
.gta-racha-premios__texto .gta-progreso { max-width: 320px; }
.gta-racha-premios__hitos { display: flex; gap: var(--sp-2); list-style: none; margin: 0; padding: 0; flex: none; }
/* P2R R8 (TANDA 22-SEP-P2R) · tarjeta redonda: icono en círculo arriba, nombre y «cuándo»
   centrados debajo, como `png/MisCursos.png` (antes era icono+texto en fila). */
.gta-racha-premios__hito {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: var(--superficie); border: 1.5px solid var(--borde); border-radius: var(--r-md);
  padding: var(--sp-3); text-align: center; min-width: 140px;
}
.gta-racha-premios__hito-icono {
  display: grid; place-items: center; width: 48px; height: 48px; margin-bottom: var(--sp-1);
  border-radius: 50%; background: var(--sol-100); font-size: 22px;
}
.gta-racha-premios__hito-nombre { display: block; font-weight: 700; }
@media (max-width: 640px) {
  .gta-racha-premios__hitos { width: 100%; }
  .gta-racha-premios__hito { flex: 1 1 0; min-width: 0; }
}
/* D1.3 (TANDA 13-SEP-D) · la portada del curso (imagen real o el ícono de respaldo, sin
   bitmap: gta_curso_icono_svg()), la próxima lección y el botón de acción — hoy la tarjeta
   era título + barra y nada más. */
.gta-card-curso__portada {
  position: relative; display: flex; align-items: center; justify-content: center; overflow: hidden;
  height: 100px; margin: 0 0 var(--sp-3); border-radius: var(--r-md); background: var(--teal-50);
  color: var(--teal-500);
}
.gta-card-curso__portada img { width: 100%; height: 100%; object-fit: cover; }
/* P2R R8 chunk 5 (TANDA 22-SEP-P2R) · pill de estado y badge de % circular sobre la portada
   (`png/MisCursos.png`): mismo `$grupo`/`$c['pct']` que ya trae la tarjeta, sin consulta nueva. */
.gta-card-curso__estado {
  position: absolute; top: var(--sp-2); left: var(--sp-2); z-index: 1;
  display: inline-flex; align-items: center; gap: 4px; background: #fff; color: var(--tinta);
  font-size: var(--fs-300); font-weight: 700; border-radius: var(--r-pill); padding: 4px 10px;
}
.gta-card-curso__pct {
  position: absolute; bottom: var(--sp-2); right: var(--sp-2); z-index: 1;
  width: 48px; height: 48px; display: grid; place-items: center; background: #fff;
  border-radius: 50%; box-shadow: var(--sombra-card);
}
.gta-card-curso__pct svg { position: absolute; inset: 0; }
.gta-card-curso__pct b { position: relative; font-size: var(--fs-300); font-weight: 800; color: var(--tinta); }
/* P2R R8 chunk 11 (TANDA 22-SEP-P2R) · caja «SIGUIENTE LECCIÓN» de `png/MisCursos.png`, en vez
   del párrafo suelto «Próxima: …». */
.gta-card-curso__proxima {
  margin: 0 0 var(--sp-2); background: var(--fondo); border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
}
.gta-card-curso__proxima-etiqueta {
  margin: 0; font-size: var(--fs-300); font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--secundario);
}
.gta-card-curso__proxima-titulo { margin: 2px 0 0; font-weight: 700; }
.gta-card-curso__proxima-reloj { margin: 2px 0 0; }
.gta-card-curso__accion { margin-top: var(--sp-2); width: 100%; }
/* K2.3 (TANDA 14-SEP-K) · con 1-2 cursos, tarjeta ANCHA: portada a la izquierda, texto y
   botón a la derecha, en vez de la columna vertical de siempre (que a 1280 deja una tarjeta
   angosta sola en su fila). A 390 sigue en columna: no hay ancho para dos mitades. */
@media (min-width: 641px) {
  .gta-grid-cursos--ancha .gta-card-curso {
    display: flex; align-items: center; gap: var(--sp-4);
  }
  .gta-grid-cursos--ancha .gta-card-curso__portada {
    flex: 0 0 180px; height: 110px; margin: 0;
  }
  .gta-grid-cursos--ancha .gta-card-curso__cuerpo { flex: 1; min-width: 0; }
  .gta-grid-cursos--ancha .gta-card-curso__accion { width: auto; }
}

/* ===== Logros P17 ===== */
.gta-tabs { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.gta-tabs a {
  text-decoration: none; font-weight: 800; color: var(--secundario);
  padding: 10px 18px; border-radius: var(--r-pill); min-height: var(--touch-min); display: inline-flex; align-items: center;
}
.gta-tabs a.activo { background: var(--teal-600); color: #fff; }
.gta-grid-insignias { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
@media (min-width: 641px) { .gta-grid-insignias { grid-template-columns: repeat(4, 1fr); } }
/* AVISO 24-sep punto 8 · rejilla circular de R26: 2 columnas a 390, 4 desde 641 (antes fija a 4, con scroll horizontal). */
.gta-grid-insignias-circular { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px 10px; }
@media (min-width: 641px) { .gta-grid-insignias-circular { grid-template-columns: repeat(4, 1fr); } }
/* AVISO 24-sep D6 · hoja P15: «Cómo se ganan»/«En qué los usas» eran un grid de 2 columnas fijo
   sin este breakpoint, así que a 390px cada tarjeta quedaba con ~120px y sus filas (icono + texto
   + cifra en un solo `flex` sin min-width:0) forzaban el ancho de página a 465px (scroll_ok en
   rojo en AlumnoPremios/PrimariaPremios). Apilado a 1 columna hasta 641px, como el resto de
   rejillas de esta pantalla. */
.gta-como-ganan { display: grid; grid-template-columns: 1fr; gap: 20px; }
@media (min-width: 641px) { .gta-como-ganan { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Mismo defecto en las 3 tarjetas KPI de la cabecera (Bekis/racha/insignias): `repeat(3,1fr)`
   sin minmax(0,…) dejaba que el contenido de cada tarjeta (icono fijo + texto) empujara el
   ancho de la página a 448px en vez de los 358 disponibles a 390px de viewport. */
.gta-logros-kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
/* D1 (TANDA 24SEP-P15B) · «Invita a un compañero», «Insignias premium» y «Cómo se ganan» no
   están en AlumnoPremios.html/PrimariaPremios.html (proto 1000px): van detrás de este
   <details> para que /logros/ no mida 2122px de puro contenido que el prototipo no pinta. */
.gta-logros-extra {
  margin-bottom: var(--sp-3); background: var(--superficie); border-radius: var(--r-lg);
  box-shadow: var(--sombra-card); padding: 0 var(--sp-5);
}
.gta-logros-extra > summary {
  list-style: none; cursor: pointer; font-weight: 700; font-family: Sora, sans-serif;
  font-size: 15px; padding: var(--sp-3) 0; min-height: var(--touch-min); display: flex; align-items: center;
}
.gta-logros-extra > summary::-webkit-details-marker { display: none; }
.gta-logros-extra > summary::after { content: '▾'; margin-left: auto; }
.gta-logros-extra[open] > summary::after { content: '▴'; }
.gta-logros-extra > summary + * { margin-top: 0; }
.gta-logros-extra[open] { padding-bottom: var(--sp-5); }
.gta-logros-extra .card { box-shadow: none; padding: 0; margin-bottom: 0; }
.gta-insignia {
  background: var(--superficie); border-radius: var(--r-md); box-shadow: var(--sombra-card);
  padding: var(--sp-4); text-align: center;
}
.gta-insignia.bloqueada { opacity: .55; filter: grayscale(1); }
.gta-insignia__icono { font-size: 2rem; display: block; margin-bottom: var(--sp-2); }
.gta-racha { text-align: center; }
/* O3 (N245) · el enlace de referido: se selecciona entero de un toque, sin JS. */
.gta-referido__enlace { display: block; word-break: break-all; user-select: all; -webkit-user-select: all; padding: .5rem .75rem; border-radius: 8px; background: var(--teal-50); font-size: .95rem; }
.gta-racha__numero { font-size: 4rem; font-weight: 800; margin: 0; color: var(--teal-600); font-variant-numeric: tabular-nums; }
.gta-calendario { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; max-width: 420px; margin: var(--sp-4) auto; }
.gta-calendario .dia {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border-radius: 8px; background: var(--teal-50); font-size: var(--fs-300); font-weight: 700;
}
.gta-calendario .dia.valido { background: var(--teal-500); color: #fff; }
.gta-calendario .dia.protegido { background: var(--sol-400); }
.gta-calendario .dia.hoy { box-shadow: 0 0 0 2px var(--teal-700); }
.gta-colapsable { text-align: left; max-width: 480px; margin: 0 auto var(--sp-4); }
.gta-colapsable summary { font-weight: 700; color: var(--teal-600); cursor: pointer; }
.gta-hitos { list-style: none; padding: 0; text-align: left; max-width: 480px; margin: 0 auto; }
.gta-hitos li { border-left: 3px solid var(--borde); padding: var(--sp-2) var(--sp-3); }
.gta-hitos li.logrado { border-color: var(--sol-400); }
.gta-hitos a { text-decoration: none; color: var(--tinta); }

/* ===== Recompensas P18 ===== */
.gta-grid-recompensas { display: grid; gap: var(--sp-3); }
@media (min-width: 641px) { .gta-grid-recompensas { grid-template-columns: repeat(2, 1fr); } }
.gta-recompensa--disponible { border: 2px solid var(--sol-400); }
.gta-recompensa--logrado { border: 2px solid var(--teal-500); }
/* N189 · la tarjeta es del HITO y puede traer más de un premio (el de 30 días da insignia
   Y curso bonus): los premios son una lista, no un párrafo. */
.gta-hito-premios { list-style: none; padding: 0; margin: 0 0 var(--sp-2); }
.gta-hito-premios li { padding: 2px 0; font-weight: 600; }
.gta-hito-premios li + li { border-top: 1px solid var(--borde); padding-top: 6px; margin-top: 4px; }
.gta-radio-card { display: flex; gap: 10px; align-items: center; border: 1.5px solid var(--borde); border-radius: var(--r-sm); padding: 10px 14px; margin-bottom: var(--sp-2); cursor: pointer; font-weight: 400; }
.gta-radio-card:has(input:checked) { border-color: var(--teal-500); background: var(--teal-50); }
.gta-como-funciona ol { padding-left: 20px; }

/* ===== Guías / certificados ===== */
.gta-grid-guias, .gta-grid-certs { display: grid; gap: var(--sp-3); }
@media (min-width: 641px) { .gta-grid-guias, .gta-grid-certs { grid-template-columns: repeat(2, 1fr); } }
.gta-card-guia { text-decoration: none; color: var(--tinta); display: block; }
.gta-card-guia:hover { box-shadow: var(--sombra-flotante); }

/* H10 (TANDA 23-SEP-P4H) · /certificados/ pasó al sistema `.ap-cert-hero`/`.ap-cert-camino__*`
   de `aula-premium.css`. `.gta-grid-certs` de arriba sigue viva: la usa `mi-beca.php`. Los
   íconos del copiar/compartir siguen aquí porque su clase de comportamiento (`.gta-copiar`,
   `.gta-compartir`) no cambió de fichero al portar sólo la vista de certificados. */
.gta-compartir__icono, .gta-copiar__icono { display: inline-flex; vertical-align: -3px; }

/* ===== Datos / mi beca ===== */
.gta-datos { margin: 0; }
.gta-datos > div { display: flex; justify-content: space-between; gap: var(--sp-3); padding: 10px 0; border-bottom: 1px solid var(--borde); }
.gta-datos > div:last-child { border-bottom: 0; }
/*
 * La ÚNICA excepción a la regla global de `.gta-main`, y la única pantalla de las catorce que
 * se movía con ella. El motivo es que este par ya estaba medio tratado: el `dd` de abajo lleva
 * `anywhere` + `min-width: 0` desde las 16:44, así que al heredar el `dt` la regla global, los
 * dos lados del flex encogían su ancho mínimo a la vez y el reparto se corría hacia el `dd`.
 * Medido a 320 px: el `dt` de «Institución» pasaba de 83 px a 43 y la etiqueta se partía en
 * «Instit|ución»; «Nombre» en «Nomb|re»; «Constancia de estudios» en «Const|ancia … estudi|os».
 *
 * Y partirlas es un empeoramiento sin nada a cambio: los TRECE `dt` son cadenas que escribe el
 * portal («Nombre», «Código de beca», «Días restantes»…), nunca una persona, así que jamás
 * pierden sus espacios y no hay desbordamiento del que salvarlas. `normal` es lo que había
 * antes de la regla global, o sea que esta línea repone el comportamiento, no lo inventa.
 *
 * Comprobado: con esta excepción el delta de layout de `/mi-beca/` vuelve a CERO en los cinco
 * anchos, y las palabras partidas de las etiquetas quedan en las MISMAS que ya había sin la
 * regla (3 a 320 px, 2 a 390) — que son de estrechez heredada y no de este trozo.
 */
.gta-datos dt { font-weight: 700; color: var(--secundario); overflow-wrap: normal; }
/*
 * El `dd` de «Nombre» lleva el `display_name`, y ése lo teclea el propio alumno en el asistente
 * de activación, en dos `<input type="text">` SIN `maxlength` («Nombres» y «Apellidos»). Medido a
 * 320 px con un nombre pegado de 204 caracteres: la página se iba a 1.784 px y se desplazaba de
 * lado entera. `min-width: 0` además del wrap porque el padre es flex, y un hijo de flex no
 * encoge por debajo de su ancho mínimo de contenido sin él.
 */
.gta-datos dd { margin: 0; text-align: right; overflow-wrap: anywhere; min-width: 0; }
/*
 * N187 · La galería de avatares. Antes cada clase `--buho-1`, `--gato-1`… era SÓLO un color de
 * fondo: doce discos lisos, indistinguibles, sin dibujo. Ahora el dibujo lo pone el SVG de
 * `gta_avatar_svg()` (que lleva su propio fondo de marca) y el CSS sólo se ocupa del marco de
 * «éste es el mío» y del nombre debajo. Por eso desaparecen las doce reglas de color.
 */
.gta-avatares { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.gta-avatar-op {
  position: relative; cursor: pointer; display: flex; flex-direction: column;
  align-items: center; gap: 4px; width: 76px;
}
.gta-avatar-op input { position: absolute; opacity: 0; }
.gta-avatar {
  display: block; width: 52px; height: 52px; border-radius: 50%;
  border: 2.5px solid transparent; line-height: 0;
}
.gta-avatar .gta-avatar-dib { display: block; border-radius: 50%; }
.gta-avatar-op__nombre { font-size: 0.78rem; color: var(--secundario); text-align: center; line-height: 1.15; }
.gta-avatar-op:has(input:checked) .gta-avatar { border-color: var(--teal-600); }
.gta-avatar-op:has(input:checked) .gta-avatar-op__nombre { color: var(--teal-700); font-weight: 700; }
/* El foco de teclado tiene que verse: el radio de verdad es invisible a propósito. */
.gta-avatar-op:has(input:focus-visible) .gta-avatar { outline: 3px solid var(--teal-500); outline-offset: 2px; }
/*
 * Q5 · D-067 §2 — el avatar/marco PREMIUM se distingue en la galería aunque no esté elegido: un
 * borde dorado en vez del transparente de los doce libres, para que la etiqueta «premium» del
 * nombre no sea la única pista de que esta opción se canjeó.
 */
.gta-avatar-op--premium .gta-avatar { border-color: #E0B667; }
.gta-avatar-op--premium:has(input:checked) .gta-avatar { border-color: var(--teal-600); }
.gta-avatares-premium__aviso { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* El avatar dentro del enlace «Mi beca» de la barra: la única cara del becario en toda pantalla. */
.gta-navbar__mibeca { display: inline-flex; align-items: center; gap: 6px; }
.gta-navbar__mibeca .gta-avatar-dib { border-radius: 50%; flex: 0 0 auto; }

/* ===== Trámites del alumno (pausar la beca) ===== */
/*
 * Una fila por solicitud, en columna y no en tabla: a 320 px una tabla de cuatro columnas
 * empujaría la página, que es justo el desbordamiento que se cerró el 11-ago. El textarea y el
 * select heredan el estilo de formulario del portal; sólo hace falta que ocupen el ancho, que
 * es lo que un celular necesita para que el pulgar acierte.
 */
#gta-form-pausa textarea, #gta-form-pausa select { width: 100%; }
#gta-form-pausa button { min-height: var(--touch-min); }
.gta-tramites { list-style: none; margin: 0; padding: 0; }
.gta-tramite {
  display: grid; gap: 2px; padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--borde); font-size: var(--fs-400);
  overflow-wrap: anywhere;
}
.gta-tramite:last-child { border-bottom: 0; }
.gta-tramite__que { font-weight: 700; }
.gta-tramite__cuando, .gta-tramite__nota { color: var(--secundario); }
.gta-tramite__estado { font-weight: 700; }
.gta-tramite--aplicada .gta-tramite__estado, .gta-tramite--aprobada .gta-tramite__estado { color: var(--exito); }
.gta-tramite--rechazada .gta-tramite__estado { color: var(--secundario); }
.gta-tramite--fallida .gta-tramite__estado { color: var(--error); }
/* N356 · El trámite del que habla la campana: llega por ?tramite=<id>#tramite-<id>. El resalte
   es de apoyo, no la única señal — el cartel de arriba lo dice con palabras y en role=status. */
.gta-tramites__senalado { margin: 0 0 var(--sp-2); padding: var(--sp-2) var(--sp-3); border-left: 4px solid var(--sol-400); background: var(--sol-100); border-radius: var(--r-sm); }
.gta-tramite--senalado { border-left: 4px solid var(--sol-400); background: var(--sol-100); padding-left: var(--sp-3); }

/* ===== Estados vacíos / Beki ===== */
.gta-vacio { text-align: center; padding: var(--sp-6); }
.gta-vacio .gta-beki { margin-bottom: var(--sp-3); }

/* ===== Verificar (registro formal) ===== */
.gta-registro-formal { max-width: 640px; margin: 0 auto; }
.gta-verificar-ok { border-left: 6px solid var(--exito); }
.gta-verificar-no { border-left: 6px solid var(--secundario); }
.gta-verificar-revocado { border-left: 6px solid var(--sol-400); }
.gta-verificar-pie { text-align: center; font-size: var(--fs-400); }
/* Único enlace de la pantalla 10 del guion —la que abre quien verifica un certificado desde
   fuera, a menudo desde el teléfono y sin cuenta— y medía 140x20. Es el único contenido
   pulsable de su párrafo, o sea un control. */
.gta-verificar-pie a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--touch-min); padding: 0 var(--sp-2);
}

/* ===== Player ===== */
.gta-player-frame { position: relative; aspect-ratio: 16 / 9; border-radius: var(--r-md); overflow: hidden; background: var(--tinta); margin-bottom: var(--sp-3); }
.gta-player-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* H7 chunk 5/N (TANDA 22-SEP-P4G/23-SEP-P4H) · el reproductor de `Leccion.html` lleva 22px de
   radio (`--ap-r-lg`), más redondeado que el `--r-md` de base. Escopado a `body.single-lesson`
   (WP lo añade solo en la lección) y no al selector base: la misma clase `.gta-player-frame`
   viste también el video de una guía (`single-gta_guia.php`), fuera de este chunk. */
body.single-lesson .gta-player-frame { border-radius: 22px; }

/* ===== Documentos legales ===== */
/*
 * `overflow-wrap: anywhere` no es un adorno: un documento legal está lleno de cadenas que el
 * navegador NO parte por su cuenta —el correo del canal oficial, las líneas de firma hechas de
 * guiones bajos seguidos, una URL de política— y una sola de ellas empuja la PÁGINA entera.
 * Medido a 320 px en /reglamento/ y /reglamento-publico/: desbordaban 56 px, y a 360 px, 16.
 * `anywhere` en vez de `break-word` porque también encoge el ancho mínimo del bloque, que es lo
 * que hace que la tarjeta que lo contiene deje de empujar a su vez.
 */
.gta-doc-legal, .gta-doc-scroll { font-size: var(--fs-400); color: var(--tinta); overflow-wrap: anywhere; }
.gta-doc-scroll { max-height: 320px; overflow-y: auto; border: 1.5px solid var(--borde); border-radius: var(--r-sm); padding: var(--sp-3); margin-bottom: var(--sp-3); }
.gta-tyc-resumen ol { padding-left: 22px; }
.gta-tyc-resumen li { margin-bottom: 6px; }
/*
 * El documento se pinta desde su Markdown (GTA_Doc_Markdown), así que dentro de .gta-doc-legal
 * hay ahora listas, encabezados, citas y tablas de verdad. Los anexos son formularios de
 * llenar a mano: la segunda columna va vacía a propósito y se ve como la casilla que es.
 */
.gta-doc-legal h2, .gta-doc-scroll h2 { font-size: var(--fs-500); margin: var(--sp-4) 0 var(--sp-2); }
.gta-doc-legal h3, .gta-doc-scroll h3,
.gta-doc-legal h4, .gta-doc-scroll h4 { font-size: var(--fs-400); margin: var(--sp-3) 0 var(--sp-2); }
.gta-doc-legal ul, .gta-doc-scroll ul,
.gta-doc-legal ol, .gta-doc-scroll ol { padding-left: 20px; margin: var(--sp-2) 0; }
.gta-doc-legal li, .gta-doc-scroll li { margin-bottom: 6px; }
.gta-doc-legal blockquote, .gta-doc-scroll blockquote {
  margin: var(--sp-3) 0; padding-left: var(--sp-3);
  border-left: 3px solid var(--borde); color: var(--secundario);
}
/*
 * `table-layout: fixed` + `width: 100%` no es estética: sin ellos la tabla del Anexo País pide
 * el ancho de su celda más larga y vuelve a empujar la página a 320 px, que es justo el
 * desbordamiento que se cerró a las 04:03. Medido en demo/30-portal-anchos-chicos.mjs.
 */
.gta-doc-tabla {
  width: 100%; table-layout: fixed; border-collapse: collapse;
  margin: var(--sp-3) 0; font-size: var(--fs-300);
}
.gta-doc-tabla td { border: 1.5px solid var(--borde); padding: var(--sp-2); vertical-align: top; }
.gta-doc-tabla td:empty { min-width: 0; }
.gta-doc-tabla td:empty::after { content: ""; display: block; min-height: 22px; }

/* ===== 403 / 404 / mantenimiento ===== */
.gta-403, .gta-404, .gta-mantenimiento { text-align: center; padding: var(--sp-7) var(--sp-4); max-width: 560px; margin: 0 auto; }

/* ===== Chat Beki (P23) — DESIGN §4.6 ===== */
.gta-chat-burbuja {
  /* `bottom` derivado de la tabbar y no un 72 escrito a mano: la burbuja se levanta lo que
     mide la tabbar más el hueco mínimo entre destinos táctiles (DESIGN §8). El 72 anterior
     daba por hecha una tabbar de 64 y la de verdad mide 65. */
  position: fixed; right: 16px; bottom: calc(var(--tabbar-h) + var(--burbuja-hueco)); z-index: 90;
  width: 56px; height: 56px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--teal-600); color: #fff; font-size: 1.6rem;
  box-shadow: var(--sombra-flotante); display: flex; align-items: center; justify-content: center;
}
/* La cara de Beki dentro del círculo y de la cabecera: sin medida, el SVG llega a tamaño natural (210 px). */
.gta-chat-burbuja img { width: 38px; height: auto; }
.gta-chat-head img { width: 34px; height: auto; }
@media (min-width: 641px) { .gta-chat-burbuja { bottom: var(--sp-5); } }
.gta-chat-badge {
  position: absolute; bottom: -4px; right: -6px;
  background: var(--exito); color: #fff; font-size: 9px; font-weight: 800;
  border-radius: var(--r-pill); padding: 2px 6px; border: 2px solid var(--fondo);
}
.gta-chat-panel {
  position: fixed; right: 16px; bottom: 140px; z-index: 95;
  width: min(360px, calc(100vw - 32px)); height: min(520px, calc(100vh - 120px));
  background: var(--superficie); border-radius: var(--r-lg); box-shadow: var(--sombra-flotante);
  display: flex; flex-direction: column; overflow: hidden;
}
/*
 * El `display: flex` de arriba anulaba el atributo `hidden` del panel: la regla del
 * navegador para [hidden] es `display: none` con especificidad mínima, así que cualquier
 * `display` de autor la gana. Consecuencia real: Beki aparecía abierto en cada carga
 * tapando el reproductor de la lección, y el botón de cerrar no hacía nada visible aunque
 * el JavaScript sí ponía panel.hidden = true. Detectado con la validación en navegador:
 * el DOM decía oculto y los píxeles decían visible.
 */
.gta-chat-panel[hidden] { display: none; }
@media (min-width: 641px) { .gta-chat-panel { bottom: 88px; } }
.gta-chat-head {
  background: var(--teal-600); color: #fff; padding: 12px 14px;
  display: flex; align-items: center; gap: 10px; font-size: 1.3rem;
  /* La cabecera cierra el panel (ver chat.js), así que tiene que parecer pulsable: antes
     era la zona más grande del widget, no hacía nada y quien fallaba la ✕ caía aquí. */
  cursor: pointer;
}
.gta-chat-head:hover { background: var(--teal-700); }
.gta-chat-head div { display: flex; flex-direction: column; line-height: 1.2; flex: 1; }
.gta-chat-head strong { font-size: var(--fs-500); }
.gta-chat-head span { font-size: var(--fs-300); opacity: .85; }
.gta-chat-cerrar { background: none; border: 0; color: #fff; font-size: 1rem; cursor: pointer; min-width: var(--touch-min); min-height: var(--touch-min); }
.gta-chat-mensajes { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.gta-chat-msj {
  max-width: 85%; padding: 8px 12px; border-radius: var(--r-md); font-size: var(--fs-400); white-space: pre-wrap;
}
.gta-chat-msj--usuario { align-self: flex-end; background: var(--teal-50); }
.gta-chat-msj--beki { align-self: flex-start; background: var(--fondo); border: 1px solid var(--borde); }
.gta-chat-msj.escalado { background: var(--sol-100); border-color: var(--sol-400); font-weight: 700; }
.gta-chat-msj.escribiendo { color: var(--secundario); font-style: italic; }
.gta-chat-sugerencias { display: flex; gap: 6px; padding: 0 12px 8px; flex-wrap: wrap; }
.gta-chat-sugerencias button {
  background: var(--teal-50); border: 1px solid var(--borde); border-radius: var(--r-pill);
  font-family: var(--font); font-size: var(--fs-300); font-weight: 700; color: var(--teal-600);
  padding: 6px 10px; cursor: pointer;
}
.gta-chat-form { display: flex; gap: 8px; padding: 8px 12px; border-top: 1px solid var(--borde); }
.gta-chat-form input { flex: 1; min-height: 44px; }
.gta-chat-form .btn-pri { min-height: 44px; padding: 6px 16px; }
.gta-chat-aviso { margin: 0; padding: 0 12px 8px; font-size: 11px; color: var(--secundario); text-align: center; }

/* ===== Footer ===== */
/* La reserva de abajo despeja la tabbar; la de `.gta-con-beki` despeja ADEMÁS la burbuja, que
   está más alta. Las dos salen de los tokens de §2, no de números escritos aquí. */
.gta-footer {
  text-align: center; color: var(--secundario); font-size: var(--fs-300);
  padding: var(--sp-5) var(--sp-4) calc(var(--sp-5) + var(--tabbar-h));
}
/* Sin tabbar (≥641 px) no hay nada que despejar salvo, si está, la burbuja. */
@media (min-width: 641px) { .gta-footer { padding-bottom: var(--sp-5); } }

/* `gta-con-beki` la pone functions.php en el MISMO sitio que decide encolar el chat, para que
   la reserva no pueda desincronizarse de la existencia de la burbuja. */
.gta-con-beki .gta-footer {
  padding-bottom: calc(var(--sp-5) + var(--tabbar-h) + var(--burbuja-hueco) + var(--burbuja-d));
}
@media (min-width: 641px) {
  .gta-con-beki .gta-footer { padding-bottom: calc(var(--sp-5) + var(--sp-5) + var(--burbuja-d)); }
}

/* TANDA 22-SEP-P4F · F5 — la reserva de `.gta-con-beki .gta-footer` de arriba sólo despeja el
   PIE. Medido con Playwright a 390 px (`captura-f5-burbuja.mjs`): la burbuja también se comía
   la última tarjeta de «Tus cursos» en /mi-beca/ y /cursos/, la última pieza de un estante en
   /biblioteca/ y el enlace «Ver recursos de la lección» del área de estudio — ninguna de las
   tres es el pie, así que la reserva de arriba no las alcanzaba. `.gta-main` es el contenedor
   que envuelve el contenido de TODAS las pantallas (`header.php`), así que la misma cuenta
   —hecha con los mismos tokens, no un número nuevo— se aplica aquí y protege cualquier cosa
   que termine pegada al borde inferior, sea cual sea la pantalla. Se pisa a sí misma el
   `padding-bottom: 96px`/`var(--sp-7)` de la regla base de `.gta-main` por mayor especificidad
   (dos clases contra una), así que no hace falta tocar ese valor para quien NO tiene a Beki. */
.gta-con-beki .gta-main {
  padding-bottom: calc(var(--sp-5) + var(--tabbar-h) + var(--burbuja-hueco) + var(--burbuja-d));
}
@media (min-width: 641px) {
  .gta-con-beki .gta-main { padding-bottom: calc(var(--sp-5) + var(--sp-5) + var(--burbuja-d)); }
}

/* Los dos enlaces del pie salen en las ocho pantallas del guion que llevan pie y medían 18 px
   de alto: son navegación de verdad —el reglamento y la verificación pública de certificados—
   y no un enlace suelto dentro de una frase, así que se les da el mínimo táctil de DESIGN §2.
   `inline-flex` y no `block` para que sigan en su línea con sus separadores «·». */
.gta-footer a {
  color: var(--secundario);
  display: inline-flex; align-items: center;
  min-height: var(--touch-min); padding: 0 var(--sp-1);
}

/* =====================================================================
   Campana de notificaciones, hitos de racha y estados vacío de filtro.
   Bloque añadido al arreglar el portal del becario; va al final a propósito para no
   mover ni la regla global [hidden] ni el @font-face de Nunito, que otras partes del
   proyecto dan por situadas donde están.
   ===================================================================== */

/* ----- Campana (navbar) ----- */
/* `flex-shrink:0` por lo mismo que el logo y «Mi beca»: la campana es un control de
   44 px y encogerla para repartir el ancho la deja por debajo del mínimo táctil.

   N507 · `align-self: stretch` NO es estética: es de dónde cuelga el panel. Esta caja es el
   bloque que contiene al desplegable (es la única `position:relative` de por aquí), así que su
   borde de abajo es el `100%` que el panel usa para colocarse. Sin estirar, la caja mide lo que
   el botón —44 px, centrados en la barra—, y el botón NO crece cuando la barra crece: sube la
   mitad. Estirada, mide lo que la barra en cada ventana, y entonces «debajo de la barra» quiere
   decir debajo de la barra. El botón sigue centrado por su propio `align-items:center`, y el
   globo del contador no se mueve porque cuelga del BOTÓN (que es `position:relative`), no de
   esta caja. */
.gta-campana { position: relative; display: flex; align-items: center; flex-shrink: 0; align-self: stretch; }
.gta-campana__boton {
  position: relative; background: transparent; border: 0; cursor: pointer;
  color: #fff; font-size: 1.25rem; line-height: 1;
  min-width: var(--touch-min); min-height: var(--touch-min);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
}
.gta-campana__boton:hover, .gta-campana__boton[aria-expanded="true"] { background: var(--teal-700); }
.gta-campana__contador {
  position: absolute; top: 4px; right: 2px;
  background: var(--coral-600); color: #fff;
  font-family: var(--font); font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums;
  min-width: 18px; height: 18px; border-radius: var(--r-pill); padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
}
/* N507 · EL PANEL CUELGA DE LA BARRA, QUE ES DE QUIEN SIEMPRE QUISO COLGAR.
   Tenía `top: calc(100% + 8px)` y el `100%` era el alto del BOTÓN: ocho píxeles por debajo del
   botón, no de la barra. Mientras la barra midió 56 nadie lo notó —el panel caía 2 px por debajo
   de ella—, pero la barra tiene DOS alturas y a partir de 1025 px mide 64: el botón sigue midiendo
   44 y su borde de abajo sólo baja la MITAD de lo que baja el de la barra, así que el hueco de 2
   se convertía en -2 y el panel se metía DOS PÍXELES DENTRO de la barra. Medido en Chromium a
   1366x768 con `elementFromPoint` un píxel por encima del borde de la barra: lo que se pintaba ahí
   era `.gta-campana__cabecera`, o sea panel blanco encima de la barra verde (lleva `z-index:60`
   contra el 50 de la barra). Ahora el `100%` es el de la caja estirada —el borde de la barra— y el
   hueco vale `--sp-1` en las dos alturas. */
.gta-campana__panel {
  position: absolute; top: calc(100% + var(--sp-1)); right: 0; z-index: 60;
  width: min(340px, calc(100vw - var(--sp-4) * 2));
  max-height: min(70vh, 420px); overflow-y: auto;
  background: var(--superficie); color: var(--tinta);
  border: 1px solid var(--borde); border-radius: var(--r-md); box-shadow: var(--sombra-flotante);
}
/* A 390 px el panel se ancla al ancho de la ventana: pegado a la derecha se salía.
   N507 · aquí el panel se despega de la caja y cuelga de la VENTANA, así que el `100%` ya no
   sirve y hay que decir el número: se dice con el TOKEN de la barra, `calc(var(--navbar-h) +
   var(--sp-1))`, que es el mismo hueco que la rama de arriba. Antes ponía `60px` a mano y hoy
   vale exactamente lo mismo (56 + 4), porque por debajo de 480 px la barra sólo tiene una altura:
   ESTE CAMBIO NO MUEVE NI UN PÍXEL y está medido que no lo mueve. Lo que arregla no es un defecto,
   es que el número deje de ser una casualidad de dos reglas que nadie leía juntas. */
@media (max-width: 480px) {
  .gta-campana__panel {
    position: fixed; top: calc(var(--navbar-h) + var(--sp-1));
    right: var(--sp-4); left: var(--sp-4); width: auto;
  }
}
.gta-campana__cabecera {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: 10px 12px; border-bottom: 1px solid var(--borde);
}
.gta-campana__todas, .gta-campana__reintentar {
  background: transparent; border: 0; cursor: pointer; padding: 4px;
  font-family: var(--font); font-size: var(--fs-300); font-weight: 700; color: var(--teal-600);
  text-decoration: underline; min-height: var(--touch-min); display: inline-flex; align-items: center;
}
.gta-campana__lista { padding: 6px; display: grid; gap: 4px; }
/* «Ver más avisos» — el control con el que se baja por la lista cuando hay más de una página.
   Lleva el mínimo táctil y sus hermanos de arriba no porque éste se pulsa VARIAS VECES SEGUIDAS
   y desde el pulgar: medido a 320 px salía de 26 px de alto, por debajo de --touch-min. */
.gta-campana__mas { width: 100%; min-height: var(--touch-min); }
/*
 * `overflow-wrap: anywhere` — el aviso lo escribe una persona y llega hasta 190 de título y 255
 * de cuerpo. Medido a 320 px con los dos al tope y sin espacios: la fila medía 3.335 px dentro
 * de un panel de 288, o sea que el becario tenía el aviso delante y no podía leerlo. Aquí no se
 * ve como en el resto del portal —el panel es `position: fixed` por debajo de 480 px y lo que se
 * sale de un elemento fijo no ensancha la página—, así que el guardián de desbordamiento
 * horizontal de `validar-portal.mjs` nunca lo iba a ver: lo que se mide es que la fila quepa en
 * el panel.
 */
.gta-campana__item {
  display: grid; gap: 2px; padding: 10px 10px; border-radius: var(--r-sm);
  text-decoration: none; color: var(--tinta); font-size: var(--fs-400); cursor: pointer;
  overflow-wrap: anywhere;
}
.gta-campana__item:hover { background: var(--teal-50); }
.gta-campana__item.no-leida { background: var(--sol-100); }
/*
 * Una TANDA de avisos seguidos con el mismo título se pinta como UNA fila. Medido al escribirlo
 * (ops/medicion-campana-apilada-n219.php): 427 filas de más sobre una por pila, 425 de ellas
 * «Insignia nueva para tu colección».
 *
 * Lo que NO se hace: quedarse con uno. Aquellas 110 pilas tenían un cuerpo distinto en cada fila,
 * así que los cuerpos salen TODOS en la lista de abajo. Se agrupa el título, que es lo que se
 * repite; nunca el contenido, que es lo que no.
 *
 * N220 le quitó a esto casi todo su sujeto y está bien: aquellas 425 eran insignias que no
 * nombraban la insignia, y con el título arreglado ya no se parecen entre sí. Este estilo sigue
 * vivo para la tanda del MISMO aviso, que es lo que la agrupación quería juntar desde el principio.
 */
.gta-campana__cuantos {
  display: inline-block; background: var(--teal-600); color: #fff;
  font-size: var(--fs-300); font-weight: 800; line-height: 1.4;
  border-radius: var(--r-pill); padding: 0 8px; vertical-align: middle;
}
/* Q1 chunk 4/4 · el cuerpo del aviso (la frase que escribe una persona) se lee como cuerpo,
   no como caption: sube de 13 a >=14 px. El título y el contador siguen en --fs-300 aparte. */
.gta-campana__cuerpos {
  list-style: none; margin: 2px 0 0; padding: 0; display: grid; gap: 2px;
  color: var(--secundario); font-size: var(--fs-400);
}
/* La viñeta es un guión y no un `list-style`: el marcador nativo se sale del padding de 10 px
   del panel a 320 px, que es el ancho en el que ya mordió el `overflow-wrap` de arriba. */
.gta-campana__cuerpos li::before { content: '— '; }
.gta-campana__aviso { margin: 0; padding: 12px 10px; color: var(--secundario); font-size: var(--fs-400); }

/* Esqueleto de carga — nunca una rueda girando (ESTILO §3.3). */
.gta-esqueleto {
  height: 44px; border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--teal-50) 25%, var(--borde) 50%, var(--teal-50) 75%);
  background-size: 200% 100%; animation: gta-esqueleto 1.2s ease-in-out infinite;
}
@keyframes gta-esqueleto { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* ----- Hitos de racha (P17) ----- */
.badge-sol {
  display: inline-block; background: var(--sol-400); color: var(--tinta);
  font-weight: 800; font-size: var(--fs-300); border-radius: var(--r-pill); padding: 2px 10px;
}
.gta-hitos li.gta-hito--logrado { border-color: var(--exito); }
.gta-hitos li.gta-hito--disponible { border-color: var(--sol-400); background: var(--sol-100); }
.gta-hito__detalle { display: block; }

/* ----- La racha dicha en ᴮ (P17 · Q3 N570) ----- */
.gta-racha-bekis { text-align: left; max-width: 480px; margin: 0 auto var(--sp-4); }
.gta-racha-bekis h2 { margin-top: 0; }
.gta-racha-escalera {
  list-style: none; padding: 0; margin: var(--sp-3) 0; display: grid; gap: var(--sp-2);
}
.gta-racha-escalera__paso {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  border-left: 3px solid var(--borde); padding: var(--sp-2) var(--sp-3);
}
.gta-racha-escalera__paso--cobrado { border-color: var(--exito); }
.gta-racha-escalera__premio { font-weight: 800; color: var(--teal-600); font-variant-numeric: tabular-nums; }
.gta-racha-bekis__siguiente { margin: 0; }
.gta-racha-bekis__ir { margin: var(--sp-2) 0 0; }

/* ----- Estado vacío de un filtro ----- */
#gta-cursos-sin-resultados { padding: var(--sp-5); }
#gta-cursos-sin-resultados .btn-sec { margin-top: var(--sp-2); }
#gta-guias-sin-resultados .btn-sec { margin-top: var(--sp-2); }

/* ===== Guía individual (P21) =====
   Migas y vecinas: la plantilla single-gta_guia.php es nueva y necesita su estilo. El
   contenedor de vecinas usa grid de dos columnas para que «anterior» quede a la izquierda y
   «siguiente» a la derecha incluso cuando falta una de las dos (se pinta un <span> vacío en
   su hueco), sin recolocar el botón que sí existe. */
.gta-migas {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-400); color: var(--secundario);
  margin-bottom: var(--sp-4); flex-wrap: wrap;
}
.gta-migas a { font-weight: 700; text-decoration: none; }
.gta-migas a:hover { text-decoration: underline; }
.gta-migas__actual { color: var(--tinta); font-weight: 700; }
.gta-guia__posicion { font-variant-numeric: tabular-nums; margin-top: calc(var(--sp-2) * -1); }
.gta-guia__cuerpo > :last-child { margin-bottom: 0; }
/* P7.2: la captura real todavía no existe para esta guía — aviso honesto, nunca una imagen
   inventada (estándar 10/10, regla 2). Se retira sola en cuanto Playwright deje la captura. */
.gta-guia-captura-pendiente {
  margin: var(--sp-2) 0; padding: var(--sp-2) var(--sp-3);
  border: 1px dashed var(--borde); border-radius: var(--radio-2);
  background: var(--superficie-2); color: var(--secundario); font-size: var(--fs-400);
}
.gta-guia-captura-pendiente p { margin: 0; }
.gta-guia-captura { margin: var(--sp-2) 0; }
.gta-guia-captura img {
  display: block; width: 100%; height: auto; border-radius: var(--radio-2);
  border: 1px solid var(--borde);
}
/* El video va encima del texto y necesita separarse de él; el marco y la proporción 16:9 los
   pone .gta-player, que ya viaja con el reproductor. */
.gta-guia__video { margin: var(--sp-3) 0; }
.gta-guia__vecinas {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3);
  align-items: center; margin: var(--sp-5) 0 var(--sp-4);
}
.gta-guia__vecinas .btn-sec { justify-self: start; }
.gta-guia__vecinas .btn-pri { justify-self: end; text-align: right; }
@media (max-width: 480px) {
  /* En móvil, «siguiente» primero: es la acción que el becario suele querer. */
  .gta-guia__vecinas { grid-template-columns: 1fr; }
  .gta-guia__vecinas .btn-pri { order: -1; justify-self: stretch; }
  .gta-guia__vecinas .btn-sec { justify-self: stretch; }
}
/* «¿Sigue sin funcionar?» — MASTER P21: pregunta, botón de Beki y, última, el canal oficial.
   Las tres son hermanas y no una frase con comas, para que falte la que falte no quede una
   conjunción colgando; el hueco entre ellas lo pone este bloque y no un <br>. El botón nace
   `hidden` y lo destapa chat.js, así que aquí NO se le puede poner `display`: lo taparía
   [hidden]{display:none !important} sólo por el !important, y sin él el botón muerto se
   vería. */
.gta-guia__ayuda { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); }
.gta-guia__ayuda > p { margin: 0; }

/* ============================================================================
   «Mi grupo» — pantalla del SUPERVISOR INSTITUCIONAL (solo lectura)

   Dos cosas condicionan todo el bloque:

   1. La página NO se desplaza en horizontal, nunca. Once columnas no caben en 390 px, así que
      la que se desplaza es la tabla dentro de .gta-mg-scroll; para que un hijo con contenido
      ancho no estire a su padre en flex/grid hace falta min-width: 0 explícito, que es el
      descuido habitual y el que deja el documento moviéndose de lado.
   2. Toda cifra va con tabular-nums y alineada a la derecha (ESTILO §3.3), y el hueco de un dato
      NULO se pinta como hueco (—) y no como un 0.
   ========================================================================== */

.gta-mi-grupo { min-width: 0; }
.gta-mg-contexto { margin-top: calc(var(--sp-3) * -1); }

/* Cifras: tabulares siempre, para que las columnas de números no bailen al ordenar. */
.gta-mg-num { font-variant-numeric: tabular-nums; font-weight: 700; }
.gta-mg-nulo { color: var(--secundario); font-weight: 700; }

.gta-mg-cabecera {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-2);
}
.gta-mg-cabecera h2 { margin: 0; }
.gta-mg-acciones { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.gta-mg-conteo { margin: 0; }
.gta-mg-origen { margin: 0 0 var(--sp-3); }

/* Aviso de que un endpoint del módulo todavía no existe. Aparece sólo cuando aplica: no es un
   cartel fijo, desaparece en cuanto la ruta está publicada. */
.gta-mg-sin-endpoint {
  display: inline-block; background: var(--teal-50); border: 1px dashed var(--borde);
  border-radius: var(--r-sm); padding: 6px 12px; color: var(--secundario); font-size: var(--fs-400);
}

.gta-mg-selector { margin-bottom: var(--sp-4); }
.gta-mg-selector__fila { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.gta-mg-selector__fila select { max-width: 420px; }

/* N16 (TANDA 22-SEP-P9) · MovilApoderado/MovilDocente: `apoderado.php` (Inicio) y
   `docente-mi-aula.php` traen su rejilla en línea, como el resto de pantallas portadas de
   `gg.css` (H1) — sin clase a la que engancharse. A 390 px esas columnas fijas (1.5fr 1fr,
   repeat(5,1fr), 1fr 1fr) no caben y desbordan el ancho. Estas clases sustituyen sólo la
   propiedad `grid-template-columns` del bloque afectado; el resto del estilo en línea sigue
   igual que en el resto del portal. */
.gta-grid-2-1 { display: grid; grid-template-columns: 1.5fr 1fr; gap: 18px; align-items: start; }
@media (max-width: 640px) { .gta-grid-2-1 { grid-template-columns: 1fr; } }
/* D1 (TANDA 24SEP-P15B) · mismo defecto que ya se arregló en `.gta-grid-cursos > .card`: dentro
   de las columnas internas (los `display:grid;gap:18px` de `mi-beca.php`) el `margin-bottom` de
   `.card` se sumaba al `gap`, dejando 34px entre tarjetas apiladas en vez de 18px. */
.gta-grid-2-1 > div > .card { margin-bottom: 0; }
/* D1 (TANDA 24SEP-P15B) · `/mi-beca/?tab=beca` sigue 110px sobre el límite tras equilibrar las
   columnas: seis tarjetas en dos columnas angostas (960px de main menos 18px de gap) sobran de
   relleno. Se aprieta sólo aquí, no en todo el portal, porque el resto de pantallas con `.card`
   ya miden dentro de su límite con el relleno de siempre. */
.gta-mibeca .card { padding: var(--sp-3) var(--sp-4); }
.gta-mibeca .gta-datos > div { padding: 5px 0; }
.gta-mibeca .gta-cv-item { padding: var(--sp-3); }

.gta-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
@media (max-width: 640px) { .gta-grid-2 { grid-template-columns: 1fr; gap: 14px; } }

.gta-da-kpis { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; }
@media (max-width: 640px) { .gta-da-kpis { grid-template-columns: repeat(2, 1fr); } }

.gta-da-urgentes { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 640px) { .gta-da-urgentes { grid-template-columns: 1fr; } }

/* B4 chunk 2 (TANDA 24-SEP-P14B) · a 390px la fila icono+nombre+botón de cada tarjeta de
   «Hoy necesitan tu ayuda» dejaba el nombre en un hueco de pocos px (icono 34px + botón
   `white-space:nowrap` se lo comían todo): el navegador partía «Mateo Huamán» letra por
   letra porque no le quedaba ancho para ni una palabra. Apilar en columna le da el 100%
   del ancho de la tarjeta al texto y al botón — mismo patrón que `.gta-grid-2-1`. */
.gta-da-urgente { display: flex; gap: 14px; align-items: flex-start; }
@media (max-width: 480px) {
  .gta-da-urgente { flex-direction: column; }
  .gta-da-urgente__accion { align-self: stretch; }
  .gta-da-urgente__accion a { width: 100%; justify-content: center; }
}

/* B4 chunk 3 (TANDA 24-SEP-P14B) · a 390px los dos botones de la cabecera de DocenteMiAula
   («Escribir a mi aula» + «Programar sesión», `white-space:nowrap` por `GTA_UI::boton()`)
   no caben en la fila y desbordan el documento 13 px: la fila de la izquierda tiene
   `flex:1;min-width:280px` y se come el ancho, dejando a los botones sin espacio para
   encogerse ni para envolver. Apilarlos a 100% de ancho, uno debajo del otro, resuelve el
   desborde sin tocar `boton()` (mismo patrón que `.gta-da-urgente`). */
.gta-da-cabecera-acciones { flex-wrap: wrap; }
@media (max-width: 480px) {
  .gta-da-cabecera-acciones { flex-direction: column; align-self: stretch; width: 100%; }
  .gta-da-cabecera-acciones a { width: 100%; justify-content: center; white-space: normal !important; }
}

/* La tabla de «Mis alumnos» vive en su propio `overflow-x:auto` (min-width:640px): no
   desborda el DOCUMENTO a 390px, pero obliga a hacer scroll horizontal para leer un solo
   alumno. Bajo 640px se cambia por la lista con barra del prototipo `MovilDocente`
   (misma fuente $da_becarios); la tabla se reserva para 641px en adelante. */
.gta-da-tabla { display: block; }
.gta-da-lista-movil { display: none; }
@media (max-width: 640px) {
  .gta-da-tabla { display: none; }
  .gta-da-lista-movil { display: block; }
}

/* AVISO 24-sep punto 4 · MovilDocente («Hola, Pedro»): bajo 640px la vista de escritorio
   completa (cabecera de aula, KPIs, «Hoy necesitan tu ayuda», tabla/lista de alumnos,
   herramientas) se oculta y sale la pantalla de inicio propia del docente en su lugar —
   mismo patrón interruptor que `.gta-da-tabla`/`.gta-da-lista-movil` arriba. */
.gta-da-inicio-movil { display: none; }
@media (max-width: 640px) {
  .gta-da-escritorio { display: none; }
  .gta-da-inicio-movil { display: block; }
}
.gta-da-inicio-movil__urgentes { display: flex; flex-direction: column; gap: 10px; }

/* T3 (TANDA 25SEP-P15C) · «Quién necesita ayuda» con su chip de conteo ocupaba 3 líneas a
   390px: el título a 22px + el chip empujado por margin-left:auto no cabían en una fila.
   Bajo 480px el contador baja debajo del título en vez de compartir línea con él. */
@media (max-width: 480px) {
  .gta-da-mov-seccion--chip { flex-wrap: wrap; }
  .gta-da-mov-seccion--chip span[style*="margin-left:auto"] {
    margin-left: 34px !important;
    width: 100%;
  }
}

/* RETOMAR (24-sep, MovilApoderado alto_ok=false) · el mismo patrón para `views/apoderado.php`:
   bajo 640px el apilado de escritorio completo (cabecera larga + `gta-grid-2-1` con «Su beca» y
   «Si no puede entrar») medía 2.483 px contra 1.367 del prototipo `MovilApoderado.png` porque el
   grid de 2 columnas sólo colapsa a 1, sin recortar contenido. La pantalla compacta propia
   (`.gta-apo-inicio-movil`) vive en el HTML y el CSS decide cuál se ve, igual que
   `.gta-da-escritorio`/`.gta-da-inicio-movil` de arriba. */
.gta-apo-inicio-movil { display: none; }
@media (max-width: 640px) {
  .gta-apo-escritorio { display: none; }
  .gta-apo-inicio-movil { display: flex; flex-direction: column; gap: 16px; }
}
.gta-da-inicio-movil .gta-da-lista-movil__fila { text-decoration: none; color: inherit; }
.gta-da-lista-movil__fila {
  display: flex; align-items: center; gap: 11px; padding: 11px 0;
  border-top: 1px solid var(--line-2); text-decoration: none; color: inherit;
}
.gta-da-lista-movil__fila:first-child { border-top: 0; }
.gta-da-lista-movil__datos { flex: 1; min-width: 0; }
.gta-da-lista-movil__datos b { display: block; font-size: 14px; }
.gta-da-lista-movil__barra { display: flex; align-items: center; gap: 9px; margin-top: 5px; }
.gta-da-lista-movil__barra .num { font-size: 12.5px; font-weight: 700; }

/* P14.5 (24-sep) · `docente-reportes.php` traía sus tres rejillas en línea, sin clase a la
   que engancharse: a 390px las columnas fijas (repeat(4,1fr), 1.4fr 1fr, 1fr 1.25fr) no
   caben y desbordan el ancho (medido con Playwright: 441px de contenido contra 390 de
   sala). Mismo patrón que `.gta-grid-2-1` de arriba: sólo sustituyen `grid-template-columns`. */
.gta-dr-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
@media (max-width: 640px) { .gta-dr-kpis { grid-template-columns: repeat(2, 1fr); } }

.gta-dr-grid-a { display: grid; grid-template-columns: 1.4fr 1fr; gap: 18px; align-items: start; }
@media (max-width: 640px) { .gta-dr-grid-a { grid-template-columns: 1fr; } }

.gta-dr-grid-b { display: grid; grid-template-columns: 1fr 1.25fr; gap: 18px; align-items: start; }
@media (max-width: 640px) { .gta-dr-grid-b { grid-template-columns: 1fr; } }

/* ----- KPIs ----- */
.gta-mg-kpis { display: grid; grid-template-columns: 1fr; gap: var(--sp-3); margin-bottom: var(--sp-5); }
@media (min-width: 481px)  { .gta-mg-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 769px)  { .gta-mg-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1025px) { .gta-mg-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.gta-mg-kpi { padding: var(--sp-4); margin-bottom: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* QA móvil U3 (15-SEP): la etiqueta y la procedencia estaban a --fs-300 (13px), el docente las
   lee en el aula desde el celular. Suben a --fs-400 (15px), el piso de lectura del sistema. */
.gta-mg-kpi__etiqueta { margin: 0; font-size: var(--fs-400); font-weight: 700; color: var(--secundario); text-transform: none; }
.gta-mg-kpi__valor {
  margin: 0; text-align: right; font-size: 1.75rem; font-weight: 800; line-height: 1.1;
  font-variant-numeric: tabular-nums; color: var(--teal-600);
}
.gta-mg-kpi--nulo .gta-mg-kpi__valor { color: var(--secundario); }
/* La procedencia de la cifra, debajo de la cifra: sin esto no se puede discutir un número. */
.gta-mg-kpi__fuente { margin: 0; font-size: var(--fs-400); color: var(--secundario); line-height: 1.35; }

/* ----- Esqueletos (nunca una rueda girando) ----- */
.gta-mg-esqueletos { display: grid; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.gta-esqueleto--kpi { height: 104px; }
.gta-esqueleto--fila { height: 56px; }

/* ----- Tabla ----- */
.gta-mg-tabla-caja { min-width: 0; overflow-x: auto; }

/* P23 Q1 chunk 2/4 · tarjeta por fila de verdad a 390px, para las mismas 3 familias de tabla
   (gta-mg-tabla, gta-col-tabla, las de secretaria.php sin clase propia): ninguna tocada, root
   fix en `.gta-main table`. `assets/gta-tablas-tarjeta.js` pone `data-label` en cada `<td>` con
   el texto de su `<th>` (progresivo: si JS no corre, la tabla se queda con scroll horizontal del
   chunk 1, nunca rota). La cabecera desaparece en móvil porque su texto ya vive en cada celda. */
@media (max-width: 640px) {
	.gta-main table { display: block; width: 100%; min-width: 0 !important; max-width: 100%; }
	.gta-main table thead { display: none; }
	.gta-main table tbody { display: block; }
	.gta-main table tbody tr {
		display: block; border: 1px solid var(--borde); border-radius: var(--r-md);
		padding: var(--sp-3); margin-bottom: var(--sp-3); background: var(--blanco, #fff);
	}
	.gta-main table tbody tr:last-child { margin-bottom: 0; }
	.gta-main table td, .gta-main table tbody th {
		display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
		flex-wrap: wrap; width: 100% !important; text-align: right; padding: 6px 0;
		border-bottom: 1px solid var(--borde);
	}
	.gta-main table td:last-child { border-bottom: 0; padding-bottom: 0; }
	.gta-main table td:first-child, .gta-main table tbody th { padding-top: 0; }
	/* `<th scope="row">` es el nombre de la fila (alumno, aula…), no un dato con etiqueta: hace de
	   título de la tarjeta, a la izquierda y sin `::before`. */
	.gta-main table tbody th {
		justify-content: flex-start; text-align: left; font-size: var(--fs-500, 1.05rem);
		border-bottom: 1px solid var(--borde); margin-bottom: 4px;
	}
	/* Sólo las celdas con `data-label` (las que tenían `<th>` con texto) llevan etiqueta: una
	   celda de sólo-botones sin cabecera de texto (la última columna de acciones, sin `<th>`)
	   ocupa el ancho entero en vez de fingir una etiqueta vacía. */
	.gta-main table td[data-label]::before {
		content: attr(data-label); text-align: left; font-weight: 700; color: var(--secundario);
		flex: none;
	}
	.gta-main table td:not([data-label]) { justify-content: flex-start; text-align: left; }
	/* 28 plantillas (todo /colegio/*, /mi-grupo/*, /secretaria/ y otras) arman sus filas de
	   tarjeta (KPI, «lo que necesita tu atención», comunicados, «tus N aulas» junto a un panel al
	   1.3fr/1fr…) con `style="display:grid;grid-template-columns:…"` inline — número de columnas
	   fijo, calculado en PHP o en fracciones (`1.3fr 1fr`): a 390px ninguna de esas variantes cabe
	   y empuja el documento entero. Se corrige desde el único sitio común a las 28 — el CSS, por
	   el prefijo literal que todas comparten — sin tocar cada plantilla ni depender de cuántas
	   columnas o qué proporción les tocó: una sola columna es siempre segura a este ancho. */
	.gta-main [style*="display:grid;grid-template-columns:"] { grid-template-columns: 1fr !important; }
	/* Una sola columna no basta si el ítem del grid sigue midiendo su contenido sin encoger
	   (`min-width:auto` es el valor por defecto de un ítem de grid): sin este `min-width:0` el
	   panel más ancho (p.ej. el lateral de «Tus N aulas») sigue empujando el documento aunque ya
	   esté solo en su fila. */
	.gta-main [style*="display:grid;grid-template-columns:"] > * { min-width: 0; }
	/* Una fila `display:flex` inline (icono fijo + texto con `min-width` propio + acción
	   `flex:none`) no encoge más allá de la suma de sus mínimos: a 390px esa suma se pasa. Dejar
	   que la fila envuelva es lo seguro sin tocar cada plantilla — apila en vez de recortar. */
	.gta-main [style*="display:flex"] { flex-wrap: wrap; }
}
.gta-mg-filtros { margin-bottom: var(--sp-3); }
.gta-mg-filtros__titulo { margin: 0; font-size: var(--fs-300); font-weight: 700; color: var(--secundario); }
.gta-mg-filtros__selects { display: grid; gap: var(--sp-3); }
@media (min-width: 641px) { .gta-mg-filtros__selects { grid-template-columns: 1fr 1fr; } }
.gta-mg-filtros__selects p { margin: 0; }
/* N547 · La caja de búsqueda del grupo reutiliza la fila de /cursos (.gta-buscar__fila): misma
   caja y mismo botón que encoge y se pone debajo a 420 px. Aquí el botón es secundario para no
   competir con «Aplicar filtros», y lo único propio es la separación con los chips de bandera. */
.gta-mg-filtros__buscar { margin-bottom: var(--sp-3); }

/* El contenedor de scroll de la tabla. tabindex="0" en el HTML para poder desplazarla con
   teclado; el borde marca dónde acaba lo que se mueve. */
.gta-mg-scroll {
  /*
   * `position: relative` NO es decorativo y costó medirlo: sin él la página SÍ se desplazaba en
   * horizontal a 390 px (documento 1241 px de ancho, window.scrollX llegaba a 800) aunque el
   * contenedor tuviera overflow. La razón es que dentro de la tabla hay elementos
   * `position: absolute` — los textos sólo para lector de pantalla (.screen-reader-text) —, y un
   * ancestro con overflow no recorta a un descendiente absoluto si además no es su bloque
   * contenedor. Con `relative` lo es, y el desplazamiento se queda dentro de la tabla.
   */
  position: relative;
  overflow-x: auto; max-width: 100%; min-width: 0;
  border: 1px solid var(--borde); border-radius: var(--r-md);
  -webkit-overflow-scrolling: touch;
}
.gta-mg-tabla { width: 100%; min-width: 940px; border-collapse: collapse; font-size: var(--fs-400); }
.gta-mg-tabla thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--teal-50); text-align: left; font-size: var(--fs-300);
  color: var(--secundario); padding: 0; white-space: nowrap; border-bottom: 1px solid var(--borde);
}
.gta-mg-tabla th.num, .gta-mg-tabla td.num { text-align: right; }
.gta-mg-tabla th.num .gta-mg-orden { justify-content: flex-end; width: 100%; }
.gta-mg-orden {
  background: transparent; border: 0; cursor: pointer; width: 100%;
  font-family: var(--font); font-size: var(--fs-300); font-weight: 800; color: var(--secundario);
  padding: 10px var(--sp-3); display: inline-flex; align-items: center; gap: 4px; min-height: var(--touch-min);
}
.gta-mg-orden:hover { color: var(--teal-600); text-decoration: underline; }
/* La flecha sale del aria-sort, así que lo que se ve y lo que anuncia el lector son lo mismo. */
.gta-mg-tabla th[aria-sort="ascending"] .gta-mg-orden::after { content: '▲'; font-size: .7em; }
.gta-mg-tabla th[aria-sort="descending"] .gta-mg-orden::after { content: '▼'; font-size: .7em; }

.gta-mg-tabla tbody th, .gta-mg-tabla tbody td {
  padding: 10px var(--sp-3); border-bottom: 1px solid var(--borde); vertical-align: top; text-align: left;
}
.gta-mg-tabla tbody tr:last-child td, .gta-mg-tabla tbody tr:last-child th { border-bottom: 0; }
.gta-mg-fila:hover > * { background: var(--teal-50); }
/* Franja de color a la izquierda: el semáforo se ve de un barrido sin leer once columnas. */
.gta-mg-fila > th:first-child { border-left: 4px solid transparent; }
.gta-mg-fila--rojo  > th:first-child { border-left-color: var(--coral-400); }
.gta-mg-fila--ambar > th:first-child { border-left-color: var(--sol-400); }
.gta-mg-fila--verde > th:first-child { border-left-color: var(--exito); }
.gta-mg-fila--gris  > th:first-child { border-left-color: var(--borde); }

.gta-mg-alumno { min-width: 190px; }
.gta-mg-alumno__nombre { display: block; font-weight: 800; }
.gta-mg-alumno__codigo { display: block; font-variant-numeric: tabular-nums; font-size: var(--fs-300); }

/*
 * O2 chunk 2 (TANDA 14-SEP-O) · el botón «Ver ficha» de `/mi-grupo/` (mi-grupo-colegio.php) es
 * el primer botón dentro de una celda de `.gta-mg-tabla`: la regla global `.gta-main {
 * overflow-wrap: anywhere }` (línea ~183, con su propia advertencia sobre el reparto de columnas
 * de ESTA MISMA tabla) le calculaba un ancho mínimo de un solo carácter y el algoritmo de columnas
 * lo exprimía a eso, partiendo «Ver ficha» letra por letra. `white-space: nowrap` en el botón
 * (no en la celda ni en la tabla entera) le devuelve su ancho natural sin tocar el resto.
 */
.gta-mg-tabla .btn-sec { white-space: nowrap; }
/* Misma razón que el botón de arriba: «Próximamente» (columna Actividades) es una sola palabra
   sin espacio donde partir, y el reparto de columnas la exprimía letra por letra. */
.gta-mg-nulo--corto { white-space: nowrap; }
.gta-mg-cursos { min-width: 170px; }
.gta-mg-curso-pill {
  display: inline-block; background: var(--teal-50); border: 1px solid var(--borde);
  border-radius: var(--r-pill); padding: 1px 10px; font-size: var(--fs-300); margin: 0 2px 2px 0;
}
.gta-mg-barra { display: block; width: 90px; margin: 4px 0 0 auto; }
.gta-mg-dias { display: block; font-size: var(--fs-300); }
.gta-mg-bandera { white-space: nowrap; }
.gta-mg-bandera__txt { font-weight: 700; }
.gta-mg-ver {
  background: transparent; border: 1px solid var(--borde); border-radius: var(--r-pill);
  cursor: pointer; font-family: var(--font); font-size: var(--fs-300); font-weight: 700;
  color: var(--teal-600); padding: 6px 12px; min-height: 36px; white-space: nowrap;
}
.gta-mg-ver:hover { background: var(--teal-50); }
.gta-mg-ver[aria-expanded="true"] { background: var(--teal-600); color: #fff; border-color: var(--teal-600); }

/* ----- Fila expandible (solo lectura) ----- */
.gta-mg-detalle > td { background: var(--fondo); }
.gta-mg-detalle__caja { display: grid; gap: var(--sp-4); padding: var(--sp-2) 0; }
@media (min-width: 769px) { .gta-mg-detalle__caja { grid-template-columns: 1.4fr 1fr 1fr; } }
.gta-mg-detalle__caja h3 { font-size: var(--fs-400); margin-bottom: var(--sp-2); }
.gta-mg-lista-cursos, .gta-mg-datos { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.gta-mg-lista-cursos__titulo { display: block; font-weight: 700; }
.gta-mg-lista-cursos .gta-mg-barra { width: 100%; margin: 4px 0; }
.gta-mg-datos li {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  font-size: var(--fs-400); border-bottom: 1px dashed var(--borde); padding-bottom: 4px;
}

/* ----- Estados vacío y error ----- */
.gta-mg-vacio { padding: var(--sp-5); }
.gta-mg-vacio .btn-sec { margin-top: var(--sp-2); }
.gta-mg-error { margin-top: var(--sp-4); }
.gta-mg-error p { margin-bottom: var(--sp-2); }

/* ----- Contacto académico ----- */
.gta-mg-contacto__pie { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.gta-mg-restantes { margin: 0; font-variant-numeric: tabular-nums; }

/* ----- Agenda única del colegio (X2) ----- */
.gta-col-agenda-vistas { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.gta-col-agenda-vistas .is-activo { background: var(--acento); color: #fff; }
.gta-col-agenda-nav { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin: var(--sp-3) 0; }
.gta-col-agenda-mes { table-layout: fixed; width: 100%; }
.gta-col-agenda-mes td.gta-col-agenda-dia { vertical-align: top; height: 90px; padding: var(--sp-2); border: 1px solid var(--borde); }
.gta-col-agenda-dia--fuera { opacity: 0.4; }
.gta-col-agenda-dia--hoy { background: var(--fondo-resalte, #fff8e1); }
.gta-col-agenda-dia-num { display: block; font-weight: 600; margin-bottom: 4px; }
.gta-col-agenda-chip { display: block; font-size: var(--fs-300); text-decoration: none; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gta-col-agenda-semana { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--sp-2); }
.gta-col-agenda-semana .gta-col-agenda-dia { border: 1px solid var(--borde); padding: var(--sp-2); border-radius: 6px; }
.gta-col-agenda-semana h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-400); }

/* ----- Q1b · Autorización del apoderado (dentro del detalle de la fila) ----- */
.gta-mg-autorizacion { grid-column: 1 / -1; border-top: 1px dashed var(--borde); padding-top: var(--sp-3); }
.gta-mg-autorizacion__form input { max-width: 320px; }
.gta-mg-form-error, .gta-mg-form-ok { margin-top: var(--sp-3); }

/* Encabezado de los KPIs: sobre qué se calcula todo lo de abajo (lo dice el endpoint). */
.gta-mg-base { margin: calc(var(--sp-2) * -1) 0 var(--sp-3); }

/* Tarjeta de reparto o de tendencia: ocupa dos columnas porque una barra necesita ancho para
   poder compararse; a una columna se leería como una lista de números sueltos. */
@media (min-width: 481px) { .gta-mg-kpi--serie { grid-column: span 2; } }
.gta-mg-serie { list-style: none; margin: var(--sp-2) 0; padding: 0; display: grid; gap: 6px; }
/* Q1 chunk 4/4 · cada fila es cuerpo (nombre + valor de una serie), no un caption: >=14 px. */
.gta-mg-serie li { display: grid; grid-template-columns: minmax(70px, auto) 1fr minmax(70px, auto); gap: var(--sp-2); align-items: center; font-size: var(--fs-400); }
.gta-mg-serie__titulo { color: var(--secundario); font-weight: 700; white-space: nowrap; }
.gta-mg-serie__barra { display: block; height: 10px; background: var(--teal-100); border-radius: var(--r-pill); overflow: hidden; }
.gta-mg-serie__barra > span { display: block; height: 100%; background: var(--teal-500); border-radius: var(--r-pill); }
.gta-mg-serie__valor { text-align: right; font-variant-numeric: tabular-nums; }
.gta-mg-kpi__unidad { margin: 2px 0 0; font-size: var(--fs-300); font-weight: 700; color: var(--teal-600); }

/* ============================================================================
   P25 · MENSAJES — /mensajes ya vive en el sistema .ap (H8, TANDA 23-SEP-P4H): su marcado
   dejó las clases `gta-mensajes__*`/`gta-hilo__*`/`gta-burbuja*` de abajo y no queda nada más
   en el portal que las use — por eso el bloque entero se retiró en vez de dejarlo muerto
   peleando con `gg.css` (mandato de H1: «si un componente ya existe en gg.css, el del portal
   sobra»).
   ============================================================================ */

/* ----- La burbuja de número (navbar y tabbar) -----
   Un solo componente y dos sitios: si el número de una barra se viera distinto del de la
   otra, parecerían dos cosas y habría que aprender las dos. */
.gta-navbar__num, .gta-tabbar__num {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  background: var(--coral-600); color: #fff;
  border-radius: var(--r-pill); font-size: 12px; font-weight: 800;
  font-variant-numeric: tabular-nums; line-height: 1;
}
.gta-navbar__num { margin-left: 6px; }
/* En la tabbar va pegada al icono, no al texto: el texto ya va justo a 320 px con cinco
   pestañas, y un número detrás lo partiría en dos líneas. */
.gta-tabbar .icono { position: relative; }
.gta-tabbar__num { position: absolute; top: -2px; left: 50%; margin-left: 4px; }

/* ===== N51 · Te puede interesar (el recomendador) — /cursos ===== */
.gta-reco__lista { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-3); }
@media (min-width: 769px) { .gta-reco__lista { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.gta-reco__item {
  border: 1px solid var(--borde); border-radius: var(--r-lg); padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0;
}
/* El título puede ser largo («Programación desde cero (HTML + CSS)») y a 390 px la caja no da
   más de sí: se parte por donde haga falta antes que desbordar la tarjeta. */
.gta-reco__item h3 { margin: 0; font-size: var(--fs-500); overflow-wrap: anywhere; }
.gta-reco__item h3 a { color: inherit; text-decoration: none; }
.gta-reco__item h3 a:hover { text-decoration: underline; }
.gta-reco__porque { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.gta-reco__porque li {
  color: var(--secundario); font-size: var(--fs-300); line-height: 1.45;
  padding-left: 18px; position: relative; overflow-wrap: anywhere;
}
.gta-reco__porque li::before { content: "·"; position: absolute; left: 6px; font-weight: 800; }
.gta-reco__pedir { margin-top: auto; align-self: flex-start; }
@media (max-width: 480px) { .gta-reco__pedir { align-self: stretch; width: 100%; } }

/* ===== N53 · Busca en el catálogo (la quinta señal) — /cursos ===== */
/* P2R R7 (c) · buscador y solicitud son <details> plegados (mismo patrón que .gta-nueva de
   mensajes.php): son la última conversación de la página, no la primera. */
.gta-buscar summary,
.gta-solicitar summary { font-weight: 800; color: var(--teal-600); cursor: pointer; }
.gta-buscar[open] summary,
.gta-solicitar[open] summary { margin-bottom: var(--sp-3); }
/* P8.0 · «además» 4/7 (veredicto 23-sep) · cerrado, `.card` seguía pintando fondo, sombra y el
   relleno de var(--sp-5) alrededor de la sola línea del `<summary>`: dos cajas con el título y
   nada dentro, indistinguibles de un hueco roto. Cerrado no se pinta como caja —el propio
   `<summary>` ya trae su marcador de flecha—; abierto recupera el `.card` de siempre. */
.gta-buscar:not([open]),
.gta-solicitar:not([open]) {
  background: transparent; box-shadow: none; padding: var(--sp-2) 0;
}
/* El botón cabe al lado de la caja mientras haya sitio y se pone debajo cuando no: a 390 px
   un «Buscar» de 90 px al lado deja el campo en 200, que es donde se deja de leer lo escrito. */
.gta-buscar__label { display: block; font-weight: 700; margin-bottom: var(--sp-2); }
.gta-buscar__fila { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.gta-buscar__fila input[type="search"] { flex: 1 1 220px; min-width: 0; }
/* `0 1 auto` y no `0 0 auto`: con flex-shrink a cero el botón no puede encoger y una palabra
   larga dentro de él empuja la página de lado — es la caja nueva que la corrida de
   `wrap-global.mjs` cazó al añadir esta fila (una tercera familia superviviente donde sólo
   debía haber dos). El rótulo lo escribimos nosotros y siempre pone «Buscar», pero una regla
   que sólo aguanta mientras nadie cambie el texto no es una regla. */
.gta-buscar__fila .btn-pri,
.gta-buscar__fila .btn-sec { flex: 0 1 auto; min-width: 0; }
@media (max-width: 420px) { .gta-buscar__fila .btn-pri, .gta-buscar__fila .btn-sec { flex: 1 1 100%; } }
/* Los resultados heredan la tarjeta del recomendador (.gta-reco__item): son la misma cosa
   vista de dos maneras —un curso del catálogo con su porqué— y dos cajas distintas para lo
   mismo obligarían al alumno a aprender dos veces la misma pantalla. */
.gta-buscar__lista { margin-top: var(--sp-3); }

/* ===== P01c · Volver a entrar (N83) =====
 * Mismo ancho y mismo centrado que `/activar/`: son las dos pantallas del mismo momento —un
 * chico de pie con el móvil— y meterlas en cajas de anchos distintos hace que el recorrido
 * parezca de dos sitios. Los campos van a ancho completo porque a 320 px un input que no llena
 * la tarjeta deja al pulgar apuntando a un blanco de 200 px. */
.gta-entrar { max-width: 640px; margin: 0 auto; }
.gta-entrar__head { text-align: center; }
.gta-entrar__paso input { width: 100%; }
.gta-entrar__salida { margin: var(--sp-3) 0 0; text-align: center; font-size: var(--fs-400); color: var(--secundario); }
.gta-entrar__reenvio { margin: var(--sp-3) 0 0; text-align: center; }
/* «Mándamelo otra vez» es un <button> porque hace algo, no navega — pero tiene que LEERSE como
 * enlace: un segundo botón sólido debajo del de entrar compite con él y se pulsa por error. */
.gta-enlace { background: none; border: 0; padding: 0; color: var(--teal-600); text-decoration: underline; cursor: pointer; font: inherit; }

/* ===== Aula de Tutor · el temario habla (N164) =====
 * La sobreescritura tutor/learning-area/components/sidebar-nav-item.php mete un
 * .screen-reader-text dentro de cada item del temario, y el temario es una columna con
 * scroll. Mismo motivo MEDIDO que .gta-mg-scroll (arriba): un descendiente
 * position:absolute no queda recortado por el overflow de un ancestro que no sea su
 * bloque contenedor, y la página gana scroll horizontal a 390 px. `relative` sin
 * offsets no mueve nada visible. */
.tutor-learning-nav-item { position: relative; }

/* ===== Aula de Tutor · la lección tiene encabezado (N166) =====
 * La sobreescritura tutor/learning-area/components/header.php sube el título del aula a
 * <h1> y, cuando la pantalla enseña el CURSO, le añade el nombre de la lección en un
 * .screen-reader-text para que el encabezado nombre siempre la página.
 * Por debajo de 768 px la lección YA se ve (es el span .tutor-md-inline), así que ese
 * texto sobra y se apaga: si no, el lector la diría dos veces seguidas.
 * 768 px es EL corte de las utilidades tutor-md-* de Tutor (@media (max-width:768px) en
 * tutor-core.min.css), las mismas que deciden cuál de los dos span se ve. No es un número
 * elegido por nosotros: si Tutor lo mueve, este se mueve con él.
 *
 * AVISO 24-sep punto 3 · esas utilidades (`.tutor-hidden`, `.tutor-md-hidden`,
 * `.tutor-md-inline`) sólo existen en `tutor-core.min.css`, que la lección NUNCA encola
 * (medido en vivo: la lección sólo carga tutor.min.css/tutor-front.min.css/
 * tutor-learning-area.min.css). Sin esas reglas, un <span> vale por su valor de fábrica
 * (`inline`), así que el curso Y la lección se veían los dos a la vez — el h1 decía
 * «Excel para la vida real Sesión 10» y, para quien lee el texto entero (no sólo lo
 * pintado), la lección otra vez por el .screen-reader-text de arriba: «… Sesión 10 Sesión
 * 10». Se repite aquí, mismo corte de 768 px, sólo para este h1. */
@media (max-width: 768px) { .gta-solo-ancha { display: none; } }
.tutor-learning-header-title .tutor-hidden.tutor-md-inline { display: none; }
@media (max-width: 768px) {
	.tutor-learning-header-title .tutor-md-hidden { display: none; }
	.tutor-learning-header-title .tutor-hidden.tutor-md-inline { display: inline; }
}

/* ===== P0.2 (OBS-11a) · las pestañas «El curso»/«Avisos» ya no se montan sobre la barra
 * del sitio =====
 * `tutor.min.css` pone la regla real dentro de `@media (min-width:800px)` (bajo ese ancho
 * Tutor NO la hace sticky — `position` vuelve al valor por omisión y no hay choque
 * posible, así que el arreglo no aplica ahí):
 *   .tutor-course-details-page .tutor-course-details-tab .tutor-is-sticky
 *     { position:sticky; top:0; z-index:500; background:rgba(255,255,255,.6); blur(14px) }
 *   .admin-bar .tutor-course-details-tab .tutor-is-sticky { top:32px }
 * `.gta-navbar` también es sticky y también quiere `top:0` (o `32/46px` con la barra de
 * admin) — dos barras peleando por la misma franja, y la de Tutor gana por tener MÁS
 * z-index, tapando el menú de cuenta de P0.1.
 * El arreglo no es una cifra: `top` es el alto REAL de `.gta-navbar` en cada ancho —
 * `--navbar-h` YA cambia solo (56/64 según DESIGN §3) y `--gta-offset-superior` YA suma la
 * barra de admin de WP cuando está (32/46 px, arriba de este fichero), así que no hace
 * falta repetir la regla `.admin-bar` de Tutor. `z-index:40` la deja por debajo de
 * `.gta-navbar` (50) y de su panel de cuenta (60). El fondo pasa de translúcido con blur a
 * `--superficie` sólido: con la barra encima tapando contenido real, la translucidez deja
 * de tener sentido.
 * El selector de Tutor tiene TRES clases (especificidad 0,3,0); el nuestro iguala las tres
 * y añade `body` (un ancestro real, no un truco) para ganar por especificidad —0,3,1— y no
 * por orden de encolado: no hace falta `!important` ni declarar una dependencia sobre
 * `tutor-frontend` (mismo criterio que `assets/tutor-mayusculas.css`).
 * El área de aprendizaje (`tutor/learning-area/components/header.php`) no entra aquí: es
 * una plantilla de pantalla completa sin `get_header()`, no convive con `.gta-navbar`, y
 * su propia `.tutor-learning-header` ya trae `top:32px`/`46px` bajo `body.admin-bar`. */
@media (min-width: 800px) {
  body .tutor-course-details-page .tutor-course-details-tab .tutor-is-sticky {
    top: calc(var(--gta-offset-superior) + var(--navbar-h));
    z-index: 40;
    background-color: var(--superficie);
  }
}

/* ===== D3 · El mapa de aprendizaje: camino de nodos (N182) =====
 * Pinta lo que arma gta_mapa_nodos() en la pestaña del temario del curso
 * (tutor/single/course/course-topics.php del hijo). Colores del encargo de demo:
 * crema #FAF7F1, oro #A87C34/#E0B667/#ECD0A0/#F7EDDA — van locales al mapa y no a :root
 * porque hoy solo viven aquí; si D4/D5 los repiten, suben a tokens en ese chunk.
 * El zigzag es CSS puro (nth-child par/impar) y se apaga en móvil: a 390 px la columna
 * recta cabe y el vaivén no. */
.gta-mapa__camino { list-style: none; margin: 0 auto; padding: var(--sp-4) 0; max-width: 560px; position: relative; }
/* N586 · La frase de la cabecera: cuánto video queda por delante. Va pegada al título y
 * hereda su alineación —no se centra— porque las dos son la misma cabecera, y con el peso
 * y el color de un subtítulo: el número manda sobre el camino entero, no sobre una parada. */
.gta-mapa__queda { margin: calc(-1 * var(--sp-3)) 0 var(--sp-4); font-size: var(--fs-300);
  color: var(--secundario); }
/* W0 · Aviso de examen pendiente (SIN_EXAMEN_TOLERADO): mismo tono ámbar que el resto de la
 * casa usa para «falta algo, no es un error» — nunca el rojo de --error, que es para fallos. */
.gta-mapa__aviso--examen { margin: 0 0 var(--sp-4); padding: var(--sp-3) var(--sp-4);
  background: var(--sol-100); border: 1px solid var(--sol-400); border-radius: var(--r-md);
  font-size: var(--fs-400); color: var(--tinta); }

/* Q1.2 · El camino ya no es una barra recta: es la curva con paisaje que dibuja
 * gta_mapa_camino_svg(). Va detrás de las paradas (z-index) y estirada al alto real de la
 * lista, que en PHP no se conoce. Las paradas se pintan encima con position: relative. */
.gta-mapa__lienzo { position: relative; max-width: 560px; margin: 0 auto; }
.gta-mapa__paisaje { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.gta-mapa__camino > li { position: relative; z-index: 1; }
.gta-mapa__hito { position: relative; text-align: center; margin: var(--sp-5) 0 var(--sp-4); }
.gta-mapa__hito h4 { display: inline-block; margin: 0; padding: var(--sp-2) var(--sp-4); font-size: var(--fs-400);
  background: #FAF7F1; border: 1px solid #ECD0A0; border-radius: var(--r-pill); color: #A87C34; }
.gta-nodo { position: relative; margin: var(--sp-4) 0; display: flex; justify-content: center; }
.gta-nodo__cuerpo { position: relative; display: flex; align-items: center; gap: var(--sp-3); flex: 1 1 auto; min-width: 0;
  padding: var(--sp-2); border-radius: var(--r-md); text-decoration: none; color: inherit; }
/* Q1.3 · La parada agrupa la línea (cuerpo + botón) y su tarjeta, y es ella la que se
 * desplaza en el vaivén: si el translateX siguiera en el cuerpo, la tarjeta se quedaría
 * centrada y el desplegable saldría de otro sitio que la parada que lo abre. */
.gta-nodo__parada { position: relative; width: 100%; max-width: 300px; }
.gta-nodo__linea { display: flex; align-items: center; gap: var(--sp-2); }
a.gta-nodo__cuerpo:hover .gta-nodo__titulo, a.gta-nodo__cuerpo:focus-visible .gta-nodo__titulo { text-decoration: underline; }
/* El vaivén del camino: par a un lado, impar al otro; los hitos no se mueven. */
@media (min-width: 700px) {
  .gta-nodo:nth-child(odd)  .gta-nodo__parada { transform: translateX(-72px); }
  .gta-nodo:nth-child(even) .gta-nodo__parada { transform: translateX(72px); }
}
.gta-nodo__circulo { flex: 0 0 auto; display: grid; place-items: center; width: 56px; height: 56px; border-radius: 50%;
  background: #FAF7F1; border: 3px solid #ECD0A0; box-shadow: var(--sombra-card); }
.gta-nodo--hecho .gta-nodo__circulo { background: linear-gradient(180deg, #E0B667, #A87C34); border-color: #A87C34; }
.gta-nodo--actual .gta-nodo__circulo { border-color: var(--teal-600); background: var(--superficie); }
/* Lo que aún no ha hecho se ve apagado, lo abra Tutor o no; la diferencia entre los dos
 * la lleva el icono (punto apagado vs. candado) y el enlace, no la opacidad (N231). */
.gta-nodo--bloqueado .gta-nodo__cuerpo,
.gta-nodo--pendiente .gta-nodo__cuerpo { opacity: .72; }
a.gta-nodo__cuerpo:hover, a.gta-nodo__cuerpo:focus-visible { opacity: 1; }
/* El jefe lleva el rojo del encargo (#A8442B), que es SUYO y no el coral de las alertas:
 * un examen final no es un error. Va local al mapa como el resto de su paleta. */
.gta-nodo--jefe .gta-nodo__circulo { width: 68px; height: 68px; border-color: #A8442B; border-width: 4px;
  background: #FBF2EF; }
.gta-nodo--practica .gta-nodo__circulo { border-style: solid; border-color: #C9BEA9; }
.gta-nodo--cofre .gta-nodo__circulo { border-style: dashed; }
.gta-nodo__texto { display: flex; flex-direction: column; min-width: 0; }
.gta-nodo__tipo { font-size: var(--fs-300); color: var(--secundario); }
.gta-nodo--jefe .gta-nodo__tipo { color: #A8442B; font-weight: 700; }
.gta-nodo__titulo { font-size: var(--fs-400); font-weight: 600; overflow-wrap: anywhere; }
.gta-nodo__bekis { align-self: flex-start; margin-top: 2px; padding: 1px var(--sp-2); font-size: var(--fs-300); font-weight: 700;
  color: #A87C34; background: #F7EDDA; border: 1px solid #ECD0A0; border-radius: var(--r-pill); }
/* Beki señalando el nodo actual, posada sobre el círculo. El pulso respeta al que pidió
 * menos movimiento: sin @media, quieta. */
.gta-nodo__beki { position: absolute; top: -40px; left: 6px; line-height: 0; }
/* Aire extra sobre el nodo actual: sin él, Beki pisa la ficha del nodo anterior (visto
 * en la captura móvil de N182). */
.gta-nodo--actual { margin-top: 52px; }
.gta-nodo--actual .gta-nodo__circulo { animation: none; }
@media (prefers-reduced-motion: no-preference) {
  .gta-nodo--actual .gta-nodo__circulo { animation: gta-pulso 2s ease-in-out infinite; }
  @keyframes gta-pulso {
    0%, 100% { box-shadow: 0 0 0 0 rgb(14 91 85 / .35); }
    50%      { box-shadow: 0 0 0 10px rgb(14 91 85 / 0); }
  }
}

/* N585 · La META, hermana de la lista y no una parada más: no lleva círculo, no se
 * desplaza con el vaivén (por eso está fuera del `<ol>`, que es quien lo cuenta con
 * nth-child) y no es un enlace — no hay nada detrás a lo que ir. Beki vuelve aquí, que es
 * de donde el camino terminado la había echado. Paleta local del mapa, la misma del oro. */
.gta-mapa__meta { position: relative; z-index: 1; margin: var(--sp-4) auto 0; max-width: 300px; padding: var(--sp-4);
  text-align: center; background: #FAF7F1; border: 2px solid #ECD0A0; border-radius: var(--r-md);
  box-shadow: var(--sombra-card); }
.gta-mapa__meta-beki { display: block; line-height: 0; margin-bottom: var(--sp-2); }
.gta-mapa__meta-beki .gta-beki { display: inline-block; }
.gta-mapa__meta-texto { margin: 0; font-size: var(--fs-400); font-weight: 700; color: #A87C34; }
.gta-mapa__meta-pago { margin: var(--sp-2) 0 0; display: flex; flex-wrap: wrap; align-items: center;
  justify-content: center; gap: var(--sp-2); font-size: var(--fs-300); color: var(--secundario); }

/* Q1.3 · La tarjeta de la parada. El botón mide 44 px porque a 390 px se toca con el
 * pulgar; el resto de la parada sigue siendo el enlace a la lección, así que abrir la
 * tarjeta y entrar en la lección son dos gestos distintos y no uno ambiguo. Sin JavaScript
 * la tarjeta queda plegada: `hidden` lo pone el HTML y lo quita gta_mapa_tarjeta.js. */
.gta-nodo__mas { flex: 0 0 auto; display: grid; place-items: center; width: 44px; height: 44px; padding: 0;
  border: 1px solid #ECD0A0; border-radius: 50%; background: #FAF7F1; color: #A87C34; cursor: pointer; }
.gta-nodo__mas:hover, .gta-nodo__mas:focus-visible { background: #F7EDDA; }
.gta-nodo__flecha { display: block; line-height: 0; transition: transform .18s ease; }
@media (prefers-reduced-motion: reduce) { .gta-nodo__flecha { transition: none; } }
.gta-nodo__mas[aria-expanded="true"] .gta-nodo__flecha { transform: rotate(180deg); }
.gta-nodo__tarjeta { margin-top: var(--sp-2); padding: var(--sp-3); background: var(--superficie);
  border: 1px solid #ECD0A0; border-radius: var(--r-md); box-shadow: var(--sombra-card); }
.gta-nodo__filas { margin: 0; display: grid; gap: var(--sp-2); }
/* Q1 chunk 4/4 · el término de la fila (dt) se lee junto a su valor (dd, ya en --fs-400):
   mismo cuerpo, >=14 px. */
.gta-nodo__filas dt { font-size: var(--fs-400); color: var(--secundario); }
.gta-nodo__filas dd { margin: 0; font-size: var(--fs-400); overflow-wrap: anywhere; }

/* ===== D4 · Inicio gamificado (N183): misión del día y tarjeta de Bekis =====
 * Mismo lenguaje que las cards vecinas del panel: superficie, sombra card, y el chip de ᴮ
 * global del mapa (.gta-nodo__bekis). El cofre de la stat de racha lo dibuja gta_cofre_svg()
 * por nivel; aquí solo se alinea. Colores del encargo ya presentes en la paleta del tema. */
.gta-mision { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4);
  border-left: 4px solid #E0B667; }
.gta-mision__info { flex: 1; min-width: 220px; }
.gta-mision__objetivo { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-2); }
/* El cofre de hoy (Q3 N571): hermano de la misión, porque cuenta su consecuencia. El dibujo es
 * el mismo gta_cofre_svg() por nivel de hitos; lo de hoy lo dicen el texto y --abierto. */
.gta-cofre-dia { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  margin-bottom: var(--sp-4); border-left: 4px solid var(--borde); }
.gta-cofre-dia--abierto { border-left-color: var(--exito); }
.gta-cofre-dia__info { flex: 1; min-width: 220px; }
.gta-cofre-dia__info h2 { margin-top: 0; }
.gta-cofre-dia__cofre { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.gta-cofre-dia__cofre > span[aria-hidden] { line-height: 0; }
.gta-cofre-dia__form { margin: 0; }
.gta-cofre-dia__ir { font-size: var(--fs-400); }

.gta-bekis { margin-bottom: var(--sp-4); }
.gta-bekis h2 { display: flex; align-items: center; gap: var(--sp-2); }
.gta-bekis h2 > span[aria-hidden] { line-height: 0; }
.gta-bekis__saldo strong { font-size: var(--fs-600, 1.4rem); color: #A87C34; }
.gta-stat .gta-cofre { display: inline-block; vertical-align: middle; }

/* ===== D5 · La tienda del aula (N184): vitrina de premios en ᴮ =====
 * Mismo lenguaje que el resto del portal: cards sobre superficie, la rejilla de
 * .gta-grid-cursos y la paleta oro/teal del encargo. El distintivo distingue Solo-Bekis
 * (teal, la moneda del aula) del mixto ᴮ-o-S/ (oro, solo lo ve el adulto — §9.2). */
.gta-tienda-aula__head { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.gta-tienda-aula__head h1 { display: flex; align-items: center; gap: var(--sp-2); }
.gta-tienda-aula__head h1 > span[aria-hidden] { line-height: 0; }
.gta-tienda-aula__saldo strong { font-size: var(--fs-600, 1.4rem); color: #A87C34; }
.gta-grid-premios { display: grid; gap: var(--sp-3); }
@media (min-width: 641px) { .gta-grid-premios { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1025px) { .gta-grid-premios { grid-template-columns: repeat(3, 1fr); } }
.gta-premio { display: flex; flex-direction: column; gap: var(--sp-2); }
.gta-premio h2 { font-size: var(--fs-500, 1.15rem); margin: 0; }
.gta-premio__distintivo { align-self: flex-start; padding: 1px var(--sp-2); font-size: var(--fs-300); font-weight: 700;
  color: #0E5B55; background: #E7F2F0; border: 1px solid #5FB3A9; border-radius: var(--r-pill); }
.gta-premio__distintivo--mixto { color: #A87C34; background: #F7EDDA; border-color: #ECD0A0; }
/* margin-top:auto empuja el precio al pie: las cards de la rejilla igualan altura y el ᴮ
 * queda alineado card a card, se alargue lo que se alargue la descripción. */
.gta-premio__precio { display: flex; align-items: center; gap: var(--sp-2); margin-top: auto; }
.gta-premio__precio > span[aria-hidden] { line-height: 0; }
.gta-premio__precio strong { font-size: var(--fs-600, 1.4rem); color: #A87C34; }
/* N198 · Una sola regla para las dos: «¡Ya lo alcanzas!» de la tienda y «¡Ya te alcanzan N
 * premios!» del panel son el MISMO mensaje sobre el mismo saldo. Si un día cambia el verde,
 * cambia en las dos pantallas o el becario ve dos avisos distintos para la misma noticia. */
.gta-premio__alcanzado, .gta-bekis__listos { font-weight: 700; color: var(--teal-600); margin: 0; }
.gta-premio__pronto { font-size: var(--fs-300); color: var(--secundario); margin: 0; }
.gta-bekis__ir { margin-top: var(--sp-3); display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
/* N241 · v4-M M1: el canje. El botón sólo existe cuando el motor dice que puede; si no, el
 * motivo va en texto (.gta-premio__motivo), sin urgencia y sin dinero. */
.gta-premio__form { margin: 0; }
.gta-premio__motivo { font-size: var(--fs-300); color: var(--secundario); margin: 0; }
.gta-premio--agotado h2 { color: var(--secundario); }
.gta-tienda-aula__aviso { margin-bottom: var(--sp-4); }
.gta-canjes__lista { display: grid; gap: var(--sp-3); }
.gta-canje { display: flex; flex-direction: column; gap: var(--sp-1); }
.gta-canje__cabecera { display: flex; justify-content: space-between; gap: var(--sp-3); align-items: baseline; flex-wrap: wrap; }
.gta-canje h2 { font-size: var(--fs-500, 1.15rem); margin: 0; }
.gta-canje__bekis { font-weight: 700; color: #A87C34; white-space: nowrap; }
.gta-canje__estado { align-self: flex-start; padding: 1px var(--sp-2); font-size: var(--fs-300); font-weight: 700; border-radius: var(--r-pill);
  color: #0E5B55; background: #E7F2F0; border: 1px solid #5FB3A9; }
.gta-canje__estado--pendiente { color: #A87C34; background: #F7EDDA; border-color: #ECD0A0; }
.gta-canje__estado--anulado { color: var(--secundario); background: #F0F0F0; border-color: #D0D0D0; }
/* N242 · v4-M M3: la entrega. «Descargar» e «Ir al curso» sólo existen en un canje entregado
 * con algo detrás (archivo que existe, curso vivo); el pendiente y el anulado van en texto. */
.gta-canje__acciones { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-1); }

/* ── O6 (N246) · Las pantallas de progresión ─────────────────────────────────────────────
 * La pestaña «Bekis» de /logros/ y las dos líneas nuevas del panel (rango y «mi enlace»).
 * Ni una regla de color propia: el saldo reusa el dorado de `.gta-bekis__saldo` y la lista de
 * movimientos es la misma tarjeta de siempre, para que la cuenta se lea igual en las dos
 * pantallas donde sale. */
.gta-bekis-cuenta { margin-bottom: var(--sp-4); }
.gta-bekis__cifras { list-style: none; padding: 0; margin: var(--sp-3) 0 0; display: grid; gap: var(--sp-1); }
.gta-bekis__caduca { margin-top: var(--sp-3); }
.gta-bekis-movs { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-2); }
.gta-bekis-mov {
  background: var(--superficie); border-radius: var(--r-md); box-shadow: var(--sombra-card);
  padding: var(--sp-3); display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
}
/* Un ᴮ vencido no se tacha ni se pinta de rojo: se ganó de verdad y sigue contando para el
 * rango. Sólo pesa menos en la lista. */
.gta-bekis-mov--vencido { opacity: .7; }
.gta-bekis__rango { margin: var(--sp-3) 0 0; }
.gta-referido__acciones { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-2); }
.gta-referido-panel { margin-bottom: var(--sp-4); }
.gta-referido-panel h2 { display: flex; align-items: center; gap: var(--sp-2); }

/* ── O5 (N247) · El perfil profesional ───────────────────────────────────────────────────
 * Dos pantallas con el mismo contenido y dos tonos: /perfil/ es del portal (tarjetas de
 * siempre) y /perfil-publico/ la abre gente de fuera, así que hereda `.gta-registro-formal`
 * de la verificación de certificados (DESIGN §9: sobrio, sin mascota) y no estrena ni un color.
 * El único adorno propio es el aviso de «enlace apagado» de un certificado, que es información
 * y no decoración: dice por qué esa línea no sale fuera. */
.gta-perfil-camino { margin: 0 0 var(--sp-4); }
.gta-perfil-pro__cabecera { margin-bottom: var(--sp-4); }
.gta-perfil-pro__cabecera h2 { margin: 0; }
.gta-perfil-pro__rango { margin: var(--sp-2) 0 0; }
.gta-perfil-pro__lista, .gta-perfil-pro__certs, .gta-perfil-pro__insignias,
.gta-perfil-publico__certs, .gta-perfil-publico__insignias {
  list-style: none; padding: 0; margin: var(--sp-3) 0 0; display: grid; gap: var(--sp-2);
}
.gta-perfil-pro__lista--marcha { opacity: .8; }
.gta-perfil-pro__apagado {
  font-size: var(--fs-300); font-weight: 700; padding: 1px var(--sp-2); border-radius: var(--r-pill);
  color: var(--secundario); background: #F0F0F0; border: 1px solid #D0D0D0; white-space: nowrap;
}
.gta-perfil-pro__enlace { word-break: break-all; }
.gta-perfil-pro__acciones { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin: var(--sp-2) 0; }
.gta-perfil-pro__interruptor form { margin: var(--sp-3) 0 0; }
.gta-perfil-publico__cabecera { margin-bottom: var(--sp-4); }
.gta-perfil-publico__rango { margin: var(--sp-2) 0 0; font-size: var(--fs-500, 1.15rem); }
.gta-perfil-publico__pie { margin-top: var(--sp-4); }

/* ===== v4-R · Q-R1 · La Biblioteca del aula (N565) — móvil 390 px primero =====
   Una columna en el móvil y dos desde 769 px, que es donde ya caben dos fichas de 44 px de
   alto mínimo sin que el título parta en tres líneas. El botón de cada ficha es ancho completo
   en el móvil: es el objetivo táctil de la pantalla y no hay ninguno más al lado con el que
   se pueda confundir. */
.gta-biblio__head { margin-bottom: var(--sp-5); }
.gta-biblio__head h1 { margin: 0 0 var(--sp-2); }
.gta-biblio__head-top {
  display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-2);
}
.gta-biblio__eyebrow {
  margin: 0 0 4px; font-size: var(--fs-300); font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--secundario);
}
.gta-biblio__chip-edad {
  flex: none; padding: 6px var(--sp-3); border-radius: var(--r-pill);
  background: var(--exito-fondo, #E6F4EA); color: var(--exito); border: 1px solid var(--exito);
  font-size: var(--fs-300); font-weight: 700;
}
.gta-biblio__chip-edad::before { content: '✓ '; }
.gta-biblio__conteo { margin-top: var(--sp-1); font-weight: 700; }
.gta-biblio__estante { margin: 0 0 var(--sp-6); }
.gta-biblio__curso {
  margin: 0 0 var(--sp-3); padding-bottom: var(--sp-2);
  border-bottom: 2px solid var(--teal-100); font-size: var(--fs-700);
}
/* F4 chunk 2/2 (TANDA 22-SEP-P4F): la cabecera de «Todos los recursos» lleva el selector de
   orden a la derecha del título — el título ya no puede tener su propio borde inferior, se lo
   pone la cabecera entera para que el <select> quede alineado con él, no debajo. */
.gta-biblio__todos-cab {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--sp-2); margin: 0 0 var(--sp-3); padding-bottom: var(--sp-2);
  border-bottom: 2px solid var(--teal-100);
}
.gta-biblio__todos-cab .gta-biblio__curso { margin: 0; padding-bottom: 0; border-bottom: 0; }
.gta-biblio__orden {
  display: flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-300); font-weight: 700;
}
.gta-biblio__orden select {
  font: inherit; font-weight: 400; padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--borde); border-radius: var(--radio-2, 6px); background: #fff;
}
.gta-biblio__sin-material { margin: 0; }
.gta-biblio__familia { margin: 0 0 var(--sp-5); }
.gta-biblio__familia h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-500); color: var(--teal-700); }
.gta-biblio__piezas { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
@media (min-width: 769px) { .gta-biblio__piezas { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .gta-biblio__piezas { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .gta-biblio__piezas { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.gta-biblio__meta {
  font-size: var(--fs-300); color: var(--secundario);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.gta-biblio__accion { margin-top: var(--sp-2); width: 100%; }
@media (min-width: 481px) { .gta-biblio__accion { width: auto; align-self: flex-start; } }

/* D3.2 (TANDA 13-SEP-D) · Ícono por formato + color por familia. Antes cada ficha era el mismo
   rectángulo blanco con un título encima: "Manual del curso" y "Plantillas y archivos" sólo se
   distinguían leyendo el rótulo de la sección. El color va en el FONDO del ícono, no en el
   texto ni en el borde de la tarjeta entera, para que las cuatro familias convivan sin que la
   pantalla se vuelva un mosaico de tarjetas de colores; la forma de adentro (líneas de texto o
   rejilla, ver gta_biblio_formato_svg()) la pone el FORMATO, no la familia: las dos preguntas
   son distintas y no se pueden contestar con un solo color. */
.gta-biblio__icono {
  width: 36px; height: 36px; border-radius: var(--r-md); display: flex; align-items: center;
  justify-content: center; color: var(--tinta); flex-shrink: 0; margin-bottom: var(--sp-2);
}

/* El buscador de la biblioteca (Q-R1.4). La caja ocupa el ancho entero en el móvil: es el único
   mando de la cabecera y a 390 px no hay nada que ponerle al lado. El recuento vive DEBAJO y con
   alto reservado, porque aparece y desaparece según se teclea y sin reservarlo empujaría el
   primer estante arriba y abajo mientras el alumno escribe. */
.gta-biblio__buscar { margin: 0 0 var(--sp-5); }
.gta-biblio__buscar label { display: block; margin-bottom: var(--sp-1); font-weight: 700; }
.gta-biblio__buscar input[type="search"] { width: 100%; }
.gta-biblio__cuenta { margin: var(--sp-1) 0 0; min-height: 1.25em; font-size: var(--fs-300); }

/* Las lecturas recomendadas son de OTRA GENTE y se tienen que ver de otra manera: fondo crema
   en vez de blanco, filete lateral y la fuente ENCIMA del título. No es gusto — el encargo
   prohíbe presentar material ajeno como nuestro, y dos secciones idénticas en pantalla lo
   presentan igual por mucho que el rótulo diga otra cosa. */
.gta-biblio__familia--externa {
  background: var(--sol-100); border-radius: var(--r-lg); padding: var(--sp-4);
  border-left: 4px solid var(--sol-400);
}
.gta-biblio__familia--externa h3 { color: var(--tinta); }
/* Q1 chunk 4/4 · la advertencia de material externo es una frase de cuerpo, no un caption. */
.gta-biblio__aviso-externo { margin: 0 0 var(--sp-3); font-size: var(--fs-400); }
.gta-biblio__fuente {
  font-size: var(--fs-300); font-weight: 800; color: var(--teal-700);
  text-transform: uppercase; letter-spacing: .02em;
}

/* Lecturas libres por edad (v4-R ampliación · D-086, N.º pendiente). Estante sin curso: los
   chips de tema sustituyen al agrupado por estante porque aquí ya no hay un curso que agrupe.
   Un chip por tema, uno solo activo; "Todos" lo quita. Objetivo táctil >= 44px (DESIGN §8). */
.gta-biblio__chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-4); }
/* Q1 chunk 4/4 (TANDA 25-SEP-P23) · a 390 la barra desliza de lado en vez de partirse en varias
   filas — mismo riel que ya usa `.gta-cursos-pagina__cabecera .gta-chips` (línea ~488), para no
   inventar un segundo patrón de barra de chips. */
@media (max-width: 480px) {
  .gta-biblio__chips { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
.gta-chip {
  min-height: var(--touch-min); padding: 0 var(--sp-3); border-radius: var(--r-pill);
  border: 1px solid var(--borde); background: var(--superficie); color: var(--tinta);
  font-size: var(--fs-300); font-weight: 700; cursor: pointer;
}
.gta-chip.is-activo { background: var(--teal-700); border-color: var(--teal-700); color: #fff; }

/* La portada tipográfica: nunca una imagen de fuera (el encargo prohíbe imágenes ajenas sin
   verificar), sólo la inicial del título sobre un color por tema. El color es identidad
   DECORATIVA, no la única: el tema también se lee en el chip y en el rótulo de la ficha, así
   que un lector con daltonismo no pierde nada por no distinguir dos tonos pastel parecidos
   (paleta validada por contraste con --tinta encima, todas >= 8:1 — ver el chunk de L). */
.gta-biblio__portada {
  width: 56px; height: 56px; border-radius: var(--r-md); display: flex; align-items: center;
  justify-content: center; font-size: var(--fs-700); font-weight: 800; color: var(--tinta);
  flex-shrink: 0; margin-bottom: var(--sp-2);
}
.gta-tema-0 { background: var(--fondo); }
.gta-tema-1 { background: #dedcef; } /* Literatura */
.gta-tema-2 { background: #d9e7f8; } /* Ciencia */
.gta-tema-3 { background: #d6f1e7; } /* Matemáticas */
.gta-tema-4 { background: #d1e9d1; } /* Historia */
.gta-tema-5 { background: #fbe4da; } /* Tecnología y programación */
.gta-tema-6 { background: #fbe7ef; } /* Inglés */
.gta-tema-7 { background: #fceed1; } /* Arte y cultura */
.gta-tema-8 { background: #fadede; } /* Vida práctica */
.gta-tema-9 { background: #dfd2c6; } /* Filosofía y pensamiento */

/* «Para mi edad» (TANDA 14-SEP-P · P3): siete pestañas de Biblioteca 2.0. Reusa el componente
   `.gta-chip` de las lecturas libres (mismo objetivo táctil, mismo contraste ya validado) en vez
   de inventar un segundo estilo de pestaña que hay que volver a probar. El número dentro del chip
   dice cuántas piezas trae SIN que el alumno tenga que abrirla para saberlo. */
.gta-biblio2 { margin: 0 0 var(--sp-6); }
/* F4 (TANDA 22-SEP-P4F): los chips ya no viven dentro de `.gta-biblio2` — subieron a debajo del
   buscador, con «Todo» primero — así que ponen su propio margen inferior en vez de heredarlo. */
.gta-biblio2__tabs { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-6); }
/* Q1 chunk 4/4 · mismo riel deslizante que `.gta-biblio__chips`: siete pestañas no caben en 390
   sin partirse en dos o tres filas. */
@media (max-width: 480px) {
  .gta-biblio2__tabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
}
.gta-biblio2__tab-n {
  margin-left: var(--sp-1); font-weight: 400; opacity: .8;
}
.gta-biblio2__acciones { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-2); }
.gta-biblio2__acciones .gta-biblio__accion { margin-top: 0; }

/* P4: «Guardar para después» / «Ya lo leí», textos-enlace, no botones — son un marcador
   personal, no una acción principal de la tarjeta. QA móvil U3 (15-SEP): medían 13px y ~20px
   de alto, por debajo de --fs-400/--touch-min que sí llevan .gta-chip y .btn-sec al lado. */
.gta-biblio2__marca { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); }
.gta-biblio2__marca a {
  font-size: var(--fs-400); color: var(--teal-700); text-decoration: underline;
  min-height: var(--touch-min); display: inline-flex; align-items: center; padding: 0 2px;
}
.gta-biblio__guardados h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-500); color: var(--teal-700); }
.gta-biblio__guardados .gta-biblio__familia { margin-bottom: var(--sp-5); }

/* P13.3 (TANDA 23-SEP-P13): «Publicado por tu tutor» — lista, no grid, porque el prototipo la
   piensa como un listado corto (lecturas asignadas + material propio mezclados por fecha), no
   como una vitrina de tarjetas. */
.gta-biblio__tutor-cab {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2);
}
.gta-biblio__tutor-cab .texto-sec { margin: 0; font-weight: 700; color: var(--tinta); }
.gta-biblio__lista-tutor { list-style: none; margin: 0; padding: 0; }
.gta-biblio__fila-tutor {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0;
  border-top: 1px solid var(--borde);
}
.gta-biblio__fila-tutor:first-child { border-top: 0; }
.gta-biblio__fila-icono {
  width: 44px; height: 44px; border-radius: var(--r-md); background: var(--ap-c-excel-soft, var(--superficie-2));
  color: var(--ap-c-excel, var(--teal-700)); display: flex; align-items: center; justify-content: center; flex: none;
}
.gta-biblio__fila-cuerpo { flex: 1; min-width: 0; }
.gta-biblio__fila-cuerpo b { display: block; }
.gta-biblio__fila-nota { display: block; font-style: italic; }
.gta-biblio__fila-descarga {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--touch-min); height: var(--touch-min); border-radius: 50%;
  border: 1px solid var(--borde); background: var(--superficie); color: var(--teal-700); flex: none;
}

/* P14.0 (=P13.1, TANDA 24-SEP-P14): «Colecciones destacadas». Tarjeta = `<details>` nativo, sin
   JS: el resumen (portada, «Colección · N recursos», título, nota) es lo que se ve cerrado; al
   abrirla aparece la lista de sus recursos, cada uno con la misma descarga protegida de siempre. */
.gta-biblio__coleccion { cursor: pointer; }
.gta-biblio__coleccion-resumen { cursor: pointer; list-style: none; }
.gta-biblio__coleccion-resumen::-webkit-details-marker { display: none; }
.gta-biblio__coleccion-resumen .ap-eyebrow { display: block; margin-top: var(--sp-3); }
.gta-biblio__coleccion-resumen b { display: block; }
.gta-biblio__coleccion-lista { list-style: none; margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--borde); }
.gta-biblio__coleccion-fila {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) 0;
}

/* La portada real (miniatura de la primera página) reemplaza al placeholder EN LA MISMA CAJA:
   si no hay imagen —hoy, sin Imagick/pdftoppm en esta instalación, nunca la hay (P2)— la caja de
   color por sección hace de portada de la casa, con el ícono de formato encima (mismo trazo que
   ya usa `.gta-biblio__icono`, D3.2): no es un hueco vacío, es la portada que toca mientras la
   fábrica de contenido no entregue una imagen real. */
.gta-biblio2__portada {
  width: 100%; height: 140px; border-radius: var(--r-md); display: flex; align-items: center;
  justify-content: center; color: var(--tinta); margin-bottom: 0; object-fit: cover;
}
/* El icono de guardar (E5 chunk 2): un marcador redondo con el signo «+»/«✓», no el texto
   «Guardar para después» de antes — la ficha compacta no tiene ancho para dos frases largas
   junto al botón Descargar. El texto sigue existiendo para lector de pantalla. */
.gta-biblio2__guardar {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--touch-min); height: var(--touch-min); border-radius: 50%;
  border: 1px solid var(--borde); background: var(--superficie); color: var(--teal-700);
  flex: none;
}
.gta-biblio2__guardar::before { content: '\2605'; font-size: var(--fs-500); line-height: 1; }
.gta-biblio2__guardar.is-activo { background: var(--teal-700); border-color: var(--teal-700); color: #fff; }
.gta-biblio2__marca .gta-biblio2__guardar { text-decoration: none; min-height: var(--touch-min); }

/* D3.1 · La tabbar ya nunca pasa de 5 celdas (Inicio, Cursos, Biblioteca, Logros, Más), así
   que la regla de N565 que achicaba la letra a partir de siete pestañas quedó sin caso que
   igualar — `gta_tabbar_grupos()` manda a «Más» todo lo que sobre — y se retira en vez de
   dejarla de adorno. Lo que antes vivía en la fila (Guías, Mensajes, Ofertas, Mi grupo) sigue
   siendo el mismo enlace de siempre, sólo que dentro del menú que abre `<details>`. */
.gta-tabbar__mas { flex: 1; position: relative; }
.gta-tabbar__mas summary {
  display: block; height: 100%; box-sizing: border-box;
  text-align: center; list-style: none; cursor: pointer;
  color: var(--secundario); font-size: var(--fs-300); font-weight: 700;
  padding: 8px 0 10px; min-height: var(--touch-min);
}
.gta-tabbar__mas summary::-webkit-details-marker { display: none; }
.gta-tabbar__mas summary::marker { content: ''; }
.gta-tabbar__mas summary.activo,
.gta-tabbar__mas[open] summary { color: var(--teal-600); }
.gta-tabbar__mas-menu {
  position: absolute; bottom: 100%; right: 0; margin-bottom: var(--sp-2);
  min-width: 180px; background: var(--superficie); border: 1px solid var(--borde);
  border-radius: var(--r-md); box-shadow: var(--sombra-flotante); overflow: hidden;
}
.gta-tabbar__mas-menu a {
  display: flex; align-items: center; gap: var(--sp-2); min-height: var(--touch-min);
  padding: 0 var(--sp-3); text-decoration: none; color: var(--tinta); font-weight: 700;
}
.gta-tabbar__mas-menu a + a { border-top: 1px solid var(--borde); }
.gta-tabbar__mas-menu a.activo { color: var(--teal-600); }
.gta-tabbar__mas-menu .gta-tabbar__num { margin-left: auto; position: static; }

/* ============================================================================
   «El colegio» — panorama de DIRECCIÓN (TANDA 13-SEP-G · G2/S2)
   Los KPIs de arriba reutilizan .gta-mg-kpis / .gta-mg-kpi tal cual (misma tarjeta que ya usa
   /mi-grupo/); aquí sólo hace falta el listado de aulas y el de "quién no está entrando".
   ========================================================================== */
.gta-colegio { min-width: 0; }

.gta-col-lista-aulas, .gta-col-lista-alerta { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.gta-col-aula, .gta-col-alerta-fila { margin-bottom: 0; }
.gta-col-aula__cabecera { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); }
.gta-col-alerta-fila { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
/* O1 (TANDA 14-SEP-O): botones de acción dentro de una fila de alerta (`/mi-grupo/`, `/colegio/`). */
.gta-col-alerta-fila__botones { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.gta-col-alerta-fila__botones .gta-form-inline { margin-top: 0; }

/* ============================================================================
   El tablero de `/colegio/` (TANDA 14-SEP-N · N3): seis tarjetas con delta vs.
   hace 7 días (sobre `gta_kpi_dia`) y la barra apilada de avance 0/25/50/75/100.
   ========================================================================== */
.gta-mg-kpi__delta { font-size: var(--fs-300); color: var(--secundario); margin: 0; }

/* Z3 (TANDA 19-SEP-Z): «qué se lee y qué no» de `/mi-grupo/` y `/colegio/biblioteca/`. */
.gta-mg-lectura__lista { list-style: none; margin: var(--sp-2) 0 var(--sp-5); padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.gta-mg-lectura__lista li { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--borde); }
.gta-col-barra { display: flex; height: 10px; border-radius: var(--r-sm); overflow: hidden; background: var(--borde); margin: var(--sp-2) 0; }
.gta-col-barra__seg { height: 100%; }
.gta-col-barra__seg--0   { background: var(--coral-400); }
.gta-col-barra__seg--25  { background: var(--sol-400); }
.gta-col-barra__seg--50  { background: var(--info); }
.gta-col-barra__seg--75  { background: var(--teal-500); }
.gta-col-barra__seg--100 { background: var(--exito); }
.gta-col-barra__leyenda { display: flex; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--fs-300); color: var(--secundario); margin: 0; }

/* ============================================================================
   `/colegio/aulas/` y `/colegio/aulas/{id}` (TANDA 13-SEP-G · G3): crear aula,
   asignar tutor, mover alumnos entre aulas.
   ========================================================================== */
.gta-col-volver { margin-bottom: var(--sp-2); }
.gta-col-volver a { color: var(--teal-600); font-weight: 700; text-decoration: none; }
.gta-col-aulas__cabecera { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.gta-col-aula__enlace { display: block; color: inherit; text-decoration: none; }
.gta-col-lista-alumnos { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.gta-col-alumno-fila {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap;
}
.gta-form-inline { display: flex; align-items: flex-end; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-2); }
.gta-form-inline label { display: flex; flex-direction: column; gap: 4px; font-size: 0.9rem; font-weight: 600; }
.gta-form-inline input, .gta-form-inline select {
  min-height: var(--touch-min); padding: 0 var(--sp-2); border: 1px solid var(--borde); border-radius: var(--r-sm);
}
.gta-col-mover { margin-top: 0; }
.gta-col-aulas__acciones { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* P14.5 (24-sep): «Crear aula» y «Asignar tutor» pasan de un formulario fijo arriba de la
   página a un cajón lateral que abre desde la cabecera, como el prototipo `DireccionAulas.html`.
   `<dialog>` nativo: sin JS propio salvo `showModal()/close()` inline, ya en el marcado. */
.gta-col-cajon { position: fixed; inset: 0 0 0 auto; margin: 0; height: 100%; max-height: 100%; width: min(420px, 100vw); border: 0; border-radius: 0; box-shadow: -8px 0 32px rgb(0 0 0 / .18); padding: var(--sp-5); }
.gta-col-cajon::backdrop { background: rgb(15 23 22 / .45); }
.gta-col-cajon__cabecera { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.gta-col-cajon__form { display: flex; flex-direction: column; gap: var(--sp-3); }
.gta-col-cajon__form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.9rem; font-weight: 600; }
.gta-col-cajon__form input, .gta-col-cajon__form select {
  min-height: var(--touch-min); padding: 0 var(--sp-2); border: 1px solid var(--borde); border-radius: var(--r-sm);
}
/* Q1 chunk 4/4 (TANDA 25-SEP-P23) · a 390 el cajón ya ocupaba la pantalla completa (era
   `position:fixed; height:100%` desde P14.5), pero el botón principal —«Crear aula», «Asignar
   tutor», «Nombrar», «Guardar periodo», «Pedir cotización», «Guardar evaluación»— vivía al final
   del formulario: en el cajón más largo (evaluar docente) quedaba fuera de la pantalla y había
   que hacer scroll a ciegas para encontrarlo. `position: sticky` sobre el ÚLTIMO botón del
   formulario —el `type="submit"` que las siete plantillas ya ponen al final— lo clava abajo sin
   tocar el marcado de ninguna: se queda quieto mientras los campos de arriba se desplazan. */
@media (max-width: 480px) {
  /* `[open]` es obligatorio: sin él, `display:flex` le gana en cascada a la regla del navegador
     `dialog:not([open]){display:none}` —son las DOS reglas del mismo origen (autor), y aquí la
     de autor sin `[open]` tiene más especificidad que `dialog:not([open])`— y los cajones
     CERRADOS se pintaban igual que el abierto, todos superpuestos y bloqueando los botones que
     los abren (medido con Playwright: el clic en «Crear aula» lo intercepta el cajón «Asignar
     tutor», que nunca se había abierto). */
  .gta-col-cajon[open] { display: flex; flex-direction: column; height: 100dvh; max-height: 100dvh; padding: 0; }
  .gta-col-cajon[open] .gta-col-cajon__form { flex: 1; min-height: 0; overflow-y: auto; padding: var(--sp-5); }
  .gta-col-cajon[open] .gta-col-cajon__form > button[type="submit"] {
    position: sticky; bottom: 0; margin-top: auto; flex-shrink: 0;
    background: var(--superficie); box-shadow: 0 -4px 12px rgb(0 0 0 / .12);
  }
}

/* `/apoderado/hijo/{id}/` · «Lo que leyó» (TANDA 19-SEP-Z · Z1 chunk 2): la misma fila de
   `.gta-col-alumno-fila` con una miniatura chica de la portada delante, no la caja de 140px de
   la tarjeta grande de `/biblioteca/` — aquí es una lista de registro, no un estante. */
.gta-ah-biblio-fila { flex-wrap: nowrap; }
.gta-ah-biblio__portada { width: 40px; height: 56px; border-radius: var(--r-sm); object-fit: cover; flex-shrink: 0; }

/* P23 Q5 chunk 2/2 · tamaño declarado para las portadas sin CSS de `/colegio/catalogo/`
   (vista clásica) y de `/apoderado/catalogo/` y `/apoderado/regalo/`, para que `loading="lazy"`
   no salte la página al cargar. */
.gta-col-catalogo__portada { display: block; width: 100%; height: 140px; object-fit: cover; border-radius: var(--r-md); margin: 0 0 var(--sp-3); }
.gta-catalogo-tarjeta__portada,
.gta-regalo-tarjeta__portada { display: block; width: 100%; height: 120px; object-fit: cover; border-radius: var(--r-md); }

/* ============================================================================
   `/colegio/personas/` (TANDA 13-SEP-G · G4/S4): nombrar, retirar, permisos por casillas.
   ========================================================================== */
.gta-col-personas-aulas {
  border: 1px solid var(--borde); border-radius: var(--r-sm); padding: var(--sp-2) var(--sp-3);
  margin: var(--sp-2) 0; display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3);
}
.gta-col-personas-aulas legend { padding: 0 4px; }
.gta-col-check { display: flex; align-items: center; gap: 6px; font-weight: 400; white-space: nowrap; }
.gta-col-lista-personas-ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.gta-col-persona-fila { display: grid; gap: var(--sp-2); }
.gta-col-persona__cabecera { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap; }
.gta-col-permisos-form { margin-top: var(--sp-2); }
.gta-col-permisos-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--sp-1) var(--sp-3);
  margin-bottom: var(--sp-2);
}
.gta-col-retirar { margin-top: 0; }
.gta-col-persona-fila--pendiente { opacity: .85; border-style: dashed; }
.gta-col-badge-pendiente { margin: 0; padding: 2px 10px; font-size: var(--fs-200, .8rem); border-radius: 999px; }

/* Q3 chunk 2 (TANDA 15-SEP-Q) · `/colegio/bandeja/` — el `.gta-tabs` que ya usan mi-beca.php y
   logros.php nunca tuvo una etiqueta larga que probar a 390: sin `flex-wrap` ni `white-space`
   propios, el `overflow-wrap: anywhere` global de `.gta-main` (línea ~183) parte «Solicitudes» a
   la mitad. Se resuelve aquí, sin tocar `.gta-tabs` en general, para no arriesgar los otros dos
   sitios que ya la usan. */
.gta-col-bandeja-tabs { flex-wrap: wrap; }
.gta-col-bandeja-tabs a { white-space: nowrap; }

/* ============================================================================
   `/mi-grupo/` para cargos de tutoría y administración (TANDA 13-SEP-G · G5/S5).
   ========================================================================== */
.gta-mg-colegio-fila > * { min-width: 120px; }
.gta-mg-bandera { font-weight: 700; white-space: nowrap; }
.gta-mg-codigo { font-variant-numeric: tabular-nums; }
/* QA móvil U3 (15-SEP): medía 19x18px, el objetivo táctil más chico de las dos pantallas —
   revela el código de matrícula, un tropiezo de dedo lo dispara sin querer. */
.gta-mg-codigo__ver {
  margin-left: 6px; color: var(--teal-600); font-weight: 700; text-decoration: none;
  min-height: var(--touch-min); min-width: 44px; display: inline-flex; align-items: center;
  justify-content: center; padding: 0 4px;
}
.gta-mg-codigo__ver:hover { text-decoration: underline; }

/* ============================================================================
   `/mis-actividades/` — lo que el alumno ve y entrega de su aula (TANDA 14-SEP-O · O4).
   Mismo patrón de lista que `.gta-canjes__lista`/`.gta-canje`.
   ========================================================================== */
.gta-actividades__lista { display: grid; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.gta-actividad { display: flex; flex-direction: column; gap: var(--sp-1); }
.gta-actividad__tipo { align-self: flex-start; padding: 1px var(--sp-2); font-size: var(--fs-300); font-weight: 700; border-radius: var(--r-pill);
  color: #0E5B55; background: #E7F2F0; border: 1px solid #5FB3A9; }
.gta-actividad--vencida .gta-actividad__tipo { color: var(--error); background: #FCEBE8; border-color: var(--coral-400); }
.gta-actividad__form { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-2); }
.gta-actividad__form textarea { width: 100%; }
.gta-actividad__entrega { margin-top: var(--sp-2); }
.gta-actividad__mi-texto { white-space: pre-wrap; }
.gta-actividad__comentario { font-style: italic; color: var(--secundario); }

/* V1 (TANDA 19-SEP-V): la rúbrica de una actividad y el banco de comentarios de la revisión. */
.gta-rubrica-form { border: 1px solid var(--borde, #d9d9d9); border-radius: 8px; padding: var(--sp-2); margin: var(--sp-2) 0; }
.gta-rubrica-form__criterio { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-2); margin-bottom: var(--sp-2); }
.gta-rubrica-form__criterio label { display: flex; flex-direction: column; gap: 4px; }
.gta-rubrica { width: 100%; border-collapse: collapse; font-size: var(--fs-400); }
.gta-rubrica th, .gta-rubrica td { border: 1px solid var(--borde, #d9d9d9); padding: 6px 8px; text-align: left; vertical-align: top; }
.gta-rubrica__marcado { background: rgba(0, 128, 96, .12); }
.gta-rubrica-alumno { margin-top: var(--sp-2); overflow-x: auto; }
.gta-rubrica-nivel { display: inline-flex; flex-direction: column; font-size: var(--fs-300, .85em); margin-right: var(--sp-2); }
.gta-banco { display: flex; flex-wrap: wrap; gap: 4px; }

/* V2 (TANDA 19-SEP-V): el libro de calificaciones del aula y «Mis notas» del alumno. */
.gta-notas-libro__filtro { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.gta-notas-libro__tabla { overflow-x: auto; }
.gta-notas-tabla { width: 100%; border-collapse: collapse; font-size: var(--fs-400); }
.gta-notas-tabla th, .gta-notas-tabla td { border: 1px solid var(--borde, #d9d9d9); padding: 6px 8px; text-align: center; vertical-align: middle; }
.gta-notas-tabla thead th, .gta-notas-tabla tbody th, .gta-notas-tabla tfoot th { text-align: left; }
.gta-notas-celda--sin_calificar { background: rgba(230, 160, 0, .22); font-weight: 600; }
.gta-notas-celda--pendiente, .gta-notas-celda--no_toca { color: var(--secundario); }
.gta-mis-notas__item header { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); }
.gta-mis-notas__nota { font-size: 1.6em; font-weight: 700; }
.gta-mis-notas__comentario { font-style: italic; }
@media (max-width: 600px) {
	.gta-notas-tabla, .gta-notas-tabla thead, .gta-notas-tabla tbody, .gta-notas-tabla tfoot, .gta-notas-tabla tr, .gta-notas-tabla th, .gta-notas-tabla td { display: block; width: 100%; }
	.gta-notas-tabla thead { position: absolute; left: -9999px; }
	.gta-notas-tabla tr { border: 1px solid var(--borde, #d9d9d9); border-radius: 8px; margin-bottom: var(--sp-2); }
	.gta-notas-tabla th, .gta-notas-tabla td { border: 0; border-bottom: 1px solid var(--borde, #eee); text-align: left; }
	.gta-notas-tabla td::before { content: attr(data-actividad) ": "; color: var(--secundario); }
	.gta-rubrica td::before { content: attr(data-nivel) ": "; color: var(--secundario); }
	.gta-rubrica, .gta-rubrica thead, .gta-rubrica tbody, .gta-rubrica tr, .gta-rubrica th, .gta-rubrica td { display: block; width: 100%; }
	.gta-rubrica thead { position: absolute; left: -9999px; }
}

/* H6 chunk 3/N (TANDA 22-SEP-P4G/23-SEP-P4H) · «Ruta del curso» pasó a `.ap-*`
   (tutor/single/course/ruta-del-curso.php). `.gta-ruta`/`.gta-ruta__cabecera` siguen vivas
   sin estilo propio: son sólo los ganchos de assets/ruta-curso.js. */

/* ===== P7.1 (TANDA 22-SEP-P7, OBS-09) · Centro de guías: pestañas, más consultadas, voto y relacionadas ===== */
.gta-guias-top .gta-card-guia { border-left: 3px solid var(--teal-600); }
.gta-guia__util { margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--borde); }
.gta-guia__util-botones { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.gta-guia__util-botones button[aria-pressed="true"] { background: var(--teal-600); color: #fff; border-color: var(--teal-600); }
.gta-guia__relacionadas { margin-top: var(--sp-4); }
.gta-guia__relacionadas ul { list-style: none; padding: 0; margin: var(--sp-2) 0 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.gta-guias-contacto { margin-top: var(--sp-4); text-align: center; }

/* ===== P44 item 2 (D27-14) · M4 acceso vencido — igual a la maqueta aprobada 761798e5:
   tarjeta centrada, gratuitas arriba, la de pago al final. `--sol-*` hace de dorado (no hay
   token `--gold-*` en este tema): mismo rol que en la maqueta, marca de la opción de pago. */
.gta-vencimiento { display: flex; align-items: center; justify-content: center; padding: var(--sp-6) var(--sp-4); }
.gta-vencimiento__tarjeta {
  background: #fff; border: 1px solid var(--borde, #E7E3D8); border-radius: var(--r-lg);
  box-shadow: 0 1px 2px rgb(15 31 29 / .05); max-width: 640px; width: 100%;
  padding: var(--sp-6) var(--sp-5); text-align: center;
}
.gta-vencimiento__icono {
  width: 64px; height: 64px; border-radius: var(--r-pill); background: var(--teal-100);
  color: var(--teal-700); display: flex; align-items: center; justify-content: center;
  margin: 0 auto var(--sp-4); font-size: 28px;
}
.gta-vencimiento__titulo { margin: 0 0 var(--sp-3); }
.gta-vencimiento__cuerpo { color: var(--ink-700, #2A3A38); margin: 0 0 var(--sp-2); }
.gta-vencimiento__cierre { color: var(--teal-600); margin: 0 0 var(--sp-6); }
.gta-vencimiento__grupo-titulo {
  text-align: left; font-size: var(--fs-300, 14px); letter-spacing: .02em; text-transform: uppercase;
  color: var(--ink-500, #55635F); margin: 0 0 var(--sp-3); font-weight: 700;
}
.gta-vencimiento__opciones { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); text-align: left; }
.gta-vencimiento__opcion {
  display: flex; gap: var(--sp-3); align-items: flex-start; background: var(--teal-50);
  border: 1px solid var(--teal-100); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
}
.gta-vencimiento__opcion--pago { background: var(--sol-100); border-color: var(--sol-400); }
.gta-vencimiento__opcion a { color: inherit; text-decoration: none; }
.gta-vencimiento__opcion a:hover { text-decoration: underline; }
.gta-vencimiento__marca {
  flex: 0 0 auto; font-size: 11px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  border-radius: var(--r-pill); padding: 4px 10px; margin-top: 2px;
}
.gta-vencimiento__marca--gratuita { background: var(--teal-100); color: var(--teal-700); }
.gta-vencimiento__marca--pago { background: var(--sol-400); color: #4a3502; }
@media (max-width: 480px) {
  .gta-vencimiento__tarjeta { padding: var(--sp-5) var(--sp-4); }
}
