/* ==========================================================================
   Sala de maquinas — hoja del prototipo alternativo de landing.

   Se carga DESPUES de /assets/css/styles.css y no la sustituye: hereda todos
   los tokens del sitio (--night, --lime, --mono, --ease, la escala --s-*) y el
   sistema de figuras. Aqui solo vive lo que esta pagina anade.

   Prefijo .mr- (maquinas) por la misma razon que styles.css usa .proc- y .fx-:
   este repo ya tuvo una colision de clases que dejo el formulario de contacto
   bajo una capa a pantalla completa. Prefijo antes que build que lo cace.

   Vivio en /alt/ mientras fue prototipo, justamente para que PUBLIC_DIRS no lo
   arrastrase a produccion sin permiso. Desde el 2026-08-20 esa razon ya no aplica:
   la pagina se promovio a /trabajo tras el veredicto visual, y estar bajo assets/ es
   ahora lo correcto porque SI queremos que se publique.

   El prefijo .mr- (sala de maquinas) se conserva pese al cambio de nombre: existe para
   evitar colisiones de clase y ese trabajo lo sigue haciendo. Renombrarlo seria churn
   con riesgo y sin beneficio.
   ========================================================================== */

.mr {
  /* La consola cede ancho al riel a proposito: lo que se ensena es el diseno de los
     productos, asi que la pantalla gana los pixeles y el argumento se ajusta al hueco
     que queda.

     36% y no 40%: 40/60 es el medio blando — lo bastante desigual para desequilibrar
     y no lo bastante para leerse como decision, que era justo la queja (el lado
     izquierdo parecia sin disenar mas que deliberadamente callado). A 36 la asimetria
     se afirma, y los 47px que suelta se los queda la evidencia, que es lo que la
     pagina ha venido a ensenar.

     El titular baja a 3.6vw en el mismo gesto: los cortes van a mano con <br> y
     estaban medidos contra el 40%. Sin bajarlo, «Cuatro disciplinas.» (436px a 4vw)
     no cabe en los ~404px que deja el 36% y rompe a cuatro lineas. */
  --mr-console: 36%;
  --mr-gap: clamp(32px, 4vw, 72px);
  --mr-inset: clamp(20px, 3vw, 48px);
  /* Distancia del borde derecho del armazon al del viewport. Por debajo de
     1440+2*inset el armazon ya se come el ancho disponible y el hueco es el
     propio inset; por encima, el armazon topa en 1440 y el hueco crece con la
     pantalla. max() cubre los dos regimenes con una sola expresion. */
  --mr-bleed: max(var(--mr-inset), (100vw - 1440px) / 2);
  --mr-progress: 0;

  /* elastic.out(1, 0.3) de GSAP, muestreado en 24 puntos del original. Era lo unico
     del repertorio que exigia de verdad un motor JS — una oscilacion amortiguada no
     cabe en una cubic-bezier, que solo tiene un tramo. linear() sí: aproxima
     cualquier curva por trozos. Sobrepasa hasta 1.36 y vuelve en tres rebotes.
     Se usa UNA vez en toda la pagina. Repartida se convierte en un tic. */
  --mr-elastic: linear(
    0 0%, .3612 3.1%, .8322 6.3%, 1.1998 9.4%, 1.3641 12.5%, 1.3357 15.6%,
    1.1928 18.8%, 1.0287 21.9%, .9116 25%, .8685 28.1%, .8893 31.3%, .9438 34.4%,
    1 37.5%, 1.0364 40.6%, 1.0466 43.8%, 1.0359 46.9%, 1.0156 50%, .9857 56.3%,
    .9886 62.5%, 1.0022 68.8%, 1.0055 75%, 1.0009 81.3%, .998 87.5%, 1 100%
  );
}

/* Los vectores de entrada ahora van en % y hacia fuera, asi que una pieza que aun no
   ha entrado se sale del encuadre por la derecha. body ya llevaba overflow-x:hidden
   en styles.css, pero el contenedor de scroll es html, que no recorta: por eso el
   codigo anterior tuvo que meter todos los vectores hacia dentro.

   clip y no hidden: hidden convierte al elemento en contenedor de scroll y eso
   romperia el position:sticky de la consola. clip recorta sin crear contenedor, y
   con el eje Y en visible el sticky sigue midiendo contra el viewport.
   Con :has() para que no se escape de este prototipo a ninguna otra pagina.

   Y HAY QUE TOCAR BODY TAMBIEN, que es la parte que rompio la consola pegajosa.
   styles.css ya daba a body un overflow-x:hidden. Mientras html estaba en visible,
   el navegador PROPAGA el overflow de body al viewport y body no se convierte en
   contenedor. Al poner clip en html corte esa propagacion: body paso a gobernarse
   solo, su overflow-y computo a `auto` (la regla dice que `visible` se convierte en
   `auto` cuando el otro eje no es ni visible ni clip), y se volvio contenedor de
   scroll. La consola quedo pegada a una caja que no scrollea nunca — es decir, no
   pegada a nada, saliendose de pantalla con el resto.

   Con clip en los dos ejes de body la pareja es clip+visible, `visible` sobrevive,
   body no es contenedor y el sticky vuelve a medir contra el viewport.
   Medido: body pasa de «hidden / auto» a «clip / visible», y el ancho del documento
   sigue en 1265 = viewport, o sea que se sigue recortando sin barra horizontal. */
html:has(.mr) { overflow-x: clip; }
body.mr { overflow-x: clip; overflow-y: visible; }

/* --- cabecera ------------------------------------------------------------- */
/* La cabecera propia del prototipo (.mr-top, fija, con la bandera de «no publicado»)
   se retiro al promover la pagina: ahora usa la .site-header del sitio, que es
   position:absolute y no ocupa flujo. El padding superior de .mr-shell ya reservaba
   sitio para una cabecera superpuesta, asi que no hubo que tocarlo. */

/* --- el armazon de dos columnas ------------------------------------------- */
.mr-shell {
  display: grid;
  grid-template-columns: var(--mr-console) 1fr;
  gap: var(--mr-gap);
  align-items: start;
  width: min(1440px, calc(100% - var(--mr-inset) * 2));
  margin-inline: auto;
  padding-block: clamp(96px, 12vh, 148px) 0;
}

/* --- columna fija: el argumento y la instrumentacion ----------------------- */
/* sticky y no fixed: fixed la sacaria del flujo y la columna dejaria de
   reservar su propio ancho, con lo que el riel se comeria la pagina entera. */
.mr-console { position: sticky; top: clamp(96px, 14vh, 160px); }
/* La consola ocupa el alto pegajoso completo y reparte el sobrante en UN sitio, en
   vez de dejarlo acumulado al final. Antes el lector de posicion flotaba a media
   altura y por debajo quedaban ~250px que no descansaban, solo faltaban. Con el
   min-height y el margin-top:auto del readout, el sobrante se va todo al hueco entre
   la nota y la instrumentacion: el titular gana aire arriba y la cota se apoya en el
   suelo del viewport, que es donde un instrumento tiene sentido.

   Solo en escritorio: por debajo de 861 la consola es static y forzar el alto del
   viewport meteria un vacio enorme antes del primer panel. */
.mr-console-inner { display: flex; flex-direction: column; align-items: flex-start; }
@media (min-width: 861px) {
  .mr-console-inner {
    min-height: calc(100svh - clamp(96px, 14vh, 160px) - var(--s-7));
  }
}

.mr h1 {
  margin: 0;
  /* Display grande pero por debajo del techo de 6rem del suelo de calidad, y el
     tracking se queda en -.04em, no en el -.045 que usan los h2 del sitio: a
     esta escala -.045 empieza a cerrar las contraformas de la Manrope 800. */
  /* El suelo baja de 2.3 a 2.15rem. Entre 861 y 1022px el clamp ya toca fondo pero
     la columna sigue encogiendo, asi que ahi es donde los cortes a mano aprietan: con
     36% y el suelo viejo quedaban 7px de holgura a 868px. Siete pixeles sobre 313 es
     un 2%, y este colchon existe porque los anchos cambian mientras carga la Manrope
     — si entra la fuente de reserva, mas ancha, «Cuatro disciplinas.» rompe a cuatro
     lineas. Con 2.15rem la holgura vuelve a ~27px. */
  font-size: clamp(2.15rem, 3.6vw, 3.4rem);
  font-weight: 800;
  line-height: .98;
  letter-spacing: -.04em;
  /* Sin text-wrap:balance a proposito: los cortes ya van con <br> en el HTML y
     balance los repartia otra vez, partiendo el ultimo verso en dos lineas
     iguales aunque cupiera. Los h2, que no llevan <br>, si lo usan. */
}
.mr h1 em {
  font-style: normal;
  color: var(--lime);
}

/* --- el momento estrella: "Producto real." letra a letra ------------------- */
/* UNA vez en toda la pagina. gsap.com hace exactamente esto — parte una sola palabra
   destacada por titular, nunca el titular entero — y esa contencion es lo que hace que
   la que si se parte signifique algo. Repartido, deja de ser un momento y es un tic.

   Por CARACTERES con inline-block, no por lineas con overflow:hidden. Medido en la
   propia web de GSAP: con inline-block el innerText del padre sigue devolviendo la
   palabra entera, asi que buscar-en-pagina y copiar siguen funcionando. El split por
   lineas enmascaradas rompe las dos cosas —una frase que cruza de linea deja de
   encontrarse— y por eso no esta aqui.

   Los espacios NO se envuelven: el JS los deja como nodos de texto sueltos. Un espacio
   dentro de un inline-block colapsa, y sustituirlo por &nbsp; cambiaria el texto que
   copia el visitante. Como nodo suelto entre dos inline-block se pinta normal.

   Estado por defecto: nada escondido. La clase .is-split la pone el JS despues de
   partir, asi que sin JS el titular se ve entero y quieto — el mismo contrato que
   .is-live y que .fig en el sitio. */
.mr h1 em[data-split] { perspective: 620px; }
.mr h1 em.is-split > span {
  display: inline-block;
  opacity: 0;
  transform: rotateX(-92deg);
  transform-origin: 50% 78%;
}
/* La elastica solo en transform. En opacity daria un parpadeo, porque la curva pasa
   por encima de 1 y por debajo: la opacidad rebotaria de opaca a translucida. */
.mr h1 em.is-split.is-in > span {
  opacity: 1;
  transform: none;
  transition: opacity .45s var(--ease-out) calc(var(--i) * 40ms),
              transform 1.4s var(--mr-elastic) calc(var(--i) * 40ms);
}
/* El lede es subtitulo, no cuerpo de texto. Estaba a 16px/1,72 con medida de 62ch
   —inerte, porque la columna mide ~475px y nunca llega— y pesaba casi lo mismo que
   todo lo demas de la consola: cinco bloques con el mismo tono gris y separaciones
   iguales no son jerarquia, son una pila. Baja de tamano, aprieta el interlineado y
   se PEGA al titular (16px en vez de 24) para que los dos se lean como un grupo y el
   aire grande quede donde separa grupos, no dentro de ellos. */
.mr-lede {
  margin: var(--s-4) 0 0;
  color: var(--muted);
  font-size: .95rem;
  line-height: 1.6;
}
.mr-lede strong { color: var(--ink-soft); font-weight: 600; }

/* La frase de propiedad, con la gramatica de .mr-spec: etiqueta mono + valor sans.
   Antes era un parrafo gris del mismo tamano que el lede y justo debajo, asi que los
   dos se leian como un solo bloque de seis lineas — la frase mas creible de la pagina
   escondida en una textura. Ahora no compite: es de otra especie tipografica.

   El filete lime se va con ella. Con la etiqueta ya marcando el arranque, la regla
   vertical solo anadia un segundo marcador para lo mismo. */
.mr-own {
  margin: var(--s-5) 0 0;
  color: var(--ink-soft);
  font-size: .88rem;
  line-height: 1.65;
  text-wrap: pretty;
}
.mr-own b {
  display: block;
  margin-bottom: 5px;
  color: var(--lime);
  font: 500 .7rem var(--mono);
  letter-spacing: .14em;
}

.mr-cta { margin-top: var(--s-7); }

/* --- el lector de posicion ------------------------------------------------ */
/* Es instrumentacion, no decoracion: el numero dice por donde va del expediente
   y la barra cuanto queda. Por eso los numeros de seccion existen en esta pagina
   y no en las demas — aqui la secuencia es informacion que el visitante usa. */
.mr-readout {
  width: 100%;
  margin-top: clamp(40px, 7vh, 88px);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
/* El auto recoge TODO el sobrante de la consola y lo pone aqui, asi que el
   instrumento se apoya en el suelo del viewport en vez de flotar a media altura.
   Va despues de la regla de arriba a proposito: con la misma especificidad manda el
   orden, y declarado antes perdia contra el clamp — que es exactamente el fallo que
   ya me comi con .mr-cta-inline en esta misma hoja. */
@media (min-width: 861px) {
  .mr-readout { margin-top: auto; }
}
.mr-readout-index {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 0;
  color: var(--dim);
  font: 400 .72rem var(--mono);
  /* Cifras de ancho fijo: sin esto el 1 es mas estrecho que el 4 y el contador
     tiembla lateralmente cada vez que cambia de panel. */
  font-variant-numeric: tabular-nums;
}
.mr-readout-index b { color: var(--lime); font-size: 1.05rem; font-weight: 500; }
/* «01/05» contaba sin decir que contaba. La etiqueta convierte una cifra suelta en
   una posicion legible, que es la unica razon por la que esta pagina puede numerar. */
.mr-readout-label { letter-spacing: .14em; }
.mr-readout-name {
  margin: 10px 0 var(--s-4);
  min-height: 1.4em;
  color: var(--ink-soft);
  font: 500 .78rem var(--mono);
  letter-spacing: .1em;
}
/* Era una linea de 2px en --line (alfa .12) sobre el fondo mas oscuro del sitio: a
   la cabeza de la pagina, con el progreso en 0, el tercer elemento del lector de
   posicion sencillamente no estaba. Un indicador invisible no indica.

   Dos cambios. La pista sube a 4px y a --line-strong, asi que EXISTE aunque el
   progreso sea cero. Y se parte en cinco tramos — el mismo cinco que dice
   «SECCION 01/05» justo encima —, con lo que deja de ser un porcentaje abstracto y
   pasa a decir por que panel vas. Los cortes crean bordes, y un borde se ve donde
   una linea continua de bajo contraste no.

   El raster va en una mascara sobre el contenedor, no en el fondo: asi corta la
   pista Y el relleno con el mismo ritmo, con un solo gradiente en vez de dos que
   habria que mantener sincronizados. Es tambien la unica forma de que los tramos
   sigan cuadrando si algun dia cambia el numero de paneles: se toca el 20% y ya.

   (repeating-linear-gradient con la bendicion del suelo de calidad: prohibe las
   rayas decorativas, y exceptua explicitamente los instrumentos de medida.) */
.mr-readout-bar {
  --mr-seg: repeating-linear-gradient(90deg, #000 0 calc(20% - 4px), transparent calc(20% - 4px) 20%);
  height: 4px;
  /* No usa --line-strong (alfa .24): compuesto sobre --night da 2,07:1, por debajo
     del 3:1 que la WCAG 1.4.11 pide a un componente de interfaz. Con .36 sube a 3,0.
     Es el unico sitio de la hoja que se sale del token, y por un umbral medido. */
  background: rgba(220, 255, 236, .36);
  -webkit-mask-image: var(--mr-seg);
          mask-image: var(--mr-seg);
  overflow: hidden;
}
.mr-readout-bar i {
  display: block;
  height: 100%;
  background: var(--lime);
  /* La barra es el unico movimiento continuo de la pagina y va sobre transform,
     no sobre width: animar width relayouta la pagina en cada fotograma, que es
     exactamente el fallo que se corrigio en .service-row. */
  transform: scaleX(var(--mr-progress));
  transform-origin: left;
}

/* --- el riel de evidencia ------------------------------------------------- */
.mr-rail { min-width: 0; }

.mr-panel {
  padding-block: clamp(72px, 11vh, 132px);
  border-top: 1px solid var(--line);
}
.mr-panel:first-child { padding-top: 0; border-top: 0; }

/* Entrada direccional. Un solo momento por panel, pero cada panel llega por un
   lado distinto: data-dir en el HTML fija el vector y el CSS solo lo consume. Sin
   variedad de direccion cinco secciones con el mismo translateY se leen como una
   plantilla que se repite, que es justo lo contrario de lo que la pagina afirma.
   Sale de un estado ya visible, asi que sin JS no desaparece nada. */
/* Amplitud en % del propio elemento, no en px. Una etiqueta de tres palabras y un
   titular de tres versos recorrian los mismos 34 px y se leian distinto: en % el
   gesto es proporcional a la pieza que lo hace, que es lo que iguala la sensacion.

   La rotacion es minuscula a proposito. gsap.com gira 180-360deg, pero solo sobre
   adornos; sobre texto, cualquier giro perceptible lo vuelve ilegible mientras dura.
   Entre 1 y 2 grados no se lee como giro sino como una pieza que se asienta en su
   sitio, que es justo el gesto que se busca. */
.mr-panel { --mr-dx: 0%; --mr-dy: 34%; --mr-rot: 0deg; }
.mr-panel[data-dir="left"]  { --mr-dx: -26%; --mr-dy: 0%;  --mr-rot: -1.5deg; }
.mr-panel[data-dir="right"] { --mr-dx:  26%; --mr-dy: 0%;  --mr-rot:  1.5deg; }
.mr-panel[data-dir="up"]    { --mr-dx:   0%; --mr-dy: 38%; --mr-rot:  .9deg; }

/* La pantalla entra desde DENTRO y se desliza hacia su sangrado, no al reves.
   Medido: con el vector hacia la derecha (+54) el marco de un panel que aun no ha
   entrado se queda 54 px fuera del borde y aparece scroll horizontal real — body
   lleva overflow-x:hidden pero el contenedor de scroll es html, que no recorta.
   Un elemento que reposa pegado al borde no puede entrar desde fuera de el.
   Con el vector negativo el gesto ademas cuenta mejor: la interfaz se estira
   hacia el borde y se sale del encuadre, en vez de venir de la nada. */
/* La pantalla contra la copia: el par en oposicion. Es el unico gesto de la pagina
   donde dos piezas de la misma seccion llegan de lados contrarios, y por eso se lee
   como una escena que se compone y no como una lista que se ilumina.

   Antes esto no ocurria: el marco heredaba -54px y la copia -34px, o sea los dos
   desde la izquierda, aunque el comentario del HTML dijera que convergian. El signo
   negativo se eligio para evitar scroll horizontal, y esa razon era buena: un
   elemento que reposa pegado al borde derecho no puede entrar desde fuera de el sin
   ensanchar la pagina. Con html en overflow-x:clip (mas abajo) esa razon ya no
   aplica, asi que el marco puede por fin venir del lado opuesto de verdad. */
.mr-case .mr-frame { --mr-dx: 30%; --mr-dy: 0%; --mr-rot: 1.2deg; }
.mr-panel[data-dir="right"] .mr-case .mr-frame { --mr-dx: -30%; --mr-rot: -1.2deg; }

.mr-rail.is-live .mr-panel > :not(.mr-case),
.mr-rail.is-live .mr-panel > .mr-case > * {
  opacity: 0;
  transform: translate3d(var(--mr-dx), var(--mr-dy), 0) rotate(var(--mr-rot));
  transition: opacity .72s var(--ease-out), transform .72s var(--ease-out);
}
.mr-rail.is-live .mr-panel.is-in > :not(.mr-case),
.mr-rail.is-live .mr-panel.is-in > .mr-case > * { opacity: 1; transform: none; }

/* .mr-case no se anima nunca: si el envoltorio y sus hijos llevaran transform a
   la vez, las distancias se sumarian y el panel entraria del doble de lejos. */
.mr-rail.is-live .mr-panel.is-in > :nth-child(2),
.mr-rail.is-live .mr-panel.is-in > .mr-case > :nth-child(2) { transition-delay: .07s; }
.mr-rail.is-live .mr-panel.is-in > :nth-child(3),
.mr-rail.is-live .mr-panel.is-in > .mr-case > :nth-child(3) { transition-delay: .14s; }
.mr-rail.is-live .mr-panel.is-in > :nth-child(4),
.mr-rail.is-live .mr-panel.is-in > .mr-case > :nth-child(4) { transition-delay: .21s; }
.mr-rail.is-live .mr-panel.is-in > :nth-child(5),
.mr-rail.is-live .mr-panel.is-in > .mr-case > :nth-child(5) { transition-delay: .28s; }

.mr h2 {
  margin: 0;
  font-size: clamp(1.6rem, 2.5vw, 2.25rem);
  font-weight: 750;
  line-height: 1.04;
  letter-spacing: -.04em;
  text-wrap: balance;
}
.mr-body {
  max-width: 68ch;
  margin: var(--s-5) 0 0;
  color: var(--muted);
  font-size: .96rem;
  line-height: 1.78;
}
.mr-dim { color: var(--dim); font-size: .86rem; }

/* --- caso ----------------------------------------------------------------- */
/* .mr-case-tag se retiro entera: era un eyebrow —etiqueta encima del titular— y ese
   patron no se gana nunca, el titular lleva su propio peso. Encima duplicaba el
   estado, que ya vive en la fila «Estado» de la ficha, que es donde estan el resto
   de los hechos. Un dato dicho dos veces en el mismo panel es un dato que puede
   contradecirse a si mismo el dia que alguien edite solo uno.

   Lo que si aportaba —«esto esta funcionando ahora mismo»— sobrevive como indicador
   junto al nombre, no sobre el. El punto se alinea con la altura de la mayuscula y
   no con la linea base, que es donde un LED de estado se lee como parte del rotulo. */
.mr-live {
  display: inline-flex;
  align-items: center;
  margin-left: .45em;
  /* Centro optico de la mayuscula, no linea base. Medido con TextMetrics sobre la
     Manrope 750 cargada: altura de mayuscula 0,719em, luego su centro cae a .3595em
     sobre la baseline; el punto se apoya en la baseline, asi que necesita .246em.
     No lo estimes a ojo — mi primer intento a ojo fallo por 5px en el otro sentido. */
  vertical-align: .246em;
}
.mr-case-line {
  max-width: 60ch;
  margin: var(--s-4) 0 var(--s-6);
  color: var(--ink-soft);
  font-size: 1.02rem;
  line-height: 1.65;
}

/* El marco reserva la proporcion antes de que exista la captura, asi que el dia
   que entre la imagen no hay salto de layout ni hay que tocar nada de aqui. */
.mr-frame {
  margin: 0 0 var(--s-6);
  /* Sangra hasta el borde derecho del viewport y ahi pierde borde y radio: la
     interfaz sigue mas alla del encuadre en vez de quedarse dentro de la columna.
     Es el unico elemento de la pagina que rompe la reticula, y es el que se ha
     venido a ver. body ya lleva overflow-x:hidden en styles.css, asi que el
     desborde se recorta sin barra horizontal. */
  margin-right: calc(-1 * var(--mr-bleed));
  border: 1px solid var(--line-strong);
  border-right: 0;
  border-radius: 14px 0 0 14px;
  overflow: hidden;
  background: #0a1d15;
  /* Elevacion declarada una sola vez. El borde es la elevacion; la sombra solo
     asienta el objeto sobre el fondo, con desplazamiento y desenfoque reales. */
  box-shadow: 0 26px 60px -30px rgba(0, 0, 0, .9);
}
.mr-frame-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  background: rgba(226, 255, 238, .03);
}
.mr-frame-bar span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-strong);
}
.mr-frame-bar span:first-child { background: var(--lime); }
.mr-frame-bar p {
  margin: 0 0 0 10px;
  color: var(--dim);
  font: 400 .64rem var(--mono);
}
.mr-frame picture { display: block; }
.mr-frame img { display: block; width: 100%; height: auto; }

/* Ficha del caso: definiciones, no tarjetas. Una rejilla de tarjetas iguales
   seria el contenedor perezoso; esto es una ficha tecnica y se lee como tal. */
.mr-spec { margin: 0 0 var(--s-6); display: grid; gap: 1px; background: var(--line); }
.mr-spec > div {
  display: grid;
  grid-template-columns: 190px 1fr;
  gap: var(--s-5);
  padding: var(--s-4) 0;
  background: var(--night);
}
.mr-spec dt { margin: 0; color: var(--dim); font: 400 .72rem var(--mono); letter-spacing: .08em; }
.mr-spec dd { margin: 0; color: var(--ink-soft); font-size: .9rem; line-height: 1.6; }

/* --- la lista de servicios ----------------------------------------------------- */
.mr-pieces {
  margin: var(--s-7) 0 var(--s-6);
  padding: 0;
  list-style: none;
  display: grid;
  gap: 1px;
  background: var(--line);
}
/* Sin numerales. Los 01-05 prometian un conteo que el titular contradecia («Las
   cuatro piezas» sobre cinco elementos), y numerar una seccion solo se gana cuando la
   secuencia es informacion que el lector necesita — aqui el orden se lee en la propia
   sucesion, sin cifras. Se queda <ol> porque el orden sigue significando algo: cada
   pieza se apoya en la anterior. Al no haber columna de numero, la reticula de dos
   columnas ya no hace falta y el bloque respira mas. */
.mr-pieces li {
  padding: var(--s-5) 0;
  background: var(--night);
}
.mr-pieces h3 { margin: 0; font-size: 1.14rem; font-weight: 700; letter-spacing: -.025em; }
.mr-pieces p { margin: 7px 0 0; color: var(--muted); font-size: .89rem; line-height: 1.6; }

/* --- hechos del modelo ---------------------------------------------------- */
.mr-facts { margin: var(--s-7) 0 var(--s-6); display: grid; gap: 1px; background: var(--line); }
.mr-facts > div {
  display: grid;
  grid-template-columns: 190px 1fr;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  background: var(--night);
}
.mr-facts b { color: var(--lime); font: 500 .68rem var(--mono); letter-spacing: .1em; }
.mr-facts p { margin: 0; max-width: 62ch; color: var(--ink-soft); font-size: .92rem; line-height: 1.7; }

/* --- cierre --------------------------------------------------------------- */
.mr-panel-close { padding-bottom: clamp(96px, 16vh, 180px); }
.mr-mail { margin: var(--s-6) 0 var(--s-4); }
.mr-mail a {
  color: var(--lime);
  font-size: clamp(1.1rem, 2.1vw, 1.7rem);
  font-weight: 600;
  letter-spacing: -.03em;
  border-bottom: 1px solid var(--lime-edge);
}
.mr-mail a:hover { color: var(--lime-bright); border-bottom-color: var(--lime-bright); }

/* --- volver al inicio ------------------------------------------------------ */
/* Aparece cuando el riel pasa del 6%: antes de eso el inicio esta a un golpe de
   rueda y un boton para volver seria ruido. La clase la pone el update() que ya
   corre — cero listeners nuevos, cero observers nuevos.

   Sale escalando desde .82 y no desde 0: nada en el mundo real aparece de la nada.
   Y el hover solo mueve dentro de @media (hover:hover), porque en tactil :hover se
   dispara al tocar y se queda pegado — la misma regla del Hito 8.

   44px reales, que es el minimo de toque, y no un icono de 24 con aire alrededor. */
.mr-to-top {
  position: fixed;
  right: clamp(16px, 3vw, 32px);
  bottom: clamp(16px, 3vw, 32px);
  z-index: 45;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 1px solid var(--lime-edge);
  border-radius: 50%;
  background: rgba(6, 19, 14, .82);
  backdrop-filter: blur(8px);
  color: var(--lime);
  font-size: 1.05rem;
  line-height: 1;
  text-decoration: none;
  opacity: 0;
  transform: scale(.82);
  visibility: hidden;
  transition: opacity .3s var(--ease-out), transform .3s var(--ease-out), visibility 0s .3s;
}
body:has(.mr-rail.is-scrolled) .mr-to-top {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity .3s var(--ease-out), transform .3s var(--ease-out), visibility 0s;
}
@media (hover: hover) and (pointer: fine) {
  .mr-to-top:hover {
    border-color: var(--lime);
    background: var(--lime);
    color: #06180f;
    transform: translateY(-3px);
    transition-duration: var(--hover-in);
  }
}
@media (prefers-reduced-motion: reduce) {
  .mr-to-top { transition: none; }
}

/* --- pie ------------------------------------------------------------------ */
.mr-foot {
  padding: var(--s-6) clamp(20px, 3vw, 40px);
  border-top: 1px solid var(--line);
  text-align: center;
}
.mr-foot p { margin: 0; color: var(--dim); font: 400 .72rem var(--mono); }
.mr-foot a { color: var(--muted); border-bottom: 1px solid var(--line-strong); }

/* Fuera de movil no existe. Declarado ANTES de la media query: al reves la base
   ganaba por orden de cascada y el CTA movil no aparecia nunca. */
.mr-cta-inline { display: none; }

/* --- adapt: la mano, no el raton ------------------------------------------ */
/* En movil TODO enlace era menor de 44x44 menos el CTA principal: medidos 109x31,
   203x33, 279x29 y 124x15 para el pie. El area de toque crece con padding y un
   margen negativo que la devuelve, asi que el texto no se mueve ni un pixel y el
   dedo gana el objetivo. 44px es el minimo de WCAG 2.5.8 y de las HIG de Apple. */
@media (max-width: 860px) {
  .mr-case .text-link,
  .mr-panel > .text-link,
  .mr-mail a,
  .mr-foot a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .mr-foot a { padding: 0 var(--s-2); margin: 0 calc(var(--s-2) * -1); }

  /* El CTA intermedio solo existe aqui. En escritorio la consola pegajosa mantiene
     el principal en pantalla los 4.443 px de scroll y un segundo boton seria ruido. */
  .mr-cta-inline { display: inline-flex; margin-top: var(--s-6); }
}
/* --- superficies del navegador -------------------------------------------- */
/* Lo que no dibujas tambien lleva el diseño. El foco NO se toca aqui: styles.css
   ya lo viste con --lime-bright, que contrasta mas que --lime; redeclararlo solo
   habria empeorado el anillo. Seleccion y barra de scroll si estaban sin vestir
   en todo el sitio — si esta version se promueve, suben a styles.css y dejan de
   vivir aqui. */
.mr ::selection { background: var(--lime); color: #06180f; }
.mr { scrollbar-color: var(--lime-edge) var(--night); scrollbar-width: thin; }

/* --- audit: .mr-panel-quiet existia sin hacer nada ------------------------ */
/* La clase estaba en los paneles 2 y 4 y no casaba con ninguna regla: un gancho
   muerto desde el primer commit. Se le da el trabajo que su nombre promete y que
   ademas resuelve un hallazgo aparte — el panel 2 es el mas alto de la pagina e
   interrumpe la evidencia entre los dos casos. Los paneles de argumento leen a
   medida de lectura; los de exhibicion se quedan el ancho completo. Asi el riel
   alterna prueba ancha y comentario estrecho en vez de cinco bloques iguales. */
.mr-panel-quiet > * { max-width: 46rem; }

/* --- audit: el foco sigue al salto ---------------------------------------- */
/* #rail y #contacto reciben saltos (el skip-link y los dos CTA). Sin tabindex="-1"
   en el HTML el navegador mueve el viewport pero NO el foco, asi que el siguiente
   Tab continua desde donde estaba y quien navega con teclado se pierde. El atributo
   va en el HTML; esto solo evita que el anillo dibuje una caja enorme al recibirlo. */
[tabindex="-1"]:focus { outline: none; }
[tabindex="-1"]:focus-visible { outline: none; }

/* --- responsive ----------------------------------------------------------- */
@media (max-width: 1080px) {
  .mr { --mr-console: 40%; }
  .mr-spec > div, .mr-facts > div { grid-template-columns: 150px 1fr; gap: var(--s-4); }
}

@media (max-width: 860px) {
  /* Una sola columna: la consola deja de ser fija y pasa a ser la portada, y el
     lector de posicion se retira. Un indicador de progreso que no acompaña al
     scroll no informa de nada, solo ocupa. */
  .mr-shell { grid-template-columns: 1fr; gap: var(--s-7); }
  .mr-console { position: static; }
  .mr-readout { display: none; }
  .mr-panel:first-child { padding-top: clamp(48px, 8vh, 72px); border-top: 1px solid var(--line); }
  .mr-spec > div, .mr-facts > div { grid-template-columns: 1fr; gap: 6px; }
}

@media (max-width: 520px) {
}

/* La entrada orquestada se anula entera con movimiento reducido: sin esto, un
   visitante que pide menos movimiento se queda mirando paneles en opacity 0
   hasta que el observer los alcanza. */
@media (prefers-reduced-motion: reduce) {
  .mr-rail.is-live .mr-panel > * { opacity: 1; transform: none; transition: none; }
  .mr-readout-bar i { transition: none; }
  /* El titular partido vive en la consola, fuera de .mr-rail, asi que la regla de
     arriba no lo alcanzaba. Catorce caracteres girando en 3D con rebote elastico son
     justo lo que alguien con sensibilidad vestibular necesita apagado. El bloque
     global de styles.css deja las transiciones en .01ms, pero eso solo las acorta:
     aqui hace falta anular el estado inicial, que es lo que de verdad mueve. */
  .mr h1 em.is-split > span { opacity: 1; transform: none; transition: none; }
}
