@charset "utf-8";
/* ==========================================================================
   escena.css · La película
   --------------------------------------------------------------------------
   El escenario, los actos y el texto que flota encima del mapa.
   Normas: NORMAS.md § 9 (la película) y § 1 (dónde entra el color).

   🚨 Regla de oro de este archivo: el JavaScript solo escribe VARIABLES CSS.
   Todo lo que se mueve aquí se mueve con `transform` y `opacity`, que son las
   dos únicas cosas que un móvil anima sin recalcular la página.
   ========================================================================== */

/* ==========================================================================
   1 · El escenario
   --------------------------------------------------------------------------
   Una capa fija detrás de todo. No pertenece a ningún acto: el globo del acto 1
   es el mapa del acto 2, y si cada uno tuviera el suyo se vería la costura.

   `position: fixed` y no `sticky` a propósito. Con sticky habría que coordinar
   la altura de dos actos seguidos y, en iOS, la barra del navegador lo rompe
   (NORMAS § 9, regla 3). Con `inset: 0` no hay alturas que cuadrar.
   ========================================================================== */
.escenario {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
}
/* 🚨 SIN `transition`. La tenia, de 350 ms, y como la opacidad la escribe el
   scroll en cada fotograma, la transicion la perseguia siempre por detras: a
   mitad de la entrada el mapa marcaba 0,33 cuando le tocaba 0,68, y la Tierra
   parecia aparecer tarde y de golpe. Lo que va atado al scroll no se
   interpola: ya viene suavizado. */
.escenario.en-escena {
  visibility: visible;
  opacity: calc(var(--opacidad-mapa, 1) * (1 - var(--fin, 0)));
  /* La Tierra sube desde abajo mientras el titulo sigue delante: los dos se
     cruzan, que es lo que hace que parezca una pagina y no dos pegadas.

     🚨 Y la variable --mini encoge el mapa entero y lo sube, para el pequenio del
     viaje en coche del acto 3: ahi arriba va el mapa y abajo el dibujo. Vale 0
     casi siempre; a 1, el mapa mide la mitad y se va a la parte de arriba. Ver
     empequenecerMapa() en js/motor/lienzo.js. */
  transform:
    translateY(calc((1 - var(--p-alzado, 1)) * 34svh - var(--mini, 0) * 24svh))
    scale(calc((.9 + var(--p-alzado, 1) * .1) * (1 - var(--mini, 0) * .58)));
}
.escenario svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

/* 🚨 EL BORDE DEL MAPA PEQUENIO SE DIFUMINA, PERO SOLO ARRIBA Y ABAJO.
   Kiko, viendo el mapa del viaje en coche: «que no se corte magicamente con la
   nada». Y es literal: al encoger la capa, la costa llegaba al borde del
   rectangulo y se acababa ahi, en seco, sobre el blanco. Ningun encuadre
   arregla eso —una costa siempre sale del cuadro por algun lado—, asi que lo
   que se arregla es el corte.

   🚨 Y SOLO EN VERTICAL, que es la parte que cuesta. El primer intento
   difuminaba en redondo, hacia los cuatro lados, y se llevo por delante las
   etiquetas: TAKARAGAWA y SHINJUKU se desvanecian por la mitad justo donde hay
   que leerlas. Las etiquetas viven a media altura y salen hacia los lados, asi
   que un degradado vertical no las toca nunca.

   La cuenta hace dos cosas con una sola linea: con --mini a 0 las paradas se
   van fuera del elemento y no hay mascara ninguna; con --mini a 1 se quedan en
   el 14 % y el 86 %. Asi no hay una regla aparte que se pueda olvidar de
   apagar. */
.escenario {
  --borde: calc(14% * var(--mini, 0));
  -webkit-mask-image: linear-gradient(to bottom,
    transparent 0, #000 var(--borde), #000 calc(100% - var(--borde)), transparent 100%);
  mask-image: linear-gradient(to bottom,
    transparent 0, #000 var(--borde), #000 calc(100% - var(--borde)), transparent 100%);
}

/* Sin JavaScript no hay escenario que valga: ni se monta ni se ve */
html:not(.anim) .escenario { display: none; }

/* --- El mapa: trazo, nunca mancha --- */
.m-limbo {
  fill: none;
  stroke: var(--mapa-linea);
  stroke-width: 1;
}
.m-reticula {
  fill: none;
  stroke: var(--mapa-linea);
  stroke-width: .7;
}
/* 🚨 Las costas no se rellenan y no se cierran: cerrar un contorno recortado
   por el borde del globo dibuja una cuerda recta que lo atraviesa. */
.m-costa {
  fill: none;
  stroke: var(--mapa-costa);
  stroke-width: .9;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* Las autopistas. Un pelo mas marcadas que el callejero porque se ven de mucho
   mas lejos, pero igual de tenues que la costa: siguen siendo el contexto. */
.m-autopista {
  fill: none;
  stroke: var(--mapa-linea);
  stroke-width: .8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* El callejero. Más fino y más tenue que la costa: es el suelo por el que se
   pasa, no el dato. Si pesa lo mismo que la línea de la operadora, la tapa. */
.m-calle {
  fill: none;
  stroke: var(--mapa-linea);
  stroke-width: .6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 🚃 LA VÍA DE TREN, Y SU GROSOR ES UNA VARIABLE PORQUE ES UNA COSTURA.
   Kiko, el 20 de septiembre: «que sea el propio trazo de la línea de las vías
   lo que acaba siendo la vía donde está el tren». Así que al final del zoom del
   acto 7 esta línea engorda desde un pelo hasta el ancho de la vía dibujada,
   que se planta encima en el mismo sitio mientras el mapa se disuelve.
   🚨 `stroke-linecap: butt` y no `round`: al engordar a treinta unidades, una
   punta redonda convierte el final de cada tramo en un pegote. */
.m-via {
  fill: none;
  stroke: var(--mapa-linea);
  stroke-width: var(--grosor-via, 1);
  stroke-linecap: butt;
  stroke-linejoin: round;
}

.m-ruta {
  fill: none;
  stroke: var(--acento);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --- Marcadores ---
   🚨 Apagados por defecto. Los encienden los actos, uno a uno. Sin esta linea,
   los que ningun acto toca —Shinjuku y Meidaimae— salian encendidos desde el
   primer fotograma, flotando sobre el globo durante todo el vuelo. */
.m-hito { opacity: 0; }
.m-hito circle { fill: var(--acento); }
.m-hito text {
  font-family: var(--f-texto);
  /* 🚨 MAS GRANDE EN EL MAPA PEQUENIO, y no es un capricho de tamanio.
     El rotulo lleva un halo de 2,6 px pintado por debajo de la letra
     (paint-order) para que se lea sobre el mapa. Al encoger la capa al 42 %,
     la letra baja a siete pixeles pero el halo se le come por dentro: en
     pantalla salia una fila de guiones donde ponia TAKARAGAWA. Se vio en la
     captura del mapa pequenio.
     Creciendo con --mini, la letra vuelve a medir once pixeles reales y el halo
     vuelve a ser un halo. */
  font-size: calc(8.5px + var(--mini, 0) * 9px);
  letter-spacing: .1em;
  text-transform: uppercase;
  fill: var(--tinta-suave);
  font-weight: 600;
  paint-order: stroke;
  stroke: var(--papel);
  stroke-width: calc(2.6px + var(--mini, 0) * 2.4px);
  stroke-linejoin: round;
}
.m-destino .m-halo {
  fill: var(--acento);
  opacity: .12;
}
.m-avion { fill: var(--tinta); }

/* ==========================================================================
   2 · Los actos
   --------------------------------------------------------------------------
   `--largo` viene del HTML y dice cuántas pantallas de scroll ocupa el acto.
   Dentro, una escena pegada que ocupa una pantalla justa.
   🚨 `svh` y no `vh`: en iOS la barra del navegador cambia `vh` a mitad de
   scroll y el sticky da un salto.
   ========================================================================== */
.acto {
  position: relative;
  z-index: 1;
  height: calc(var(--largo, 300) * 1svh);
}

/* 🚨 LA PANTALLA MUERTA ENTRE ACTOS, Y POR QUÉ HAY UN MARGEN NEGATIVO.

   Una escena pegajosa deja de estarlo cuando el final de su sección llega al
   final de la pantalla. Con secciones encadenadas eso deja SIEMPRE un hueco de
   exactamente una pantalla: en un móvil de 844 px, el acto 1 termina su
   animación en el scroll 5.064 y el acto 2 no empieza hasta el 5.908. En medio,
   844 píxeles en los que el primero está clavado en su último fotograma y el
   segundo aún no ha arrancado. El mapa, que vive en una capa fija, se queda
   congelado todo ese rato.

   Kiko lo notó dos veces como «se tarda mucho desde que llega a Japón hasta que
   empieza el zoom», y las dos veces busqué la causa en los tiempos de los
   actos, que no era. Era esto, y son 844 píxeles de nada.

   El margen negativo solapa las dos secciones justo esa pantalla: el acto 2
   empieza a contar exactamente donde el acto 1 acaba. Se puede porque los dos
   actos casan en la costura —el 2 arranca en el estado en que el 1 termina— y
   porque el dibujo no está en la escena, sino en la capa fija. */
.anim .acto + .acto { margin-top: -100svh; }

.escena {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  padding-inline: var(--lado);
  padding-block: calc(env(safe-area-inset-top) + 3.4rem) calc(env(safe-area-inset-bottom) + 4.5rem);
}

/* --------------------------------------------------------------------------
   Sin JavaScript: los actos se aplanan y se leen como texto normal
   --------------------------------------------------------------------------
   🚨 No basta con quitar el `display: grid` de la escena. Los rótulos y las
   fichas viven en su propia rejilla, todos en la celda 1/1 para encadenarse, y
   si esa rejilla sigue en pie salen los siete rótulos del vuelo impresos unos
   encima de otros. Se vio en la captura sin JavaScript.
   -------------------------------------------------------------------------- */
html:not(.anim) .acto { height: auto; }
html:not(.anim) .escena {
  position: static;
  height: auto;
  display: block;
  max-width: var(--medida);
  margin-inline: auto;
  padding-block: var(--aire);
}
html:not(.anim) .rotulos,
html:not(.anim) .tramos { display: block; width: auto; text-align: left; }
html:not(.anim) .rotulo,
html:not(.anim) .tramo-ficha {
  grid-area: auto;
  opacity: 1;
  margin-top: 2.2rem;
}
html:not(.anim) .portada,
html:not(.anim) .titular-acto,
html:not(.anim) .panel {
  grid-area: auto;
  text-align: left;
  max-width: none;
  opacity: 1;
  transform: none;
  max-height: none;
  overflow: visible;
  margin-top: 2.5rem;
}
html:not(.anim) .pista { display: none; }
html:not(.anim) .ir-indice { position: static; margin-top: 2rem; }

/* 🚨 AQUI HABIA UN VELO DE PAPEL y se ha quitado.
   Eran dos degradados blancos, arriba y abajo, para que la costa no cruzara los
   titulares. Pero ocupaban un tercio de la pantalla cada uno y lo que tapaban
   de verdad era la Tierra: Kiko lo vio como "una cosa blanca que tapa la
   tierra", y tenia razon.
   Lo que protege el texto ahora es un halo pegado a las letras (abajo), que
   hace el mismo trabajo sin poner una sabana por delante del dibujo. */

/* El halo del texto que flota sobre el mapa. Es el mismo truco que ya usaban
   las etiquetas de los marcadores con paint-order, traido al HTML. */
.anim .portada,
.anim .rotulo,
.anim .tramo-ficha {
  text-shadow: 0 0 .5rem var(--papel), 0 0 .25rem var(--papel), 0 0 .1rem var(--papel);
}

/* ==========================================================================
   3 · A1 · La portada
   ========================================================================== */
.portada {
  grid-area: 1 / 1;
  text-align: center;
  max-width: 24rem;
  align-self: center;
}
.anim .portada {
  opacity: var(--p-titulo, 1);
  transform: translateY(calc((1 - var(--p-titulo, 1)) * -2.4rem));
  will-change: opacity, transform;
}
.portada h1 {
  font-size: clamp(2.7rem, 13vw, 4.6rem);
  margin-block: .7rem .9rem;
}
.portada h1 span {
  display: block;
  font-size: .42em;
  letter-spacing: .32em;
  margin-left: .32em;
  color: var(--tenue);
}
.bajada {
  color: var(--tinta-suave);
  font-size: .95rem;
  line-height: 1.6;
}

.pista {
  position: absolute;
  bottom: max(3.2rem, calc(env(safe-area-inset-bottom) + 3.2rem));
  left: 0;
  right: 0;
  text-align: center;
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--tenue);
  opacity: var(--p-pista, 1);
}
.pista span::after {
  content: '';
  display: block;
  width: 1px;
  height: 1.8rem;
  margin: .7rem auto 0;
  background: linear-gradient(var(--tenue), transparent);
}

/* Se va con el titulo: cruzando por delante del globo estorba */
.anim .ir-indice { opacity: var(--p-titulo, 1); }

.ir-indice {
  position: absolute;
  bottom: max(1rem, env(safe-area-inset-bottom));
  right: var(--lado);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--tenue);
  text-decoration: none;
  padding: .7rem 0;
  display: block;
}
.ir-indice::after {
  content: '';
  display: block;
  height: 1px;
  margin-top: .35rem;
  background: var(--pelo-fuerte);
  transition: background .25s ease;
}
.ir-indice:hover { color: var(--tinta); }
.ir-indice:hover::after { background: var(--tinta); }

/* ==========================================================================
   4 · A1 · Los rótulos del vuelo
   --------------------------------------------------------------------------
   «Los datos del vuelo, en vez de hacerlos como una sección, van apareciendo y
   difuminándose arriba al globo.» Todos ocupan la MISMA celda: se encadenan,
   no se apilan, y por eso el globo nunca se queda sin nada encima.
   ========================================================================== */
.rotulos {
  grid-area: 1 / 1;
  align-self: start;
  justify-self: center;
  display: grid;
  list-style: none;
  margin: 0;
  padding: 0;
  width: min(100%, 27rem);
  text-align: center;
  pointer-events: none;
}
.rotulo {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0;
}

.r-dato {
  font-family: var(--f-display);
  font-size: clamp(2.1rem, 10vw, 3.1rem);
  line-height: 1.05;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}
.r-dato-corto { font-size: clamp(1.5rem, 6.6vw, 2.1rem); }
.r-pie {
  margin-top: .7rem;
  font-size: .85rem;
  line-height: 1.55;
  color: var(--tinta-suave);
}
.rotulo-ancho { max-width: 22rem; justify-self: center; }

/* ==========================================================================
   5 · A2 · Las fichas de cada tramo
   --------------------------------------------------------------------------
   Se encienden cuando su línea empieza a dibujarse en el mapa. Abajo, para no
   taparlo: el trayecto que cuentan está pasando justo encima.
   ========================================================================== */
/* 🚨 EN LA PELICULA NO SE VE. Aparecia a opacidad 1 en cuanto la escena del
   acto 2 asomaba —es decir, ANTES de que empezara el zoom— y cruzaba por
   delante del globo. Kiko lo pidio claro: «me gustaria directamente ya que
   empezase con el zoom». Sigue en el HTML porque nombra la seccion para un
   lector de pantalla y porque es lo que se lee sin JavaScript. */
.titular-acto {
  grid-area: 1 / 1;
  align-self: start;
  justify-self: center;
  text-align: center;
}
.anim .titular-acto { opacity: 0; }
.titular-acto h2 {
  font-size: clamp(1.5rem, 6.4vw, 2.1rem);
  margin-top: .6rem;
}

.tramos {
  grid-area: 1 / 1;
  align-self: end;
  justify-self: center;
  display: grid;
  list-style: none;
  margin: 0;
  padding: 0;
  width: min(100%, 24rem);
  text-align: center;
  pointer-events: none;
}
.tramo-ficha {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0;
}

.t-codigo {
  font-size: .7rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--acento);
}
.t-nombre {
  font-family: var(--f-display);
  font-size: clamp(1.4rem, 6vw, 1.9rem);
  margin-top: .25rem;
  line-height: 1.1;
}
.t-pie {
  margin-top: .45rem;
  font-size: .82rem;
  color: var(--tinta-suave);
  line-height: 1.5;
}

/* ==========================================================================
   6 · A2 · El panel del alojamiento
   --------------------------------------------------------------------------
   Sube desde abajo cuando el trayecto ha terminado. Fondo blanco porque aquí
   sí tiene que leerse: el mapa se ha retirado detrás.
   ========================================================================== */
.panel {
  grid-area: 1 / 1;
  align-self: center;
  justify-self: center;
  width: min(100%, var(--medida));
  max-height: 100%;
  overflow-y: auto;
  opacity: var(--p-datos, 0);
  transform: translateY(calc((1 - var(--p-datos, 0)) * 3rem));
  pointer-events: auto;
}

.panel-cabecera { margin-bottom: 1.6rem; }
.panel h3 {
  font-size: clamp(1.7rem, 7.5vw, 2.4rem);
  margin-block: .6rem .7rem;
}

/* --- Fotos: huecos honestos mientras no haya decisión (NORMAS § 4) --- */
.fotos {
  display: flex;
  gap: .6rem;
  margin-bottom: 1.8rem;
}
.foto-hueco {
  flex: 1 1 0;
  aspect-ratio: 4 / 3;
  min-width: 0;
  display: grid;
  place-items: center;
  background: var(--papel-hondo);
  border: 1px dashed var(--pelo-fuerte);
  color: var(--tenue);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* ==========================================================================
   7 · Movimiento reducido
   --------------------------------------------------------------------------
   Los actos dejan de ser túneles de scroll y se leen como secciones normales,
   con todo el texto a la vista. El mapa se queda en su último fotograma.
   🚨 `!important` porque el motor escribe la opacidad en el propio elemento, y
   aquí tiene que perder.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .acto { height: auto; }
  /* 🚨 Y FUERA EL MARGEN NEGATIVO DE LA LEY 7, que aquí no solapa una pantalla
     muerta: solapa los actos enteros.

     El margen existe porque una escena pegajosa deja una pantalla de nada al
     final de su sección. Con movimiento reducido no hay escenas pegajosas —los
     actos se aplanan a su altura de texto— pero la regla seguía puesta, porque
     el selector .anim .acto + .acto gana en especificidad al .acto de este
     bloque. Con secciones de seiscientos píxeles y un tirón de 844 hacia
     arriba, el texto del acto 3 salía impreso encima del del 2, y el del 4
     encima del 3.

     🚨 Estaba desde que se montó el acto 2 y no lo cogió nadie: las capturas de
     movimiento reducido solo miran el principio de la página, donde todavía no
     hay dos actos que solapar. Se vio mirando el acto 4 con movimiento
     reducido, que es el cuarto de la pila. */
  .anim .acto + .acto { margin-top: 0; }
  .escena {
    position: static;
    height: auto;
    display: block;
    padding-block: var(--aire);
    max-width: var(--medida);
    margin-inline: auto;
  }
  .escenario { position: absolute; height: 100svh; }

  .rotulos, .tramos { display: block; width: auto; text-align: left; }
  .rotulo, .tramo-ficha {
    opacity: 1 !important;
    margin-top: 2rem;
  }
  .portada, .titular-acto, .panel {
    opacity: 1 !important;
    transform: none !important;
    text-align: left;
    max-width: none;
  }
  .panel { max-height: none; overflow: visible; margin-top: 2.5rem; }
  .pista { display: none; }
  .ir-indice { position: static; text-align: left; margin-top: 2rem; }
}

/* --- Marcadores secundarios: las estaciones de paso --------------------------
   Más pequeños y más tenues que los tres hitos del viaje, porque son referencia
   y no destino. Solo aparecen cuando la cámara está lo bastante cerca. */
.m-menor circle { fill: var(--tenue); }
/* 🚨 Los menores tambien crecen en el mapa pequenio. Esta regla pisaba el
   font-size de arriba, asi que Shinjuku seguia a seis pixeles mientras
   Takaragawa ya era legible: media etiqueta bien y la otra no. */
.m-menor text {
  font-size: calc(7.5px + var(--mini, 0) * 8px);
  fill: var(--tenue);
  letter-spacing: .08em;
}
