/* ==========================================================================
   Opos · hoja base
   Los tokens, la escala y los componentes vienen del traspaso de diseño
   (`design_handoff_opos/opos-base.css`). Lo que hay aquí de más son las
   pantallas que el traspaso describe en prosa pero no deja en CSS: cabecera,
   portada, catálogo, ficha y ajustes.

   Regla que manda sobre todo lo demás: **el color siempre significa algo**.
   Nunca decora, y nunca es la única señal — el acierto y el error llevan icono
   dentro del círculo.
   ========================================================================== */

/* --- 1. Tokens ----------------------------------------------------------- */

:root {
  --bg:          oklch(.968 .012 85);
  --panel:       oklch(.955 .014 85);
  --panel-2:     oklch(.985 .008 85);
  --txt:         oklch(.28 .02 60);
  --mut:         oklch(.5 .02 60);
  --rule:        oklch(.9 .012 80);
  --rule-soft:   oklch(.93 .01 80);
  --sel:         oklch(.93 .02 60);

  --teja:        oklch(.44 .13 32);   /* fuente oficial, acción primaria */
  --teja-soft:   oklch(.68 .11 32);
  --indi:        oklch(.44 .07 262);  /* enlace a otro tema */
  --indi-soft:   oklch(.62 .065 262);
  --verde:        oklch(.42 .11 150);  /* practicar, acierto, estudiado */
  --verde-bg:     oklch(.94 .04 150);
  /* El mismo verde, apagado. Es para el comentario de examen, que va sobre un
     texto largo y no puede cantar como un acierto: el acierto es un momento y
     esto se lee durante cuarenta minutos seguidos. */
  --verde-suave:    oklch(.51 .033 155);
  --verde-suave-bg: oklch(.97 .01 155);
  --azul:        oklch(.47 .11 245);  /* documentación: fuente que se consulta, no acción */
  --azul-soft:   oklch(.7 .08 245);
  --rojo:     oklch(.5 .15 30);    /* error */
  --rojo-bg:  oklch(.94 .035 30);
  --ambar:       oklch(.62 .12 70);   /* errata, aviso, apunte descolocado */
  --ambar-bg:    oklch(.955 .028 88);
  /* El papel del apunte. Amarillo de post-it ya usado: poco croma y tirando a
     verde, que es como se ve uno de verdad y no como el amarillo de un aviso. */
  --postit:       oklch(.95 .036 101);
  --postit-txt:   oklch(.42 .03 92);
  --postit-sombra: oklch(.78 .04 90 / .5);
  --marca:       var(--teja);
  --oscuro:        oklch(.24 .015 60);  /* el único bloque oscuro del modo claro */

  --serif:  'Literata', Georgia, serif;
  --titulo:  'Merriweather', Georgia, serif;
  --ui:     'Public Sans', system-ui, sans-serif;
  --mono:   'Spline Sans Mono', ui-monospace, monospace;
  --logo:   'Zilla Slab', Georgia, serif;

  --s-cuerpo:    17px;
  --lh-cuerpo:   1.75;
  --s-h1:     32px;
  --s-h2:     20px;
  --s-ui:     14px;
  --s-pequeno:  12.5px;

  --col:      780px;   /* columna de lectura; 660 en concentración */
  --radio:     3px;
  --paso:      4px;
}

[data-tema="oscuro"] {
  --bg:        #1a1b1e;
  --panel:     #212226;
  --panel-2:   #1e1f22;
  --txt:       oklch(.9 .015 85);
  /* El traspaso lo dejaba en .66. Sobre las superficies teñidas del modo oscuro
     —el papel del apunte, la opción marcada, el acierto y el error— eso da 4,3-4,4 y
     se queda a un pelo del 4,5 que pide la AA. Con .68 pasa en las cuatro. */
  --mut:       oklch(.68 .015 75);
  --rule:      #35332f;
  --rule-soft: #2b2a27;
  --sel:       oklch(.3 .03 60);

  --teja:      oklch(.75 .1 40);
  --teja-soft: oklch(.55 .09 40);
  --indi:      oklch(.75 .07 262);
  --indi-soft: oklch(.55 .06 262);
  --verde:      oklch(.75 .1 150);
  --verde-bg:   oklch(.3 .05 150);
  --verde-suave:    oklch(.71 .033 155);
  --verde-suave-bg: oklch(.262 .014 155);
  --azul:      oklch(.76 .09 245);
  --azul-soft: oklch(.56 .08 245);
  --rojo:   oklch(.68 .14 30);
  --rojo-bg:oklch(.3 .05 30);
  --ambar:     oklch(.72 .12 75);
  --ambar-bg:  oklch(.3 .035 75);
  /* De noche un post-it amarillo deslumbra y rompe la página entera. Se baja a
     un papel apagado: se sigue leyendo como otra superficie, no como una luz. */
  --postit:       oklch(.308 .025 100);
  --postit-txt:   oklch(.795 .032 95);
  --postit-sombra: oklch(.15 .01 90 / .6);
  /* El logotipo se queda en teja también de noche. El ámbar del traspaso
     desentonaba con el resto, y además el ámbar ya significa otra cosa aquí:
     es el color de lo que ponemos nosotros —el apunte y el comentario de
     examen—. Un logotipo ámbar lo diluía. */
  --marca:     var(--teja);
  --oscuro:      #16171a;
}

/* Las tres medidas de lectura. Solo afectan al cuerpo del tema, nunca a la
   interfaz: encoger los botones al encoger el texto no ayuda a nadie. */
[data-medida="pequena"]  { --s-cuerpo: 15.5px; --lh-cuerpo: 1.72; }
[data-medida="mediana"] { --s-cuerpo: 17px;   --lh-cuerpo: 1.75; }
[data-medida="gran"]    { --s-cuerpo: 19px;   --lh-cuerpo: 1.8; }

/* --- 2. Base ------------------------------------------------------------- */

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--txt);
  font-family: var(--serif);
  -webkit-font-smoothing: antialiased;
  transition: background .35s ease, color .35s ease;
}
::selection { background: rgba(255, 214, 120, .35); }

h1, h2, h3 { font-family: var(--titulo); letter-spacing: -.015em; margin: 0; }
h1 { font-size: var(--s-h1); font-weight: 300; line-height: 1.22; }
h2 { font-size: var(--s-h2); font-weight: 700; line-height: 1.3; scroll-margin-top: 20px; }
h3 { font-size: 16px; font-weight: 700; line-height: 1.35; }
p  { margin: 0 0 calc(var(--paso) * 4); font-size: var(--s-cuerpo); line-height: var(--lh-cuerpo); text-wrap: pretty; }
strong { font-weight: 600; }
a { color: inherit; }
code, kbd { font-family: var(--mono); font-size: .88em; }

.ui    { font-family: var(--ui); font-size: var(--s-ui); }
.pequeno { font-size: var(--s-pequeno); color: var(--mut); }
/* El rótulo va casi siempre pegado encima de un título —«Tema 1 · Bloc 2»,
   «Continúa aquí»— y sin aire propio las dos líneas se leían como una sola
   apelmazada. El interlineado y el hueco de debajo son suyos, no heredados. */
.rotulo {
  font-family: var(--ui); font-size: 11.5px; letter-spacing: .09em;
  line-height: 1.5; margin-bottom: 7px;
  text-transform: uppercase; color: var(--mut);
}

/* El salto al contenido no se ve hasta que el teclado llega a él, pero cuando
   llega tiene que verse de verdad, no aparecer detrás de la cabecera. */
.saltar {
  position: absolute; left: -9999px; z-index: 100;
  padding: 10px 16px; background: var(--panel); border: 1px solid var(--teja);
  font-family: var(--ui); font-size: var(--s-ui);
}
.saltar:focus { left: 8px; top: 8px; }

:focus-visible { outline: 2px solid var(--teja); outline-offset: 2px; }

/* Para el lector de pantalla, no para la vista. Lo llevan los controles cuyo
   significado está en la forma —las tres «A», el sol y la luna—, que sin texto
   se anuncian como «botón A, botón A, botón A». */
.oculto-visual {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* --- 3. Enlaces: el color dice adónde llevan ------------------------------ */

/* La documentación tiene color propio, y no por gusto: teja es estudiar y verde
   es practicar, los dos con significado, y un enlace a las bases no es ninguna
   de las dos cosas —es una fuente que se consulta—. En teja competía con la
   acción primaria de la misma pantalla. No estrena semáforo: sigue la regla de
   CONTENIDO §5, el color dice la voz y la etiqueta dice el tipo. */
.enlace-oficial {
  text-decoration: none;
  color: var(--azul);
  border-bottom: 1.5px solid var(--azul-soft);
}
.enlace-tema {
  text-decoration: none;
  color: var(--indi);
  border-bottom: 1px dotted var(--indi-soft);
}
/* Practicar **como acción** es un botón, el mismo en todas partes. Esto es otra
   cosa: un enlace suelto dentro de la prosa de un tema, que tiene que seguir
   siendo un enlace. La flecha se la ha quedado el botón. */
.enlace-practicar, .enlace-examen {
  display: inline-flex; align-items: center; gap: 8px;
  text-decoration: none; font-family: var(--ui); font-size: var(--s-ui);
  color: var(--verde);
}
.enlace-oficial:hover, .enlace-tema:hover { background: var(--sel); }

/* Un tema que esta salida no publica —o que todavía no está escrito— ocupa el
   sitio del enlace y **no es pulsable**: ni color de enlace, ni subrayado, ni
   `:hover`. Si se pareciera a un enlace sería un enlace roto con otra pintura,
   que es exactamente lo que esto viene a quitar. */
.marca-tema {
  font-family: var(--ui); font-size: var(--s-ui);
  color: var(--mut); font-style: italic;
}

/* El término (A2 §1) es un enlace de verdad —navega a otro apartado del
   temario, sin JavaScript y con lector de pantalla— así que siempre lleva
   marca de que se puede pulsar: un borde de puntos, distinto del subrayado
   de puntos de `abbr`, que no navega a ningún sitio (decisión A2, payload
   lo-da2f). «Mostrar términos» ya no decide si se ve, solo si se ve **con
   color** —doscientos enlaces de colores por tema no se leen—, sin competir
   con el color con significado de los enlaces de arriba. */
a.term {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--indi-soft);
}
[data-terminos="si"] a.term { color: var(--indi); }

/* --- 4. Cabecera --------------------------------------------------------- */

.cabecera {
  /* Envuelve. Era `nowrap`, y en cuanto la pantalla se estrechaba —el lector
     mete tres controles más— la navegación se montaba encima del nombre de la
     convocatoria en vez de bajar a la línea siguiente. */
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 18px;
  padding: 10px 22px;
  border-bottom: 1px solid var(--rule);
  background: var(--panel);
  font-family: var(--ui);
}
/* El grupo del macro (menú y, si las hay, migas debajo) es un solo bloque
   visual: la raya de abajo pasa al final del grupo, no al final del menú,
   para que no quede una raya de más entre las dos líneas cuando hay migas.
   La cabecera aislada de un examen (`.cabecera--examen`, sin este grupo)
   no pasa por aquí y conserva la suya. */
.cabecera-grupo .cabecera { border-bottom: none; }
.cabecera-grupo { border-bottom: 1px solid var(--rule); }
.marca {
  display: inline-flex; align-items: center; gap: 9px;
  text-decoration: none; flex: none;
}
.marca__nombre {
  font-family: var(--logo); font-size: 16px; font-weight: 500; letter-spacing: .07em;
}
/* Las migas (A10): siempre en su propia línea bajo el menú, nunca dentro de su
   `<header>`. Aquí puede haber tres niveles largos de categoría, así que
   `flex-wrap` basta para el móvil —el texto se ajusta de línea solo, sin
   recortar nada—, sin necesitar una regla aparte a 375 px. El fondo y la
   tipografía repiten los del menú para que las dos líneas se lean como una
   sola cabecera. */
.migas {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
  padding: 0 22px 10px;
  background: var(--panel); font-family: var(--ui);
  font-size: var(--s-pequeno); color: var(--mut); min-width: 0;
}
.migas a { text-decoration: none; }
.migas a:hover { color: var(--txt); }
.migas__sep { opacity: .55; }
.migas__final { color: var(--txt); }

.cabecera__derecha { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.nav-principal { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; font-size: 13.5px; }
/* stylelint-disable-next-line no-descending-specificity -- `.migas a:hover` solo se aplica dentro de las migas de pan; un enlace de `.nav-principal` nunca es descendiente de `.migas` — comprobado con getComputedStyle: no hay elemento que case las dos reglas. */
.nav-principal a {
  padding: 6px 10px; border-radius: var(--radio); text-decoration: none; color: var(--mut);
}
.nav-principal a:hover { background: var(--sel); color: var(--txt); }
.nav-principal a[aria-current="page"] { color: var(--txt); background: var(--sel); }

/* La convocatoria activa vive en la cabecera. El menú es un `<details>`: sin
   JavaScript sigue abriéndose, que es lo que importa. */
.eleccion-conv { position: relative; font-size: 13px; }
.eleccion-conv > summary {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px; border: 1px solid var(--rule); border-radius: 999px;
  cursor: pointer; list-style: none; color: var(--txt);
  /* Aunque la convocatoria declare nombre corto, hay nombres largos: una sola
     línea y lo que sobre, con puntos suspensivos. El nombre entero está en el
     `title` y en su página. La cabecera no envuelve, así que el tope va en `vw`
     y el botón se deja encoger —`min-width: 0`—: sin eso empujaba la navegación
     fuera de la pantalla en vez de recortarse él. */
  max-width: min(32vw, 300px); white-space: nowrap;
}
.eleccion-conv > summary > :first-child,
.eleccion-conv > summary { overflow: hidden; text-overflow: ellipsis; }
.eleccion-conv { min-width: 0; }
.eleccion-conv > summary::-webkit-details-marker { display: none; }
.eleccion-conv > summary::after {
  content: ""; width: 7px; height: 7px; margin-left: 2px;
  border-right: 1.3px solid var(--mut); border-bottom: 1.3px solid var(--mut);
  transform: rotate(45deg) translate(-2px, -2px);
}
.eleccion-conv[open] > summary { background: var(--sel); }
.eleccion-conv__menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  width: 290px; padding: 6px;
  background: var(--panel-2); border: 1px solid var(--rule); border-radius: var(--radio);
}
/* stylelint-disable-next-line no-descending-specificity -- igual que en el nav principal: el menú de convocatorias y las migas de pan son ramas distintas del DOM, nunca coinciden en el mismo enlace (getComputedStyle sin solape). */
.eleccion-conv__menu a {
  display: block; padding: 9px 11px; border-radius: var(--radio); text-decoration: none;
}
.eleccion-conv__menu a:hover { background: var(--sel); }
.eleccion-conv__menu .pequeno { display: block; margin-top: 2px; }

/* --- 5. Botones y controles ---------------------------------------------- */

/* Un botón que se lee como enlace: los POST de «Salir» y de «quitar» (T7, T9),
   que no pueden ser un `<a>` porque cambian estado. */
.boton--enlace {
  padding: 0; border: 0; background: none; color: inherit; font: inherit;
  text-decoration: underline; cursor: pointer;
}
.en-linea { display: inline; }

/* Un botón mide lo que mide, y lo mide aquí. Había dos familias con dos alturas
   —38 px `.boton`, 31 px `.boton--accion`— y dos rellenos, y como las dos salen
   juntas en la misma fila (ver el temario y simulacro, practicar e imprimir) la
   diferencia se leía como jerarquía donde no la hay. La medida es una: 34 px de
   alto y 7/14 de relleno. Lo que cambia entre familias es el **color**, que sí
   significa algo. */
.boton, .boton--accion { min-height: 34px; padding: 7px 14px; }
.boton {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: transparent; color: var(--txt);
  font-family: var(--ui); font-size: var(--s-ui); text-decoration: none;
  cursor: pointer; transition: background .2s ease, border-color .2s ease;
}
.boton:hover { background: var(--sel); }
.boton--primario {
  background: var(--teja); border-color: var(--teja); color: var(--bg); font-weight: 500;
}
.boton--primario:hover { background: var(--teja); filter: brightness(1.1); }
.boton--hecho { background: var(--verde); border-color: transparent; color: var(--bg); }
/* La oposición que preparas es un **estado**, no una acción: teja como todo lo
   de estudiar, y sin relleno, que el relleno es de lo que se pulsa. En verde
   —el color de practicar— parecía ofrecer un test. */
.boton--activa { color: var(--teja); border-color: var(--teja); }
.boton--peligro { color: var(--rojo); border-color: var(--rojo); }
.boton--pequeno { min-height: 30px; padding: 4px 10px; font-size: var(--s-pequeno); }
/* Un botón que se lee como un enlace. Existe porque «saltar» **tuvo que dejar
   de ser un enlace** —ahora escribe que pasaste por la pregunta (U-4)— y no por
   eso puede ponerse a competir con «responder y seguir», que es la acción de
   verdad. Subrayado y no relieve: lo que cambia es el verbo HTTP, no la
   jerarquía de la pantalla. */
.boton--desnudo {
  background: none; border: 0; padding: 0; min-height: 0;
  font-family: inherit; color: var(--enlace, var(--teja));
  text-decoration: underline; cursor: pointer;
}
.boton--desnudo:hover { color: var(--txt); }

/* Las tres letras: la activa con fondo, y cada una de su tamaño real. */
.medidas { display: flex; align-items: center; border: 1px solid var(--rule); border-radius: 4px; overflow: hidden; }
.medidas button {
  width: 30px; height: 26px; padding: 0;
  border: none; border-right: 1px solid var(--rule); background: transparent;
  color: var(--mut); font-family: var(--ui); cursor: pointer;
}
.medidas button:last-child { border-right: none; }
.medidas button[aria-pressed="true"] { background: var(--sel); color: var(--txt); font-weight: 600; }
.medidas button:nth-child(1) { font-size: 11px; }
.medidas button:nth-child(2) { font-size: 13px; }
.medidas button:nth-child(3) { font-size: 15.5px; }

.interruptor {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 28px; padding: 5px 12px;
  border: 1px solid var(--rule); border-radius: 4px; background: transparent;
  color: var(--mut); font-family: var(--ui); font-size: var(--s-pequeno); cursor: pointer;
  transition: all .2s ease;
}
.interruptor[aria-pressed="true"] { border-color: var(--teja); color: var(--teja); background: var(--sel); }
/* Por debajo de esto, «Concentración» se queda en su icono: es el control más
   ancho de la cabecera —unos 110 px de rótulo— y el que menos falta hace leído,
   porque se pulsa una vez y se nota al momento. */
@media (max-width: 1000px) {
  .interruptor--concentracion, .interruptor--terminos { padding: 5px 8px; }
  .interruptor--concentracion .interruptor__nombre, .interruptor--terminos .interruptor__nombre {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}
.interruptor--icono { padding: 0; width: 30px; justify-content: center; }

/* El popover de un término (A2 §1): un solo elemento, colocado por JavaScript
   junto al enlace que lo abrió. `popover` lo esconde por defecto y le da el
   cierre con Escape y al pulsar fuera; el resto es solo el recuadro. */
.term-popover {
  position: fixed; margin: 0; max-width: 320px;
  padding: 12px 14px; border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--panel); box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  font-family: var(--ui); font-size: var(--s-pequeno); line-height: 1.5;
}
.term-popover::backdrop { background: transparent; }
.term-popover p { margin: 6px 0 0; }
.term-popover p:first-child { margin-top: 0; }
.term-popover [data-popover-ir] { margin-top: 10px; }

/* --- 6. Páginas normales -------------------------------------------------- */

.pagina { max-width: 1080px; margin: 0 auto; padding: 32px 26px 90px; }
.pagina--estrecha { max-width: 720px; }

.columnas { display: grid; grid-template-columns: 1fr 246px; gap: 34px; align-items: start; }

.seccion { margin-top: 34px; }
.seccion > h2 { margin-bottom: 14px; }

/* El glosario de un temario (A2 §2): una entrada por clave, con la frase, de
   dónde sale y dónde se cita. `dl` porque es exactamente eso —término,
   descripción— y no una lista cualquiera. */
.glosario { margin: 20px 0 0; }
.glosario__entrada { padding: 16px 0; border-top: 1px solid var(--rule-soft); }
.glosario__entrada:first-child { border-top: none; padding-top: 0; }
.glosario__entrada dt { font-family: var(--titulo); font-weight: 700; font-size: 16px; }
.glosario__entrada dd { margin: 6px 0 0; }
.glosario__entrada dd > p:first-child { margin-top: 0; }

.caja {
  padding: 18px 20px;
  background: var(--panel-2);
  border: 1px solid var(--rule);
  border-radius: var(--radio);
}
.caja--principal { border-left: 3px solid var(--teja); }
.caja--oscura {
  background: var(--oscuro); color: oklch(.93 .015 85); border-color: transparent;
}
.caja--oscura .rotulo, .caja--oscura .pequeno { color: oklch(.72 .02 75); }
.caja + .caja { margin-top: 12px; }

.pareja { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; }
/* Dentro de la rejilla la separación la pone `gap`. El margen de apilar cajas
   una debajo de otra bajaba 12 px todas menos la primera, y de ahí venía que
   dos cajas de la misma fila parecieran de alturas distintas. */
.pareja > .caja + .caja { margin-top: 0; }
/* Y que la acción quede a la misma altura aunque una caja diga más que la otra:
   botones a distinto nivel se leen como un descuadre, no como información. */
/* stylelint-disable-next-line no-descending-specificity -- `.pareja > .caja + .caja` solo fija margin-top; no toca display ni flex-direction, así que no pisa nada de esta regla. */
.pareja > .caja { display: flex; flex-direction: column; }
.pareja > .caja > :last-child { margin-top: auto; padding-top: 10px; }
/* …salvo si es un botón. El relleno de un botón es su forma, y sumarle 10 px
   solo por arriba lo deja torcido y más alto que el mismo botón de al lado. El
   aire lo pone el hueco de la caja. */
/* stylelint-disable-next-line no-descending-specificity -- `.pareja > .caja + .caja` solo fija margin-top; row-gap es una propiedad distinta, no hay pisado posible. */
.pareja > .caja { row-gap: 10px; }
.pareja > .caja > .boton--accion:last-child { padding-top: 6px; }

.cifra { font-family: var(--titulo); font-weight: 700; font-size: 30px; line-height: 1.1; }
/* «182 días», no «182» y debajo una línea que hay que ir a buscar. */
.cifra__unidad { font-size: var(--s-pequeno); font-weight: 400; margin-left: 6px; }
.cifra--gran { font-size: 46px; }
.cifra--pequena { font-size: 17px; }
.cifra--mono { font-family: var(--mono); font-weight: 400; }

.lista-limpia { list-style: none; margin: 0; padding: 0; }

.acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 16px 0 0; }
.acciones form { margin: 0; }

/* Los filtros llevan nombres de bloque largos: en una fila sola se salían de la
   pantalla. Ahora envuelven, y el resalte es un rectángulo y no una píldora —con
   `border-radius: 999px` un filtro de dos líneas salía con los cantos redondos
   por arriba y por abajo y parecía una mancha. */
.filtros { display: flex; flex-wrap: wrap; gap: 4px; margin: 18px 0 14px; font-size: 13.5px; }
/* stylelint-disable-next-line no-descending-specificity -- los enlaces de `.filtros` nunca están dentro de `.migas`: comprobado con getComputedStyle, no coinciden en el mismo `<a>`. */
.filtros a {
  padding: 5px 12px; border-radius: var(--radio);
  text-decoration: none; color: var(--mut);
  /* Un bloque cuyo título ocupa media pantalla no puede empujar a los demás. */
  max-width: 22em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.filtros a[aria-current="true"] { background: var(--sel); color: var(--txt); }

/* El cuadro de texto del buscador (B1): mismo trazo que `.apunte textarea`. */
.busqueda { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 18px 0 0; }
.busqueda label { font-size: var(--s-pequeno); color: var(--mut); }
.busqueda input[type="search"] {
  flex: 1 1 16em; min-width: 10em; padding: 7px 12px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--bg); color: var(--txt); font-size: 14.5px;
}

/* --- Test en curso -------------------------------------------------------- */

.test-cap { display: flex; align-items: baseline; justify-content: space-between; }
.test-cap__barra { margin: 8px 0 0; }

/* La cabecera del examen: lo justo y nada por donde salirse sin querer. Con la
   navegación completa arriba, pinchar «Temario» te sacaba sin avisar y con el
   reloj corriendo. */
.cabecera--examen { gap: 14px; flex-wrap: wrap; }
.cabecera--examen__sortida { margin-left: auto; }
/* Los dos números que **cambian en su sitio**, y por eso llevan cifra tabular y
   hueco reservado: aquí el ancho no puede depender de qué dígitos toquen.

   El que se movía era el contador de preguntas, no el reloj. La cabecera es una
   fila, así que al ensancharse de «9/40» a «10/40» empujaba al cronómetro 5 px,
   y con tres cifras, veinte. Se le reserva el hueco de tres —«hasta 3 cifras, no
   especulemos con 4»: el examen publicado más largo tiene 100 preguntas— y se
   alinea a la derecha, que es lo que deja el 7 y el 127 acabando en la misma
   columna.

   El cronómetro ya venía en monoespaciada, pero tenía el mismo defecto una vez
   por examen: los minutos se imprimen con `padStart(2)`, que no recorta, así
   que un ejercicio de 105 minutos empieza en «105:00» y encoge un carácter al
   caer a «99:59». Seis huecos y a la derecha: los mismos 105 minutos del común
   de 2021 que justifican las tres cifras de al lado.

   **`ch` no es el ancho de una cifra tabular, y esto se midió.** `ch` es el
   avance del «0» tal como lo dibuja la fuente por defecto, sin los rasgos
   activados: en Public Sans la cifra tabular es más ancha, y reservar `3ch`
   dejaba el reloj quieto de 9 a 10 pero lo movía 3,3 px al llegar a 100. Por
   eso los dos van en la monoespaciada, donde `ch` **sí** es una cifra: es el
   único sitio donde reservar N huecos con `ch` significa reservar N cifras. */
.cuenta-preguntas { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.cuenta-preguntas__actual { display: inline-block; min-width: 3ch; text-align: right; }
.cuenta-atras {
  font-size: 20px; font-variant-numeric: tabular-nums;
  display: inline-block; min-width: 6ch; text-align: right;
}
/* Los últimos cinco minutos, en el rojo del error: es cuando hay que decidir
   qué se rellena a ciegas y qué se deja. */
.cuenta-atras[data-poco] { color: var(--rojo); font-weight: 600; }
.cuenta-atras[data-agotado] { color: var(--rojo); font-size: 15px; }
/* Parado se ve parado: apagado, para que no se lea como que sigue corriendo. */
.cuenta-atras--parada { color: var(--mut); }

/* La pausa: una capa **encima del examen**, no otra página. La gracia es ver
   que sigue ahí detrás, quieto — de ahí el desenfoque y no un fondo opaco.

   `position: fixed` y no `absolute` porque el examen es más largo que la
   pantalla: con `absolute` se podía bajar por debajo de la capa y seguir
   leyendo las preguntas con el reloj parado. */
.pausa {
  position: fixed; inset: 0; z-index: 20;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: color-mix(in oklch, var(--bg) 55%, transparent);
  backdrop-filter: blur(7px);
}
/* Sin `backdrop-filter` —Firefox lo trae desactivado en algunas versiones— el
   fondo semitransparente solo no esconde nada: se sube la opacidad para que la
   capa siga leyéndose como una capa y no como un recuadro flotando. */
@supports not (backdrop-filter: blur(1px)) {
  .pausa { background: color-mix(in oklch, var(--bg) 88%, transparent); }
}
.pausa__caja {
  max-width: 380px; padding: 26px 30px; text-align: center;
  background: var(--bg); border: 1px solid var(--rule); border-radius: 10px;
}
.pausa__caja .acciones { justify-content: center; }

.a-medias {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px 0; border-bottom: 1px solid var(--rule);
}
.a-medias > :first-child { flex: 1 1 260px; }
/* stylelint-disable-next-line no-descending-specificity -- `.a-medias` solo existe en /test y `.term-popover` solo en /tema: páginas distintas, el navegador nunca ve las dos reglas sobre el mismo párrafo. */
.a-medias p { margin: 3px 0 0; }
.a-medias__acciones { display: flex; gap: 8px; }

.mapa-preguntas { display: flex; flex-wrap: wrap; gap: 4px; margin: 26px 0; font-family: var(--ui); }
/* stylelint-disable-next-line no-descending-specificity -- el mapa de preguntas del test y las migas de pan son componentes distintos; comprobado con getComputedStyle en /test/<sesión> (100 enlaces, ningún solape con `.migas a:hover`). */
.mapa-preguntas a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border: 1px solid var(--rule); border-radius: var(--radio);
  text-decoration: none; font-size: var(--s-pequeno); color: var(--mut);
}
.mapa-preguntas a:hover { background: var(--sel); }
/* Contestada, no acertada: durante el test no se sabe todavía si está bien, y
   pintarla de verde aquí lo insinuaría.

   **El relleno y la negrita no son adorno: son lo que la distingue sin color.**
   Antes se separaba de la no leída solo por el color del borde y de la letra, y
   en gris o en papel eran la misma casilla. La norma de la casa —la misma que
   `NORMAS_DE_ESQUEMAS.md` exige a las figuras— pide que sobreviva a la escala de
   grises.

   **Los dos estados van cualificados con `a`, y no es manía: sin eso no se
   aplicaban.** `.mapa-preguntas a` pone el borde y el color de la casilla y vale
   (0,1,1) de especificidad; una clase modificadora suelta vale (0,1,0) y pierde,
   por mucho que venga después. El `--blanco` que había aquí llevaba desde la
   #137 declarando un borde de rayas que **el navegador descartaba**: su estado y
   el de la no leída se pintaban idénticos, píxel a píxel, y eso es exactamente
   lo que el usuario vio y reportó. Ningún test lo cazó: la puerta no mira CSS
   (`lo-336c`). */
.mapa-preguntas a.mapa-preguntas--hecha {
  border-color: var(--teja); color: var(--txt);
  background: var(--sel); font-weight: 600;
}
/* Vista y pasada sin contestar: la que saltaste y la que enviaste sin marcar.
   La raya del borde es lo que la separa de la no leída sin depender del color, y
   el texto oculto lo dice igualmente. */
.mapa-preguntas a.mapa-preguntas--saltada {
  border-style: dashed; border-color: var(--mut); color: var(--txt);
}
.mapa-preguntas a[aria-current="true"] { background: var(--teja); border-color: var(--teja); color: var(--bg); }

/* El veredicto de una pregunta corregida, escrito. Sin él, una en blanco se lee
   como acertada: la correcta sale con su check verde exactamente igual que
   cuando la marcaste tú. */
.veredicto {
  font-family: var(--ui); font-size: var(--s-pequeno); margin: 0 0 12px;
  padding: 6px 10px; border-radius: var(--radio); display: inline-block;
}
.veredicto--blanco { background: var(--panel-2); color: var(--mut); }
.veredicto--be { background: var(--verde-bg); color: var(--verde); }
.veredicto--mal { background: var(--rojo-bg); color: var(--rojo); }

.resultado { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }
.resultado__calificacion { text-align: center; }
.cuenta { font-size: 16px; line-height: 1.7; }

/* --- Supuesto práctico ---------------------------------------------------- */

/* Un caso con sus preguntas, tal como cayó. Lo usan la vista de examen y la
   impresión; la página del supuesto tiene su propia rejilla, más abajo. */
.supuesto { margin-top: 34px; }

.pagina--supuesto { max-width: 1240px; }
.caso-y-preguntas { display: grid; grid-template-columns: 372px 1fr; gap: 30px; align-items: start; }
/* El caso se queda quieto: se consulta en cada una de las treinta preguntas. */
.caso-y-preguntas__caso { position: sticky; top: 20px; max-height: calc(100vh - 60px); overflow-y: auto; }
.caso-y-preguntas__preguntas { min-width: 0; }
@media (max-width: 900px) {
  .caso-y-preguntas { grid-template-columns: 1fr; }
  .caso-y-preguntas__caso { position: static; max-height: none; }
}

/* --- Ajustes -------------------------------------------------------------- */

.ajuste { padding: 16px 0; border-bottom: 1px solid var(--rule-soft); font-family: var(--ui); }
.ajuste > label { display: block; font-size: var(--s-ui); font-weight: 500; }
.ajuste > label input { margin-right: 8px; }
.ajuste .pequeno { margin: 6px 0 0; line-height: 1.5; }
.ajuste .elegir { margin: 8px 0 0; }
/* Un campo escrito a mano dentro de una fila de formulario: mismo trazo que el
   buscador y que `.apunte textarea`, que es el que ya tiene esta casa. Sin esto
   el navegador pinta el suyo y la página deja de parecerse a sí misma. */
.ajuste textarea, .ajuste input[type="text"] {
  width: 100%; margin: 8px 0 0; padding: 8px 12px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--bg); color: var(--txt);
  font-family: var(--ui); font-size: 14.5px; line-height: 1.6; resize: vertical;
}

.ficha { margin-bottom: 12px; }
/* Lo que está a medias se dibuja a medias: línea discontinua, y el número real
   escrito al lado. Enseñarlo entero sería mentir sobre lo que hay. */
.ficha--incompleta { border-style: dashed; }
/* «En construcción» es la decisión, no la medida: se dice con palabras y en
   negrita, no con otro borde. Dos bordes distintos para dos cosas parecidas no
   se distinguen de un vistazo, y esta es la que importa (P-1). */
.aviso-construccion { margin: 6px 0 0; font-weight: 700; }
.inventario { margin: 10px 0 0; font-size: var(--s-ui); line-height: 1.7; }
.pie-catalogo { margin-top: 40px; }

.prueba { border-top: 3px solid var(--rule); }
.prueba__nombre { margin: 0 0 2px; font-size: 18px; }
/* La fecha manda sobre el resto de la caja: con las pruebas separadas por un
   año, cuál cae antes decide qué se estudia hoy. */
.prueba__quan { margin: 0 0 10px; font-family: var(--ui); font-size: var(--s-ui); }
.prueba__quan .pequeno { margin-left: 8px; }
.prueba__baremo { margin: 8px 0 14px; font-size: var(--s-ui); line-height: 1.6; }
.prueba__examenes { margin: 10px 0 0; }
/* Las acciones abajo del todo y alineadas entre cajas, aunque una diga más. */
.prueba__acciones { margin-top: auto; padding-top: 14px; }
/* Practicar es verde en todas partes: el enlace del tema, el acierto y este
   botón. Si aquí fuera gris, el color dejaría de significar lo mismo. */
/* Imprimir se ve igual en el temario, en el bloque, en el tema y en los apuntes:
   el mismo icono y el mismo tratamiento. Antes era un botón en un sitio y un
   enlace suelto en otro, y no se reconocía como la misma acción. */
/* **Practicar e imprimir son el mismo botón**, y solo se diferencian en el
   icono y en el color: la flecha en verde y la impresora en gris. Las dos
   acciones se ofrecen en todas las pantallas —el temario, el bloque, el tema, tu
   espacio— y hasta ahora cada sitio las pintaba a su manera: botón relleno en la
   prueba, enlace con flecha dentro del tema, flecha suelta en cada fila del
   índice. Eran la misma acción y no lo parecían.
   Lo único que cambia entre sitios es el tamaño. */
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija padding-top (comprobado: 6px, igual en / y en /test); ninguna de las propiedades de este `.boton--accion` —color, fondo, borde…— la toca. */
.boton--accion {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--panel-2); color: var(--mut);
  font-family: var(--ui); font-size: var(--s-ui); line-height: 1.2;
  text-decoration: none; cursor: pointer;
  /* Un botón no se estira. Dentro de una caja en columna —«Mi espacio»— el
     estirado por defecto lo dejaba de 326 px de ancho para decir «Practicar».
     Todos los de una misma fila miden lo mismo de alto, así que alinear arriba
     no mueve nada donde van en línea. */
  align-self: start;
}
/* stylelint-disable-next-line no-descending-specificity -- mismo caso: `padding-top` es la única propiedad de la regla ganadora, y `:hover` aquí solo cambia fondo/color/borde — no hay solape. */
.boton--accion:hover { background: var(--sel); color: var(--txt); border-color: var(--mut); }
.boton--accion svg { flex: none; }

/* El color de practicar. En gris queda lo que va al papel: no compite con las
   acciones de estudiar, que son las que llevan color con significado. */
.boton--practicar { color: var(--verde); border-color: var(--verde-suave); }
.boton--practicar:hover { color: var(--verde); border-color: var(--verde); background: var(--verde-bg); }

/* Grande para la acción de cabecera de una prueba o del selector de test;
   pequeño y solo con icono para las filas del índice, donde hay setenta y dos
   seguidas y el texto sería setenta y dos veces la misma palabra. */
.boton--gran { padding: 9px 18px; font-size: 15px; }
/* Los de dentro de una fila del temario son la excepción, y a propósito: hay
   setenta y dos seguidos y a 34 px la lista se vuelve una escalera de botones.
   Pequeños los dos, y con la misma altura entre ellos. */
.boton--icono { padding: 0; width: 28px; height: 26px; min-height: 0; gap: 0; }

.avance-bloque { margin-bottom: 12px; }
.avance-bloque__cap { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 5px; }

.filas { display: flex; flex-direction: column; }
.filas > * {
  display: flex; align-items: baseline; gap: 14px;
  padding: 10px 0; border-bottom: 1px solid var(--rule-soft);
  font-family: var(--ui); font-size: var(--s-ui);
}
.filas > *:last-child { border-bottom: none; }
.filas .data { flex: none; width: 92px; color: var(--mut); font-size: var(--s-pequeno); }

/* El historial de tests reutiliza `.filas` pero cada fila es un enlace: se
   abre uno pasado con un solo clic, no con el «data» suelto y un botón aparte.
   `display: contents` en el enlace deja que el `<li>` siga siendo quien reparte
   la fila en flex; sin esto el `<a>` se metería como una caja más dentro. */
/* stylelint-disable-next-line no-descending-specificity -- los enlaces del historial de tests (`.filas > li > a`, en /progreso) no viven dentro de `.migas`: comprobado con getComputedStyle, sin solape. */
.filas > li > a { display: contents; color: inherit; text-decoration: none; }
.filas > li:has(a):hover { background: var(--panel-2); }

/* --- 7. Índice del tema (barra lateral) ----------------------------------- */

.indice-tema { display: flex; flex-direction: column; gap: 2px; font-family: var(--ui); }
.indice-tema ul { list-style: none; margin: 0; padding: 0; }
.indice-tema li ul { margin-left: 12px; }
/* stylelint-disable-next-line no-descending-specificity -- el índice del tema y las migas de pan son ramas distintas del DOM: comprobado con getComputedStyle en /tema, sin solape. */
.indice-tema a {
  display: block;
  padding: 7px 10px;
  margin: 0 -10px;
  border-left: 2px solid transparent;
  border-radius: var(--radio);
  text-decoration: none;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--mut);
  transition: background .2s ease, color .2s ease;
}
.indice-tema a:hover { color: var(--txt); }
/* El observador de scroll marca `aria-current`; al llegar al final del documento
   manda la última sección visible, no la que cruza el umbral. */
.indice-tema a[aria-current="true"] {
  color: var(--txt);
  background: var(--sel);
  border-left-color: var(--teja);
}

.progreso-lectura { height: 3px; background: var(--rule); border-radius: 2px; overflow: hidden; }
.progreso-lectura > span { display: block; height: 100%; background: var(--teja); transition: width .2s linear; }

/* --- 8. Apuntes propios --------------------------------------------------- */

/* Papel amarillo gastado, no un recuadro más de la maqueta. Es lo único de la
   pantalla que has escrito tú, y tiene que leerse como algo pegado encima del
   temario. El comentario de examen, que es texto nuestro pero impreso, lleva
   recuadro verde: así no se confunden. */
.apunte {
  padding: 13px 16px;
  margin: calc(var(--paso) * 4) 0;
  background: var(--postit);
  border: none;
  border-radius: 2px;
  /* La sombra corta es lo que hace de papel encima del papel. Sin borde: un
     post-it no tiene filete, tiene canto. */
  box-shadow: 0 1px 2px var(--postit-sombra);
}
.apunte > .rotulo { margin-bottom: 6px; color: var(--postit-txt); }
/* stylelint-disable-next-line no-descending-specificity -- `.apunte` cuelga de `<article>`; `.term-popover` es hermano de `<article>` dentro de `.marco__texto`. Son subárboles distintos: ningún `<p>` es descendiente de los dos a la vez. */
.apunte p { font-size: 14.5px; line-height: 1.6; margin: 0; }
.apunte--tema { margin-bottom: calc(var(--paso) * 6); }
.apunte textarea {
  width: 100%; margin: 8px 0; padding: 10px 12px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--bg); color: var(--txt);
  font-family: var(--serif); font-size: 14.5px; line-height: 1.6; resize: vertical;
}
/* Reubicado por parecido, o sin párrafo al que volver: en los dos casos el
   apunte comenta algo que ya no dice exactamente lo que decía, y se avisa. */
.apunte--movido, .apunte--huerfano { border-left: 3px solid var(--ambar); border-radius: 0 2px 2px 0; }
.cita { color: var(--mut); font-style: italic; font-size: 13.5px; }
.apunte .cita { color: var(--postit-txt); opacity: .8; }

/* --- El «+» de cada párrafo ------------------------------------------------ */

/* El hueco que `render` deja detrás de cada bloque anotable. Vacío no ocupa. */
.anclaje:empty { display: none; }

/* Absoluto sin `top` ni `left`: se queda en su posición estática —justo antes
   del bloque que va detrás— y de ahí lo mueven los márgenes. Así no empuja el
   texto ni se mete dentro de una tabla, y **acompaña al párrafo al desplazarse**
   porque el artículo es `relative` y hace de bloque contenedor. */
.anotar-aqui {
  position: absolute;
  /* A la derecha con `right`, no con un margen en porcentaje: el margen se mide
     contra el bloque contenedor y acababa sacando barra horizontal. Con `right`
     queda clavado en el canalón del artículo, donde no pisa el texto.
     `top` sigue en `auto`, que es lo que mantiene la altura de su párrafo. */
  right: 10px;
  margin: 24px 0 0;
  width: 24px; height: 24px; padding: 0;
  border: 1px solid var(--rule-soft); border-radius: 50%;
  background: none; color: var(--mut);
  font-family: var(--ui); font-size: 16px; line-height: 1;
  cursor: pointer; opacity: .5; transition: opacity .12s;
}
/* **Siempre visible, y flojo.** Antes salía solo al pasar el ratón por su
   párrafo, y eso deja la función sin existir en un móvil: no hay «pasar por
   encima». Al 50 % no compite con el texto y se ve que está. Se enciende del
   todo el de su párrafo, que es la ayuda que sí depende del ratón —con el
   mismo borde y fondo que al pasar por encima del propio botón, que solo la
   opacidad no se notaba. */
.anotar-aqui:has(+ [data-ancla]:hover) {
  opacity: 1; border-color: var(--rule); background: var(--panel);
}
/* Y no se apaga al ir a pulsarlo: hay que salir del párrafo para llegar al
   margen, y sin esta regla el botón desaparecía justo antes del clic. */
/* stylelint-disable-next-line no-descending-specificity -- mismo valor que la regla ganadora (opacity: 1; border-color: var(--rule); background: var(--panel)) para `:hover` y `:focus`: son variantes deliberadas del mismo estado visual (botón enfocado/pasado vs. párrafo vecino en hover), no un pisado — gane la que gane, se pinta igual. */
.anotar-aqui:hover, .anotar-aqui:focus { opacity: 1; border-color: var(--rule); background: var(--panel); }
/* Con el teclado tiene que verse siempre: si solo aparece al pasar el ratón,
   con `Tab` se salta a un botón invisible. */
/* stylelint-disable-next-line no-descending-specificity -- la opacidad coincide (1) con la regla ganadora; outline/outline-offset no los toca esa regla — no hay pisado real, solo se añade el contorno de foco visible. */
.anotar-aqui:focus-visible { opacity: 1; outline: 2px solid var(--teja); outline-offset: 1px; }
/* Al estar fuera del flujo, el margen superior del bloque no lo empuja: se lo
   suma cada uno. Un encabezado deja más aire encima que un párrafo. */
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija opacity/border-color/background; esta solo pone margin-top: no comparten ninguna propiedad. */
.anotar-aqui:has(+ p)  { margin-top: 20px; }
/* stylelint-disable-next-line no-descending-specificity -- igual que la anterior: la ganadora no toca margin-top. */
.anotar-aqui:has(+ h2) { margin-top: 40px; }
/* stylelint-disable-next-line no-descending-specificity -- igual que las dos anteriores: la ganadora no toca margin-top. */
.anotar-aqui:has(+ h3) { margin-top: 32px; }

/* El del tema entero va en la fila del título, que es `flex`: ahí no hace falta
   posición absoluta ni esperar a pasar por encima de nada. */
.anotar-aqui--tema {
  position: static; margin: 6px 0 0; flex: none;
  opacity: .7; border-color: var(--rule);
}
.anotar-aqui--tema:hover { opacity: 1; background: var(--panel); }

/* Las dos cosas que se pueden hacer sobre un párrafo: apuntar algo para ti, o
   avisar de que está mal. El menú es flotante, anclado a los puntos con la
   misma API `popover` que el término (A2 §1): de ahí el `position: fixed` y
   que JavaScript solo tenga que fijar `left`/`top`. En columna y del ancho de
   su contenido —`width: max-content`—, como cualquier menú contextual: dos
   opciones cortas no necesitan una caja tan ancha como el párrafo. */
.menu-parrafo {
  display: flex; flex-direction: column; gap: 2px; margin: 0;
  padding: 6px; border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--panel); box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  position: fixed; width: max-content; max-width: calc(100vw - 16px);
}
.menu-parrafo::backdrop { background: transparent; }
.menu-parrafo__opcion {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px; border: 1px solid transparent; border-radius: var(--radio);
  background: none; color: var(--txt);
  font-family: var(--ui); font-size: var(--s-ui); cursor: pointer;
}
/* Cada opción con su icono: son dos cosas distintas —una es tuya y la otra va a
   quien escribe los temas— y a dos palabras de distancia se eligen mal. */
.menu-parrafo__opcion svg { flex: none; color: var(--mut); }
.menu-parrafo__opcion:hover svg { color: inherit; }
.menu-parrafo__opcion:hover { background: var(--sel); }

/* Avisar de un error no es un apunte y no lleva papel amarillo: es una nota
   dirigida a quien escribe los temas, no algo tuyo pegado encima. Y es
   efímera —se va al aceptar, con el envío del formulario— así que flota
   anclada a los puntos en vez de abrirse debajo del párrafo: no empuja el
   texto ni deja hueco. Mismo mecanismo que el menú: `popover` nativo,
   `position: fixed`, JavaScript solo coloca `left`/`top`. */
.sugerencia {
  background: var(--panel); color: var(--txt); box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
  position: fixed; margin: 0; width: 400px; max-width: calc(100vw - 16px);
}
.sugerencia::backdrop { background: transparent; }
.sugerencia select { margin: 4px 0 8px; }

/* El apunte del tema entero, plegado si no lo hay. Un recuadro de texto siempre
   abierto al final del tema ocupaba sitio y no se usaba; uno ya escrito tiene
   que verse sin abrir nada, y por eso el `details` sale `open` cuando existe. */
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `background`; este `> summary` fija cursor/tipografía/color — ninguna propiedad compartida. */
.apunte-del-tema > summary {
  cursor: pointer; font-family: var(--ui); font-size: var(--s-ui); color: var(--mut);
}
.apunte-del-tema[open] > summary { margin-bottom: 8px; }


/* --- 9. Test: pregunta, opciones y corrección ----------------------------- */

.bloque-pregunta {
  padding: 18px 20px;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--rule);
  border-radius: var(--radio);
}
.bloque-pregunta + .bloque-pregunta { margin-top: 12px; }
.bloque-pregunta--error   { border-left-color: var(--rojo); }
.bloque-pregunta--blanco   { border-left-color: var(--mut); }
.bloque-pregunta--acierto  { border-left-color: var(--verde); }

.bloque-pregunta__meta {
  display: flex; align-items: baseline; gap: 10px;
  font-family: var(--ui); font-size: var(--s-pequeno); color: var(--mut);
}
.bloque-pregunta fieldset { margin: 0; padding: 0; border: none; }
.bloque-pregunta legend { padding: 0; font-size: 16.5px; line-height: 1.65; }

.opciones { display: flex; flex-direction: column; gap: 6px; margin: 14px 0 0; padding: 0; list-style: none; }
.opcion {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: 44px;            /* obligatorio: se marca con el dedo */
  padding: 10px 14px;
  margin: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radio);
  font-size: 15.5px;
  line-height: 1.55;
}
.opcion label { display: flex; align-items: flex-start; gap: 12px; width: 100%; cursor: pointer; }
.opcion--elegida  { border: 1.5px solid var(--teja); background: var(--sel); }
.opcion.correcta { border-color: transparent; background: var(--verde-bg); }
.opcion.fallo  { border-color: transparent; background: var(--rojo-bg); }
.opcion--descartada {
  border: none; padding: 4px 14px; font-size: 14px; color: var(--mut); min-height: 0;
}
.opcion .letra { flex: none; font-family: var(--ui); font-weight: 600; color: var(--mut); }
.opcion img { max-width: 100%; height: auto; }
/* El icono va DENTRO del círculo de color: quien no distingue verde y rojo
   tiene que poder leer el resultado igualmente. */
.opcion__marca {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%; margin-top: 1px;
}
.opcion__marca--be  { background: var(--verde); color: var(--bg); }
.opcion__marca--mal { background: var(--rojo); color: var(--bg); }

.justificacion { margin: 14px 0 0; padding: 14px 16px; background: var(--panel); }
.justificacion .rotulo { font-family: var(--titulo); font-weight: 700; font-size: var(--s-pequeno); }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora fija margin-top; esta fija margin-bottom — lados distintos del margen, no hay pisado. */
.justificacion p:last-child { margin-bottom: 0; }
.errata {
  margin: 12px 0 0;
  padding: 14px 16px;
  background: var(--ambar-bg);
  border-left: 2px solid var(--ambar);
}
.marca-errata {
  display: inline-block; width: 6px; height: 6px;
  background: var(--ambar); transform: rotate(45deg);
}

.relato {
  padding: 16px 20px; margin: 0 0 18px;
  background: var(--panel); border-left: 2px solid var(--rule);
  font-size: 15.5px; line-height: 1.7;
}
/* stylelint-disable-next-line no-descending-specificity -- mismo caso que `.justificacion`: margin-top (ganadora) y margin-bottom (esta) son lados distintos. */
.relato p:last-child { margin-bottom: 0; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `background`; este `> summary` fija tipografía/color/cursor — sin propiedad compartida. */
.relato-plegado > summary { font-family: var(--ui); font-size: var(--s-pequeno); color: var(--mut); cursor: pointer; }
.contexto { margin: 0 0 10px; font-size: 15.5px; line-height: 1.65; color: var(--mut); }

/* Pregunta de otra categoría o subgrupo (C-19). Se lee antes del enunciado,
   porque cambia cómo hay que tomársela: entrena, pero no mide qué va a caer.
   Va con la barra a la izquierda, como el relato, y no solo con color: en
   papel y sin distinguir el ámbar sigue leyéndose el texto. */
.hermana {
  margin: 0 0 10px; padding: 4px 0 4px 10px;
  border-left: 2px solid var(--ambar);
  font-family: var(--ui); font-size: var(--s-pequeno); color: var(--mut);
}

.aviso {
  display: inline-block; padding: 2px 8px;
  background: var(--ambar-bg); border-left: 2px solid var(--ambar);
  font-family: var(--ui); font-size: var(--s-pequeno); color: var(--txt);
}

/* --- 10. Temario: bloques y estado de cada tema --------------------------- */

.bloque { border: 1px solid var(--rule); border-radius: var(--radio); margin-bottom: 10px; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `background`; este `> summary` fija layout/tipografía — sin propiedad compartida. */
.bloque > summary {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px; cursor: pointer; list-style: none;
  font-family: var(--titulo); font-weight: 700; font-size: 16px;
}
.bloque > summary::-webkit-details-marker { display: none; }
.bloque > summary::before {
  content: ""; flex: none; width: 7px; height: 7px;
  border-right: 1.4px solid var(--mut); border-bottom: 1.4px solid var(--mut);
  transform: rotate(-45deg);
}
.bloque[open] > summary::before { transform: rotate(45deg); }
/* **La cifra fija sirve para lo que cambia y estorba en lo que no**, y este
   rótulo es de los que no: el «2/4» de un bloque del temario se lee una vez,
   dentro de una línea de texto, y no se compara con el de arriba ni con el de
   abajo. En monoespaciada —como estaba— se veía espaciado y ajeno a la letra
   que lo rodea, sin ganar nada a cambio.

   `proportional-nums` va escrito aunque hoy sea lo que Public Sans ya hace por
   su cuenta: es la mitad de una pareja, y la pareja es lo que se quiere leer de
   un vistazo. */
.bloque__cuenta {
  margin-left: auto; font-family: var(--ui); font-variant-numeric: proportional-nums;
  font-size: var(--s-pequeno); color: var(--mut);
}
/* La otra mitad: el recuento del selector de test **cambia en su sitio** con
   cada casilla que marcas. Ahí el ancho no puede depender de qué cifras toquen,
   o el rótulo baila al pasar de 9 a 10. */
.bloque__cuenta--viva { font-family: var(--mono); }
.bloque__temas { padding: 0 18px 12px; }

.tema-fila {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 0; border-top: 1px solid var(--rule-soft);
  font-family: var(--ui); font-size: var(--s-ui);
  border-radius: var(--radio); scroll-margin-top: 20px;
  transition: box-shadow .5s ease-out;
}
/* El tema del que vienes, al volver al índice (U-1): un destello que se apaga
   solo. No es `--sel` —el fondo de lo ya elegido— a propósito: esto no es una
   selección que se quede, es un «aquí estabas» de paso, y por eso es un
   contorno que se retira, no un relleno que se queda puesto. Cuánto dura la
   decide `opos.js` con un `setTimeout`; aquí solo se dice cómo entra y cómo
   sale. Con `prefers-reduced-motion` la regla de más arriba ya deja
   `transition-duration` en `.01ms`: entra y sale de golpe sin animación, pero
   sigue puesta mientras `opos.js` la mantenga, así que no se pierde. */
.tema-fila--destello { box-shadow: inset 3px 0 0 var(--teja), 0 0 0 3px var(--teja-soft); }
/* stylelint-disable-next-line no-descending-specificity -- la fila de tema en el selector de test y las migas de pan no comparten nunca elemento: comprobado con getComputedStyle, sin solape. */
.tema-fila a { text-decoration: none; }
.tema-fila a:hover { text-decoration: underline; }
.tema-fila__num { flex: none; width: 26px; color: var(--mut); font-size: var(--s-pequeno); text-align: right; }
.tema-fila__datos { margin-left: auto; display: flex; align-items: center; gap: 10px; color: var(--mut); font-size: var(--s-pequeno); }
/* Ancho fijo también cuando el dato falta: es lo que hace que las columnas de
   setenta y dos filas queden una debajo de otra y bajo su rótulo. */
/* El botón de practicar de cada fila lleva el número dentro. Ancho fijo, y el
   hueco también cuando el tema no tiene preguntas: es lo que mantiene las
   setenta y dos filas en columna. */
.boton--cuenta {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  width: 56px; height: 26px; min-height: 0; padding: 0;
  font-variant-numeric: tabular-nums;
}

/* La marca de estado: la casilla del logotipo, marcada cuando el tema está
   estudiado y vacía cuando no. En teja, que es el color de estudiar; el verde
   es el de practicar y aquí confundía las dos cosas. Empezado y pendiente
   comparten dibujo y se separan por el tono. Lleva texto alternativo porque el
   color solo no basta. */
.estado {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  /* En teja las tres, y en gris ninguna: la casilla vacía en `--rule` se leía
     como un checkbox de formulario y no como la marca de aquí. */
  color: var(--teja-soft);
  /* El ancho es el del porcentaje —«100 %»—, no el del icono: sin él las filas
     con casilla y las que llevan porcentaje empezaban el título en sitios
     distintos. */
  width: 34px; justify-content: flex-start;
  font-size: var(--s-pequeno); font-variant-numeric: tabular-nums;
}
.estado--hecho, .estado--curso { color: var(--teja); }
.rombo-errata {
  display: inline-block; flex: none;
  width: 7px; height: 7px; background: var(--ambar); transform: rotate(45deg);
}

/* --- 11. Progreso --------------------------------------------------------- */

/* La gráfica con su escala al lado. Sin ella una barra sola es un rectángulo
   de colores: no se sabe de cuánto es ni sobre qué. */
.grafica { display: flex; gap: 10px; align-items: stretch; }
.grafica__eix {
  display: flex; flex-direction: column; justify-content: space-between;
  height: 120px; font-family: var(--ui); font-size: 11px; color: var(--mut);
  text-align: right; min-width: 16px;
}

.evolucion {
  position: relative; flex: 1;
  display: flex; align-items: flex-end; gap: 5px;
  height: 120px; margin: 0; padding: 0; list-style: none;
  border-bottom: 1px solid var(--rule);
}
/* La línea del cinco. Una calificación no dice nada hasta que se ve de qué lado
   del aprobado cae. */
.evolucion::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 50%;
  border-top: 1px dashed var(--rule);
}
.evolucion__barra {
  position: relative;
  /* Con tope: un solo test no puede salir como una franja de lado a lado. */
  flex: 1 1 auto; min-width: 4px; max-width: 44px;
  background: oklch(.82 .04 60); transform-origin: bottom;
  animation: barra .6s cubic-bezier(.2, .8, .2, 1) both;
}
.evolucion__barra--ultima { background: var(--teja); }
.evolucion__cifra {
  position: absolute; bottom: 100%; left: 0; right: 0;
  font-family: var(--ui); font-size: 11px; color: var(--mut); text-align: center;
  padding-bottom: 3px;
}
@keyframes barra { from { transform: scaleY(.04); } to { transform: scaleY(1); } }

.mapa-dias__semana {
  display: grid; grid-template-columns: repeat(7, 17px); gap: 4px; margin-bottom: 4px;
  font-family: var(--ui); font-size: 10px; color: var(--mut); text-align: center;
}
.leyenda { display: flex; align-items: center; gap: 4px; margin-top: 8px; }
.leyenda__cubo { width: 11px; height: 11px; border-radius: 1px; background: var(--rule-soft); }
.leyenda__cubo[data-nivel="1"] { background: oklch(.75 .07 150); }
.leyenda__cubo[data-nivel="2"] { background: oklch(.6 .1 150); }
.leyenda__cubo[data-nivel="3"] { background: oklch(.5 .12 150); }
.leyenda__cubo[data-nivel="4"] { background: oklch(.42 .13 150); }
.leyenda > span:first-child { margin-right: 4px; }
.leyenda > span:last-child { margin-left: 4px; }

.mapa-dias { display: grid; grid-template-columns: repeat(7, 17px); gap: 4px; margin: 0; padding: 0; list-style: none; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `border-bottom: none`; este `> *` del mapa de días fija alto/color/radio — sin propiedad compartida. */
.mapa-dias > * { height: 17px; border-radius: 1px; background: var(--rule-soft); }
.mapa-dias > *[data-nivel="1"] { background: oklch(.75 .07 150); }
.mapa-dias > *[data-nivel="2"] { background: oklch(.6 .1 150); }
.mapa-dias > *[data-nivel="3"] { background: oklch(.5 .12 150); }
.mapa-dias > *[data-nivel="4"] { background: oklch(.42 .13 150); }
.mapa-dias > *[data-hoy]      { background: none; border: 1.5px solid var(--teja); }

.anillo { display: flex; align-items: center; gap: 18px; }
/* Los días que aún no han llegado se dejan marcados pero apagados: el mapa
   cuadra en semanas completas sin fingir que esos días ya pasaron. */
.dia-futuro { opacity: .35; }

.barra-mini { height: 3px; background: var(--rule); border-radius: 2px; overflow: hidden; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `margin-right`; este `> span` de la barra fija alto/fondo/transición — sin propiedad compartida. */
.barra-mini > span { display: block; height: 100%; background: var(--teja); transition: width .2s linear; }
/* stylelint-disable-next-line no-descending-specificity -- igual que la anterior: la ganadora no toca `background`. */
.barra-mini--verde > span { background: var(--verde); }

table { border-collapse: collapse; width: 100%; font-family: var(--ui); font-size: var(--s-ui); }
th, td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--rule-soft); }
thead th { background: var(--panel); font-weight: 600; border-bottom: 1px solid var(--rule); }

/* --- 12. Marco de lectura ------------------------------------------------- */

.marco { position: relative; height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
.marco__fila { flex: 1; min-height: 0; display: flex; }
.marco__lateral {
  flex: none; width: 262px; height: 100%; overflow-y: auto;
  padding: 24px 20px 96px; border-right: 1px solid var(--rule);
}
.marco__lateral-titulo {
  font-family: var(--titulo); font-weight: 700; font-size: 15px;
  line-height: 1.35; margin: 0 0 18px;
}
.marco__texto { flex: 1; min-width: 0; height: 100%; overflow-y: auto; scroll-behavior: smooth; }
/* La barra de scroll tiene que quedar en el canto de la ventana, no al lado
   del texto: por eso scrollea el contenedor y no la columna. */
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `border-bottom: none`; `.marco__texto > *` fija ancho/margen/padding — sin propiedad compartida. */
.marco__texto > * { max-width: var(--col); margin: 0 auto; padding: 40px 46px 140px; }
/* El pie va **debajo** del artículo, así que el hueco para la barra flotante lo
   tiene que dejar él: el artículo ya no es lo último. Sin esto, `footer.pagina`
   ganaba con sus 40 px propios —más específico que `.marco__texto > *`— y la
   barra se comía el aviso legal, que es justo el que no puede quedar oculto. */
.marco__texto > footer.pagina { padding-bottom: 80px; }
/* `right` se queda corto 16 px, el ancho de la barra de scroll de `.marco__texto`
   en un navegador de escritorio normal: a ras de borde, la franja flotante se
   la comía y ni se veía ni se podía arrastrar. En un scrollbar superpuesto
   (macOS, móvil) sobra el hueco, pero no se ve: no reserva sitio. */
.marco__barra {
  position: absolute; left: 0; right: 16px; bottom: 0;
  padding: 12px 26px; border-top: 1px solid var(--rule); background: var(--panel);
  font-family: var(--ui);
}
.marco__barra > div { display: flex; align-items: center; gap: 14px; transition: opacity .3s ease; }
.marco__barra form { margin: 0; }
.marco__barra-derecha { margin-left: auto; display: flex; align-items: center; gap: 18px; }

.lateral__pie { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--rule); }
.lista-fonts { margin-top: 14px; font-size: 15px; line-height: 1.6; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `background` en `:hover`; `margin-bottom` de esta regla es una propiedad distinta. */
.lista-fonts li { margin-bottom: 9px; }
/* Con bullets, y solo la de la convocatoria: una lista de documentos se recorre
   con la vista y se ve de un golpe cuántos hay. Las otras `lista-fonts` —las
   fuentes de un tema, el papel— son la ficha de una fuente y ahí el punto
   estorba. Modificador y no cambio de `.lista-fonts`, por eso. */
.lista-fonts--puntos { padding-left: 1.15em; list-style: disc; }
.lista-fonts--puntos li::marker { color: var(--mut); }
.practicar-final { margin-top: 30px; }
/* stylelint-disable-next-line no-descending-specificity -- `.ajuste .elegir` gana a propósito dentro de `.ajuste` (los dos `<select>` de /ajustes y el `<input>` de /test): comprobado, margin-top da 8px ahí. Fuera de `.ajuste` —el campo `#confirmar` de borrar datos, en /ajustes— esta regla sí manda: comprobado, margin-top da 6px. Es un override de contexto a propósito, no un defecto. */
.elegir {
  display: block; margin: 6px 0 12px; padding: 7px 10px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--bg); color: var(--txt); font-family: var(--ui); font-size: var(--s-ui);
}

/* Los títulos **del tema** escalan con las tres «A»; los de la interfaz no.
   Estaban en píxeles fijos, así que al pedir letra grande crecía el cuerpo y el
   título se quedaba igual: desde arriba del tema parecía que no había pasado
   nada y que hacía falta recargar. Van en `em` contra el propio artículo, que es
   quien lleva el tamaño de lectura. */
/* `relative` no es decorativo: sin un antepasado posicionado, los «+» absolutos
   se colocan contra la ventana y se quedan clavados mientras el texto —que
   scrollea en `.marco__texto`, no en la página— pasa por debajo. */
.marco__texto article { position: relative; font-size: var(--s-cuerpo); }
.marco__texto h1 { font-size: 1.88em; }
.marco__texto h2 { margin: 34px 0 0; font-size: 1.18em; }
.marco__texto h3 { margin: 26px 0 0; font-size: 1em; }
/* stylelint-disable-next-line no-descending-specificity -- el primer párrafo del popover de término gana a propósito: sin margen superior para no dejar hueco en un recuadro flotante pequeño — comprobado en /tema: `margin-top` da 0px en ese párrafo, con `.marco__texto p` puesto en la hoja pidiendo 14px. */
.marco__texto p { margin: 14px 0 0; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `margin-left`; `.marco__texto ul` fija tipografía — sin propiedad compartida. */
.marco__texto ul, .marco__texto ol { font-size: var(--s-cuerpo); line-height: var(--lh-cuerpo); }
.marco__texto table { margin: 18px 0 0; border: 1px solid var(--rule); border-radius: var(--radio); }

/* Cada sigla que el tema abre —«COBIT (Control Objectives for…)»— llega marcada
   con `<abbr title="…">` (render, lo-4f10). El navegador ya da gratis el
   subrayado y el desarrollo al pasar el ratón; esto solo evita que se pierda
   ese aspecto entre el resto de la tipografía del cuerpo. Sin `cursor: help`
   a propósito: ese cursor invita a pulsar y `abbr` no responde a ningún clic
   (decisión A2, payload lo-da2f). */
.marco__texto abbr {
  text-decoration: underline dotted 1px;
  text-underline-offset: 2px;
}
/* La primera aparición es la que lleva el desarrollo al lado, en el propio
   texto —el resto son la sigla suelta—, así que se distingue con trazo
   continuo y va sin `title`: repetir en un hint lo que ya está escrito al
   lado sobra. Las apariciones posteriores sí llevan `title`, que es donde
   hace falta (decisión A2, payload lo-da2f). */
.marco__texto abbr.abbr--primera { text-decoration-style: solid; }

/* Las tres clases de cita del temario. Antes se leían las tres igual, y eso
   hacía imposible saber si una frase era el enunciado oficial del punto, el
   texto literal de una ley o un consejo nuestro sobre qué preguntan. La etiqueta
   sale del idioma del artículo: `render` no conoce las cadenas de la interfaz y
   no tiene por qué. */
.destacado { margin: 22px 0 0; }
/* stylelint-disable-next-line no-descending-specificity -- mismo valor que la regla ganadora (`margin-top: 0`) en las dos: gane la que gane, el resultado es idéntico. */
.destacado > p:first-child { margin-top: 0; }
.destacado::before {
  display: block; margin-bottom: 6px;
  font-family: var(--ui); font-size: 11px; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase;
}

/* El enunciado del punto oficial: es lo único de la página que ha escrito el
   tribunal, y va en teja, que es el color de la fuente oficial. */
.destacado--enunciado {
  padding: 12px 16px; border-left: 2px solid var(--teja);
  background: var(--panel-2); font-family: var(--ui); font-size: 15px;
}
.destacado--enunciado::before { content: var(--et-enunciado, "Enunciado oficial"); color: var(--teja); }
.destacado--enunciado strong:first-child { display: none; }

/* Texto literal de una norma. Sin caja: es texto para leer seguido, y encajarlo
   lo convierte en un adorno. La sangría y el filete de la izquierda bastan. */
.destacado--norma {
  padding-left: 18px; border-left: 2px solid var(--rule);
  font-style: normal; color: var(--txt);
}
.destacado--norma::before { content: var(--et-norma, "Texto literal"); color: var(--mut); }

/* Comentario nuestro sobre qué se pregunta. Va en verde, que en toda la
   aplicación es el color del examen y de practicar —el enlace «practicar este
   tema», el acierto, el recuento de preguntas—, y esto es exactamente eso:
   una observación sobre qué cae.

   Estaba en ámbar y se confundía con los apuntes propios, que también son
   ámbar. Son dos cosas distintas y tienen que parecerlo: esto es texto de la
   casa, impreso; el apunte es un papel que has pegado tú encima. Por eso este
   lleva recuadro y el apunte lleva papel de color. */
.destacado--examen {
  padding: 12px 16px; border-radius: var(--radio);
  border: 1px solid var(--verde-suave); background: var(--verde-suave-bg);
  font-family: var(--ui); font-size: 15px; line-height: 1.6;
}
.destacado--examen::before { content: var(--et-examen, "Clave de examen"); color: var(--verde-suave); }

/* Las etiquetas en la lengua del temario. El artículo declara su `lang` y de
   ahí salen: así no hay que pasar cadenas por una capa que no las conoce. */
[lang="ca"] {
  --et-enunciado: "Enunciat oficial";
  --et-norma: "Text literal";
  --et-examen: "Clau d'examen";
}

/* Modo concentración: en concentración solo el texto del tema está a plena
   luz; todo lo demás —texto y controles de la cabecera y de la barra
   flotante, tamaños de letra y claro/oscuro incluidos— al 25 %, y vuelve al
   pasar el ratón por su franja. El botón de Concentración se atenúa menos que
   el resto (a la mitad, no al 25 %): es el único camino de vuelta, y apagarlo
   igual que todo lo demás deja al lector encerrado. La medida de línea no se
   toca: si el lateral se apaga, se aprovecha el sitio.

   **Solo donde hay lector** (`:has(.marco__texto)`). La preferencia vive en
   `localStorage` y viaja a todas las páginas, pero el interruptor solo se pinta
   en el lector: en el aviso legal dejaba la cabecera apagada y sin manera de
   volver al modo normal. */
[data-concentracion="si"]:has(.marco__texto) .marco__lateral { display: none; }
/* La franja de arriba se apaga entera, línea incluida: dejarle el borde a plena
   intensidad mantenía el corte horizontal cruzando la pantalla, que es
   justamente lo que se quiere quitar de la vista. */
[data-concentracion="si"]:has(.marco__texto) .cabecera-grupo { border-bottom-color: transparent; transition: border-color .3s ease; }
/* Se atenúan los controles uno a uno, no la franja `.cabecera__derecha` que los
   envuelve: si se atenuara el envoltorio, la opacidad del botón de
   Concentración se multiplicaría por la del envoltorio y no habría forma de
   dejarlo más visible que sus vecinos. Las migas (A10) están fuera del
   `<header>`, en su propia línea, así que se apagan por su cuenta junto al
   resto del grupo. */
[data-concentracion="si"]:has(.marco__texto) .marco__barra > div,
[data-concentracion="si"]:has(.marco__texto) .cabecera > *:not(.cabecera__derecha),
[data-concentracion="si"]:has(.marco__texto) .migas,
[data-concentracion="si"]:has(.marco__texto) .cabecera__derecha > *:not(.interruptor--concentracion) { opacity: .25; transition: opacity .3s ease; }
[data-concentracion="si"]:has(.marco__texto) .cabecera__derecha > .interruptor--concentracion { opacity: .5; transition: opacity .3s ease; }
/* La navegación es lo primero que sobra cuando se lee: se va del todo, no a
   medias, y vuelve al pasar el ratón por la franja como el resto. */
[data-concentracion="si"]:has(.marco__texto) .cabecera .nav-principal { opacity: 0; }
[data-concentracion="si"]:has(.marco__texto) .cabecera-grupo:hover { border-bottom-color: var(--rule); }
/* Las dos franjas vuelven igual: se pasa el ratón por encima y se ve lo que hay.
   La de abajo estaba escrita, pero agrupada con la regla del borde en vez de con
   la de la opacidad, así que se le pedía a la barra flotante —que no tiene
   borde— que recuperase un borde, y el contenido se quedaba al 25 %. Pasar el
   ratón por cualquiera de las dos líneas del grupo —menú o migas— recupera
   las dos, porque `.cabecera-grupo:hover` cubre a ambas. */
[data-concentracion="si"]:has(.marco__texto) .marco__barra:hover > div,
[data-concentracion="si"]:has(.marco__texto) .cabecera-grupo:hover .cabecera > *:not(.cabecera__derecha),
[data-concentracion="si"]:has(.marco__texto) .cabecera-grupo:hover .migas,
/* stylelint-disable-next-line no-descending-specificity -- los dos selectores están en la MISMA regla (mismo bloque `{ opacity: 1 }`, lista de selectores de las líneas 1275-1296): el orden entre ítems de una lista no cambia el resultado, ambos pintan igual. */
[data-concentracion="si"]:has(.marco__texto) .cabecera-grupo:hover .cabecera__derecha > *,
[data-concentracion="si"]:has(.marco__texto) .cabecera-grupo:hover .nav-principal,
/* Con el foco **de teclado**, no con el que deja un clic. Era `:focus-within`, y
   como el botón de concentración se queda con el foco al pulsarlo, la cabecera
   no se atenuaba nunca: parecía que el interruptor no hacía nada, y solo
   recargando —que pierde el foco— se veía el efecto.

   Dos formas por grupo: `:focus-visible` para cuando el propio control recibe
   el foco (el enlace del logo, los botones), `:has(:focus-visible)` para
   cuando lo recibe algo que envuelve (el grupo de tamaños, las migas). Antes
   solo se comprobaba `:has()`, así que enfocar el propio enlace del logo con
   el tabulador —que no tiene hijos enfocables— no lo encendía. */
[data-concentracion="si"]:has(.marco__texto) .marco__barra > div:has(:focus-visible),
/* stylelint-disable-next-line no-descending-specificity -- misma regla que la ganadora (línea 1275-1296, `{ opacity: 1 }`): no hay pisado posible entre selectores de un mismo bloque. */
[data-concentracion="si"]:has(.marco__texto) .cabecera > *:not(.cabecera__derecha):focus-visible,
/* stylelint-disable-next-line no-descending-specificity -- misma regla que la ganadora: ambos selectores forman parte del mismo bloque `{ opacity: 1 }`. */
[data-concentracion="si"]:has(.marco__texto) .cabecera > *:not(.cabecera__derecha):has(:focus-visible),
/* stylelint-disable-next-line no-descending-specificity -- misma regla que la ganadora: ambos selectores forman parte del mismo bloque `{ opacity: 1 }`. */
[data-concentracion="si"]:has(.marco__texto) .migas:has(:focus-visible),
/* stylelint-disable-next-line no-descending-specificity -- misma regla que la ganadora: ambos selectores forman parte del mismo bloque `{ opacity: 1 }`. */
[data-concentracion="si"]:has(.marco__texto) .cabecera__derecha > *:focus-visible,
/* stylelint-disable-next-line no-descending-specificity -- misma regla que la ganadora: ambos selectores forman parte del mismo bloque `{ opacity: 1 }`. */
[data-concentracion="si"]:has(.marco__texto) .cabecera__derecha > *:has(:focus-visible),
[data-concentracion="si"]:has(.marco__texto) .cabecera .nav-principal:has(:focus-visible) { opacity: 1; }

/* El check del logo al marcar estudiado. */
@keyframes trazo { from { stroke-dashoffset: 46; } to { stroke-dashoffset: 0; } }
.trazo { stroke-dasharray: 46; animation: trazo .45s cubic-bezier(.3, .8, .3, 1) both; }

/* --- 13. Móvil ------------------------------------------------------------ */

@media (max-width: 860px) {
  .columnas { grid-template-columns: 1fr; }
  .cabecera { flex-wrap: wrap; gap: 10px; padding: 10px 16px; }
  .migas { padding: 0 16px 10px; }
  .pagina { padding: 22px 18px 90px; }
}

@media (max-width: 720px) {
  /* El texto no se encoge en el móvil: se estudia igual en el metro. */
  .marco__texto > * { padding: 20px 22px 120px; }
  /* Antes tapaba la pantalla entera (`position: fixed; inset: 0`) sin ningún
     interruptor que lo abriera o cerrara: en cualquier tema con apartados el
     artículo quedaba inalcanzable. No hace falta inventar un botón para
     abrirlo y cerrarlo — las migas ya llevan el título del tema, y el
     porcentaje de lectura ya se repite en la barra de abajo — así que en
     móvil el índice simplemente no sale. */
  .marco__lateral { display: none; }
  .opcion { padding: 13px 15px; border-radius: 8px; }
  .boton, .interruptor { min-height: 44px; }
  .nav-principal { font-size: 13px; }
  .filas > * { flex-wrap: wrap; }
  /* El título de una convocatoria puede partirse en varias líneas —el nombre
     largo de una categoría— y a esta anchura ya no cabe al lado del botón de
     imprimir: se montaban uno encima del otro. El botón baja debajo, sin
     estirarse (sigue midiendo lo que mide `.boton--accion`, 34 px). */
  .tema__cap { flex-direction: column; align-items: flex-start; }
  .tema__cap .boton--accion { margin-top: 8px; }
  /* Estado, «Ver el índice» y el botón de marcar caben; «Anterior»/«Siguiente»
     se caen primero: marcar como estudiado ya avanza al siguiente tema, así
     que no faltan del todo, solo se repiten aquí sin sitio para los dos. */
  .marco__barra-derecha .boton--vecino { display: none; }
}

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

/* --- Avanzar de tema ------------------------------------------------------- */

/* Marcar el tema pasa al siguiente. Sin nada que lo diga, aparece otro texto y
   parece que se haya perdido la página. La entrada deslizada dice que **has
   avanzado**, y el aviso de arriba dice desde dónde. */
.marco__texto--avanza article { animation: entra-tema .34s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes entra-tema {
  from { opacity: 0; transform: translateX(26px); }
  to   { opacity: 1; transform: none; }
}
.avanzaste {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 18px; padding: 9px 14px;
  border-left: 2px solid var(--verde); background: var(--verde-bg);
  font-family: var(--ui); font-size: 13.5px; color: var(--txt);
  animation: se-va 6s ease-in 1.2s both;
}
/* Se retira sola: es el acuse de algo que ya sabes, no un aviso que atender. */
@keyframes se-va { from { opacity: 1; } to { opacity: 0; height: 0; margin: 0; padding: 0; border: 0; } }

/* Quien pide menos movimiento no recibe ninguno: el aviso se queda quieto y
   visible, que es lo que hace falta. */
@media (prefers-reduced-motion: reduce) {
  .marco__texto--avanza article, .avanzaste { animation: none; }
}

/* El título del tema y su botón de imprimir en la misma línea. */
.tema__cap { display: flex; align-items: flex-start; gap: 12px; }
/* `balance` reparte el título entre líneas en vez de dejar la última con una
   palabra suelta: con nombres largos de categoría es donde más se nota. */
.tema__cap h1 { min-width: 0; flex: 1; text-wrap: balance; }
/* Practicar e imprimir, juntos y arriba: al abrir el tema ya se ven las dos
   cosas que se pueden hacer con él, sin bajar a buscarlas. */
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `padding-top`; `.tema__cap .boton--accion` fija `flex`/`margin-top` — sin propiedad compartida. */
.tema__cap .boton--accion { flex: none; margin-top: 4px; }

/* Los nombres de las dos columnas de la derecha del temario, alineados con sus
   números. Sin ellos, un «0 %» al lado de un check de estudiado se lee como una
   contradicción: parece cuánto has leído y son aciertos en los tests. */
/* Los mismos anchos que los datos de la fila: si no, el rótulo dice una cosa y
   la columna está debajo de otra. Los 76 px de la derecha son los dos botones de
   la fila —28 px cada uno— más los dos huecos de 10 que los separan del dato. */
/* Los dos rótulos, cada uno sobre su columna. La versalita con `letter-spacing`
   los hacía más anchos que las columnas que rotulan —«PREGUNTAS» pide 60 px y su
   columna mide 34—, así que se desbordaban a la izquierda y se leía
   «ACIERTOSPREGUNTAS», pegados. Las columnas se ensanchan hasta donde piden los
   rótulos y el interlineado de la versalita baja: es más barato que abreviar
   dos palabras que dicen exactamente lo que hay debajo. */
/* Lo primero que se ve, una sola vez. Ancho de lectura y no de pantalla: son
   tres párrafos que hay que leer, no un cartel que se cierra sin mirar. */
.primera-vez {
  position: relative;
  max-width: 46ch; padding: 26px 28px;
  border: 1px solid var(--rule); border-radius: var(--radio);
  background: var(--panel); color: var(--txt);
}
.primera-vez::backdrop { background: rgb(0 0 0 / .45); }
.primera-vez h2 { margin: 0 0 12px; }
/* stylelint-disable-next-line no-descending-specificity -- `.primera-vez` es el diálogo de bienvenida (`<dialog>`, fuera de `<main>`); `.term-popover` vive dentro de `.marco__texto`: nunca coinciden en el mismo párrafo. */
.primera-vez p { margin: 0 0 12px; font-size: var(--s-ui); line-height: 1.55; }
.primera-vez form { margin-top: 18px; }
/* La cruz, arriba a la derecha y fuera del flujo del texto: el título empieza
   donde empezaba antes. Cierra y ya está —el cartel vuelve la próxima vez—,
   así que no compite con el botón de abajo, que sí es una decisión. */
.primera-vez__cerrar { position: absolute; top: 14px; right: 14px; margin-top: 0; }
/* stylelint-disable-next-line no-descending-specificity -- la regla ganadora solo fija `border-right: none`; este botón fija tamaño/altura de letra — sin propiedad compartida. */
.primera-vez__cerrar button { font-size: 17px; line-height: 1; }

/* --- El pie, el mismo en todas las pantallas ------------------------------- */

/* Centrado y con aire arriba: es el pie de la aplicación, no la última línea de
   lo que estabas leyendo. Suelto y alineado a la izquierda se confundía con el
   final del texto. */
/* stylelint-disable-next-line no-descending-specificity -- `.marco__texto > footer.pagina` añade aire extra a propósito en las páginas de tema; en el resto de páginas (sin `.marco__texto`) manda esta regla entera — comprobado: `padding-bottom` da 80px en /tema y 40px en las demás. */
footer.pagina {
  padding-top: 26px; padding-bottom: 40px;
  border-top: 1px solid var(--rule-soft);
  text-align: center;
}
/* stylelint-disable-next-line no-descending-specificity -- `footer.pagina` y `.term-popover` son hermanos dentro de `<main>` en /tema: ningún `<p>` es descendiente de los dos a la vez. */
footer.pagina p { margin: 0; text-wrap: balance; }

/* Una pregunta nuestra no es evidencia de nada: no ha caído nunca. Se marca
   como la hermana —el mismo aviso al principio— pero en gris y no en ámbar: la
   hermana sí cayó en algún sitio, esta no ha caído en ninguno. */
.propia { border-left-color: var(--mut); }

/* Cuántas preguntas ha generado un apartado. Va pegado a su entrada del índice y
   en pequeño: es un dato de calibración —qué parte del tema cae—, no el título. */
.indice-tema__cuenta {
  margin-left: 6px; padding: 1px 6px; border-radius: 8px;
  background: var(--sel); color: var(--mut); font-size: 11px;
}

/* --- Resultados de la búsqueda (lo-0c4e) ---------------------------------- */

/* La lista va numerada en el marcado y sin enseñar el número. El orden es de
   verdad un ranking —primero lo del propio ejercicio, y dentro, lo que más pesa:
   un `define:` por delante de una palabra suelta, y una palabra entera por
   delante de un trozo— pero la cifra no le dice nada a nadie. */
.resultados { list-style: none; margin: 10px 0 0; padding: 0; }
.resultado { padding: 14px 0; border-top: 1px solid var(--rule-soft); }
.resultado:first-child { border-top: none; }
.resultado__sitio { font-family: var(--titulo); font-weight: 700; font-size: 15px; }
.resultado__fragmento { margin: 4px 0 0; color: var(--mut); font-size: var(--s-pequeno); }
.resultado__fragmento mark { background: var(--ambar-bg); color: var(--txt); padding: 0 1px; }

.resultados__titulo { margin: 26px 0 0; font-size: 16px; }

/* El grupo de otro ejercicio. La franja ámbar a la izquierda es la misma que
   marca lo que hay que mirar dos veces en el resto de la aplicación: esto no
   entra en tu convocatoria, y la lista de debajo no debe leerse como temario
   propio. Sin ella, un resultado del específico es indistinguible de uno del
   común y manda a estudiar lo que no cae. */
.resultados__titulo--ajeno { color: var(--ambar); }
.aviso-alcance {
  margin: 6px 0 0; padding: 8px 12px;
  border-left: 3px solid var(--ambar); background: var(--ambar-bg);
  font-size: var(--s-pequeno);
}

/* Con cuentas, elegir la activa es un POST (T9): el botón del formulario se
   pinta igual que los enlaces del menú. */
.eleccion-conv__menu form { margin: 0; }
.eleccion-conv__opcion {
  display: block; width: 100%; padding: 9px 11px; border: 0; border-radius: var(--radio);
  background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.eleccion-conv__opcion:hover { background: var(--sel); }
