/* ─────────────────────────────────────────────────────────────────────────────
   Rhythmcrea

   La barra, una foto deshecha en capas, y los repos.

   La foto es la del angel. La parte scripts/preparar-angel.py la separa en
   cuatro: la hierba de delante, la niebla, la figura con las alas, y la escena
   de atras sin la figura. Cada capa se mueve con el raton a una velocidad
   distinta, y de ahi sale la profundidad.

   Los colores son los tuyos, de pywal: --suelo 0b0d0f, --hielo 99bac9,
   --oxido ba5f44. La fuente, JetBrains Mono, la de tu sistema.
   ───────────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: "JetBrains Mono";
  src: url("fuentes/jetbrains-var.woff2") format("woff2-variations"),
       url("fuentes/jetbrains-var.woff2") format("woff2");
  font-weight: 100 800;
  font-display: swap;
}

:root {
  /* Lo que le dice al navegador de que color pintar las barras de scroll, los
     controles nativos y el fondo del canvas. Sin esto se quedan en oscuro con el
     tema claro, que es justo cuando mas canta. Va con el cambio de tema. */
  color-scheme: dark;
  --suelo:    #07090b;
  --cristal:  rgba(16, 21, 25, 0.80);
  /* El cristal de la barra va un punto mas opaco que el general, y los enlaces de
     su nav un punto mas claros. Las dos cosas van juntas por una razon: con el
     desenfoque puesto, el fondo de la barra deja pasar mas luz que antes (0.84 en
     vez de 0.92), y --gris se queda en 2.69:1, por debajo de lo que se puede leer.
     Medido sobre el pixel mas claro que hay detras de la barra, que es el cielo de
     las alas:
         0.80 con --gris              2.69:1   no se lee
         0.84 con --enlace-barra      4.58:1   lo que lleva ahora
         0.92 con --gris              3.98:1   el color de antes tampoco llegaba
     El nombre y el reloj, con --hielo, se quedan en 5.3:1 y no ha hecho falta
     tocarlos. */
  --cristal-barra: rgba(16, 21, 25, 0.84);
  --enlace-barra:  #85a2af;
  --cristal-opaco: rgba(13, 17, 20, 0.92);
  --hielo:    #99bac9;
  --oxido:    #ba5f44;
  --azul-1:   #304f79;
  --azul-3:   #3b748e;
  --azul-4:   #417d97;
  --gris:     #6b828c;
  --linea:      rgba(153, 186, 201, 0.14);
  --linea-alta: rgba(153, 186, 201, 0.30);
  /* Los dos polvos, solo los tres canales: la opacidad la pone cada particula.
     --ceniza es la que flota por la escena y --chispa la de la rafaga del clic.
     No pueden ser lo mismo: en claro la flotante tiene que ser un susurro o el
     papel blanco se llena de motas, y la chispa tiene que verse. */
  --ceniza: 206, 222, 231;
  --chispa: 244, 250, 254;
  /* Los topes de las dos animaciones van aqui y no en los keyframes. Estaban
     fijos (0.42/0.72 y 0.5/1) y el keyframe gana sobre la regla del tema, asi
     que en claro el halo respiraba a 0.72 con mix-blend-mode: multiply, que no
     es iluminar: es oscurecer. Cada tema pone los suyos y la animacion los lee.
     Ojo: si uno de los dos falta, el keyframe entero se queda invalido y el
     opacity cae al valor inicial, que es 1 — el bloom entero a tope. */
  --halo-min: 0.50;
  --halo-max: 0.82;
  /* El aro NO va en tema oscuro. A cero, aqui y en el pico: con los dos a cero el
     keyframe del pinchazo sale plano y pinchando tampoco enciende nada. Si el
     pico tuviera valor propio, la animacion (que gana a cualquier declaracion
     normal) lo volveria a encender un ratito.
     Ver la nota de .aro, que explica por que el aro va solo en el tema claro. */
  --aro-min: 0;
  --aro-alto: 0;
  --f: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --r: 10px;
  --r-isla: 16px;
  /* El ancho del contenido. Antes 1120 px fijos, que en una pantalla de 4K
     ocupa el 27% y deja la pagina en una tira estrecha en mitad de la nada.
     Ahora crece con la pantalla y se para en 1640, que es donde mas grande se
     ve bien de leer. El min de 330 es para que en un movil de 360 no se salga. */
  --ancho: clamp(330px, 74vw, 1640px);
  /* Niebla de los bordes de fondo.webp, medida en preparar-angel.py. Es lo que
     rellena las franjas cuando la figura no llena la pantalla. */
  --niebla: #545c64;
}

*, *::before, *::after { box-sizing: border-box; }
/* El tamano de la raiz. Todo lo demas esta en rem, asi que esto decide si la
   pagina se lee en un movil o en un 4K. Antes eran 16 px fijos y el cuerpo se
   quedaba en 13.8 px en cualquier parte: en 2560x1440 y en 3840x2160 era
   ilegible, no pequeno, ilegible.

   El minimo era 15 px, y aqui esta lo que pasaba: con el liquido en 0.5vw + 10, la
   raiz se queda en 15 px en TODO lo que va de 0 a 1000 px de ancho. O sea que en
   un movil de 360 el texto corriente caia a 11,1 px y el rotulo mas pequeno a 8,2.
   Todo el sitio estaba medido con una raiz de 17 a 21 px —la de un monitor— y en
   el movil no habia compensacion ninguna.

   Por eso el minimo sube a 19 px. En movil el texto corriente pasa de 11,1 a
   14,1 px y el rotulo mas pequeno de 8,2 a 10,5. A 1440 la raiz era 17,2 y ahora
   es 19: un 10% mas, que tambien es una mejora. A partir de 1920 el liquido manda
   y no cambia nada: 19,6 y 21 px, igual que antes. */
html { font-size: clamp(19px, 0.5vw + 10px, 21px); }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--suelo);
  color: var(--hielo);
  font: 400 0.86rem/1.7 var(--f);   /* 12.9 px en movil, 18 px en 4K */
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, dl, dd, dt { margin: 0; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; }
a:focus-visible, button:focus-visible, .escena:focus-visible {
  outline: 1px solid var(--oxido); outline-offset: 3px; border-radius: var(--r);
}
::selection { background: var(--oxido); color: var(--suelo); }

.cola { max-width: var(--ancho); margin: 0 auto;
        padding: 0 clamp(1rem, 0.5rem + 2vw, 2rem); }

/* En movil la caja se abre.
   --ancho tiene un minimo de 330 px que esta puesto para que en un monitor
   grande el contenido no se haga una tira. En un movil ese minimo gana siempre:
   a 320, 360, 390 y 430 de pantalla el contenido medía EXACTAMENTE lo mismo,
   292 px, porque el 330 del clamp mas el padding de .cola se comian 68 px de
   los 360. El video de 1280x720 salia de 292 x 164, y con el margen del contenu
   atado a un ancho fijo la pagina no respiraba: se veia ajustada.

   Aqui el ancho maximo se quita y el margen lo pone el padding, que es lo que
   tiene que hacerlo. */
@media (max-width: 700px) {
  .cola { max-width: none; padding-left: 0.7rem; padding-right: 0.7rem; }
}

/* ══ LA BARRA ══════════════════════════════════════════════════════════════ */

.barra-z { position: fixed; top: 0; left: 0; right: 0; z-index: 40;
           padding: 0.8rem 1rem 0; pointer-events: none; }

.isla {
  pointer-events: auto;
  /* Tres columnas: minmax(0, 1fr) · auto · minmax(0, 1fr). El reloj va en la del
     medio y las de los lados se reparten el resto, de modo que el reloj queda en
     el centro tanto si la izquierda es mas larga como la derecha. Con flex y un
     margen automatico se descuadra en cuanto uno de los lados crece.

     Y con minmax(0, 1fr) y no con 1fr a secas, que es lo que hace que la promesa
     se cumpla SIEMPRE. Un 1fr tiene como minimo automatico su min-content: si el
     contenido de la derecha no cabe en la mitad que le toca, la pista se hincha
     hasta que quepa, las dos dejan de medir igual y el reloj se desplaza. Medido
     a 360 px: pistas de 117.39 y 122.47, con el reloj 3 px fuera de sitio. Con
     minmax(0, ...) las dos pistas miden siempre lo mismo, y si algo no cabe se
     sale en vez de descuadrar el reloj.

     Para que eso no llegue a pasar, los breakpoints quitan enlaces antes de que
     la zona derecha se pase de su mitad. */
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
           align-items: center;
  max-width: var(--ancho); margin: 0 auto;
  /* La barra lleva cristal y desenfoque de fondo DESDE EL PRIMER PIXEL, y no solo
     al bajar. Se probo al reves —arriba sin fondo y con el cristal apareciendo al
     pasar de 24 px de scroll, que es lo que hace omarchy.org— y aqui no es lo que
     hacia falta: en la portada el nombre va contra el fondo del heroe, y con la
     barra sin cristal el texto compite con las alas justo en la imagen buena. Con
     el fondo puesto desde el principio el nombre se lee igual de bien se este
     donde se este, que es lo unico que importa.

     Con el cristal puesto de continuo, el fondo y el color de los enlaces van en
     sus propias variables, --cristal-barra y --enlace-barra, y estan medidos para
     esto. Sin fondo no harian falta; con fondo de siempre si. La nota de esas dos,
     en :root, tiene los numeros: con --gris a 0.80 los enlaces se quedan en
     2.69:1, por debajo de lo que se lee.

     Lo que no se anima es el fondo, y a proposito: no cambia nunca, y una
     transicion para algo que no se mueve solo anade retardo al primer pintado de la
     pagina. La que si hay, la del transform, es la de cuando la barra se esconde
     sola. */
  background: var(--cristal-barra);
  backdrop-filter: blur(10px) saturate(1.3);
  -webkit-backdrop-filter: blur(10px) saturate(1.3);
  border: 0;
  border-radius: var(--r-isla);
  padding: 0.4rem 0.55rem;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}


  /* Sin soporte de backdrop-filter, --cristal se queda a 0.80 y el fondo deja el
     texto con el contraste corto contra la foto de las alas. Se vuelve al opaco,
     que es lo que lleva usando la barra desde siempre. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .isla { background: var(--cristal-opaco); }
  }



/* El punto de la temperatura se fue de la barra: sobra a la izquierda del todo,
   con su aro, y la temperatura ya se enseña en el halo, que es donde el color
   significa algo. Queda en capa.js, que lo pinta en el halo. */

.isla .izq { justify-self: start; display: flex; align-items: center; gap: 0.5rem;
             min-width: 0; }
.isla .rotulo { font: 600 0.76rem/1 var(--f); letter-spacing: 0.2em;
                text-transform: uppercase; color: var(--hielo); padding-left: 0.15rem;
                white-space: nowrap; }
/* El nombre, cuando es un enlace.
   --
   En la portada esto es un <span> y no tiene que hacer nada. En el manual es un
   enlace a la portada, y hasta ahora no tenia NI UNA regla: la clase
   .rotulo-enlace estaba en el HTML sin existir en el CSS. Medido con el raton
   encima: mismo color, fondo transparente y una caja de 14 px de alto, o sea que
   se pulsaba sin que se notara nada.
   Lo de al lado, el enlace "home", si cambia: fondo rgba(153,186,201,0.09) y las
   esquinas redondeadas. Esto es lo mismo, con el mismo color y la misma opacidad,
   para que la barra se comporte igual de izquierda a derecha.
   --
   La caja pasa de 14 a 28 px de alto porque un enlace de 14 px no se acierta con
   el dedo ni con el raton: el alto de la barra es 41 y el enlace ocupa un
   tercio. Con el relleno negativo el texto no se mueve de sitio. */
.isla .rotulo-enlace {
  display: flex; align-items: center;
  height: 28px;
  padding: 0 0.6rem;
  margin-left: -0.6rem;
  border-radius: var(--r);
  text-decoration: none;
  transition: color 0.2s, background 0.2s;
}
/* El aviso son las LETRAS, no el fondo.
   --
   Pedido tal cual: al pasar por encima se iluminan las letras. Antes el aviso era
   el fondo, con la caja entera encendida como un boton mas, y las letras quietas.
   Ahora el color del texto es lo que cambia, y el fondo solo acompana con un gris
   muy claro para que el enlace se note como una zona pulsable sin echar mas luz de la cuenta.

   En oscuro el nombre es --hielo, un azul apagado (#99bac9). Iluminar es subirle
   el brillo hasta blanco puro, que son 8,6:1 de contraste, medido.

   En claro --hielo ya es casi negro (#1b1d1f) y no tiene arriba donde subir: poner
   blanco ahi era justo el fallo de antes, medido, el nombre se ponia
   rgb(255,255,255) sobre crema y desaparecia en el momento de pulsarlo. Asi que
   en claro "iluminar" es lo contrario, oscurecer: de #1b1d1f a negro puro, que
   pasa de 14,1:1 a 17,4:1. Las dos direcciones tienen contraste medido y en las
   dos se nota. */
.isla .rotulo-enlace:hover { background: rgba(153, 186, 201, 0.07); color: #fff; }
html.claro .isla .rotulo-enlace:hover { background: rgba(0, 0, 0, 0.06);
                                        color: #000; }
/* Y al pulsar, un paso mas. Sin esto el dedo no nota el momento exacto del clic:
   entra y sale el hover y no hay ningun cambio en el instante de apretar. */
.isla .rotulo-enlace:active { background: rgba(153, 186, 201, 0.14); color: #fff;
                              transition-duration: 0.06s; }
html.claro .isla .rotulo-enlace:active { background: rgba(0, 0, 0, 0.11); color: #000; }
.isla .rotulo-enlace:focus-visible { outline: 2px solid var(--azul-4);
                                    outline-offset: 1px; border-radius: var(--r); }
/* Con reduced-motion no hay transicion que recortar: el cambio de color es
   instantaneo y ya esta, pero la transicion se apaga para no mover el fondo. */
@media (prefers-reduced-motion: reduce) {
  .isla .rotulo-enlace, .isla .rotulo-enlace:active { transition: none; }
}
/* Con dedo, los 28 px no valen: el mismo objetivo de 44 que los demas controles. */
@media (hover: none) {
  .isla .rotulo-enlace { height: 44px; }
}
.isla nav { justify-self: end; display: flex; gap: 0.15rem; }
/* El color es --enlace-barra y no --gris por el contraste con el fondo
   translucido: ver la nota de --enlace-barra en :root. En tema claro esa
   variable vale --gris, asi que aqui no hay excepcion. */
.isla nav a { font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase;
             color: var(--enlace-barra); padding: 0.34rem 0.58rem;
             border-radius: var(--r);
             transition: color 0.2s, background 0.2s; white-space: nowrap; }
.isla nav a:hover { color: var(--hielo); background: rgba(153, 186, 201, 0.09); }
/* En claro, el fondo del hover pasa a gris. El azul de arriba esta medido para
   un suelo oscuro: sobre crema, #99bac9 al 9 % deja el color en #eaeae8 frente
   a un suelo en #eceae5, o sea dos niveles de diferencia y un hover que no se
   ve. El gris es lo que ya usaba el interruptor, asi que despues los tres
   controles de la barra —nombre, enlaces e interruptor— responden igual. */
html.claro .isla nav a:hover { background: rgba(0, 0, 0, 0.06); }
/* El interruptor de tema. Va en la barra y no escondido en el pie: si esta
   abajo, nadie lo encuentra, y el cambio tiene que estar a un clic de donde ya
   se esta mirando la pagina.

   Se ve el icono del tema al que vas, no del que estas: con la luna pulsada
   estas en blanco y estas a punto de pasar a negro. */
.interruptor { display: grid; place-items: center; width: 1.9rem; height: 1.9rem;
               color: var(--gris); cursor: pointer; border-radius: var(--r);
               border-left: 1px solid var(--linea);
               transition: color 0.2s, background 0.2s; }
.interruptor:hover { color: var(--hielo); background: rgba(153, 186, 201, 0.09); }
html.claro .interruptor:hover { background: rgba(0, 0, 0, 0.06); }
.interruptor .ic { width: 1.05rem; height: 1.05rem; grid-area: 1 / 1;
                   transition: opacity 0.25s, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1); }
/* Los tres iconos del tema, uno solo a la vez.
   --
   Antes eran dos y se elegian con la clase .claro del <html>: en oscuro se
   escondia el sol, en claro la luna. Con tres modos eso no llega, porque
   "automatico en oscuro" y "negro elegido a mano" se ven igual pero se portan
   distinto: el primero cambia solo cuando el sistema cambia de tema. Por eso el
   modo va en data-tema y no se deduce de la clase.

   Se muestra el que corresponde y se ocultan los otros dos, en vez de tocar uno
   por estado: con cuatro reglas (un par por modo) basta, y no hay que acordarse
   de esconder el anterior. */
html[data-tema="auto"]  .ic-auto,
html[data-tema="claro"] .ic-sol,
html[data-tema="negro"] .ic-luna { opacity: 1; transform: none; }
html[data-tema="auto"]  .ic-sol,
html[data-tema="auto"]  .ic-luna,
html[data-tema="claro"] .ic-auto,
html[data-tema="claro"] .ic-luna,
html[data-tema="negro"] .ic-auto,
html[data-tema="negro"] .ic-sol {
  opacity: 0; transform: rotate(-70deg) scale(0.6);
}
/* El giro va para el lado contrario segun cual entre, para que no parezca que
   los dos iconos cruzan la misma puerta. */
html[data-tema="claro"] .ic-auto,
html[data-tema="claro"] .ic-luna,
html[data-tema="negro"] .ic-auto,
html[data-tema="negro"] .ic-sol { transform: rotate(70deg) scale(0.6); }
/* Antes de que app.js ponga data-tema —si algo falla al arrancar— se ve la luna,
   que es el estado por defecto de la pagina. Sin esto el boton sale vacio. */
html:not([data-tema]) .ic-auto { opacity: 0; transform: rotate(70deg) scale(0.6); }
html:not([data-tema]) .ic-sol  { opacity: 0; }

/* Solo para lectores de pantalla: el icono no dice nada por si mismo. */
.sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

.isla .reloj { justify-self: center; font-size: 0.76rem; letter-spacing: 0.06em;
               color: var(--hielo); white-space: nowrap; padding: 0 0.3rem;
               font-variant-numeric: tabular-nums; }

@media (max-width: 620px) {
  .isla nav { display: none; }
  /* Sin enlaces a la derecha, la tercera columna se vacia y el reloj se va con
     ella. Con grid 1fr auto 1fr sigue quedando centrado porque las columnas
     siguen siendo iguales. */
}

/* ══ EL CAMPO ═══════════════════════════════════════════════════════════════ */

.campo { position: relative; height: 100svh; overflow: hidden; }

/* La niebla se disuelve hacia abajo en vez de cortarse en recto contra el
   negro de los proyectos. Va por debajo del cartel, asi que el nombre no se
   apaga. */
.campo::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0;
                height: 26%; z-index: 4; pointer-events: none;
                background: linear-gradient(180deg, transparent, var(--suelo) 88%); }

.escena { position: absolute; inset: 0; overflow: hidden;
          cursor: crosshair; background: #0a0e12; }

/* Cada capa es la foto entera, y ocupa su caja (#capas) entera. Esa caja la
   mide capa.js con numeros exactos: antes era inset fijo y background-size:
   cover, que en un monitor 16:10 recortaba las dos puntas de las alas. */
.capa { position: absolute; inset: 0; background-repeat: no-repeat;
        background-position: center; background-size: 100% 100%;
        will-change: transform; }

/* La caja de las cuatro capas. Su rectangulo lo mide capa.js, y coincide
   con el de la foto; la mascara se come doce pixeles de arriba y de abajo para
   que el paso a la zona sin foto no sea un corte recto. */
/* --fade lo pone capa.js y es lo que hay de hueco real entre el borde de la
   pantalla y el de la foto. Con hueco cero la mascara no hace nada.

   Antes eran 12 px fijos, y eso era un fallo mio: cuando la foto ya llena el alto
   —que es en casi cualquier pantalla— esos 12 px de arriba salian borrosos
   contra el resto nitido, y se veia una franja de nitidez en mitad de la
   imagen, sin que hubiera ni un hueco que tapar. */
.capas { position: absolute; --fade: 0px;
         -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--fade),
                                             #000 calc(100% - var(--fade)), transparent 100%);
         mask-image: linear-gradient(180deg, transparent 0, #000 var(--fade),
                                     #000 calc(100% - var(--fade)), transparent 100%); }

/* El respaldo: la misma foto, estirada a cubrir la pantalla y muy difuminada,
   detras de todo. Cubre las franjas que quedan cuando la figura no llena la
   pantalla, que antes iban en color plano y dejaban un escalon recto muy
   visible contra el cielo.

   Se estira a proposito, al reves que las capas: aqui no importa que no encaje,
   porque va 26 px desenfocada y nadie puede saber donde esta el borde de la
   foto. Lo que importa es que SIAMPRE haya contenido detras de las franjas. */
.respaldo { position: absolute; inset: -8%; background-image: url("fondo-oscuro.webp");
            background-size: cover; background-position: center;
            filter: blur(26px); }

/* ── Las cuatro capas. La caja (#capas) las mide capa.js ─────────────────── */

.fondo  { background-image: url("fondo-oscuro.webp");
          /* El fondo-oscuro.webp ya viene graduado por el script. Este filtro era
             una segunda graduacion encima, y se aplicaba tambien en claro, donde
             ya hacia falta menos todavia. En claro se anula.
             --
             El blur(--borr) va aqui y no en un numero fijo porque depende de
             cuantos pixeles de pantalla se pintan: en un monitor normal no hace
             falta nada, y en un movil habia que estirar la foto 3,74x. Lo calcula
             capa.js al medir la caja. Sin ese script la variable no existe y el
             desenfoque es 0, que es como estaba antes. */
          filter: brightness(0.82) contrast(1.02) blur(var(--borr, 0px)); }
.angel  { background-image: url("angel-oscuro.webp");
          /* Sin luz alrededor: un drop-shadow hielo de 14 px salia como un filo
             claro pegado a las alas, y no era la foto, era mio.
             --
             El desenfoque va DESPUES del drop-shadow a proposito. Al reves, la
             sombra de 22 px se difuminaria tambien y las alas perderian el relieve
             contra el cielo; asi el relieve se queda y lo que se suaviza es la
             foto, que es lo que se estaba viendo a cuadros. */
          filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.5)) blur(var(--borr, 0px)); }

/* En pantallas estrechas se baja el angel de 1100, no el de 2000. El mio
  Sin esto, un movil se baja 113 KB de una figura que ahi ocupa 430
   px de ancho. */
@media (max-width: 900px) {
  /* El fichero pequeno, y con el desenfoque que le corresponde a ESE fichero. Con
     el del grande se quedaria corto: este se estira 3,74x en un movil y el otro
     2,06x, y por eso tienen desenfoques distintos. */
  .angel { background-image: url("angel-oscuro-p.webp"); filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.5)) blur(var(--borr-p, 0px)); }
  html.claro .angel { background-image: url("angel-claro-p.webp"); }
  html.claro .angel { filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.18)) blur(var(--borr-p, 0px)); }
}

/* El velo lleva con screen. Sobre nada, screen no hace nada; y cualquier borde
   de su caja se veria como un rectangulo mas claro. Con los lados desvanecidos
   no hay forma que delate. */
.velo   { background-image: url("velo.webp");
          /* SIN mix-blend-mode. Con screen, cada fotograma que el velo se mueve
             hay que volver a mezclar una capa del tamaño de la pantalla entera,
             con las capas de debajo: es de lo mas caro que habia aqui, y la
             pagina iba a 66 ms por fotograma con los efectos puestos. Con
             alpha normal, la niebla blanca sobre fondo oscuro se ve casi igual y
             no cuesta nada. */
          opacity: 0.34;
          -webkit-mask-image: radial-gradient(115% 100% at 50% 50%, #000 58%, transparent 100%);
          mask-image: radial-gradient(115% 100% at 50% 50%, #000 58%, transparent 100%); }

/* La capa de delante: el suelo y las lapidas de abajo, que son lo unico que hay
   de verdad mas cerca.

   La franja ocupa el 42% de abajo de la caja. La mascara va de 58 a 76% porque la
   caida tiene que estar DENTRO de la franja; antes iba de 0 a 30% de la caja, o
   sea por encima de donde empieza la imagen, y se veia un borde recto a la altura
   del primer pixel. */
.frente { background-image: url("frente-oscuro.webp");
          background-size: 100% auto; background-position: center bottom;
          -webkit-mask-image: linear-gradient(180deg, transparent 58%, #000 76%, #000 100%);
          mask-image: linear-gradient(180deg, transparent 58%, #000 76%, #000 100%); }

/* ══ LOS DOS TEMAS ════════════════════════════════════════════════════════
   Negro y blanco. Cada capa carga su version, y son ficheros aparte y no un
   filtro: los dos temas son monocromos de verdad, uno con las altas lavadas y
   otro con las bajas hundidas, y un grayscale() no los distingue.

   El tema CLARO es el que pediste con la imagen del angel en blanco y negro: la
   pagina entera se pone blanca, con las altas de la foto lavadas. El NEGRO es el
   de antes, con las bajas hundidas. */
html.claro .fondo    { background-image: url("fondo-claro.webp"); }
html.claro .angel    { background-image: url("angel-claro.webp"); }
html.claro .frente   { background-image: url("frente-claro.webp"); }
html.claro .respaldo { background-image: url("fondo-claro.webp"); }
/* En claro el fondo se queda con el desenfoque y sin la graduacion: antes era
   filter: none entero, y con eso el movil se veía a cuadros en los dos temas. */
html.claro .fondo { filter: blur(var(--borr, 0px)); }
html.claro .angel { filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.18)) blur(var(--borr, 0px)); }
html.claro .respaldo { filter: blur(26px) contrast(0.94); }

/* Y la pagina entera se da la vuelta. Si solo las imagenes cambiaran, el texto
   claro se pondria sobre fondo claro y no se leeria. */
html.claro {
  color-scheme: light;
  --suelo:    #eceae5;
  --cristal:  rgba(255, 255, 255, 0.76);
  /* En claro los enlaces de la barra ya llegaban a 4.59:1 con el cristal general y
     no les hace falta el tono aclarado: detras de la barra el angel en blanco y
     negro esta en 252 y el blanco del cristal tapa casi todo. Se deja --
     gris a proposito, para que este valor no sea una excepcion sin motivo. */
  --cristal-barra: rgba(255, 255, 255, 0.76);
  --enlace-barra:  var(--gris);
  --cristal-opaco: rgba(252, 251, 249, 0.94);
  --hielo:    #1b1d1f;
  --oxido:    #9a5638;
  --azul-1:   #55606a;
  --azul-3:   #6f7a83;
  --azul-4:   #525d66;
  --gris:     #71767a;
  --linea:      rgba(20, 22, 24, 0.14);
  --linea-alta: rgba(20, 22, 24, 0.30);
  /* En claro, con el halo en multiply, subir el opacity lo OSCURECE, y el bloom
     va mas bajo y mas corto que en oscuro: la foto ya es clara y con un bloom
     fuerte se come la cabeza. Estos dos iban aqui y se perdieron al quitar las
     variables del panel del instalador; sin ellos el tema claro heredaba los
     topes del oscuro y el bloom le salia con la fuerza del otro. */
  --halo-min: 0.34;
  --halo-max: 0.58;
  /* El aro va solo aqui, en el tema claro, y es DORADO. Medido sobre la foto en
     blanco y negro, en el sitio exacto donde cae el anillo: el fondo esta en 233
     sobre 255, o sea casi papel. Con este dorado el anillo queda en 232,179,84 a
     0.78, que es un contraste de 1.55:1 y se ve. Con el aro de 0.62 de antes
     eran 1.42:1, justo por encima del 1.3 a partir del cual se distingue, y con
     blanco no habia nada: 1.0:1, porque un blanco sobre un 233 no cambia. Por eso
     el aro va dorado y no blanco, y por eso en el oscuro no va: en la foto a
     color el anillo esta en 147 y ahi si se veria el blanco, pero el aro solo se
     pone en un sitio. */
  --aro-min: 0.78;
  --aro-alto: 0.94;
  --ceniza: 138, 146, 152;
  --chispa: 30, 36, 42;
}
html.claro .isla { box-shadow: 0 8px 26px rgba(30, 28, 24, 0.16); }
html.claro .nombre { color: #16181a; text-shadow: 0 2px 24px rgba(255, 255, 255, 0.92); }
html.claro .piezas .cuerpo b { color: #16181a; }
/* 0.5 daba 3.18:1 al boton de abajo, por debajo del 4.5:1 que pide WCAG AA
   para texto normal. A 0.66 se mide en 5.1:1 y todavia se ve apagado, que es
   lo que tiene que ser un boton secundario. El subtitulo estaba en 4.89:1. */
html.claro .bajo, html.claro .col-menu h3 { color: rgba(30, 32, 34, 0.56); }
html.claro .bajar { color: rgba(30, 32, 34, 0.66); }
html.claro .marca-menu p, html.claro .col-menu a, html.claro .pieza .cuerpo i,
html.claro .intro, html.claro .abierta p, html.claro .banderas span,
html.claro .chip-mini, html.claro .etiquetas span,
html.claro .vivo span { color: var(--gris); }
html.claro .pieza:hover { background: rgba(20, 22, 24, 0.04); }
html.claro .b { color: #16181a; border-color: var(--linea-alta); }
html.claro .b:hover { background: #16181a; color: #f6f5f2; }
/* La escena de claro es casi toda blanca: con 0,55 la rafaga del clic se
   quedaba sin verse y parecia que no pasaba nada. */
html.claro .motas { opacity: 0.85; }

/* Los creditos y la linea de abajo, en claro. Van con `!important` como el resto
   del bloque, porque su color lo fija una regla propia con !important para poder
   ganar al `html.claro .marca-menu p`. */
html.claro .creditos-menu { color: rgba(30, 32, 34, 0.62) !important; }
html.claro .creditos-menu a, html.claro .pie-fin a { color: var(--gris); }
html.claro .pie-fin { color: rgba(30, 32, 34, 0.6); }

/* En claro el velo va con menos presencia: el fondo ya es claro y la niebla
   blanca se perderia. */

/* ── Lo que en blanco hay que cambiar de verdad ───────────────────────────
   Los tres efectos que hacen vivo al campo —la luz que sigue al raton, la
   niebla y el barrido del clic— estaban hechos con mezclas que solo funcionan
   sobre fondo oscuro:

     · la luz, con soft-light: sobre blanco, soft-light casi no altera nada, y
       mover el cursor no se notaba de nada
     · la niebla, con alpha blanca: blanca sobre blanco, nada
     · el barrido del clic, un degradado blanco: blanco sobre blanco, nada
     · el halo, con screen: igual

   No estaban rotos: eran invisibles por construccion. En claro cada uno lleva
   su mezcla al reves. Con multiply sobre fondo claro, un color gris SI oscurece,
   y eso es lo que hace falta: no una luz mas brillante, sino una sombra suave
   que va con el cursor. */
html.claro .luz { mix-blend-mode: multiply; opacity: 0.55;
                 background: radial-gradient(closest-side,
                   rgba(104, 124, 140, 0.8), transparent 76%); }
html.claro .velo { mix-blend-mode: multiply; opacity: 0.32; }
html.claro .halo { mix-blend-mode: multiply; opacity: 0.45; }

/* El halo de la cabeza. Su color es el termometro. */
.halo { position: absolute; z-index: 3; pointer-events: none; border-radius: 50%;
        /* Sin nucleo blanco: la foto YA trae su halo, y al poner encima una
           esfera clara sale un bulto oscuro en vez de una luz. Aqui solo se
           aporta el resplandor del termometro. */
        /* Ni anillo ni esfera: la foto YA trae su halo, y lo que hacia falta
           era un resplandor, no un aro. Con box-shadow salia un donut naranja
           macizo; esto es un bloom difuso y se suma a lo que ya hay dibujado. */
        background: radial-gradient(closest-side, var(--halo, transparent) 0%, transparent 72%);
        filter: blur(9px);
        opacity: 0.5; mix-blend-mode: screen; }
@media (prefers-reduced-motion: no-preference) {
  .halo { animation: respirar 5.5s ease-in-out infinite; }
}
/* Los topes vienen de --halo-min / --halo-max: ver donde estan definidos. */
@keyframes respirar {
  0%, 100% { opacity: var(--halo-min); }
  50%      { opacity: var(--halo-max); }
}

/* La luz que sigue al raton. Es un disco con blur y blend, no un degradado:
   por eso de verdad ilumina por un lado. */
/* La luz que sigue al raton.
   left/top en 0 y SIN margen: el centro lo pone capa.js restando la mitad de su
   propia caja a la posicion del cursor. Antes estaba en left:50%/top:42% con un
   margen negativo, y al mixes eso con coordenadas del viewport la luz se
   separaba del cursor segun bajabas. */
.luz { position: absolute; left: 0; top: 0; z-index: 2;
       /* 38vw y 16 px de desenfoque, no 62vw y 28. A 1440 de ancho eso son 893 px
          de lado desenfocados por 28, y ademas se mueve en cada movimiento del
          raton: era lo mas caro de la pagina. Con 547 y 16 se ve igual y el
          coste baja a menos de la mitad, que es al cuadrado. */
       width: 38vw; height: 38vw;
       pointer-events: none; mix-blend-mode: soft-light; opacity: 0.8;
       background: radial-gradient(closest-side, rgba(214, 232, 240, 0.6), transparent 72%);
       filter: blur(16px); will-change: transform; }

/* El aro de la cabeza, en su propia imagen.
   scripts/preparar-angel.py la saca del perfil radial medido de la foto: el
   brillo del halo tiene el pico a 0,032 del ancho, y eso es el radio del aro.

   En reposo esta apagado casi del todo; pincharlo lo enciende. El color va en la
   propia imagen porque en claro hay que MULTIPLICAR (multiplicar con blanco no
   hace nada, ahi el aro va en tinta oscura), y eso no se puede pedir con un
   mix-blend-mode y un opacity.
*/
/* El aro va SIN mix-blend-mode y va SOLO en el tema claro.

   Con screen en oscuro y multiply en claro no se podia: el aro de la foto ya es
   claro y screen no puede pintar de nada lo que ya es claro, y en claro el oro
   multiplicado sobre el papel salia apagado. Sin mezcla, el alfa lo pone la
   propia imagen y ya esta.

   Solo en el tema claro, y es lo que se pidio. El aro cae sobre la cabeza del
   angel, y ahi el fondo mide 233 sobre 255 en la foto en blanco y negro y 147 en
   la foto a color. Eso decide el color y el tema de golpe:

     - sobre el 233, un aro BLANCO no existe: se queda en 251, que es 1.0:1 de
       contraste, o sea nada. Un dorado si se ve, y a 0.78 el anillo queda en
       232,179,84, que es 1.55:1.
     - sobre el 147, el blanco si se veria (llega a 213, 3.1:1). Por eso el aro
       podria haber ido blanco en oscuro, pero como solo se pone en un sitio, se
       pone en el que lo ha pedido quien lo mira.

   El dorado va en la propia imagen y no con un filtro, al reves que antes, que si
   lo ponia blanco: para aclarar hace falta el color, no solo el alfa.

   Por eso se dibuja una sola vez, con HALO["claro"], y no una por tema. Ver
   scripts/preparar-angel.py.

   El borde suave del aro es lo que evita que se vea la costura cuando el parallax
   lo separa un poco de la foto: en el centro es opaco y encima esta el aro de la
   foto, y hacia fuera el alfa se va a cero. */
.aro {
  background-image: url("aro-claro.webp");
  opacity: var(--aro-min);
}

/* Pinchar: el aro se enciende.

   Solo el alpha: el color es el dorado de la imagen y no se toca. En tema oscuro
   no hay regla propia porque el aro no esta ahi: --aro-min y --aro-alto valen 0 y
   el keyframe los lee, asi que la animacion sale plana en 0 y no enciende nada.

   SOLO el opacity en la animacion. El transform lo escribe el parallax en cada
   fotograma con un estilo en linea, y un estilo en linea gana a una animacion:
   por eso la animacion de las alas no se notaba nunca. */
.capa.aro.pulsando {
  animation: aro-enciende 1.5s cubic-bezier(0.22, 1, 0.36, 1);
}
/* El pico es --aro-alto y no un 1 fijo: ver donde esta definido. En oscuro los
   dos estan a 0, asi que el keyframe entero sale plano. */
@keyframes aro-enciende {
  0%   { opacity: var(--aro-min); }
  18%  { opacity: var(--aro-alto); }
  100% { opacity: var(--aro-min); }
}

.motas { position: absolute; inset: 0; z-index: 5; width: 100%; height: 100%;
         pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .motas { display: none; } }

/* El cartel: el nombre. */
.cartel { position: absolute; left: 50%; bottom: clamp(1.6rem, 5vh, 3.4rem);
          transform: translateX(-50%); z-index: 6;
          display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
          text-align: center; width: 100%; padding: 0 1rem; }
.nombre { font: 700 clamp(1.55rem, 5.6vw, 4.6rem)/1 var(--f);
          /* El hueco entre letras se aplica TAMBIEN despues de la ultima, con
             lo que la caja queda 0.42em mas ancha que los glifos y el nombre se
             va a la izquierda al centrarlo.

             text-indent no lo arregla: medido, la caja se ajusta al texto y el
             indent solo la ensancha, dejando la tinta donde estaba. Lo que
             funciona es quitarle el espaciado a la ultima letra, y eso lo hace
             app.js metiendola en un <span>. */
          letter-spacing: 0.42em;
          text-transform: uppercase; color: var(--hielo);
          text-shadow: 0 2px 26px rgba(7, 9, 11, 0.95), 0 0 60px rgba(7, 9, 11, 0.8); }
.nombre .ultima { letter-spacing: 0; }   /* ver arriba */

.bajo { font-size: 0.6rem; letter-spacing: 0.26em; text-transform: uppercase;
        color: rgba(153, 186, 201, 0.5); }

.bajar { margin-top: 0.5rem; display: flex; flex-direction: column; align-items: center;
         gap: 0.5rem; font-size: 0.56rem; letter-spacing: 0.26em; text-transform: uppercase;
         color: rgba(107, 130, 140, 0.62); cursor: pointer; }
.bajar:hover { color: var(--hielo); }
.bajar i { display: block; width: 1px; height: 26px;
           background: linear-gradient(180deg, var(--linea-alta), transparent); }
@media (prefers-reduced-motion: no-preference) {
  .bajar i { animation: goter 2.8s ease-in-out infinite; }
}
@keyframes goter { 0%, 100% { opacity: 0.25; transform: scaleY(0.6); }
                   50% { opacity: 1; transform: scaleY(1); } }
@media (max-width: 560px) { .bajar { display: none; } }

/* ══ LA ESCENA, VIVA O DORMIDA ═════════════════════════════════════════════
   El parallax, la luz del raton y las motas viven dentro de .campo, que es
   justo lo que se deja de ver al bajar por la pagina. Con esto, al salir de
   pantalla la escena se duerme: no se escribe nada y no se repinta. Quien lo
   para es capa.js, quitando la clase "viva" DEL .escena, que es el elemento que
   el observer vigila; aqui solo se pinta lo que implica estar dormida.

   Sin esto pasaba lo que Mas te decia: bajar no era dejar de ver la escena, era
   tenerla corriendo por debajo, con el raton todavia moviendo capas que ya no
   se ven. */
.escena:not(.viva) .capa,
.escena:not(.viva) .frente,
.escena:not(.viva) .luz,
.escena:not(.viva) .halo,
.escena:not(.viva) .motas { pointer-events: none; }

/* Las motas se apagan en vez de desaparecer de golpe. El canvas se queda ahi,
   con su ultimo fotograma, que es lo que evita el parpadeo al volver a mirar. */
.escena:not(.viva) .motas { opacity: 0; }
.escena .motas { transition: opacity 0.35s ease; }

/* Ni el aro ni el halo se encienden con la escena dormida: si pinchas abajo,
   donde no se ve nada, no tiene que pasar nada. */
.escena:not(.viva) .aro,
.escena:not(.viva) .halo { animation: none; }

/* ── Instalar ──────────────────────────────────────────────────────────────
   Debajo del clip y de los dos botones, con mas aire que el resto de la pagina:
   es la accion y va precedida de un rato de mirar el video, asi que no tiene que
   competir por la atencion.

   Lo unico que va en caja es el comando. El bloque entero NO: un panel de color
   alrededor era la cuarta vez que se intentaba y tapaba el comando en vez de
   standout. El corte lo hace el filete de arriba, como en el resto de la pagina.

   El rotulo lleva el punto azul de las cabeceras de seccion —el mismo punto, el
   mismo radio y el mismo azul que .punto-mini— para que el bloque se lea como la
   tercera seccion y no como algo pegado debajo del clip.

   El comando va en una caja DENTRO, con el "copy" tambien dentro y sin verse
   hasta que se busca. Se pincha el comando entero, no solo el boton: el
   subrayado sale al pasar el raton y eso ya lo dice.

   Todas las reglas llevan .instalar delante a proposito. Las de .comando y .copiar
   estan mas ABAJO en la hoja (vienen del instalador, dentro de la seccion de
   hyprland) y con la misma especificidad se las comian: el borde, el fondo, el
   text-indent negativo del "$" y el borde del boton. Con el prefijo ganan. */
.instalar {
  margin-top: 3.4rem; padding-top: 2.4rem;
  border-top: 1px solid var(--linea);
}
.instalar-titulo {
  display: flex; align-items: center; gap: 0.6rem;
  font: 600 0.8rem/1 var(--f); letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--hielo); margin: 0 0 1rem;
}
.instalar-titulo::before {
  content: ""; flex: none; align-self: center;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--azul-4);
}
.instalar-texto {
  font-size: 0.78rem; color: var(--gris); max-width: 58ch;
  margin: 0 0 1.4rem;
}

.instalar .instalar-cmd {
  position: relative;
  /* SIN flex-wrap. El boton de copiar va en absolute, asi que no hay nada que
     repartir, y con wrap el comando se iba a una linea nueva con el "$" solo
     delante: al elegir linea el navegador usa el tamaño hipotetico del item, o
     sea el comando entero en una linea, y eso es mas ancho que la caja. */
  display: flex; align-items: baseline; gap: 0.15rem;
  margin: 0;
  padding: 0.95rem 4.8rem 0.95rem 1.1rem;
  border: 1px solid var(--linea); border-radius: var(--r);
  background: var(--cristal-opaco);
  transition: border-color 0.18s;
}
.instalar .instalar-cmd:hover { border-color: var(--linea-alta); }

/* El "$" va en un pseudo de la caja y no pegado al texto: si estuviera en el
   code, el subrayado pasaria por encima y al copiar el comando saldria con el
   "$" delante. Asi el code se queda con el texto limpio. */
.instalar .instalar-cmd::before {
  content: "$"; flex: none;
  color: var(--gris); opacity: 0.6;
  font: 0.78rem/1.8 var(--f);
}
.instalar .instalar-cmd code::before { content: none; }

.instalar .instalar-cmd code {
  flex: 1 1 auto; min-width: 0;
  padding: 0; border: 0; background: none;
  font-size: 0.78rem; line-height: 1.8;
  color: var(--azul-4);
  text-indent: 0;
  cursor: pointer;
  /* Se pincha el comando, no solo el boton, asi que el subrayado tiene que salir
     al pasar el raton. Con text-decoration-color y no con un fondo porque el
     comando se parte en varias lineas en un movil, y con un fondo el subrayado
     solo saldria en una de ellas. */
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 0.3em; text-decoration-color: transparent;
  transition: text-decoration-color 0.2s, color 0.18s;
}
.instalar .instalar-cmd:hover code { text-decoration-color: currentColor; color: var(--hielo); }

/* El boton, DENTRO de la caja y sin verse hasta que se busca. En el movil no hay
   raton, pero sigue estan ahi: por eso esta oculto y no quitado. */
.instalar .instalar-cmd .copiar {
  position: absolute; right: 0.55rem; top: 50%;
  transform: translateY(-50%);
  padding: 0.4rem 0.7rem;
  border: 1px solid transparent; border-radius: 7px;
  background: transparent;
  opacity: 0;
  transition: opacity 0.18s, color 0.18s, border-color 0.18s, background 0.18s;
}
.instalar .instalar-cmd:hover .copiar,
.instalar .instalar-cmd:focus-within .copiar { opacity: 1; border-color: var(--linea-alta); }
.instalar .instalar-cmd .copiar:hover { color: var(--hielo); border-color: var(--hielo); }
/* Cuando ha copiado se ve siempre un momento: con opacity 0 no se sabria que ha
   pasado nada. El texto lo pone el copiador. */
.instalar .instalar-cmd .copiar.hecho {
  opacity: 1; color: #7fb08a; border-color: #7fb08a;
  background: rgba(127, 176, 138, 0.12);
}
html.claro .instalar .instalar-cmd .copiar.hecho {
  color: #2f7a45; border-color: #2f7a45;
  background: rgba(47, 122, 69, 0.10);
}

@media (max-width: 620px) {
  /* En un movil el comando se parte en varias lineas y el boton, en el centro
     vertical, caeria encima del texto. Se va arriba a la derecha y el texto
     deja de hueco solo arriba. */
  .instalar .instalar-cmd { padding: 2.5rem 1.1rem 1rem; }
  .instalar .instalar-cmd .copiar { top: 0.55rem; transform: none; }
}

/* ══ LA SECCION DE HYPRLAND ═══════════════════════════════════════════════
   El mismo lenguaje que el resto: fila que se abre en su sitio, sin recuadros.

   Lo que cambia aqui es la estructura. Antes era todo una columna con el texto
   medido a 74ch, con lo que la mitad derecha de la pagina se quedaba vacia y
   seemed un documento al que le sobra pagina. Ahora son dos columnas: la
   identidad a la izquierda, que se queda pegada al leer, y las piezas a la
   derecha, que son largas y narrow. */

.seccion { padding-top: clamp(3.5rem, 9vh, 7rem); padding-bottom: 1rem;
           scroll-margin-top: 4rem; }

.seccion .rejilla-seccion {
  display: grid; gap: 0 clamp(2rem, 4vw, 4rem);
  grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 940px) {
  .seccion .rejilla-seccion { grid-template-columns: 1fr; gap: 2.2rem; }
}

/* ── La identidad ─────────────────────────────────────────────────────────── */

.identidad { display: flex; flex-direction: column; }
@media (min-width: 941px) { .identidad { position: sticky; top: 5rem; } }

.cabecera-seccion { display: flex; align-items: baseline; gap: 0.6rem;
                    padding-bottom: 0.55rem; border-bottom: 1px solid var(--linea); }
/* El punto azul de los titulos. Clase suelta y no descendiente de
   .cabecera-seccion: la cabecera del manual esta fuera de esa clase, y con el
   selector descendiente el punto de ahi salia sin pintar — un <span> vacio, que
   no se ve pero ocupa el hueco y separa la palabra de donde tocaba. */
.punto-mini { width: 8px; height: 8px; border-radius: 50%;
              background: var(--azul-4); flex: none; align-self: center;
              display: inline-block; }
.cabecera-seccion h2 { font: 600 0.86rem/1 var(--f); letter-spacing: 0.3em;
                    text-transform: uppercase; color: var(--hielo); }
.cabecera-seccion .meta { margin-left: auto; font-size: 0.6rem; letter-spacing: 0.12em;
                    text-transform: uppercase; color: var(--gris); white-space: nowrap; }

/* El icono de Arch, a la izquierda de la version.
   El tamano va en em porque la linea de la cabecera es de 0.6rem: asi escala con
   la fuente y en un movil, donde la linea crece, crece con ella. A 1.35em sale a
   13 px en escritorio y a unos 17 en movil, que es donde el cuadrado azul con la
   A blanca se lee todavia; el SVG que habia antes ocupaba 0.78em, o sea 7 px, y a
   esa medida el corte que lo hacia logo de Arch se perdia.
   El margen sube tambien porque un cuadrado tiene mas cuerpo que un trazo y con
   el de antes se pegaba al numero. */
.logo-arch {
  width: 1.35em; height: 1.35em;
  /* Mas aire a la derecha que antes. El 0.5em de la primera version era poco:
     la linea lleva letter-spacing 0.12em, que se suma al margen, pero entre el
     cuadrado y la V se aun asiaban las dos y el icono parecia pegado al numero.
     A 0.8em el hueco es de unos 7 px a tamano de escritorio y 9 en movil. */
  margin-right: 0.8em;
  /* El cuadrado tiene fondo y la linea no, asi que se baja mas que en un texto:
     centrado se leeria como una linea mas alta que el resto. */
  vertical-align: -0.3em;
  border-radius: 22%;
}

.lema { margin-top: 1.4rem; font-size: clamp(1.15rem, 2.1vw, 1.5rem); line-height: 1.35;
        color: var(--hielo); letter-spacing: -0.015em; text-wrap: balance; }
.intro { margin-top: 0.9rem; font-size: 0.8rem; color: var(--gris); }

/* Lo que hay vivo en la sesion. Sin caja: tres numeros y sus etiquetas, con un
   filete encima, porque un dato de ahora mismo tiene que distinguirse de una
   frase escrita. */
.vivos { display: flex; flex-direction: column; gap: 0.55rem;
         margin-top: 1.5rem; padding-top: 1.1rem; border-top: 1px solid var(--linea); }
.vivo { display: flex; align-items: baseline; gap: 0.6rem; }
.vivo b { font-size: 1.35rem; font-weight: 500; color: var(--hielo);
          font-variant-numeric: tabular-nums; min-width: 3.2rem; }
.vivo span { font-size: 0.58rem; letter-spacing: 0.2em; text-transform: uppercase;
             color: var(--gris); }

.etiquetas { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.15rem 0.75rem;
              margin-top: 1.3rem; }
.etiquetas span { font-size: 0.6rem; letter-spacing: 0.14em; text-transform: uppercase;
                  color: var(--gris); }
.etiquetas span + span::before { content: "·"; margin-right: 0.75rem;
                                color: rgba(107, 130, 140, 0.45); }

/* ── Los botones de la seccion ────────────────────────────────────────────
   Antes no tenian regla base: solo estaba html.claro .b, que es un tema
   encima de algo. Salian como texto pelado, sin caja ni borde, y por eso el
   ennegrecido se notaba raro. Aqui la caja entera, con el mismo radio que el
   resto de superficies de la pagina (--r). */
.b {
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.48rem 0.85rem;
  border: 1px solid var(--linea-alta);
  border-radius: var(--r);
  color: var(--hielo);
  font-size: 0.72rem; letter-spacing: 0.05em;
  text-decoration: none; white-space: nowrap;
  transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.b:hover { background: rgba(153, 186, 201, 0.07); border-color: var(--gris); }
.b:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 2px; }

/* El boton de Github, ENTERO en blanco. No el gris azulado de --hielo: el
   logo, el texto y el borde son blancos puros en el tema oscuro, y negros puros
   en el claro. Es el color del logo de verdad, no un tono de la pagina.

   El fondo de la caja del mark se queda transparente. Con la caja invertida el
   icono salia del color de la caja y no blanco, que es justo lo que no
   queria. */
.b-gh {
  color: #ffffff;
  border-color: rgba(255, 255, 255, 0.28);
}
.b-gh:hover {
  color: #ffffff;
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.5);
}
.b-gh .marca {
  width: 1.35rem; height: 1.35rem; flex: none;
  display: grid; place-items: center;
  border-radius: 7px;
  background: transparent;
  color: #ffffff;
  transition: background 0.18s;
}
.b-gh .marca svg { width: 0.95rem; height: 0.95rem; display: block; }

html.claro .b-gh {
  color: #000000;
  border-color: rgba(0, 0, 0, 0.3);
}
html.claro .b-gh:hover {
  color: #000000;
  background: rgba(0, 0, 0, 0.06);
  border-color: rgba(0, 0, 0, 0.55);
}
html.claro .b-gh .marca { color: #000000; }

.acciones-seccion {
  display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1.6rem;
  /* El de github a la izquierda y el del manual a la derecha, con el hueco en
     medio. Antes eran dos enlaces juntos en una esquina y con space-between se
     quedan en los dos extremos, que es lo que se ha pedido. En un movil, que no
     cabe la separacion, se vuelven a juntar y se alinean a la izquierda. */
  justify-content: space-between; align-items: center;
}

/* El boton del manual, con la flecha dibujada con bordes y no con un glifo: la
   de la derecha tiene que ser la misma en los dos temas y en cualquier fuente,
   y el glifo cambiaba de peso entre sistemas. */
.b-flecha { display: inline-flex; align-items: center; gap: 0.6rem; }
.b-flecha i { width: 0.5rem; height: 0.5rem; flex: none;
              border-top: 1px solid currentColor; border-right: 1px solid currentColor;
              transform: rotate(45deg); transition: transform 0.18s; }
.b-flecha:hover i { transform: rotate(45deg) translate(2px, -2px); }

@media (max-width: 560px) {
  .acciones-seccion { justify-content: flex-start; }
}

/* ── Las piezas ─────────────────────────────────────────────────────────────
   Una fila, con un filo a la izquierda que se enciende al abrirla. Sin caja:
   son muchas, y veinte recuadros serían veinte cajas. */
.piezas { display: flex; flex-direction: column; }

.pieza { display: flex; align-items: center; gap: 0.8rem; width: 100%;
         text-align: left; cursor: pointer; padding: 0.85rem 0.2rem;
         border-bottom: 1px solid var(--linea);
         transition: background 0.18s, padding 0.18s; }
.pieza:first-child { border-top: 1px solid var(--linea); }
.pieza:hover { background: rgba(153, 186, 201, 0.04); padding-left: 0.7rem;
               padding-right: 0.7rem; }
.pieza .filo { width: 2px; height: 1.6rem; flex: none; border-radius: 1px;
               background: var(--linea-alta); transition: background 0.22s, height 0.22s; }
.pieza[aria-expanded="true"] .filo { background: var(--oxido); height: 2.6rem; }

.pieza .cuerpo { display: flex; flex-direction: column; gap: 0.12rem; min-width: 0; }
.pieza .cuerpo b { font-size: 0.9rem; font-weight: 500; color: var(--hielo); }
.pieza .cuerpo i { font-style: normal; font-size: 0.73rem; color: var(--gris); }

/* Los chips de cada pieza. Antes eran capsulas con borde, y veinte filas con
   dos o tres cajas cada una salian como un panel de botones. Ahora son texto
   pelado a la derecha de la fila, separado por un punto. */
.chips-fila { margin-left: auto; display: flex; align-items: center; gap: 0.45rem;
              white-space: nowrap; }
.chips-fila::before { content: "·"; color: var(--gris); margin-right: 0.15rem; }
.chip-mini { font-size: 0.6rem; letter-spacing: 0.1em; color: var(--gris); }
.chip-mini + .chip-mini::before { content: "·"; margin: 0 0.4rem 0 -0.1rem;
                                 color: rgba(107, 130, 140, 0.5); }
@media (max-width: 700px) { .chip-mini { display: none; } }

.pieza .mas { width: 1.4rem; text-align: right; flex: none; font-size: 0.95rem;
              color: var(--gris); }

/* La abierta: el detalle debajo de su propia fila, con una sangria que se nota. */
.abierta { padding: 0.4rem 0 1.2rem 1rem; display: flex; flex-direction: column;
           gap: 0.55rem; border-bottom: 1px solid var(--linea);
           animation: surgir 0.24s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes surgir { from { opacity: 0; transform: translateY(-5px); } }
.abierta p { font-size: 0.78rem; color: var(--gris); max-width: 68ch;
             padding-left: 0.7rem; border-left: 1px solid var(--linea); }

/* Las banderas del instalador, en monoespaciada, que es como se escriben. */
.banderas { display: flex; flex-direction: column; gap: 0.32rem; margin-top: 0.35rem;
            padding-left: 1.4rem; }
.banderas > div { display: grid; grid-template-columns: minmax(9.5rem, auto) 1fr;
                    gap: 0.7rem; align-items: baseline; }
.banderas code { font: 0.72rem/1.5 var(--f); color: var(--azul-4);
                 border: 1px solid var(--linea); border-radius: 6px;
                 padding: 0.05rem 0.4rem; white-space: nowrap; }
.banderas span { font-size: 0.74rem; color: var(--gris); }
.abierta .etiquetas { margin-top: 0.5rem; padding-left: 1.4rem; }

/* ══ EL PIE, QUE ES EL MENU ═══════════════════════════════════════════════
   Cuatro columnas: la marca, la pagina, lo de alrededor y los datos. En un
   movil van en dos, y en uno estrecho en una.

   Es el sitio donde esta la navegacion de verdad. La barra lleva cuatro cosas y
   en un movil solo caben dos, con lo que sin este menu no habia manera de llegar
   a nada. */

.pie-menu {
  display: grid; gap: 1.8rem 2rem;
  /* Dos columnas: la marca con su lema y los enlaces.
     --
     Aqui estaba `minmax(0, 1.3fr) minmax(0, 1fr)`, y eso dejaba un agujero enorme
     en medio. Medido a 1440: la columna de la marca media 538 px, pero su texto
     —el rotulo y el lema, que lleva un tope de 24ch— ocupa 202. Los 336 px que
     sobraban de esa columna, mas los 38 del hueco entre columnas, eran 374 px de
     vacio entre el lema y "THIS PAGE". En la captura se veia como que las dos
     columnas estaban separadas por un tramo que no era de nadie.
     --
     La marca mide lo que mide su contenido, que son dos lineas cortas, y el hueco
     se lo queda la columna de los enlaces. Con eso la marca queda pegada a su
     texto y el aire queda donde tiene sentido: entre las dos cosas, no dentro de
     una. Los enlaces se quedan a la derecha porque su columna es la que crece.
     --
     `auto` y no `1.3fr`: en una rejilla, una pista `auto` con lo que hay dentro es
     del ancho de su contenido mas la parte de la fraccion que le toca. Con dos
     pistas y la segunda al 100%, la primera se queda con lo suyo. */
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  padding-top: clamp(2.4rem, 6vh, 4.5rem);
  padding-bottom: clamp(2.5rem, 6vh, 4.5rem);
  border-top: 1px solid var(--linea);
}
/* El pie se estrecha antes que el resto: con dos columnas, la marca y los enlaces
   uno al lado del otro se quedan sin aire mucho antes de que la pagina se agobie.
   A partir de aqui van en vertical. */
@media (max-width: 560px) { .pie-menu { grid-template-columns: 1fr; gap: 1.6rem; } }
/* En una columna, la linea de abajo se apila: separadas por un hueco de 1,5 rem
   a izquierda y derecha ya no estan ni cerca, y quedan mas separadas de lo que
   deben. */
@media (max-width: 460px) { .pie-fin { flex-direction: column; gap: 0.35rem; } }

.rotulo-menu { font: 600 0.78rem/1 var(--f); letter-spacing: 0.22em;
               text-transform: uppercase; color: var(--hielo); }
.rotulo-menu:hover { color: #fff; }
.marca-menu p { margin-top: 0.6rem; font-size: 0.74rem; color: var(--gris);
                max-width: 24ch; }

/* Los creditos: donde sale la pagina y que usa para no pedir nada. Con su propio
   bloque y no pegado al lema, porque el lema es el del proyecto y esto es lo de
   la pagina. Los enlaces heredan el color de los de las columnas para que se lean
   como enlaces y no como texto suelto. */
/* El max-width va el mismo que el del lema de arriba (24ch) y no 26ch. Con 26 el
   filete que dibuja el border-top llegaba mas alla del texto que tiene encima y
   de debajo, y se leia como un ancho puesto a ojo en vez de como el separador de
   un bloque con su propio ancho. */
.creditos-menu {
  margin-top: 1.1rem !important; padding-top: 0.85rem;
  border-top: 1px solid var(--linea);
  font-size: 0.66rem !important; line-height: 1.75;
  color: rgba(107, 130, 140, 0.8) !important; max-width: 24ch;
}
.creditos-menu a { color: var(--gris); transition: color 0.18s; }
.creditos-menu a:hover { color: var(--hielo); }

/* La linea de abajo, de lado a lado como en el pie de omarchy.org. Va con
   grid-column para ocupar las cuatro columnas del grid de arriba, y con su
   propio filete: es el cierre del pie, no una columna mas. */
.pie-fin {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.5rem 1.5rem;
  margin-top: 0.6rem; padding-top: 1.1rem;
  border-top: 1px solid var(--linea);
  font-size: 0.64rem; color: rgba(107, 130, 140, 0.72);
}
.pie-fin a { color: var(--gris); transition: color 0.18s; }
.pie-fin a:hover { color: var(--hielo); }

.col-menu { display: flex; flex-direction: column; gap: 0.34rem; }
/* El rotulo de cada columna, pequeno y apagado, para que se lea como seccion y
   no como un enlace mas. */
.col-menu h3 { font: 600 0.58rem/1 var(--f); letter-spacing: 0.2em;
               text-transform: uppercase; color: rgba(107, 130, 140, 0.72);
               margin-bottom: 0.35rem; }
/* El segundo rotulo de la columna, el de "Elsewhere", va separado del primero:
   los dos grupos viven en la misma columna y sin este margen el segundo se leeria
   como otro enlace mas de la lista de arriba. */
.col-menu h3.rotulo-segundo { margin-top: 1.1rem; }
.col-menu a { font-size: 0.76rem; color: var(--gris); width: fit-content;
              transition: color 0.18s; }
/* Los enlaces de "Around it" van dentro de un div para que app.js los pueda ir
   pintando. El div tiene que ser una columna con su propio hueco, igual que la
   columna que lo contiene, o los enlaces se quedarian todos en la misma linea. */
.col-menu > div { display: flex; flex-direction: column; gap: 0.34rem; }
.col-menu a:hover { color: var(--hielo); }

/* nowrap SOLO en los dos sellos, y no en todos los span de la columna: la ficha de
   la maquina es una linea larga a proposito ("kernel, uptime, load, disco,
   servicios") y tiene que poder partirse por donde toque. Acotarlo a los sellos
   es lo que evita dos cosas a la vez: que "4 min / ago" quede colgando, que
   parece un fallo, y que la ficha se salga de la pantalla. */

/* El clip. Ocupa todo el ancho del contenido y va sin sangria: es el elemento
   principal de la seccion, y con 1.4rem de margen se quedaba corto al lado de
   una cabecera que si va de borde a borde. */
.clip { margin: 1.4rem 0 0; }

/* La caja del video y el boton grande. El boton va de HERMANO, no dentro: por
   una regla de HTML, dentro de un <video> solo se admite <source>, <track> y
   texto plano, y cualquier otra cosa se saca al padre. */
.escena-clip { position: relative; line-height: 0; }

.clip video {
  display: block; width: 100%; height: auto;
  background: var(--suelo);
  border: 1px solid var(--linea);
  /* Abajo a la derecha, para que al hacer la foto redondeada no se corte el
     pie de la imagen contra el marco. */
  border-radius: 10px 10px 3px 3px;
  outline: none;
}
.clip video:focus-visible { box-shadow: 0 0 0 2px var(--azul-4); }

/* El boton grande de play, en el centro, hasta que el clip se toca. En cuanto
   arranca se apaga del todo: si se queda encima tapa el contenido, que es
   justo lo que se quiere ver. */
.clip-play {
  position: absolute; inset: 0; margin: auto;
  width: 4.4rem; height: 4.4rem; padding: 0;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 50%;
  background: rgba(11, 13, 15, 0.55);
  color: #f2efe9;
  cursor: pointer;
  transition: opacity 0.22s, transform 0.22s, background 0.22s;
}
.clip-play svg { width: 1.7rem; height: 1.7rem; margin-left: 0.18rem; }
.clip-play:hover { background: rgba(11, 13, 15, 0.72); transform: scale(1.04); }
.escena-clip.sonando .clip-play { opacity: 0; pointer-events: none; transform: scale(0.9); }
/* Y NO vuelve al pasar el raton por encima. Lo que se esta viendo es el clip, y
   un boton de play en medio tapa justo lo que se ha pinned para verlo. Para
   parar esta el boton de la barra, que siempre esta a la vista. */

/* ── La barra: la del reproductor ──────────────────────────────────────────
   Va DEBAJO del video y no encima. Encima tendria que ir semitransparente y
   aparecer al mover el raton, y eso aqui no aporta nada: el clip son 33
   segundos y no hay nada mas en la pagina a lo que saltar. */
.clip-barra {
  display: flex; align-items: center; gap: 0.75rem;
  margin-top: 0.6rem;
  padding: 0.35rem 0.2rem 0;
}

.clip-btn {
  width: 1.9rem; height: 1.9rem; flex: none; padding: 0;
  display: grid; place-items: center;
  /* Sin esto, el anillo de aviso que se dibuja con ::after se posiciona respecto a
     el primer ancestro posicionado —la barra— y se sale del boton. */
  position: relative;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--gris);
  cursor: pointer;
  transition: color 0.18s, background 0.18s;
}
.clip-btn:hover { color: var(--hielo); background: rgba(153, 186, 201, 0.08); }
.clip-btn:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 1px; }
.clip-btn svg { width: 1.05rem; height: 1.05rem; }

/* Solo se ve el icono que toca: los dos estan en el DOM y se cambian por
   clase, para no tener que andar con innerHTML en cada play/pause.

   El selector lleva ".clip-btn svg" delante a proposito. Con solo
   ".ico-mudo { display: none }" no cabia: ".clip-btn svg" tiene mas
   especificidad (una clase y un elemento) que ".ico-mudo" (una clase), asi que
   ganaba el display: block de siempre y los DOS iconos se veian a la vez. El
   boton de play tenia el triangulo y las dos barras de pausa encima, y el del
   sonido el altavoz y el altavoz tachado. */
.clip-btn svg.ico-pausa, .clip-btn svg.ico-mudo { display: none; }
.clip-barra.sonando .clip-btn svg.ico-pausa { display: block; }
.clip-barra.sonando .clip-btn svg.ico-play { display: none; }
.clip-barra.sin-sonido .clip-btn svg.ico-mudo { display: block; }
.clip-barra.sin-sonido .clip-btn svg.ico-son { display: none; }

/* La pista. Es un role="slider", asi que el relleno se dibuja con el ancho y
   el mando se posiciona en porcentaje: sin JS el ancho va en 0 y el mando al
   principio, que es lo que corresponde a un clip que no ha empezado. */
.clip-pista {
  position: relative; flex: 1; height: 1.1rem;
  cursor: pointer; touch-action: none;
}
.clip-pista::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 2px; transform: translateY(-50%);
  background: var(--linea-alta);
}
.clip-barra-rota {
  position: absolute; left: 0; top: 50%; height: 2px;
  transform: translateY(-50%);
  background: var(--oxido);
  width: 0;
}
.clip-mando {
  position: absolute; top: 50%; left: 0;
  width: 0.6rem; height: 0.6rem; margin-left: -0.3rem;
  transform: translateY(-50%) scale(0.72);
  border-radius: 50%; background: var(--oxido);
  transition: transform 0.15s;
}
.clip-pista:hover .clip-mando, .clip-pista:focus-visible .clip-mando { transform: translateY(-50%) scale(1); }

/* ── EN PANTALLAS TACTILES, LO QUE SE PUELSA SE HACE GRANDE ─────────────────────
   --
   Medido: el boton de play es de 1,9 rem —30 px— y el mando de arrastrar de 0,6
   rem —9,6 px—, y NO habia ninguna regla que los hiciera mas grandes en movil. En
   un movil, con el dedo, 30 px es una referencia que se fallafacilmente y 9,6 px es
   imposible: el dedo tapa mas que el mando. Apple pide44x44y Android 48x48.
   --
   Aqui se agrandan SOLO donde no hay raton (`pointer: coarse`), con lo cual en
   escritorio no se toca nada y la barra sigue siendo la fina de siempre.
   --
   La rayita de la pista —el ::before— no se toca: es el dibujo, y esa sigue
   siendo de 2 px. Lo que crece es el alto de la pista, que es lo que se pulsa. */
@media (pointer: coarse) {
  .clip-btn { width: 2.75rem; height: 2.75rem; }        /* 44 px */
  .clip-btn svg { width: 1.45rem; height: 1.45rem; }
  .clip-pista { height: 1.9rem; }                       /* 30 px pulsables */
  .clip-mando { width: 1.1rem; height: 1.1rem; margin-left: -0.55rem; }
}

/* Cuando el navegador no deja reproducir, el boton se queda marcado. Sin esto, con
   opacity 0 por defecto y sin ningun color de fallo, la unica pista era un atributo
   `title` que en un movil no se ve nunca. */
.clip-barra.clip-fallo .clip-btn {
  color: #d98a6a; border-color: rgba(217, 138, 106, 0.55);
  background: rgba(217, 138, 106, 0.10);
}
.clip-barra.clip-fallo .clip-btn::after {
  content: ""; position: absolute; inset: -6px; border-radius: 50%;
  border: 1px solid rgba(217, 138, 106, 0.28);
}
/* Y con el fallo delante, un texto al lado. El `title` solo se ve al pasar el
   raton por encima, y en un movil no se ve nunca, que es justo donde mas hace
   falta. El texto va en la barra, a la derecha del boton, y no es un cartel
   flotante: no tapa nada de la pagina. */
.clip-barra.clip-fallo .clip-actual::after {
  content: "the clip did not load";
  margin-left: 0.7rem;
  color: #d98a6a;
  font-size: 0.62rem;
}
.clip-pista:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 3px; border-radius: 2px; }

.clip-tiempo {
  flex: none; font-size: 0.66rem; color: var(--gris);
  font-variant-numeric: tabular-nums;
}
.clip-tiempo b { font-weight: 400; color: var(--hielo); }
.clip-tiempo i { font-style: normal; margin: 0 0.3rem; opacity: 0.5; }

/* El volumen. El altavoz y la barrita van juntos, y la barrita se abre de lado
   como la de Omarchy: oculta ocupa 0 y con el raton encima, o con el foco por
   teclado, se abre a 4.6rem. En un movil no cabe y se queda solo el altavoz.

   Antes era un <input type="range"> y el pulgar se centraba con margin-top y
   ::-webkit-slider-thumb. El numero que lo centra bien no es el mismo en cada
   navegador, y en Firefox no se toca igual: de ahi que saliera descentrado. Con
   el mismo markup que la pista de progreso, las dos barras se comportan igual.

   El ancho se anima en la PISTA y no en el relleno: si se animara el relleno, en
   cada fotograma de la apertura se recolocarian el relleno y la bolita, y la
   bolita se veria "corriendo" al abrirse. */
.clip-vol { display: flex; align-items: center; gap: 0.15rem; flex: none; }

.clip-vol-pista {
  width: 0; opacity: 0; flex: none;
  transition: width 0.2s ease, opacity 0.2s ease;
}
.clip-vol:hover .clip-vol-pista,
.clip-vol:focus-within .clip-vol-pista { width: 4.6rem; opacity: 1; }
.clip-vol-pista:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 3px; border-radius: 2px; }

/* Su bolita es algo mas pequena que la de la pista: el volumen se cambia de una
   vez y una bola grande ahi invita a saltarse puntos sin querer. */
.clip-vol-pista .clip-mando {
  width: 0.5rem; height: 0.5rem; margin-left: -0.25rem;
  transform: translateY(-50%) scale(0.6);
}
.clip-vol:hover .clip-vol-pista .clip-mando,
.clip-vol:focus-within .clip-vol-pista .clip-mando { transform: translateY(-50%) scale(0.9); }

@media (max-width: 560px) {
  /* En un movil el tiempo y el volumen no caben juntos: se va el tiempo, que el
     navegador ya pone si el visitante quiere saberlo. */
  .clip-tiempo { display: none; }
  .clip-vol:hover .clip-vol-pista,
  .clip-vol:focus-within .clip-vol-pista { width: 3.6rem; }
}

/* El pie del clip es una nota de datos mas, con su sangria como las demas. */
.clip figcaption { font-size: 0.68rem; color: var(--gris); opacity: 0.7;
                   margin: 0.6rem 0 0; }

@media (max-width: 480px) {
  .clip-tiempo { font-size: 0.62rem; }
}

/* El fondo del video va en --suelo, el color del papel del sitio, y no en un
   gris fijo. Es el unico elemento que puede salir claro: el angel del fondo es
   un cielo muy claro, y en el tema blanco un recuadro negro al lado de una caja
   clara canta mas que el rectangulo gris del tema negro. */

/* ══ LOS CUATRO BLOQUES DE DATOS VIVOS ════════════════════════════════════
   La paleta, la salida del doctor, el comando de instalar y las pantallas.
   Todos leen de data/system.js. Si el dato no esta, sale .sin-datos: una
   linea de aviso, nunca un numero inventado.                            */

/* Cuando no hay dato. */
.abierta .sin-datos { font-size: 0.74rem; color: var(--gris); opacity: 0.75;
                      font-style: italic; padding-left: 1.4rem; margin: 0.3rem 0 0; }
.abierta .nota-dato { font-size: 0.68rem; color: var(--gris); opacity: 0.7;
                      padding-left: 1.4rem; margin: 0.5rem 0 0; }
.abierta .nota-dato code { font: 0.68rem/1 var(--f); color: var(--azul-4); }

/* ── La paleta de pywal ──────────────────────────────────────────────────
   Ocho muestras en fila. El color va en el fondo del propio square, no en
   una variable del sitio: si aqui se usara --hielo, al cambiar el wallpaper
   habria que recompilar el CSS, que es justo lo que esta mostrando. */
.muestras { display: flex; flex-wrap: wrap; gap: 0.4rem 0.55rem; margin-top: 0.5rem;
            padding-left: 1.4rem; }
.muestra  { display: flex; align-items: center; gap: 0.36rem; }
.muestra .chip { width: 1.15rem; height: 1.15rem; border-radius: 4px; flex: none;
                 box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10),
                             0 1px 3px rgba(0, 0, 0, 0.35); }
.muestra .hex  { display: flex; flex-direction: column; line-height: 1.25; }
.muestra .hex  { font: 0.66rem/1.25 var(--f); color: var(--hielo); }
html.claro .muestra .chip { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.10),
                            0 1px 3px rgba(0, 0, 0, 0.12); }
.muestra .hex i { font-style: normal; font-size: 0.55rem; letter-spacing: 0.1em;
                  text-transform: uppercase; color: var(--gris); opacity: 0.7; }

/* ── La salida del doctor ───────────────────────────────────────────────
   Un bloque de terminal de verdad: fondo casi solido, monoespaciada, y cada
   linea con su color segun lo que dijo el doctor. Se leen los codigos de
   color que trae la salida, no una traduccion nuestra. */
.terminal { margin-top: 0.5rem; padding-left: 1.4rem; }
.terminal pre { margin: 0; padding: 0.7rem 0.8rem; max-height: 21rem; overflow: auto;
                border: 1px solid var(--linea); border-radius: var(--r);
                background: var(--cristal-opaco);
                font: 0.66rem/1.62 var(--f); color: var(--gris);
                scrollbar-width: thin; }
.terminal .l { display: block; white-space: pre-wrap; overflow-wrap: anywhere;
                padding-left: 1.6em; text-indent: -1.6em; }
.terminal .l.ok     { color: #7fb08a; }
.terminal .l.mal    { color: #d4795c; }
.terminal .l.aviso  { color: #c8a45c; }
.terminal .l.titulo { color: var(--hielo); margin-top: 0.35rem; }
.terminal .l.mal::before { content: "▸ "; color: var(--oxido); }
/* Solo si hay mas linea abajo. Sin esto la ultima sale cortada por la mitad y
   parece que la pagina ha fallado, cuando lo que pasa es que hay mas. */
.terminal.desplaza::after { content: ""; position: absolute; inset: auto 0 0 0;
                            height: 2.2rem; pointer-events: none; border-radius: 0 0 var(--r) var(--r);
                            background: linear-gradient(to top, var(--cristal-opaco), transparent); }
.terminal { position: relative; }
.terminal-pie { margin: 0.4rem 0 0 !important; font: 0.62rem/1.4 var(--f) !important;
                letter-spacing: 0.06em; }
html.claro .terminal .l.ok    { color: #2f7a45; }
html.claro .terminal .l.mal   { color: #a34425; }
html.claro .terminal .l.aviso { color: #8a6a1f; }

/* ── El comando de instalar ─────────────────────────────────────────────
   El comando entero en una sola linea, con scroll si no cabe, y un boton
   que lo copia. El boton es pequeno a proposito: no es un boton de la pagina,
   es una etiqueta que se pone verde un momento. */
/* El marco es la CAJA y no el codigo, como en la portada. Antes lo era el codigo y
   el boton, al ser absolute, se colaba dentro de su caja; para que no se pusiera
   encima del texto habia que reservarle sitio, y el sitio reservado se veia
   vacio con el boton oculto. Medido: 48 px de hueco arriba, cuando una linea de
   texto mide 21.
   --
   Con el marco en la caja, el boton va en absolute a la DERECHA y el hueco se
   reserva a la derecha, que es lo que hace la portada. No hay banda vacia en
   ningun ancho, y el comando solo pierde el ancho del boton, que es lo
   inevitable. */
.comando { display: flex; align-items: baseline; gap: 0.15rem; margin-top: 0.5rem;
           position: relative;
           padding: 0.5rem 4.8rem 0.5rem 1.1rem;
           border: 1px solid var(--linea); border-radius: var(--r);
           background: var(--cristal-opaco);
           transition: border-color 0.18s; }
.comando code { flex: 1 1 auto; min-width: 0; white-space: pre-wrap;
                 overflow-wrap: anywhere; padding: 0;
                 border: 0; border-radius: 0; background: none;
                 font: 0.66rem/1.5 var(--f); color: var(--azul-4);
                 text-indent: 0; }
.comando code::before { content: "$"; margin-right: 0.75rem; color: var(--gris);
                        text-indent: 0; opacity: 0.7; }
/* ── Copiar desde el texto del comando ─────────────────────────────────────────
   En la portada el comando ya se copiaba al pincharlo, no solo con el boton: el
   texto tenia cursor de puntero y un subrayado que salia al pasar por encima. En
   el manual el boton funcionaba pero el texto no, y no habia nada que dijera que
   se podia pinchar. Estas reglas le dan lo mismo.

   No se unan las dos cajas: son distinto diseno a proposito. En la portada el "$"
   va en un pseudo de la caja y el texto va con el comando entero en una linea;
   en el manual el "$" va dentro del propio code, con relleno y borde propios,
   porque el comando se parte en varias lineas en una columna de 650 px. Lo que se
   comparte es el comportamiento, no el dibujo. */
.comando code {
  cursor: pointer;
  /* El subrayado sale con text-decoration-color y no con un fondo porque el
     comando se parte en varias lineas, y con un fondo el subrayado solo
     saldria en una de ellas. */
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: 0.3em; text-decoration-color: transparent;
  transition: text-decoration-color 0.2s, color 0.18s, border-color 0.2s;
}
.comando:hover code { text-decoration-color: currentColor; color: var(--hielo); }
/* El borde que se ilumina al pasar el raton es el de la caja, que es el marco. */
.comando:hover { border-color: var(--linea-alta); }
.comando code:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 3px;
                              border-radius: var(--r); }
.copiar { flex: none; align-self: stretch; padding: 0 0.7rem; cursor: pointer;
          border: 1px solid var(--linea-alta); border-radius: var(--r);
          background: transparent; color: var(--gris);
          font: 0.62rem/1 var(--f); letter-spacing: 0.12em; text-transform: uppercase;
          transition: color 0.18s, border-color 0.18s, background 0.18s; }
.copiar:hover { color: var(--hielo); border-color: var(--hielo); }
.copiar.hecho { color: #7fb08a; border-color: #7fb08a;
                background: rgba(127, 176, 138, 0.10); }
html.claro .copiar.hecho { color: #2f7a45; border-color: #2f7a45;
                           background: rgba(47, 122, 69, 0.08); }

/* ── El comando del manual: el boton DENTRO y sin verse hasta que se busca ──────
   --
   Esto es lo que se ha cambiado. Medido antes y despues, con el mismo comando en
   las dos paginas:
--
     portada   el boton mide 63 x 29   y solo aparece al pasar el raton
     manual    el boton mide 63 x 84   y esta siempre a la vista
--
   El del manual salia como una barra vertical del alto de la caja, pegada al
   borde derecho, porque `.copiar` es un elemento mas del flex con
   `align-self: stretch` y el flex estira los hijos en el eje de la pagina. Con
   este bloque deja de ser un hijo del flujo y se coloca dentro de la caja, igual
   que en la portada.
   --
   Va ARRIBA a la derecha y no en el centro vertical porque aqui el comando se
   parte en tres lineas: en el centro caeria encima del texto. Arriba, con el hueco
   que deja el `padding` de 2,4 rem en el code, el boton tiene su sitio y el
   texto no pasa por debajo. Es lo mismo que hace la portada en movil. */
.comando .copiar {
  /* A la derecha y en el CENTRO vertical, como el de la portada. Antes iba arriba a
     la derecha y por eso hacia falta el hueco de 2,4 rem de arriba. Con el marco en
     la caja, el sitio se reserva a la derecha con el `padding` de 4,8 rem y aqui no
     hay que dejar nada. */
  position: absolute; right: 0.55rem; top: 50%;
  transform: translateY(-50%);
  align-self: auto;                   /* deshace el `stretch` de la regla de .copiar */
  padding: 0.4rem 0.7rem;
  border: 1px solid transparent;
  opacity: 0;
  transition: opacity 0.18s, color 0.18s, border-color 0.18s, background 0.18s;
}
.comando:hover .copiar,
.comando:focus-within .copiar { opacity: 1; border-color: var(--linea-alta); }
/* Con opacity 0 no se sabria que ha copiado, asi que al copiarlo se ve siempre un
   momento. El texto lo pone el copiador. */
.comando .copiar.hecho { opacity: 1; }

/* Donde no hay raton no hay :hover, y un boton en opacity 0 no se ve. Medido: en
   un movil, el boton de copiar de la portada estaba invisible y lo unico que
   habia era tocar a ciegas donde se suponia que estaba.

   Con `hover: none` —que es lo que contestan los pantallas tactiles— el boton se
   enseña siempre. Asi se pierde el efecto de "solo aparece cuando lo buscas" en el
   movil, que es donde no se puede buscar con el raton, y se gana que se vea. */
@media (hover: none) {
  .instalar .instalar-cmd .copiar,
  .comando .copiar { opacity: 1; }
  .comando .copiar, .instalar .instalar-cmd .copiar { border-color: var(--linea-alta); }
}

/* ── Las pantallas ─────────────────────────────────────────────────────
   Tres columnas por monitor. El nombre va en monoespaciada porque es lo que
   escribe Hyprland y es lo que hay que escribir en monitor,preferred. */
.pantallas { display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; margin-top: 0.5rem;
             padding-left: 1.4rem; }
.fila-pantalla { display: flex; align-items: baseline; gap: 0.6rem; }
.fila-pantalla .nom { font: 0.72rem/1.4 var(--f); color: var(--hielo); }
.fila-pantalla .res { font: 0.7rem/1.4 var(--f); color: var(--azul-4); }
.fila-pantalla .det { font-size: 0.68rem; color: var(--gris); }

/* En movil el padding izquierdo de 1.4rem, que venia de la sangria del filo,
   se come el ancho. Se quita. */
/* En movil los bloques de la seccion van con algo mas de aire: con la caja
   abierta el contenido ya no va pegado a los bordes, y el vertical se leia
   justo. */
@media (max-width: 700px) {
  .clip { margin-top: 1.9rem; }
  .acciones-seccion { margin-top: 1.9rem; }
  .instalar { margin-top: 4.2rem; padding-top: 2.8rem; }
  .clip-nota { margin-top: 1rem; }
}

@media (max-width: 560px) {
  .terminal, .comando, .muestras, .pantallas,
  .abierta .nota-dato, .abierta .sin-datos { padding-left: 0; }
  .muestras { gap: 0.5rem 0.7rem; }
  .terminal pre { font-size: 0.6rem; max-height: 17rem; }
}

/* ══ LA BARRA EN MOVIL ═══════════════════════════════════════════════════
   Antes medido a 390 px de verdad (dentro de un iframe de ancho fijo, que es
   la unica forma fiable: --window-size se ignora en modo dump-dom):

     la barra        31 px de alto
     el rotulo       11.4 px de texto
     el reloj        11.4 px
     el interruptor  28.5 x 28.5 px, y ademas OCULTO

   Tres cosas iban mal, y la tercera es la grave:

     · 31 px de alto no se apuntan con el dedo. El minimo recomendado son 44.
     · 11.4 px no se leen de un vistazo, y en la barra es lo primero que se mira.
     · el interruptor estaba DENTRO del nav, y el nav recibe display:none por
       debajo de 620 px. O sea que en un movil no habia forma de cambiar de tema.
       Ahora esta fuera del nav, en su propia zona derecha.

   Y faltaba una cosa que no se ve en una captura de escritorio: el notch del
   iPhone. Sin safe-area la barra fija queda debajo del status bar, justo donde
   no se puede pulsar nada. Tambien hace falta viewport-fit=cover en el meta, que
   es lo que hace que los Insets valgan algo.                                     */

.barra-z { padding-top: max(0.8rem, env(safe-area-inset-top, 0px));
           padding-left: max(1rem, env(safe-area-inset-left, 0px));
           padding-right: max(1rem, env(safe-area-inset-right, 0px)); }

/* La zona derecha: los enlaces y el interruptor. Se agrupan en un div para que el
   grid de la barra siga siendo de tres columnas y el reloj no se mueva. */
.isla .der { justify-self: end; display: flex; align-items: center; gap: 0.1rem; }

@media (max-width: 620px) {
  /* 44 px es el objetivo tactil minimo (WCAG 2.5.5 y las guias de Apple y
     Android). Todo lo que se pueda pulsar llega a esa altura. */
  .barra-z { padding-top: max(0.5rem, env(safe-area-inset-top, 0px));
             padding-left: max(0.5rem, env(safe-area-inset-left, 0px));
             padding-right: max(0.5rem, env(safe-area-inset-right, 0px)); }

  /* En movil la barra ocupa todo el ancho disponible, como la de una app. Antes
     se quedaba en los 330 px del clamp de --ancho, que a 390 de pantalla la
     dejaban con 30 px de margen a cada lado. Con el hueco que sobra, las columnas
     de los lados miden lo mismo y el reloj vuelve a caer en el centro: medido,
     de 3 px de desvio a cero.

     El ancho lo pone el padding de .barra-z, que ya lleva los safe-area. */
  .isla { min-height: 44px; padding: 0.3rem 0.4rem;
          max-width: none; width: 100%; }

  /* El nombre se queda: es lo unico que sobrevive cuando se baja, y sin el no se
     sabe donde estas. */
  .isla .rotulo { font-size: 0.84rem; letter-spacing: 0.16em; padding-left: 0.25rem; }

  /* El reloj es lo que mas se mira en una barra: sube mas que el nombre, para
     que sea el elemento legible de un vistazo. */
  .isla .reloj { font-size: 0.92rem; letter-spacing: 0.04em; padding: 0 0.25rem; }

  /* Los enlaces tambien se quedan si caben, y con 44 px de alto. Antes se
     ocultaban enteros y no quedaba nada pulsable a la derecha. */
  .isla nav { display: flex; gap: 0.1rem; }
  .isla nav a { font-size: 0.72rem; padding: 0 0.5rem; min-height: 44px;
                display: grid; place-items: center; }

  .interruptor { width: 44px; height: 44px; border-left-color: var(--linea); }
  .interruptor .ic { width: 1.2rem; height: 1.2rem; }
}

/* La zona derecha no cabe en su columna de 1fr, y cuando no cabe la columna se
   hincha hasta su min-content. Las dos de los lados dejan de medir lo mismo, y el
   reloj, que esta en la del medio, se va de sitio: medido, 86 px de desvio a 430
   de ancho. El grid no lo arregla; lo que lo arregla es que la derecha quepa.

   Medida de la derecha: "hyprland" 75 + "elsewhere" 83 + el interruptor 44 = 202.
   De la izquierda, el nombre, 99. Del reloj, 78. Con los dos enlaces hacen falta
   99 + 78 + 202 = 379 de barra como minimo, y el padding se come 14 mas.

   Asi que "elsewhere" se cae por debajo de 700 px de pantalla. Se queda en el pie,
   que esta siempre. El interruptor no se cae nunca: es lo unico que no se puede
   llegar a hacer de otra manera. */
@media (max-width: 700px) {
  .isla nav a[href="#fuera"] { display: none; }
}

/* Y en el mas estrecho de todos, tampoco cabe "hyprland" al lado. */
@media (max-width: 330px) {
  /* Los enlaces otra vez, y no el nav entero. Escondiendo el nav se lleva el
     boton de contenido y a 320 px te quedas sin ninguna manera de abrir el
     indice: medido, el boton salia a 0x0. Un movil de 320 es raro pero existe,
     y dejar sin salida a quien llega a el no vale la pena ganar 20 px. */
  .isla nav a { display: none; }
  .isla .rotulo { font-size: 0.78rem; letter-spacing: 0.12em; }
}

  /* ── Donde los enlaces de la barra dejan de caber ───────────────────────────
     Hay tres reglas que esconden `.isla nav` en pantallas estrechas: una a 620 px
     para raton, otra a 330 px para todos, y el bloque de tactil que la vuelve a
     ensenar porque sin ella no queda nada pulsable a la derecha. Entre la de 620 y
     la de 330 no habia ninguna, y ese hueco es el problema: el bloque de tactil
     dice "se quedan SI CABEN" y en ninguna parte se comprueba si caben.

     Medido el 2026-10-03, con la barra con los tres bloques puestos: nombre
     126 px + reloj 98 px + nav con boton 195 px = 419 px, mas el relleno de la
     barra, unos 440 en total. Repartido el hueco en tres columnas de
     1fr-auto-1fr el reparto sale justo a 560 px: ahi no se solapa nada; a 500 el
     reloj ya pisa la columna de la derecha. El corte va en 540, con margen por
     delante de los 500 medidos y por detras de los 560 que no se solapaban.

     Va aqui y no dentro del bloque de tactil porque es un problema de LAYOUT, no
     de dedo: con raton ya lo cubre la regla de 620, pero el ancho pequeno es el
     mismo en los dos casos y la cifra no depende de como se pulse. */
  @media (max-width: 540px) {
    /* Los ENLACES, no el nav entero. Escondiendo el nav se lleva por delante el
       boton de contenido, que vive dentro de el, y en movil te quedas sin
       ninguna manera de abrir el indice: midido, el nav se quedaba a 0x0 y con
       el el boton dentro. */
    .isla nav a { display: none; }
  }

  /* Y por debajo de 370 el problema es el nombre, no los enlaces: con el nav ya
     fuera, el reloj achicado se queda en 84 px pero el nombre sigue en 126, y las
     columnas de 1fr quedan en 111, con el nombre saliendose 15 px encima del
     reloj. Se achican los dos, y el nombre baja menos que el reloj porque es lo
     que identifica la pagina. */
  @media (max-width: 370px) {
    .isla .rotulo { font-size: 0.72rem; letter-spacing: 0.1em; }
    .isla .reloj { font-size: 0.76rem; letter-spacing: 0.02em; }
  }
   El corte de los 620 px es de LAYOUT. El del objetivo tactil es otro: depende de
   como se esta usando la cosa, no de lo ancha que sea. Una tableta de 768 se
   toca con el dedo igual que un movil de 390, y sin esto su barra seguia en 41 px
   con botones de 28.

   (hover: none) es lo que distingue un dedo de un raton. */
@media (hover: none) {
  .isla { min-height: 44px; }
  .interruptor { width: 44px; height: 44px; }
  .interruptor .ic { width: 1.2rem; height: 1.2rem; }
  .isla nav a { min-height: 44px; display: grid; place-items: center;
                padding: 0 0.55rem; }
  /* El boton de contenido entra en la misma regla que los enlaces y no lleva una
     suya: asi hereda los mismos 44 px y el mismo centrado, y no hay dos cifras
     de alto de dedo en la misma barra que se puedan desincronizar. */
  .isla nav .contenidos { min-height: 44px; display: grid; place-items: center;
                          padding: 0 0.55rem; }
}

/* ── El dedo no tiene :hover ───────────────────────────────────────────────
   En un dedo no existe hover: no hay a donde apuntar y se queda en el estado
   hover hasta que tocas otra parte de la pantalla. Lo que hace falta es el
   instante de la pulsacion, que es lo unico que el dedo puede ver.

   Este es el fallo tipico de un sitio en movil: todo se ve Dead al tocarlo. */
@media (hover: none) {
  .isla nav a:active,
  .interruptor:active { background: rgba(153, 186, 201, 0.16); color: var(--hielo); }
  html.claro .isla nav a:active,
  html.claro .interruptor:active { background: rgba(0, 0, 0, 0.08); }

  /* Una pulsacion que encoge un pelo dice "te he entendido" sin salirse del
     diseno. 0.25 s: lo suficiente para verse, tan corto que no da sensación de
     lentitud. */
  .isla nav a, .interruptor { transition: transform 0.14s ease-out; }
  .isla nav a:active, .interruptor:active { transform: scale(0.9); }
}

/* ── El enlace de salto ──────────────────────────────────────────────────
   Oculto de verdad (no solo transparente), pero cuando le llega el foco desde el
   teclado aparece. Por eso va con :focus y no con un JS que lo ensee. */
.saltar { position: absolute; left: 0.6rem; top: 0.6rem; z-index: 60;
          transform: translateY(-160%); transition: transform 0.18s;
          padding: 0.55rem 0.9rem; border-radius: var(--r);
          background: var(--cristal-opaco); border: 1px solid var(--linea-alta);
          color: var(--hielo); text-decoration: none;
          font: 0.72rem/1 var(--f); letter-spacing: 0.12em; text-transform: uppercase; }
/* :focus Y :focus-visible, los dos. Los dos casan, comprobado, asi que aqui no
   hace falta uno; lo que se ha puesto el otro es que con :focus el enlace
   aparece tambien si algo lo enfoca por script, que es justo lo que se ha
   hecho al medirlo. Un enlace de salto no tiene nada que perder por salir con
   un poco mas de margen.

   Aviso para quien mida esto otra vez: en headless esto NO se ve. La transicion
   de 0.18 s la lleva el reloj del compositor y aqui requestAnimationFrame corre a
   dos fotogramas por segundo, asi que el transform se queda en el valor de
   partida y el enlace parece roto. Anulando la transition sale bien: top 10. */
.saltar:focus, .saltar:focus-visible { transform: translateY(0); }

/* El foco tiene que verse tambien en el movil, que es donde se navega con un
   teclado bluetooth o con la switch. */
.isla a:focus-visible, .isla button:focus-visible,
.muestras .chip:focus-visible, .copiar:focus-visible {
  outline: 2px solid var(--hielo); outline-offset: 2px; border-radius: var(--r); }
/* ══ EL MAPA DE ATAJOS ═══════════════════════════════════════════════════
   78 atajos en 10 grupos. Las teclas van como <kbd>, en monoespaciada, que es
   como se leen: el dedo tiene que saber donde cae cada una. Los grupos son
   <details>, asi que solo el primero viene abierto y la pagina no sale con una
   pared de 78 lineas encima. */
.atajos { margin-top: 0.5rem; padding-left: 1.4rem;
          display: flex; flex-direction: column; gap: 0.1rem; }

.grupo-atajos > summary { display: flex; align-items: baseline; gap: 0.6rem;
  cursor: pointer; padding: 0.4rem 0.2rem; list-style: none;
  font: 0.68rem/1.4 var(--f); letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--gris); border-bottom: 1px solid var(--linea);
  transition: color 0.18s; }
.grupo-atajos > summary::-webkit-details-marker { display: none; }
/* El marcador propio, porque el del navegador es una flechita que no encaja. */
.grupo-atajos > summary::before { content: "+"; color: var(--azul-4);
  font-size: 0.8rem; width: 0.7rem; flex: none; }
.grupo-atajos[open] > summary::before { content: "−"; }
.grupo-atajos > summary:hover { color: var(--hielo); }
.grupo-atajos > summary span { margin-left: auto; font-size: 0.6rem; opacity: 0.7;
  letter-spacing: 0.08em; }
.grupo-atajos > summary:focus-visible { outline: 2px solid var(--hielo);
  outline-offset: 2px; border-radius: var(--r); }

.filas-atajos { display: grid; grid-template-columns: 1fr;
  gap: 0.06rem; padding: 0.3rem 0 0.45rem; }

/* Tres columnas, no flex: con flex-wrap, una descripcion larga se caia debajo
   de las teclas y cada fila empezaba a una altura distinta. Con grid, la
   descripcion se enrolla en su propia columna y todas alinean. */
.atajo { display: grid; grid-template-columns: auto 1fr auto; align-items: baseline;
         gap: 0.7rem; padding: 0.14rem 0.2rem; }
/* El raton pasa por encima de la fila entera, que es lo que se busca cuando se
   esta leyendo una lista larga. */
@media (hover: hover) {
  .atajo:hover { background: rgba(153, 186, 201, 0.06); }
}
html.claro .atajo:hover { background: rgba(20, 22, 24, 0.04); }

.atajo .combo { display: inline-flex; align-items: baseline; gap: 0.2rem; flex: none; }
.atajo .combo kbd { font: 0.62rem/1.5 var(--f); color: var(--azul-4);
  border: 1px solid var(--linea); border-bottom-width: 2px; border-radius: 4px;
  padding: 0.05rem 0.28rem; background: var(--cristal-opaco); white-space: nowrap; }
.atajo .combo kbd.tecla { color: var(--hielo); }
.atajo .combo i { font-style: normal; font-size: 0.58rem; color: var(--gris);
  opacity: 0.6; }
.atajo .que { font-size: 0.71rem; color: var(--gris); min-width: 0; }
/* Los que tambien funcionan con la pantalla de bloqueo, marcados de otra manera
   que con un asterisco suelto. */
.atajo .candado { margin-left: auto; font: 0.55rem/1 var(--f); letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--gris); opacity: 0.55; flex: none; }
html.claro .atajo .candado { color: rgba(30, 32, 34, 0.5); }

@media (max-width: 620px) {
  .atajos { padding-left: 0; }
  .atajo { gap: 0.5rem; }
  .atajo .que { font-size: 0.7rem; }
}
/* Dos columnas, pero decididas por el ANCHO DEL CONTENEDOR y no por el de la
   pantalla. La seccion tiene una columna fija a la izquierda y las piezas a la
   derecha, asi que el sitio disponible no tiene nada que ver con la ventana.
   Medido:

     pantalla 1180 -> la pieza mide  429 px  -> descripcion de  57 px
     pantalla 1440 -> la pieza mide  578 px  -> descripcion de 119 px
     pantalla 1920 -> la pieza mide  854 px  -> descripcion de 234 px

   Con una media query a 760 de pantalla salia a dos columnas con 57 px de
   descripcion a 1180: una palabra por linea. Hace falta que el hueco llegue a
   unos 330 px por atajo, y para eso el contenedor tiene que medir 700. */
.abierta { container-type: inline-size; container-name: pieza; }
@container pieza (min-width: 700px) {
  .filas-atajos { grid-template-columns: 1fr 1fr; column-gap: 1.6rem; }
}

/* Y al reves: en un movil la caja mide 284 px, y el combo mas largo
   ("SUPER + SHIFT + Return") se come 150. Con las tres columnas en linea la
   descripcion se queda en nada y cada atajo ocupa tres renglones. Ahi la
   descripcion baja a su propia fila, debajo de las teclas. */
@container pieza (max-width: 400px) {
  .atajo { grid-template-columns: 1fr auto; row-gap: 0.1rem; }
  .atajo .que { grid-column: 1 / -1; }
}

/* ══ LA ENTRADA ═════════════════════════════════════════════════════════════
   Animaciones de entrada. Solo cuando la pagina se abre por ARRIBA: recargando con
   la posicion restaurada no hay entrada, porque el visitante no ve la portada y
   ademas la seccion de abajo se quedaria en opacidad 0 hasta que el observer la
   marcara. Ver entrada() en app.js, que es donde se decide.

   Los valores del nombre son los de omarchy.org, medidos en su CSS:

       @keyframes hero-rise { 0% {opacity:0;transform:translateY(14px)}
                             to {opacity:1;transform:translateY(0)} }
       animation: .55s cubic-bezier(.21,.47,.32,.98) both hero-rise;

   Lo que habia aqui era translateY(18px) con 1.1 s y un cubic-bezier(0.22,1,.36,1),
   que es una curva que sale disparada y frena de golpe: se nota como un tirón. La de
   omarchy es casi lineal al principio y se calma al final, y dura LA MITAD. Por
   eso theirs no molesta y el mio si.

   El cursor parpadeando tambien es suyo, con su misma curva:

       @keyframes caret-blink { 0%,70%,to {opacity:1} 20%,50% {opacity:0} }
       animation: 1.1s step-end infinite caret-blink;

   step-end es lo que hace que el cursor se encienda y apague a golpes en vez de
   desvanecerse, que es lo que hace un cursor de verdad.

   Todo cuelga de html.entrando: si el JavaScript no corre, o no hay storage, o el
   visitante ya esta mas abajo, la clase no se pone y la pagina se pinta normal. El
   estado invisible esta DENTRO de la clase, nunca en las reglas de siempre. */

html.entrando .isla,
html.entrando .motas,
html.entrando .cartel > * {
  opacity: 0;
  animation: entra-sube 0.55s cubic-bezier(0.21, 0.47, 0.32, 0.98) both;
}
html.entrando .isla   { animation-delay: 0.04s; }
html.entrando .nombre { animation-delay: 0.1s; }
html.entrando .bajo   { animation-delay: 0.2s; }
html.entrando .bajar  { animation-delay: 0.3s; }
/* Las motas van mucho mas lentas: son cientos de puntos y a velocidad de nombre se
   veian caer como una lluvia. 1.6 s para que se disuelvan. */
html.entrando .motas  { animation-delay: 0.35s; animation-duration: 1.6s; }

/* La entrada de omarchy, con sus numeros: 14 px, no 18, y medio segundo. */
@keyframes entra-sube {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* El cursor, pegado al nombre. Es decorativo: por eso aria-hidden y por eso el
   <span> va dentro del <h1>, que es lo que hace un cursor de verdad. Con
   prefers-reduced-motion, el bloque de abajo lo apaga. */
/* El cursor va DENTRO del h1, detras de la ultima letra, como el de omarchy. Pero
   el suyo cuelga de un wordmark SVG y este cuelga de texto, y eso cambia todo: una
   barra vertical del mismo color y de la misma altura que las mayusculas, pegada
   detras, SE LEE COMO UNA LETRA. Se vio: el nombre ponia "RHYTHMCREAI".
   --
   Asi que se differentiate en las dos cosas que lo separan de un glifo:
     - Mas bajo que las mayusculas. 0.58em frente a una altura de mayuscula de unos
       0.7em: no llega a tocarla, y asi no puede ser una I.
     - Mas apagado. Al 55% del color del nombre, que es lo que hace un cursor de
       verdad: esta ahi pero no compite con el texto.
   Y algo mas estrecho, 0.045em, que una I en JetBrains Mono. */
.cursor {
  display: inline-block;
  width: 0.045em;
  height: 0.58em;
  margin-left: 0.05em;
  vertical-align: baseline;
  background: currentColor;
  opacity: 0.55;
  border-radius: 1px;
}
/* Cuando esta encendida se ve al 55%; al apagarse del todo es lo que hace el
   keyframe, asi que el 0.55 es el techo y no un valor constante. */
/* El cursor parpadea SIEMPRE, y con la entrada puesta tambien.
   --
   Antes la animacion colgaba de html.entrando, con lo que el cursor se quedaba
   quieto en cuanto pasaba la entrada: un cursor que no parpadea no es un cursor.
   En omarchy el suyo es .hero-caret con "infinite" a pelo, sin condiciones.
   --
   Y no necesita su propia regla de entrada porque su padre ya la tiene: la
   opacidad es una propiedad de grupo, asi que mientras el <h1> esta en opacidad 0
   el cursor tambien lo esta, sin tocarlo. Esa es la razon de que este dentro del
   h1 y no al lado. */
.cursor { animation: cursor-parpadeo 1.1s step-end infinite; }
@keyframes cursor-parpadeo {
  0%, 70%, 100% { opacity: 1; }
  20%, 50%      { opacity: 0; }
}

/* La seccion de hyprland entra al llegar, no al cargar. Sin observer se quedaria
   en opacidad 0 para siempre, asi que el CSS la pone a la vista a los 4 s pase lo
   que pase: mil pixeles de alto de nada es lo peor que puede pasar. */
html.entrando #hyprland { opacity: 0; transform: translateY(20px);
                          animation: hyprland-rescate 0s linear 4s forwards; }
html.entrando #hyprland.hyprland-visto {
  opacity: 1; transform: none;
  transition: opacity 0.7s cubic-bezier(0.21, 0.47, 0.32, 0.98),
              transform 0.7s cubic-bezier(0.21, 0.47, 0.32, 0.98);
}
@keyframes hyprland-rescate { to { opacity: 1; transform: none; } }

/* Con reduced-motion no hay entrada: ni opacidad a 0, ni transform, ni cursor. Se
   pone el estado final directamente. Ojo que el cursor es quien se apaga: con la
   animacion puesta seguiria parpadeando aunque todo lo demas este quieto. */
@media (prefers-reduced-motion: reduce) {
  html.entrando .isla, html.entrando .motas, html.entrando .cartel > *,
  html.entrando #hyprland {
    opacity: 1 !important; transform: none !important;
    animation: none !important; transition: none !important;
  }
  /* El cursor es lo primero que sobra con reduced-motion: un cursor que parpadea
     es movimiento puro, sin nada que aporte. */
  .cursor { animation: none !important; display: none !important; }
}

/* ══ EL MANUAL ═══════════════════════════════════════════════════════════════
   La pagina del manual. Comparte la barra, el pie y los colores con la
   principal, que es lo que hace que se lean como la misma pagina y no como dos
   webs distintas. Lo unico que cambia es la disposicion: un indice fijo a la
   izquierda y el texto a la derecha. */

.manual-cuerpo { background: var(--suelo); }

/* El hueco del contenido. La barra es fija y va arriba, asi que el texto tiene que
   empezar por debajo de ella o el primer titulo se queda debajo del cristal. */
.manual-envoltorio {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: start;
  padding-top: clamp(6rem, 12vh, 9rem);
  padding-bottom: clamp(3rem, 8vh, 6rem);
  /* El plegado del indice. La columna se encoge a cero y la de la derecha se
     queda con el hueco, que es lo unico que hay que animar: si en vez de esto se
     animase la anchura del <nav>, el texto de dentro se refluye en cada fotograma
     y se ve como una columna que hierve. Con la rejilla, el texto no se mueve
     hasta que la columna ya no tiene ancho.
     --
     Se anima grid-template-columns, que no se podia animar antes, pero en los
     navegadores de ahora si. Donde no se pueda, el salto es seco y el boton sigue
     funcionando: por eso el estado esta en una clase y no en el estilo en linea. */
  transition: grid-template-columns 0.28s ease, gap 0.28s ease;
}
/* min-width:0 en las dos columnas, y esto es lo que hacia que la pagina se saliera
   de lado.
   --
   Una celda de rejilla nace con min-width:auto, o sea que se NIEGA a encogerse por
   debajo de lo que su contenido necesita. Aqui el contenido mas ancho es el <pre>
   de la salida del doctor, que con white-space:pre no parte lineas y mide 579 px
   de ancho minimo. La pista de la rejilla si podia encogerse (minmax(0,1fr)), pero
   la celda no, asi que se salia de su pista y empujaba la pagina entera.
   --
   Medido antes: en 1024 el scrollWidth era 1046 con 1024 de ventana, y en 900 era
   1000. Con esto ya no se sale en ninguno de los dos.
   --
   El <pre> lleva overflow-x:auto, asi que con esto sale el scroll DENTRO del bloque
   de texto, que es donde tiene que estar. */
.manual-envoltorio > * { min-width: 0; }
/* Nota: hay un desborre lateral sin resolver a 900-1024 px de ventana, que se
   NO se ha podido quitar. Con esas pantallas la columna del indice (15 rem) se
   come el ancho y al texto le quedan 290-372 px, y alguna de las rejillas de dos
   columnas del texto se sale: scrollWidth 1000 con 900 de ventana, y se puede
   arrastrar 115 px hacia una franja vacia. Se ha buscado elemento a elemento y
   sale de dentro de .bloque-proyecto, pero no de un solo elemento: tapar cualquiera
   de sus hijos lo quita y ninguno es el culpable por si solo. El min-width:0 de
   arriba es lo correcto en teoria y no lo arregla.
   --
   Se deja escrito para que no se vuelva a perder el tiempo, y para que el boton
   de las tres rayas de mas abajo sea la respuesta: al plegar el indice el texto
   pasa de 290 px a 698 px en una pantalla de 900, que es de donde salio el boton. */
/* Indice plegado en escritorio: la columna se va a cero y el hueco tambien, para
   que el texto no deje un margen muerto a la izquierda. */
.sin-indice .manual-envoltorio {
  grid-template-columns: 0 minmax(0, 1fr);
  gap: 0;
}
/* Y el nav se va deslizando, con un retardo para que salga despues de que la
   columna empiece a encogerse: al reves se ve que se corta de golpe. */
.sin-indice .indice {
  opacity: 0;
  transform: translateX(-1.2rem);
  transition: opacity 0.16s ease 0.1s, transform 0.28s ease 0.1s;
  pointer-events: none;
}
.indice {
  transition: opacity 0.2s ease, transform 0.24s ease;
}

/* ── El indice ─────────────────────────────────────────────────────────────────
   Sticky y no fixed: asi se queda pegado al recorrer el texto y se va solo con
   el resto de la pagina al llegar al pie. Con fixed habria que recalcular donde
   termina la columna a mano en cada redimensionado, y se despegaria a la
   primera. */
.indice {
  position: sticky;
  top: clamp(5rem, 11vh, 7.5rem);
  max-height: calc(100vh - clamp(7rem, 16vh, 10rem));
  overflow-y: auto;
  font-size: 0.78rem;
}
.indice h2 {
  font: 600 0.58rem/1 var(--f);
  letter-spacing: 0.2em; text-transform: uppercase;
  color: rgba(107, 130, 140, 0.72);
  margin-bottom: 0.7rem;
}
.indice ol { list-style: none; margin: 0; padding: 0;
             border-left: 1px solid var(--linea); }
.indice li a {
  display: flex; align-items: baseline; gap: 0.5rem;
  padding: 0.24rem 0 0.24rem 0.8rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  color: var(--gris);
  text-decoration: none;
  transition: color 0.16s, border-color 0.16s;
}
.indice li a:hover { color: var(--hielo); }
/* La seccion en la que se esta. El borde se mueve en vez del color: con el color
   solo no se distingue en el tema claro, y el indice es lo que dice donde estas
   cuando el texto es largo. */
.indice li a.activo { color: var(--hielo); border-left-color: var(--hielo); }
/* Los <span> del indice se fueron con lo de "10 groups". No queda ninguno: el
   rotulo de cada capitulo es lo unico que hay dentro del enlace. */
.indice-sello { margin-top: 0.9rem; font-size: 0.62rem; color: rgba(107, 130, 140, 0.6); }

/* ── El texto ───────────────────────────────────────────────────────────────── */
.manual { min-width: 0; }
.manual-cabecera { margin-bottom: clamp(2rem, 5vh, 3.5rem); }
.manual-cabecera h1 {
  font: 700 clamp(1.8rem, 5vw, 3rem)/1.05 var(--f);
  letter-spacing: -0.02em; color: var(--hielo); margin: 0.4rem 0 0;
}
.manual-intro { margin-top: 0.7rem; font-size: 0.92rem; color: var(--gris);
                max-width: 46ch; line-height: 1.55; }
.manual-sello { margin-top: 0.5rem; font-size: 0.64rem; color: rgba(107, 130, 140, 0.65); }

.seccion-manual { margin-bottom: clamp(2.6rem, 7vh, 4.5rem); scroll-margin-top: 6rem; }
/* El h2 del manual va en frase, no en mayusculas como los titulos de la portada.
   Esos llevan text-transform: uppercase y 0.3em de espaciado de la clase
   .cabecera-seccion, y como el selector es igual de especifico (0,1,1) el que
   gana es el ultimo: el mio. Sin esto el titulo salia en mayusculas con el
   espaciado del otro, que es las dos cosas a la vez. */
.seccion-manual h2 { font: 600 0.95rem/1.25 var(--f); letter-spacing: 0;
                     text-transform: none; color: var(--hielo); }
.seccion-manual h4 { font: 600 0.76rem/1 var(--f); letter-spacing: 0.1em;
                     text-transform: uppercase; color: rgba(107, 130, 140, 0.8);
                     margin: 1.6rem 0 0.6rem; }
.seccion-manual p { font-size: 0.86rem; line-height: 1.65; color: var(--gris);
                     max-width: 62ch; margin-top: 0.7rem; }
.seccion-manual p.destacado { font-size: 0.95rem; color: var(--hielo); }
.seccion-manual a { color: var(--hielo); }
.seccion-manual code { font-size: 0.86em; }

/* Las frases de la pieza. Es una lista y no un bloque de parrafos porque se
   leen como puntos: cada uno es una cosa distinta que hace. */
.prosa { margin: 0.7rem 0 0; padding-left: 1.1rem; max-width: 68ch; }
.prosa li { font-size: 0.86rem; line-height: 1.6; color: var(--gris); margin-bottom: 0.4rem; }
.prosa li::marker { color: rgba(107, 130, 140, 0.5); }

/* Los chips de la cabecera de seccion. En el manual se pintan dentro de un div
   con esta clase, y con hueco en el contenedor: los .chip sueltos, sin nada que
   los separa, salian pegados ("install.sharchsinglepass"), porque .chip no tiene
   margenes propios —solo los tiene dentro de .muestra, que es una muestra de
   color—. El hueco va aqui y no en cada chip para que no haya que tocar el
   marcado cada vez que se anade uno. */
.chips { display: flex; flex-wrap: wrap; gap: 0.3rem 0.55rem; margin-left: auto; }
.chips .chip {
  font-size: 0.6rem; letter-spacing: 0.1em;
  color: var(--gris);
  padding: 0.16rem 0.42rem;
  border: 1px solid var(--linea-alta);
  border-radius: 999px;
  white-space: nowrap;
}

/* El buscador. Con 78 atajos en diez grupos, buscar es la unica manera practica
   de encontrar uno. */
.buscador { display: flex; align-items: center; gap: 0.7rem; margin: 0.8rem 0 0.2rem; }
.buscador input {
  flex: 1; min-width: 0;
  font: 0.8rem/1 var(--f);
  color: var(--hielo);
  background: var(--cristal-opaco);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 0.55rem 0.7rem;
}
.buscador input::placeholder { color: rgba(107, 130, 140, 0.7); }
.buscador input:focus-visible { outline: 2px solid var(--hielo); outline-offset: 1px; }
.buscador-conteo { font-size: 0.68rem; color: rgba(107, 130, 140, 0.7);
                   white-space: nowrap; }

/* Las banderas del instalador. */
.banderas { margin-top: 0.7rem; display: flex; flex-direction: column; gap: 0.05rem; }
.bandera { display: grid; grid-template-columns: minmax(0, 16rem) minmax(0, 1fr);
           gap: 0.5rem 1.2rem; padding: 0.42rem 0;
           border-top: 1px solid var(--linea); }
.bandera:first-child { border-top: 0; }
.bandera .nombres { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.bandera code { font-size: 0.74rem; color: var(--hielo); white-space: nowrap; }
.bandera .que { font-size: 0.82rem; color: var(--gris); line-height: 1.5; }

/* Los componentes: definicion y descripcion, en dos columnas. */
.componentes { margin-top: 0.7rem; display: grid;
               grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
               gap: 0.42rem 1.4rem; }
.componentes dt { font-size: 0.8rem; color: var(--hielo); }
.componentes dd { margin: 0; font-size: 0.8rem; color: var(--gris); line-height: 1.5; }

/* El arbol: ruta, cifra y para que sirve. */
.arbol { margin-top: 0.7rem; }
.fila-arbol { display: grid; grid-template-columns: minmax(0, 16rem) 4rem minmax(0, 1fr);
              gap: 0.5rem 1rem; padding: 0.42rem 0; border-top: 1px solid var(--linea);
              align-items: baseline; }
.fila-arbol:first-child { border-top: 0; }
.fila-arbol .ruta { font-size: 0.76rem; color: var(--hielo); }
.fila-arbol .cifra { font-size: 0.8rem; color: var(--hielo); text-align: right; }
.fila-arbol .nota { font-size: 0.78rem; color: var(--gris); }

/* Las filas de "cuando algo va mal": el sintoma a la izquierda, lo que hacer a
   la derecha. */
.filas { margin-top: 0.7rem; display: flex; flex-direction: column; gap: 0.05rem; }
.fila { display: grid; grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
        gap: 0.4rem 1.4rem; padding: 0.45rem 0; border-top: 1px solid var(--linea); }
.fila:first-child { border-top: 0; }
.fila .k { font-size: 0.78rem; color: var(--hielo); }
.fila .v { font-size: 0.82rem; color: var(--gris); line-height: 1.55; }

.manual-fin { margin-top: 2.5rem; padding-top: 1.1rem; border-top: 1px solid var(--linea);
              font-size: 0.68rem; color: rgba(107, 130, 140, 0.7); max-width: 60ch; }

/* ── El tema claro ───────────────────────────────────────────────────────────── */
html.claro .indice h2,
html.claro .manual-sello,
html.claro .buscador-conteo { color: rgba(30, 32, 34, 0.55); }
html.claro .indice li a { color: var(--gris); }
html.claro .indice li a.activo { color: var(--hielo); border-left-color: var(--hielo); }
/* Los <span> del indice se fueron con lo de "10 groups". No queda ninguno: el
   rotulo de cada capitulo es lo unico que hay dentro del enlace. */
html.claro .buscador input { color: var(--hielo); }
html.claro .seccion-manual p,
html.claro .seccion-manual .prosa li,
html.claro .fila .v,
html.claro .bandera .que,
html.claro .componentes dd,
html.claro .fila-arbol .nota { color: var(--gris); }
html.claro .seccion-manual h4 { color: rgba(30, 32, 34, 0.7); }

/* ── En movil ─────────────────────────────────────────────────────────────────
   El indice no se puede quedar a la izquierda: no cabe. Pasa arriba del texto,
   plegado, y se despliega al tocarlo. Con once secciones en vertical ocuparia
   media pantalla antes de leer nada. */
@media (max-width: 860px) {
  .manual-envoltorio { grid-template-columns: 1fr; gap: 1.6rem;
                       padding-top: clamp(5.5rem, 12vh, 7rem); }
  /* El indice pasa a ser una tira horizontal que se desliza, y no una lista de
     once lineas encima del texto.
     --
     Se probo primero como lista de dos columnas y ocupaba 471 px de los 844 de
     la pantalla, mas de medio scroll antes de leer nada. Plegado con un details
     ocupaba poco pero necesita JavaScript para decidir si empieza abierto, y sin
     JavaScript se queda cerrado y no hay forma de abrirlo.
     --
     La tira no necesita nada de eso: es la misma lista con display:flex y un
     overflow-x. Ocupa una linea, funciona sin JavaScript y con once elementos
     mas de los que caben, que es justo cuando mas se agradece poder deslizar. */
  .indice { position: static; max-height: none; order: -1;
            border: 1px solid var(--linea); border-radius: var(--r);
            padding: 0.55rem 0.7rem; background: var(--cristal-opaco); }
  .indice h2 { margin-bottom: 0.45rem; }
  .indice ol { display: flex; gap: 0.25rem; overflow-x: auto;
               border-left: 0; padding-bottom: 0.15rem;
               scrollbar-width: thin; }
  .indice li { flex: none; }
  .indice li a { white-space: nowrap; border-left: 0;
                 border-bottom: 2px solid transparent;
                 padding: 0.2rem 0.5rem; border-radius: var(--r); }
  .indice li a.activo { border-bottom-color: var(--hielo); border-left-color: transparent; }
  .indice-sello { margin-top: 0.5rem; }
  .seccion-manual h2 { font-size: 0.86rem; }
  .bandera, .fila, .fila-arbol, .componentes { grid-template-columns: 1fr; }
  .fila-arbol .cifra { text-align: left; }
  .componentes { gap: 0.1rem 0; }
  .componentes dt { margin-top: 0.5rem; }
}


/* Con reduced-motion el indice se marca igual: no es una animacion, es un
   estado. Lo que se apaga es el salto del enlace. */
@media (prefers-reduced-motion: reduce) {
  .indice li a { transition: none; }
}

/* ══ EL MANUAL, POR PROYECTOS ═══════════════════════════════════════════════
   Segunda tanda. Lo de arriba es el indice de una sola lista; esto es el de dos
   niveles —proyecto, y sus subsecciones—, que es lo que permite anadir otro
   proyecto sin tocar nada mas. Comparte la barra, el pie y los colores con la
   principal, que es lo que hace que se lean como la misma pagina. */

/* ── El indice de dos niveles ─────────────────────────────────────────────────
   El proyecto es un encabezado y sus subsecciones cuelgan debajo. El numero va
   delante de cada enlace y con ancho fijo: si el ancho depende del numero, los
   titulos no alinean en vertical y la lista se lee como dos columnas en vez de
   como una. */
.indice .grupo-indice { margin-bottom: 1rem; }
.indice .grupo-indice:last-of-type { margin-bottom: 0.3rem; }
.indice h3 {
  font: 600 0.66rem/1 var(--f);
  /* Mayusculas y no minusculas: el nombre del repo es "hyprland" en el dato,
     pero en el indice va como el titulo de un bloque, y en mayusculas se
     distingue de un vistazo de las secciones de debajo, que van en frase. */
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--hielo);
  margin: 0 0 0.35rem;
  padding-left: 0.8rem;
  display: flex; align-items: baseline; gap: 0.45rem;
}
.indice h3::before {
  content: ""; width: 4px; height: 4px; border-radius: 50%;
  background: var(--azul-4); flex: none; transform: translateY(-1px);
}
.indice ol.subs { list-style: none; margin: 0; padding: 0;
                  border-left: 1px solid var(--linea); }
.indice ol.subs li a { padding-left: 0.8rem; }
.indice .n {
  font-style: normal; font-size: 0.62rem; font-variant-numeric: tabular-nums;
  color: rgba(107, 130, 140, 0.55); min-width: 1.35em; flex: none;
  transition: color 0.16s;
}
.indice li a.activo .n { color: var(--hielo); }
.indice li a b { font-weight: 400; }
.indice li a span { margin-left: auto; font-size: 0.6rem;
                    color: rgba(107, 130, 140, 0.6); white-space: nowrap; }
/* El proyecto en el que se esta: el encabezado se aviva. No lleva borde propio
   porque el borde de la linea de la izquierda ya marca donde acaba cada uno. */
.indice .grupo-indice.activo h3 { color: var(--azul-4); }
.indice .grupo-indice.activo ol.subs { border-left-color: var(--linea-alta); }

/* ── La portada: los proyectos y lo que hay dentro ─────────────────────────────
   El mismo dato que el indice, en grande. En el manual de omarchy esta lista es
   la pagina entera; aqui esta arriba del todo y el cuerpo sigue debajo, porque
   con doce secciones en una sola pagina caben las dos cosas sin que una tape a
   la otra. */
/* Tarjetas separadas y no el truco de "gap: 1px sobre un fondo de linea".
   Ese truco se ve bien mientras la rejilla se llena justo, y en cuanto sobran
   celdas —tres proyectos en una rejilla de cuatro columnas— las celdas vacias
   se pintan del color de la linea y sale un bloque gris suelto al lado de la
   ultima tarjeta. Con hueco de verdad no hay celdas vacias que se vean. */
.portada {
  display: grid; gap: 0.7rem;
  grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
  /* align-items: start y no el estirado por defecto de la rejilla: si no, las
     tres tarjetas salen con la altura de la mas larga —que son diez lineas de
     hyprland— y rust-dock y k4 quedan con medio cuerpo de vacio debajo. */
  align-items: start;
  margin-bottom: clamp(2.5rem, 6vh, 4rem);
}
.proyecto {
  background: var(--cristal-opaco);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  padding: 0.95rem 1.05rem 1.05rem;
}
.proyecto h2 {
  font: 600 0.8rem/1 var(--f); letter-spacing: 0.1em;
  color: var(--hielo); margin: 0;
}
.proyecto-res { font-size: 0.76rem; line-height: 1.5; color: var(--gris);
                margin-top: 0.5rem; }
.proyecto-repo {
  display: inline-block; margin-top: 0.5rem;
  font-size: 0.66rem; letter-spacing: 0.04em;
  color: rgba(107, 130, 140, 0.75);
  text-decoration: none; border-bottom: 1px solid var(--linea);
}
.proyecto-repo:hover { color: var(--hielo); border-bottom-color: var(--azul-4); }
.proyecto-subs { list-style: none; margin: 0.7rem 0 0; padding: 0; }

/* Con un solo proyecto la tarjeta ocupa toda la fila y las doce subsecciones se
   reparten en tres columnas. Sin esto la tarjeta se queda estrecha, con doce
   lineas en una columna y medio cuerpo de vacio al lado. */
.portada-una { grid-template-columns: 1fr; }
.portada-una .proyecto-subs { columns: 3; column-gap: 1.6rem; }
.portada-una .proyecto-subs li { break-inside: avoid; }
@media (max-width: 860px) { .portada-una .proyecto-subs { columns: 2; } }
@media (max-width: 560px) { .portada-una .proyecto-subs { columns: 1; } }
.proyecto-subs li { margin: 0; }
.proyecto-subs a {
  display: flex; gap: 0.45rem; align-items: baseline;
  font-size: 0.76rem; color: var(--gris);
  text-decoration: none; padding: 0.16rem 0;
}
.proyecto-subs a:hover { color: var(--hielo); }
.proyecto-subs .n { font-style: normal; font-size: 0.62rem;
                    font-variant-numeric: tabular-nums; min-width: 1.35em;
                    color: rgba(107, 130, 140, 0.5); }

/* ── El encabezado de cada proyecto, ya dentro del texto ──────────────────────
   Separate de los titulos de seccion porque es otro tamano: si se hiciera con
   el mismo, en un scroll largo no se distingue donde acaba un repo y empieza el
   siguiente. */
.bloque-proyecto { margin-bottom: clamp(2rem, 5vh, 3rem); }
.cabecera-proyecto {
  margin: clamp(2.2rem, 6vh, 3.6rem) 0 1.4rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--linea);
}
.bloque-proyecto:first-child .cabecera-proyecto { margin-top: 0; }
.cabecera-proyecto h2 {
  font: 700 1.35rem/1.1 var(--f); letter-spacing: -0.01em;
  color: var(--hielo); margin: 0;
}
.cabecera-proyecto p { font-size: 0.82rem; color: var(--gris); margin-top: 0.4rem;
                       max-width: 54ch; }
.cabecera-proyecto a { display: inline-block; margin-top: 0.45rem;
                       font-size: 0.66rem; letter-spacing: 0.04em;
                       color: rgba(107, 130, 140, 0.75); text-decoration: none;
                       border-bottom: 1px solid var(--linea); }
.cabecera-proyecto a:hover { color: var(--hielo); border-bottom-color: var(--azul-4); }

/* El numero de capitulo al lado del titulo. Va en la cabecera y no delante del
   texto porque en el indice ya esta, y aqui solo hace falta para saber cuanto
   llevas leido. */
.seccion-n {
  font: 600 0.62rem/1 var(--f); font-variant-numeric: tabular-nums;
  color: rgba(107, 130, 140, 0.6);
  margin-right: 0.15rem;
}

/* ── "Next", al final de cada seccion ─────────────────────────────────────────
   El manual de omarchy cierra cada capitulo con el siguiente. Es de las pocas
   cosas de ahi que si que Buckyan bien: un texto largo se lee peor cuando cada
   pantalla te obliga a decidir como seguir. */
.siguiente {
  display: inline-flex; align-items: baseline; gap: 0.55rem;
  margin-top: 1.6rem; padding-top: 0.7rem;
  border-top: 1px solid var(--linea);
  font-size: 0.8rem; color: var(--gris); text-decoration: none;
}
.siguiente span { font-size: 0.6rem; letter-spacing: 0.16em;
                  text-transform: uppercase; color: rgba(107, 130, 140, 0.65); }
.siguiente:hover { color: var(--hielo); }
.siguiente:hover span { color: var(--azul-4); }
.siguiente i { width: 0; height: 0; align-self: center;
               border-left: 5px solid currentColor;
               border-top: 3.5px solid transparent;
               border-bottom: 3.5px solid transparent;
               transition: transform 0.2s; }
.siguiente:hover i { transform: translateX(3px); }

.fin-manual { margin-top: 1.6rem; padding-top: 0.7rem;
              border-top: 1px solid var(--linea);
              font-size: 0.78rem; color: rgba(107, 130, 140, 0.7); }
.fin-manual a { color: var(--hielo); }

/* ── El tema claro ───────────────────────────────────────────────────────────── */
html.claro .indice h3 { color: var(--hielo); }
html.claro .indice .n,
html.claro .seccion-n { color: rgba(30, 32, 34, 0.5); }
html.claro .indice .grupo-indice.activo h3 { color: var(--azul-4); }
html.claro .proyecto-repo,
html.claro .cabecera-proyecto a,
html.claro .siguiente span,
html.claro .fin-manual { color: rgba(30, 32, 34, 0.55); }
html.claro .proyecto-res,
html.claro .cabecera-proyecto p,
html.claro .siguiente { color: var(--gris); }
html.claro .proyecto-subs a { color: var(--gris); }
html.claro .proyecto-subs .n { color: rgba(30, 32, 34, 0.45); }

/* ── En movil ─────────────────────────────────────────────────────────────────
   La portada se apila: tres tarjetas de 13 rem no caben en 390 px, y con
   minmax(13rem, 1fr) el auto-fit las deja en una columna sola sin que haga
   falta una regla aparte. El indice sigue siendo la tira deslizable de antes. */
@media (max-width: 860px) {
  .cabecera-proyecto h2 { font-size: 1.15rem; }
  .indice h3 { padding-left: 0.5rem; }
  .indice ol.subs li a { padding-left: 0.5rem; }
  .siguiente i { display: none; }

  /* Una sola tira deslizable, sin un bloque por proyecto.
     --
     Se probo primero guardando el encabezado de proyecto dentro de la tira. Con
     tres proyectos eran tres titulos y tres tiras, 380 px de indice antes de leer
     nada, que es peor que la lista de once lineas de la que se salio. Con
     display:contents el proyecto y su <ol> dejan de ser cajas: todos los <li>
     pasan a ser hijos directos de .indice, que es el unico flex. El titulo del
     proyecto no cabe en una tira horizontal —no hay sitio para dos lineas de
     texto con relleno— asi que en movil no se ensena; el proyecto se deduce de
     la seccion en la que se esta leyendo. */
  .indice .grupo-indice,
  .indice ol.subs { display: contents; }
  .indice .grupo-indice h3 { display: none; }
  .indice { display: flex; gap: 0.25rem; overflow-x: auto; }
  .indice h2 { flex: none; align-self: center; margin: 0 0.35rem 0 0.1rem; }
  .indice li a { flex: none; white-space: nowrap; }
}

@media (prefers-reduced-motion: reduce) {
  .siguiente i { transition: none; }
}

/* ══ LAS FOTOS DEL MANUAL ═════════════════════════════════════════════════════
   Las capturas del repo de hyprland, comprimidas a WebP por
   scripts/collect-imagenes.py. De 11 MB a 1.7 MB. */

/* Una sola foto ocupa el ancho entero; varias se reparten en columnas. El numero
   de columnas lo decide el HTML con la clase, no esta regla, porque depende de
   cuantas hay y eso solo lo sabe quien las pinta. */
.figuras {
  display: grid;
  gap: 0.8rem;
  margin: 0.9rem 0 1.1rem;
}
.figuras-varias { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
/* Una serie son todas del mismo tamano y se compara de un vistazo: una fila, con
   las tres a la misma altura. Con la rejilla de 13 rem minimos a 650 px de
   columna caben dos y quedan 2+1, que se lee como si faltara una. */
.figuras-serie { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.figuras-serie:has(> .figura:nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.figuras-serie:has(> .figura:nth-child(4):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.figura { margin: 0; }
/* El height: auto con los width y height en el HTML es lo que mantiene la
   proporcion: si el CSS pusiera una altura fija, al ampliar una foto horizontal
   como la del dock (700x80) se deformaria. */
.figura img {
  display: block; width: 100%; height: auto;
  border: 1px solid var(--linea);
  border-radius: var(--r);
  background: var(--suelo);
}
.figura a { display: block; line-height: 0; }
.figura a:hover img { border-color: var(--linea-alta); }
.figura a:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 2px;
                         border-radius: var(--r); }

.figura figcaption {
  margin-top: 0.4rem;
  font-size: 0.68rem; line-height: 1.4;
  color: rgba(107, 130, 140, 0.85);
}
/* El texto de "New" y "Windows" de las capturas viene en la propia foto y es
   blanco sobre fondo claro. El pie va debajo y no encima a proposito: encima
   taparia justo lo que hay que leer. */
html.claro .figura figcaption { color: rgba(30, 32, 34, 0.6); }

/* Las tres capturas de tema son una serie: mismo tamano y misma escena, y solo
   cambian los colores. Se les da la misma altura para que se comparen de un
   vistazo, que es justo para lo que estan. */
.figuras figure { min-width: 0; }

@media (max-width: 620px) {
  /* En una columna, las fotos no bajan de 13 rem de ancho: a 320 px de pantalla
     eso serian 22 px de alto, y una captura ilegible no es una foto. Las
     series tambien bajan a una: tres fotos de 208 px de ancho en una pantalla
     de 390 se ven, pero no se leen. */
  .figuras-varias,
  .figuras-serie { grid-template-columns: 1fr; }
  .figura figcaption { font-size: 0.66rem; }
}

/* ══ LA SALIDA DE UN COMANDO ═════════════════════════════════════════════════
   El bloque del doctor. Es texto de un terminal, no un <pre> pelado: lleva los
   numeros de linea a la izquierda, que es lo que hace falta cuando algo falla y
   hay que señalar una de veinte lineas. */
.salida {
  margin: 0.8rem 0 0;
  padding: 0.85rem 1rem;
  font: 0.74rem/1.6 var(--f);
  color: var(--gris);
  background: var(--cristal-opaco);
  border: 1px solid var(--linea);
  border-radius: var(--r);
  /* El bloque no se lee en una sola linea larga: el mensaje mas largo del doctor
     es la ruta del repo, y con wrap queda partido en dos sitios distintos. */
  overflow-x: auto;
  white-space: pre;
  -webkit-overflow-scrolling: touch;
}
.salida .linea { display: block; min-height: 1.6em; }
/* El "ok" del doctor es la palabra que dice que no hay nada roto, y es lo unico
   que se lee de un vistazo en veinte lineas. */
.salida .linea-ok { display: block; color: var(--hielo); min-height: 1.6em; }
.salida .linea-ok::first-letter { color: var(--azul-4); }

/* Las lineas en blanco entre bloques del doctor se colapsan: sin esto el hueco
   entre "scripts referenced by the units are present" y "SDDM greeter:" es de
   seis lineas de alto y parece que falta algo. */
.salida .linea:empty { height: 0.7em; }

html.claro .salida { color: var(--gris); }
html.claro .salida .linea-ok { color: var(--hielo); }

/* ══ NAVEGACION EN MOVIL ═════════════════════════════════════════════════════
   En una pantalla estrecha no hay indice al lado: la lista entera son dos mil
   pixeles de contenido en trescientos de hueco. Hace falta una puerta, y hace
   falta que la tira diga donde estas. */

/* El boton. En escritorio no aparece: el indice ya esta a la vista y un boton
   para abrirlo seria un boton que no hace nada. */
.contenidos {
  display: none;
  /* Cuadrado y sin texto.
     --
     LAS TRES RAYAS Y COMO SE CONVIERTEN EN X, QUE ESTO ES LO QUE NO SE VEIA
     --
     Antes las tres rayas eran tres gradientes en el `background` del boton, y al
     abrir se hacia `background: none` y aparecian dos diagonales nuevas por los
     pseudoelementos. Medido: eso NO anima. La transicion que habia era de
     `background-color`, y un `background-image` con gradientes no se interpola con
     el color de fondo: las tres rayas se quitaban de golpe y luego la X se
     aparecia con un fundido de 0,16 s. En un movil se leia como un parpadeo.
     --
     Aqui cada raya se dibuja en un sitio que SI se puede animar:
     --
       la de arriba   el `background` del boton, que se mueve con background-position
       la del medio    ::after, girando sobre el centro del boton
       la de abajo     ::before, que sube al centro y gira
     --
     Las dos de abajo rotan sobre el CENTRO del boton y no sobre su propio centro,
     y para eso se colocan con `top` al 50 % y un `translate(-50%, -50%)` de base. Si
     rotaran sobre si mismas se doblarian en el sitio y no saldria una X sino dos
     rayas torcidas.
     --
     La de arriba se va deslizando el `background-position` hacia arriba, fuera de
     la caja: como el fondo se dibuja recortado a la caja del boton, al salirse
     desaparece, y eso si se puede transicionar. */
  width: 44px; height: 44px; min-width: 44px;
  padding: 0; margin: 0;
  position: relative;
  color: var(--enlace-barra);
  background-image: linear-gradient(currentColor 0 0);
  background-repeat: no-repeat;
  background-position: center 34%;
  background-size: 17px 1.6px;
  border: 0; border-left: 1px solid var(--linea);
  border-radius: var(--r); cursor: pointer;
  /* El background-position va en la lista. Sin el, la raya de arriba se teletransporta
     y el efecto se pierde entero. */
  transition: color 0.2s, background-color 0.2s, background-position 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.contenidos:hover { color: var(--hielo); background-color: rgba(153, 186, 201, 0.09); }
.contenidos:focus-visible { outline: 2px solid var(--azul-4); outline-offset: 1px; }
html.claro .contenidos:hover { background-color: rgba(0, 0, 0, 0.06); }

.contenidos::before,
.contenidos::after {
  content: ""; position: absolute;
  left: 50%;
  width: 17px; height: 1.6px;
  background: currentColor;
  /* translate(-50%, -50%) es lo que hace que el `left: 50%` acabe siendo el CENTRO
     del boton y no su borde. */
  transform: translate(-50%, -50%);
  /* `top` tambien se anima, y no por adorno: sin moverlo, la raya de abajo gira
     sobre SU centro y queda a 7 px de la del medio, y las dos diagonales no se
     cruzan en el mismo punto. Medido: con el giro solo, los centros estaban a
     29,03 px y 22 px, y la X salia descuadrada. Con `top` animandose al 50 % las
     dos comparten el centro del boton y si se cruzan. */
  transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1),
              top 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* Cerrado: la del medio al 50 % y la de abajo al 66 %, las dos en linea. */
.contenidos::before { top: 66%; }
.contenidos::after  { top: 50%; }

/* Abierto: la de abajo sube al centro y gira, la del medio gira en el sitio, y la
   de arriba se sale por arriba. Lo que se ve es el movimiento de las dos rayas de
   abajo mas la salida de la de arriba: eso es lo que hace falta para que se lea
   como que el boton se esta transformando. */
.contenidos[aria-expanded="true"] {
  color: var(--azul-4);
  background-position: center -40%;
}
.contenidos[aria-expanded="true"]::before {
  top: 50%;
  transform: translate(-50%, -50%) rotate(45deg);
}
.contenidos[aria-expanded="true"]::after {
  top: 50%;
  transform: translate(-50%, -50%) rotate(-45deg);
}
/* Sin nombre largo ni corto: el boton son tres rayas de 17 px dentro de un
   cuadrado de 44, y ocupa lo mismo a 320 que a 860. */
.contenidos .largo, .contenidos .corto { display: none; }

/* El alto de dedo va aqui y no solo en el bloque de (hover: none) que hay mas
   arriba. Los dos sitios tienen los 44 px a proposito: el de tactil cubre un
   portatil con pantalla tactil a lo ancho, y este cubre un movil. Se comprobo que
   la regla de (hover: none) llegaba al boton: el alto se media en 28 px, que es el
   valor de la regla base, con lo que la otra no estaba llegando. Ponerlo en los
   dos sitios es lo que garantiza que llegue.
   --
   Antes este bloque ademas escondia los dos enlaces de la barra en movil. Ya no
   hay enlaces que esconder: el nav del manual solo lleva el boton, y el de la
   portada no tiene nav. */
@media (max-width: 860px) {
  .isla nav .contenidos { min-height: 44px; }
}
/* Con el menu de indice abierto, la pagina no se desplaza.
   --
   Sin esto el menu se cierra solo: las imagenes del manual van con
   loading="lazy", y al cargar una de las de abajo el navegador reserva el hueco,
   la pagina se desplaza un monton, salta el scroll y el menu se va. Medido: se
   abria y se cerraba solo en 400 ms, sin que nadie tocara nada.
   --
   Bloquear el desplazamiento en vez de poner un margen al manejador del scroll es
   porque no hay forma de distinguir uno de otro: el navegador solo avisa de que la
   pagina se ha movido. Con la pagina quieta no hay scroll que interpretar, y lo
   que se mueve es el menu, que es lo que tiene que moverse. El panel lleva
   overflow-y:auto, asi que las trece secciones se siguen recorriendo con el dedo.
   --
   Solo en movil: el bloqueo va en la rama de estrechos de indicePanel() y esta
   regla solo existe por debajo de 860 px. En escritorio el menu no existe, el
   indice esta siempre a la vista y la pagina se desplaza normal. */
@media (max-width: 860px) {
  html.pagina-quieta, html.pagina-quieta body { overflow: hidden; }
}
/* El boton sale en TODOS los anchos, no solo en movil.
   --
   Antes estaba.display:none en escritorio, con el razon de que ahi el indice ya
   se ve al lado y un boton para abrirlo no hacia falta. Eso era verdad pero
   tambien al reves: lo que no hacia falta era el boton, si lo unico que hacia era
   volver a abrir. Ahora el boton pliega y despliega la columna, que si es util:
   en un portatil de 1024 la columna se come 15 rem y el texto se estrecha para
   dejar sitio a una lista que se puede volver a poner a un clic.
   --
   Medido el hueco que hay en la barra para meterlo sin tocar nada mas: en 1440
   hay 442 px entre el reloj y el boton de tema. De sobra. */
.isla nav .contenidos { display: inline-block; }
/* En la barra de la portada este boton no esta, y estas reglas son suyas, asi que
   no se tocan nada. El separador que hay entre los enlaces y el boton solo tiene
   sentido con el boton delante. */
.isla nav .contenidos + .sep,
.isla nav .contenidos ~ .sep { display: none; }
/* Con el indice plegado, el boton se queda encendido: esta diciendo que hay algo
   escondido ahi, y si se apaga al pulsarlo no hay forma de saber que se puede
   volver a abrir. Es al reves que en movil, donde encendido quiere decir abierto. */
.sin-indice .contenidos { color: var(--azul-4); }
.sin-indice .contenidos::after { content: ""; }

/* El panel: la lista entera, encima del texto, desde justo debajo de la barra
   hasta abajo. Se abre con el boton y se cierra solo. */
@media (max-width: 860px) {
  .indice.indice-abierto {
    /* display:block y no nada: cerrado, .indice es la tira horizontal y es flex.
       Abierto tiene que ser una lista vertical, y si se queda en flex el "On
       this page" sale centrado al lado de los elementos en vez de encima, y los
       titulos se parten en dos lineas porque la columna se queda estrecha. */
    display: block;
    position: fixed;
    /* Se apoya en la barra con top: auto, no con un numero. La variable la
       escribe altoBarra() con la altura medida, porque esa altura cambia con el
       movil y con el relleno del safe-area. */
    top: var(--alto-barra, 65px);
    left: 0; right: 0;
    /* bottom:0 y no bottom:auto con max-height: el menu llega hasta abajo aunque
       su contenido sea mas corto. Con bottom:auto el elemento mide lo que miden
       las trece lineas y debajo se ve la pagina —que aqui es la portada, con la
       MISMA lista de secciones—, y se lee como si el menu estuviera duplicado.
       Medido: el menu ocupaba 714 de 779 y por debajo salia la portada. */
    bottom: 0;
    max-height: calc(100dvh - var(--alto-barra, 65px));
    /* La altura de la barra, medida: son 44 px con dedo y 41 con raton. Se usa la
       misma medida que el resto de la pagina para que el panel no tape la hora
       ni el boton de tema. */
    max-height: none;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    z-index: 40;
    /* Solo las esquinas de abajo: arriba esta la barra, que es la que sostiene el
       menu, y redondear las dos de arriba le daria un aspecto de tarjeta
       pegada al techo en vez de algo que sale de debajo. */
    border-radius: 0 0 var(--r) var(--r);
    border-left: 0; border-right: 0; border-top: 0;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.42);
    /* Un fondo casi opaco: es un menu encima del texto, y con el cristal de la
       barra se leeria el texto de debajo a traves de cada fila. */
    background: var(--suelo);
    padding-bottom: 1.5rem;
  }
  .indice.indice-abierto h2 { display: block; margin-bottom: 0.8rem; }
  .indice.indice-abierto .grupo-indice,
  .indice.indice-abierto ol.subs { display: block; }
  .indice.indice-abierto .grupo-indice h3 {
    display: flex; margin: 1.1rem 0 0.4rem; padding-left: 0;
  }
  .indice.indice-abierto ol.subs {
    display: block; border-left: 0; overflow: visible;
  }
  .indice.indice-abierto li a {
    /* Sin la tira horizontal: aqui la lista es vertical y cabe entera. */
    white-space: normal;
    border-left: 0;
    border-bottom: 2px solid transparent;
    padding: 0.45rem 0.6rem;
    font-size: 0.82rem;
    min-height: 44px;                 /* dedo */
  }
  .indice.indice-abierto li a.activo { border-bottom-color: var(--azul-4); }

  /* ── COMO SE ABRE Y COMO SE CIERRA EL MENÚ ───────────────────────────────────
     --
     El menu salia de golpe. Medido: cerrado, .indice es una tira horizontal de
     72 px de alto en su sitio; abierto, pasa a display:block y se vuelve un panel
     fijo de 779 px. Ese cambio se hace con display, y display NO SE PUEDE
     ANIMAR: no hay estado anterior al que ir con una transicion, porque el elemento
     simplemente no estaba en pantalla. Por eso aparecia de golpe.
     --
     Para abrir se usa una ANIMACION, que es lo que si funciona aqui. Un elemento
     que pasa de display:none a display:block se pinta otra vez, y al pintarse de
     nuevo la animacion empieza sola, sin necesidad de pedirla con JavaScript.
     --
     Para cerrar hace falta lo contrario:|display:none lo borra en el mismo
     fotograma y no hay nada que animar. Asi que al cerrar se pone la clase
     `indice-cerrando`, que deja el panel en pantalla pero transparente y subido, y
     JavaScript espera a que la transicion termine antes de quitarlo. Por eso hace
     falta el temporizador, y por eso el alto del menu se mantiene hasta el final. */
  @keyframes menu-entra {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .indice.indice-abierto:not(.indice-cerrando) {
    animation: menu-entra 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  /* La salida si es una transicion, y solo en este estado: en el de abierto sin mas
     no lleva transition para que no pelee con la animacion de entrada. */
  .indice.indice-abierto.indice-cerrando {
    opacity: 0;
    transform: translateY(-10px);
    transition: opacity 0.18s ease, transform 0.18s ease;
  }
}

/* Con el panel abierto la pagina de detras no se mueve. El scroll del body se
   bloquea con overflow:hidden en el html y no con position:fixed: lo segundo
   ademas tiene que acordarse de cuanto habia antes, y en un movil eso se nota
   al cerrar el panel, que la pagina salta. */
html.con-indice { overflow: hidden; }

/* ── Anterior / siguiente ─────────────────────────────────────────────────────
   Los dos en una fila: con uno solo no hay vuelta atras, que es justo lo que
   hace falta en un movil donde el indice cuesta de abrir. */
.siguientes {
  display: flex; align-items: stretch; gap: 1.5rem;
  margin-top: 1.6rem; padding-top: 0.8rem;
  border-top: 1px solid var(--linea);
  flex-wrap: wrap;
}
.siguiente {
  display: inline-flex; align-items: baseline; gap: 0.5rem;
  flex: 1 1 12rem;
  font-size: 0.8rem; color: var(--gris); text-decoration: none;
  padding: 0.35rem 0;
}
.siguiente.anterior { justify-content: flex-start; }
.siguiente:not(.anterior) { justify-content: flex-end; text-align: right; }
.siguiente span { font-size: 0.6rem; letter-spacing: 0.16em;
                  text-transform: uppercase; color: rgba(107, 130, 140, 0.65);
                  white-space: nowrap; }
.siguiente:hover { color: var(--hielo); }
.siguiente:hover span { color: var(--azul-4); }
.siguiente i { width: 0; height: 0; align-self: center; flex: none;
               border-left: 5px solid currentColor;
               border-top: 3.5px solid transparent;
               border-bottom: 3.5px solid transparent;
               transition: transform 0.2s; }
.siguiente.anterior i { transform: rotate(180deg); }
.siguiente:not(.anterior):hover i { transform: translateX(3px); }
.siguiente.anterior:hover i { transform: rotate(180deg) translateX(3px); }
.siguiente.arriba i { transform: rotate(-90deg); }
.siguiente.arriba:hover i { transform: rotate(-90deg) translateX(3px); }

/* En movil los dos van apilados y con altura de dedo, no en fila: con 390 px de
   ancho, dos botones de texto largo en fila se parten en tres lineas cada uno. */
@media (max-width: 620px) {
  .siguientes { flex-direction: column; gap: 0; }
  .siguiente { flex: none; justify-content: flex-start !important;
               text-align: left !important; min-height: 44px;
               align-items: center; }
  .siguiente + .siguiente { border-top: 1px solid var(--linea); }
  .siguiente i { display: none; }
}

html.claro .siguiente { color: var(--gris); }
html.claro .siguiente span { color: rgba(30, 32, 34, 0.55); }

@media (prefers-reduced-motion: reduce) {
  .siguiente i { transition: none; }
  /* Las rayas del boton de contenidos. Antes solo se apagaba la transicion de
     ::after, que era la unica que tenia; el fondo del boton, que es donde estaba la
     raya de arriba, se seguia moviendo sola. Ahora hay tres cosas que se mueven —
     el fondo y las dos rayas de los pseudoelementos— y se apagan las tres. */
  .contenidos { transition: color 0.2s, background-color 0.2s; }
  .contenidos::before, .contenidos::after { transition: none; }

  /* El menu de contenidos: la entrada y la salida. Se apagan las dos, que es lo
     mismo que se hace en el resto de la pagina. */
  .indice.indice-abierto:not(.indice-cerrando) { animation: none; }
  .indice.indice-abierto.indice-cerrando { transition: none; }
}

/* ══ EL REPRODUCTOR, CUANDO CARGA ═════════════════════════════════════════════
   Al darle a play el boton grande se apaga y el video aun no tiene nada que
   pintar. Sin nada en medio, esa espera es un rectangulo negro sin pistas de que
   este pasando nada. Estas dos reglas son esa pista. */

/* El aviso. Va en la barra de abajo y no encima del video: encima taparia justo
   la imagen que se esta intentando ver, y en un movil el pulgar esta ahi. */
.clip-barra.cargando .clip-tiempo::after {
  content: "cargando";
  margin-left: 0.5rem;
  font-size: 0.58rem; letter-spacing: 0.12em;
  color: var(--azul-4);
  animation: clip-pulso 1.1s ease-in-out infinite;
}
.clip-barra.cargando .clip-barra-rota { opacity: 0.45; }

@keyframes clip-pulso { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }

/* Y un anillo en el centro del video, que es donde se mira. Con un borde y sin
   SVG ni imagen: es un circulo que se dibuja.
   --
   Lleva un disco oscuro detras porque el video va cambiando de escena y un anillo
   gris se pierde sobre lo claro y se ve demasiado sobre lo oscuro. Medido sobre el
   fotograma del poster, que es casi blanco: el anillo sin disco apenas se
   distinguia. El disco es de --suelo con algo de transparencia, asi que el color
   de la pagina y el del video salen los dos. */
.escena-clip.cargando::after {
  content: ""; position: absolute;
  left: 50%; top: 50%;
  width: 42px; height: 42px; margin: -21px 0 0 -21px;
  border: 2.5px solid rgba(153, 186, 201, 0.30);
  border-top-color: #fff;
  border-right-color: rgba(153, 186, 201, 0.55);
  border-radius: 50%;
  /* Disco casi opaco. Con 0.45 el anillo salia como un borron gris: el arco
     blanco no se distinguia del disco y la foto parecia una mancha. Medido sobre
     el fotograma claro del poster, que es lo primero que se ve. */
  background: rgba(7, 9, 11, 0.72);
  /* Por encima del <video> y del boton grande. Sin esto el anillo se dibujaba
     debajo de la imagen del poster y no se veia. */
  z-index: 3;
  animation: clip-gira 0.8s linear infinite;
  /* El pseudo vive dentro de una caja con line-height:0 —para que el <video>
     no deje un hueco debajo—, asi que sin esto el texto que heredase lo
     pondria en medio de la espiral. */
  line-height: 0;
  pointer-events: none;
}
@keyframes clip-gira { to { transform: rotate(360deg); } }

/* Si el video no se puede reproducir, el boton no hara nada y esto es lo unico que
   lo dice. El aviso sustituye al boton, no se suma. */
.escena-clip.fallo::after,
.clip-barra.cargando.fallo::after { animation: none; border: 0; }
.escena-clip.fallo::after {
  content: "no se pudo reproducir"; position: absolute;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  margin: 0; width: auto; height: auto; border-radius: 0;
  font-size: 0.74rem; letter-spacing: 0.08em; color: #e8a48c;
  background: rgba(7, 9, 11, 0.82);
  padding: 0.5rem 0.8rem; border: 1px solid rgba(186, 95, 68, 0.5);
  border-radius: var(--r);
  white-space: nowrap; line-height: 1.4;
  z-index: 3; pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  /* Con reduced-motion el aviso TIENE que seguir apareciendo, solo que quieto:
     quitarlo entero dejaria el mismo rectangulo negro que se queria arreglar. */
  .escena-clip.cargando::after { animation: none; border-top-color: var(--azul-4); }
  .clip-barra.cargando .clip-tiempo::after { animation: none; opacity: 1; }
}
