/* ═══════════════════════════════════════════════════════════════════════
   Carta de cumpleaños para Rossina — 19 de agosto de 2026

   La página va casi toda de noche, y se abre una sola vez a la luz: en el
   triptico de fotos, sobre las nubes rosas. Arranca en el estadio, pasa por
   las razones, se abre en las fotos de ella, vuelve a la noche para la carta
   -- que se lee sobre una hoja de papel, no sobre la foto -- y cierra en el
   mismo estadio del principio con el 보라해.

   Cada sección se funde con la siguiente por arriba y por abajo, para que no
   haya cortes secos de un fondo a otro.

   Nada de esto necesita build. Es CSS a mano, y se abre igual desde el
   servidor que haciendo doble clic en index.html.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Papel ────────────────────────────────────────────────────────────
     El hanji es papel coreano de morera: cálido, pero tirando a rosa, no
     al beige. El beige-terracota es justo el fondo que sale por defecto en
     cualquier página "elegante"; este tiene el rosa de su propio mundo. */
  --hanji:        #FDF6F2;
  --hanji-hondo:  #F6E7E0;
  --hanji-linea:  #E8D2C8;

  /* ── Tinta ────────────────────────────────────────────────────────────
     Nunca negro puro: el texto es morado muy oscuro, para que ni el cuerpo
     de la carta se salga de la paleta. */
  --tinta:        #2B1B36;
  --tinta-suave:  #6E5A78;

  /* ── El morado ────────────────────────────────────────────────────────
     borahae es el morado de ARMY; bomb es el halo de la lámpara encendida. */
  --borahae:      #7B4EC4;
  --borahae-vivo: #9B6FE0;
  --bomb:         #C3A6F0;

  /* ── Gochujang ────────────────────────────────────────────────────────
     La pasta de guindilla coreana. Es el único acento cálido, y aparece
     poquísimo: los cuencos y poco más. */
  --gochu:        #D6413B;

  /* ── Noche ────────────────────────────────────────────────────────────
     El estadio con las luces apagadas. */
  --noche:        #150A21;
  --noche-alta:   #24123A;

  /* ── Tipografías ──────────────────────────────────────────────────────
     Black Han Sans es la letra gorda de los carteles de la calle coreana:
     la de los puestos de comida. Se usa solo para los titulares, y por eso
     puede permitirse ser tan bruta.
     Gowun Batang es la serif de lectura, la que sostiene las 965 palabras de
     la carta. Las dos escriben hangul y latín con la misma mano, así que
     "Rossina" y 로시나 no parecen de dos páginas distintas. */
  --display: 'Black Han Sans', system-ui, sans-serif;
  --serif:   'Gowun Batang', Georgia, serif;
  --sans:    'Gowun Dodum', system-ui, sans-serif;

  /* ── Ritmo ────────────────────────────────────────────────────────────
     Un solo escalón de aire vertical para todas las secciones, para que no
     haya dos paddings distintos peleándose. */
  --aire:    clamp(5rem, 14vh, 9rem);
  --margen:  clamp(1.5rem, 6vw, 3rem);

  /* La curva de todo lo que se mueve. Sale rápido y frena largo: es la que
     hace que algo parezca que "llega" en vez de que "aparece". */
  --curva:   cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  /* Noche, no papel. Cada sección pinta su propio fondo, así que el del body
     solo se ve por las rendijas de un píxel que deja el navegador al redondear
     alturas fraccionarias entre secciones. Siendo papel claro, esas rendijas
     salían como una raya luminosa cruzando la pantalla justo en cada frontera:
     medido, rgb(33,22,45) en una sola fila entre dos de noche puro. Es el
     mismo destello en tres costuras distintas, y no se arregla tocando ningún
     degradado, porque no lo causa ninguno. */
  background: var(--noche);
  color: var(--tinta);
  font-family: var(--serif);
  font-size: clamp(1.02rem, 0.95rem + 0.4vw, 1.18rem);
  line-height: 1.75;
  overflow-x: hidden;
}

/* El foco tiene que verse. Se navega con teclado más gente de la que parece. */
:focus-visible {
  outline: 3px solid var(--borahae);
  outline-offset: 4px;
  border-radius: 2px;
}

/* ═══ El reveal al bajar ══════════════════════════════════════════════════
   Todo lo que entra usa estas dos clases y nada más. guion.js pone .visible
   cuando el elemento asoma. Una sola vez: lo que ya se vio no se vuelve a
   esconder al subir. */
.aparece {
  opacity: 0;
  transform: translateY(1.75rem);
  transition: opacity 0.9s var(--curva), transform 0.9s var(--curva);
}
.aparece.visible {
  opacity: 1;
  transform: none;
}


/* ═══ 1. Portada ═════════════════════════════════════════════════════════ */

.portada {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--aire) var(--margen);
  overflow: hidden;
  color: var(--hanji);
  text-align: center;

  background:
    radial-gradient(120% 90% at 50% 6%, #3A1D5C 0%, transparent 58%),
    var(--noche);
}

/* La foto del concierto, abajo, como horizonte.

   Va en su propia capa y no como una capa más del `background` porque
   necesita máscara propia: puesta directamente, la foto empezaba de golpe y
   dejaba una raya horizontal nítida cruzando la portada, justo debajo de
   "feliz cumpleaños". El degradado del velo no la tapaba, porque el corte no
   es de brillo sino de textura.

   Tampoco se usa `cover`: con la portada tan alta habría que ampliar tanto
   que se saldrían de cuadro los de los extremos. Con `100% auto` la foto
   ocupa justo el ancho y se ancla abajo, que es donde tiene que estar. */
.portada::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;

  /* La caja tiene EXACTAMENTE la proporción de la foto (800x632, igual que la
     versión ancha), así que su alto sale del ancho de la pantalla y coincide
     al píxel con la imagen.

     Esto no es un adorno. Con una altura en porcentaje, la caja medía 586 px
     y la foto escalada solo 325: la máscara terminaba de abrirse mucho antes
     de donde empezaba la imagen, y la foto seguía apareciendo de golpe. La
     raya horizontal no se iba por más que se ajustara el degradado, porque el
     degradado no era el problema. */
  aspect-ratio: 800 / 632;
  background: url('fondo/estadio-800.webp') center / 100% 100% no-repeat;

  /* Se desvanece hacia arriba dentro de la propia foto -- y también en el
     último 4% de abajo.

     Ese 4% final no es estética: sin él quedaba una raya de UN píxel en el
     borde de la portada (rgb(33,21,45) entre filas de noche puro), que es la
     última fila de la imagen asomando por redondeo de subpíxel fuera del velo.
     Se ve como una costura fina cruzando la pantalla justo donde empieza la
     sección siguiente. */
  mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 96%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 96%, transparent 100%);
}

/* A partir de tablet entra la versión grande: la de móvil son 800 px de ancho
   y en un portátil se vería lavada.

   Y cambia el encaje. En una pantalla apaisada, mantener la proporción de la
   foto le daba 1.138 px de alto en un viewport de 900: la foto se comía la
   portada entera y el nombre acababa flotando sobre el escenario. Aquí se le
   fija la altura y se recorta con `cover`, que llena la caja exactamente
   -- y por eso la máscara sigue cuadrando, que es lo que se buscaba con la
   proporción en móvil. Se encuadra al centro para no cortarles la cabeza. */
@media (min-width: 48rem) {
  .portada::before {
    aspect-ratio: auto;
    height: 66%;
    background-image: url('fondo/estadio-1600.webp');
    background-size: cover;
    background-position: center 62%;
  }
}

/* El velo. Es lo que sostiene el nombre: sobre el foco blanco del escenario,
   un texto blanco sin velo desaparece. Casi opaco arriba, se abre en la franja
   del estadio, y VUELVE A CERRARSE en el borde de abajo.

   Ese cierre final es la transición con la sección siguiente. Antes el velo
   terminaba abierto al 0,22, así que la portada acababa de golpe con el
   estadio a plena luz y debajo empezaba el negro liso de las razones: un corte
   seco, sin nada que llevara de una a otra. Cerrando el velo al final, el
   estadio se apaga solo antes de llegar al borde y las dos secciones se tocan
   ya en el mismo color. */
.portada::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom,
    var(--noche) 0%,
    rgba(21, 10, 33, 0.92) 30%,
    rgba(21, 10, 33, 0.62) 52%,
    rgba(21, 10, 33, 0.28) 72%,
    rgba(21, 10, 33, 0.45) 88%,
    rgba(21, 10, 33, 0.88) 97%,
    var(--noche) 100%);
}

/* Las luces y el contenido, por encima de la foto y del velo. */
.portada > .mar { z-index: 2; }

.portada > .portada__fecha,
.portada > .portada__nombre,
.portada > .portada__felicita {
  position: relative;
  z-index: 3;
}

/* La línea que baja va aparte: ya es `absolute`, y meterla en la regla de
   arriba le ponía `relative` encima, con lo que perdía el centrado y se iba
   al borde derecho. Aquí solo necesita el z-index. */
.portada > .portada__bajar {
  z-index: 3;
}

.portada__fecha {
  margin: 0 0 clamp(2rem, 6vh, 3.5rem);
  font-family: var(--sans);
  font-size: 0.78rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--bomb);
  opacity: 0.85;
}

.portada__nombre {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.9rem, 2.5vh, 1.4rem);
}

.portada__hangul {
  font-family: var(--display);
  /* Enorme a propósito: su nombre en hangul es lo primero y lo más grande
     que hay en toda la página. Son solo tres sílabas, así que aguanta 26vw
     sin acercarse a los márgenes. */
  font-size: clamp(4.2rem, 26vw, 12rem);
  line-height: 0.86;
  letter-spacing: 0.02em;
  color: #FFFFFF;
  /* El halo es el de una lámpara encendida, no una sombra de texto. */
  text-shadow:
    0 0 28px rgba(155, 111, 224, 0.55),
    0 0 90px rgba(123, 78, 196, 0.4);
}

.portada__latino {
  font-family: var(--sans);
  font-size: clamp(0.72rem, 2.4vw, 0.95rem);
  letter-spacing: 0.52em;
  text-transform: uppercase;
  /* El tracking abre por la derecha; sin esto el bloque queda descentrado. */
  text-indent: 0.52em;
  color: var(--bomb);
}

.portada__felicita {
  margin: clamp(2.5rem, 8vh, 4rem) 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.portada__felicita-ko {
  font-family: var(--serif);
  font-size: clamp(1.35rem, 5vw, 2rem);
  color: var(--bomb);
}

.portada__felicita-es {
  font-family: var(--sans);
  font-size: 0.8rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(253, 246, 242, 0.78);
  text-indent: 0.28em;
}

/* La línea que baja sola. Es el único aviso de que la página sigue. */
.portada__bajar {
  position: absolute;
  bottom: clamp(2rem, 6vh, 3.5rem);
  left: 50%;
  transform: translateX(-50%);
  width: 1px;
  height: 4.5rem;
  overflow: hidden;
  background: rgba(195, 166, 240, 0.18);
}

.portada__bajar-linea {
  display: block;
  width: 100%;
  height: 45%;
  background: linear-gradient(to bottom, transparent, var(--bomb));
  animation: bajar 2.6s var(--curva) infinite;
}

@keyframes bajar {
  0%        { transform: translateY(-120%); }
  60%, 100% { transform: translateY(240%); }
}


/* ═══ El mar morado ══════════════════════════════════════════════════════
   Las luces las crea guion.js como hijos .luz. Flotan muy despacio; si se
   mueven rápido dejan de parecer un estadio y parecen burbujas. */
.mar {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.luz {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, var(--bomb) 0%, rgba(123, 78, 196, 0.35) 45%, transparent 70%);
  filter: blur(0.5px);
  will-change: transform, opacity;
  animation: flotar var(--dur, 9s) ease-in-out var(--retraso, 0s) infinite;
}

@keyframes flotar {
  0%, 100% { transform: translateY(0)      scale(1);    opacity: var(--op, 0.5); }
  50%      { transform: translateY(-22px)  scale(1.14); opacity: calc(var(--op, 0.5) * 1.5); }
}


/* ═══ Títulos de sección ═════════════════════════════════════════════════
   El hangul va gigantísimo y clarísimo, como una marca de agua; el español
   va encima, pequeño y legible. El coreano es la textura, no la etiqueta. */

.titulo {
  position: relative;
  margin: 0 0 clamp(3rem, 8vh, 4.5rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  text-align: center;
}

.titulo__ko {
  font-family: var(--display);
  font-size: clamp(3.5rem, 14vw, 7rem);
  line-height: 1;
  /* Marca de agua, pero visible. Con --hanji-hondo desaparecia entero en la
     seccion de la mesa, que tiene justo ese color de fondo: el titulo 한 상
     no se veia. --hanji-linea contrasta con los dos papeles. */
  color: var(--hanji-linea);
  user-select: none;
}

.titulo__es {
  /* Se monta sobre el hangul, sin empujarlo: por eso el margen negativo. */
  margin-top: clamp(-2.4rem, -6vw, -1.4rem);
  font-family: var(--sans);
  /* Subido desde 0,82rem: a 13 px, y con el tracking tan abierto, estos
     rótulos se leían con esfuerzo encima de una foto. */
  font-size: clamp(0.92rem, 2.8vw, 1.05rem);
  letter-spacing: 0.34em;
  text-transform: uppercase;
  text-indent: 0.34em;
  color: var(--borahae);
}


/* ═══ Texto encima de una foto ═══════════════════════════════════════════
   Un color solo es legible contra un fondo conocido, y una foto no lo es: la
   misma línea cruza zonas claras y oscuras. Los velos de cada sección hacen
   casi todo el trabajo, pero el borde de una nube clara o el foco de un
   escenario siguen pudiendo comerse una letra.

   La sombra es el seguro. Va en la dirección contraria al color del texto
   -- oscura bajo texto claro, clara bajo texto oscuro -- y es lo bastante
   difusa como para no verse: solo despega la letra de lo que tiene detrás. */

.galeria .titulo__es {
  text-shadow: 0 1px 10px rgba(253, 246, 242, 0.9), 0 0 3px rgba(253, 246, 242, 0.8);
}

.carta .titulo__es,
.portada__felicita-es,
.portada__fecha,
.portada__latino,
.cierre__romaja {
  text-shadow: 0 1px 12px rgba(21, 10, 33, 0.85);
}

.cierre__sentido,
.cierre__linea,
.cierre__firma,
.portada__felicita-ko {
  text-shadow: 0 1px 14px rgba(21, 10, 33, 0.8);
}


/* ═══ 2. Por qué tú ══════════════════════════════════════════════════════ */

/* Esta sección es de noche, no de papel.
   La foto que va detrás (el logo con las flores sobre el cielo estrellado) es
   oscura: metida como marca de agua tenue detrás de un papel claro no se
   vería, y aclararla la habría destrozado. Así que aquí manda la foto y el
   texto se pasa a claro. La carta larga sigue en papel, que es donde de verdad
   importa la comodidad de lectura. */
.razones {
  position: relative;
  padding: var(--aire) var(--margen);
  overflow: hidden;
  color: var(--hanji);

  /* El resplandor de arriba es la transición con la portada.

     Las dos secciones son de noche, así que no había ningún corte de color
     -- y por eso mismo tampoco había transición: se pasaba del estadio
     iluminado al negro liso de golpe, como si se apagara un interruptor.
     Este halo morado recoge la luz que dejaba el escenario y la apaga poco a
     poco, de modo que una sección parece continuar dentro de la otra. */
  background:
    radial-gradient(135% 42% at 50% 0%, rgba(123, 78, 196, 0.34) 0%, rgba(58, 29, 92, 0.14) 45%, transparent 78%),
    var(--noche);
}

/* El logo, detrás de las razones.

   Va con `cover` sobre una caja alta, no con la proporción de la foto. La foto
   es apaisada y esta sección es alta: respetando su proporción, el logo salía
   metido en una banda estrecha en medio y quedaba diminuto, con las flores
   irreconocibles. Con `cover` la imagen se amplía hasta llenar la caja, así
   que el logo crece y de paso la máscara sigue cuadrando -- que era lo único
   que la proporción estaba resolviendo. Lo que se recorta a los lados es
   cielo con estrellas, que no se echa de menos. */
.razones::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 0;
  height: 64%;
  background: url('fondo/logo-900.webp') center / cover no-repeat;
  mask-image: linear-gradient(to bottom, transparent 0%, #000 20%, #000 80%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 20%, #000 80%, transparent 100%);
}

@media (min-width: 48rem) {
  .razones::before {
    background-image: url('fondo/logo-1800.webp');
  }
}

/* El velo. Aquí encima van tres frases que hay que poder leer del tirón, así
   que pesa más que el de la portada. */
.razones::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom,
    var(--noche) 0%,
    rgba(21, 10, 33, 0.78) 22%,
    rgba(21, 10, 33, 0.72) 50%,
    rgba(21, 10, 33, 0.82) 78%,
    var(--noche) 100%);
}

.razones > .titulo,
.razones > .razones__lista {
  position: relative;
  z-index: 2;
  max-width: 52rem;
  margin-inline: auto;
}

/* Sobre la noche, la marca de agua del título no puede ser el color del papel:
   sería una mancha clara. Va en morado casi apagado. */
.razones .titulo__ko { color: rgba(195, 166, 240, 0.16); }
.razones .titulo__es { color: var(--bomb); }
.razones .razon::before { background: var(--bomb); }

.razones__lista {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: clamp(2.25rem, 6vh, 3.25rem);
}

.razon {
  position: relative;
  padding-left: clamp(1.75rem, 5vw, 2.75rem);
  font-size: clamp(1.15rem, 1rem + 1.1vw, 1.6rem);
  /* En regular, el trazo de Gowun Batang es tan fino que a este tamano las
     tres frases se veian lavadas y sin peso. Son el "por que": tienen que
     pesar. En la carta larga se queda en regular, que ahi es lo correcto. */
  font-weight: 700;
  line-height: 1.62;
  text-wrap: pretty;
}

/* Un corazón morado pequeño en vez de un número. Las tres razones no son
   una secuencia: no hay una primera ni una última, así que numerarlas
   diría algo que no es cierto. */
.razon::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 0.72rem;
  height: 0.72rem;
  background: var(--borahae);
  mask: url('corazon.svg') center / contain no-repeat;
  -webkit-mask: url('corazon.svg') center / contain no-repeat;
}


/* ═══ 3. Las fotos de ella ══════════════════════════════════════════════
   La única sección con color cálido de toda la página: las nubes rosas del
   fondo ARMY. Va entre dos secciones de noche a propósito, para que se abra
   como un claro y las fotos de ella no compitan con nada.

   Esa foto NO está teñida de morado como las otras: ya nace rosa y morada. */

.galeria {
  position: relative;
  /* Bastante más aire abajo que arriba: es el hueco donde queda a la vista el
     logo ARMY de las nubes antes de que empiece el fundido hacia la carta.
     Sin él, las fotos y el fundido se comían el logo entero y la nota cálida
     de la página pasaba sin que diera tiempo a verla. */
  padding: var(--aire) var(--margen) calc(var(--aire) * 2.9);
  overflow: hidden;
  isolation: isolate;
  color: var(--tinta);
}

.galeria[hidden] { display: none; }

.galeria__nubes {
  position: absolute;
  inset: -8% 0;          /* de sobra por arriba y por abajo, para el parallax */
  z-index: -2;
  /* El encuadre coloca el logo ARMY DEBAJO de las fotos, en el hueco que deja
     el padding de abajo: ni detrás del título (donde se estorbaba con 그대) ni
     detrás de las fotos (donde quedaba tapado). Ahí se ve entero, y solo
     después empieza el fundido hacia la carta.

     El tamaño es `auto 132%` y no `cover` a propósito. Con `cover`, la imagen
     acababa midiendo justo el alto del contenedor, y entonces
     `background-position` no tiene margen para mover nada en vertical: daba
     igual el valor que se le pusiera, el logo caía siempre en el mismo sitio
     -- detrás del vídeo. Dándole un 32% de alto de más, hay recorrido para
     colocarlo donde toca. */
  background: url('fondo/nubes-720.webp') center 4% / auto 132% no-repeat;

  /* La imagen se desvanece en sus propios bordes.

     No es lo mismo que el velo de `.galeria::before`, y hace falta además de
     él: midiendo los píxeles de la frontera se veía una raya de UN píxel de
     rgb(60,45,65) entre dos filas de noche puro. Era el borde de esta imagen
     asomando por redondeo de subpíxel, en la rendija que el velo no llegaba a
     tapar. Un degradado más suave no lo arreglaba, porque el degradado nunca
     fue el problema. */
  mask-image: linear-gradient(to bottom, transparent 0%, #000 10%, #000 90%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 10%, #000 90%, transparent 100%);
}

@media (min-width: 48rem) {
  .galeria__nubes {
    background-image: url('fondo/nubes-1440.webp');
    /* En apaisado cambia cuál de los dos lados manda. `auto 132%` deriva el
       ancho de la altura, y en una pantalla ancha se quedaba corto: las nubes
       salían como una columna centrada con dos franjas oscuras a los lados.
       Aquí manda el ancho, y la altura sobra de largo, que es justo lo que
       hace falta para poder colocar el logo. */
    background-size: 100% auto;
    /* Bajado desde el 41%: el símbolo del logo quedaba partido por el vídeo
       del centro. Aquí el conjunto entero (símbolo y palabra) cae por debajo
       de las tres fotos, sin que ninguna lo pise. */
    background-position: center 30%;
  }
}

/* La costura con las secciones de al lado.

   Arriba y abajo la sección se funde a `--noche`, que es el fondo de lo que
   viene antes y de lo que viene después. Es la frontera más brusca de la
   página: de la noche a unas nubes rosas.

   El fundido va en `vh`, NO en porcentaje de la sección. Con porcentajes, en
   una sección corta como esta el degradado se comprimía a unos 80 px y se veía
   una raya horizontal nítida en el borde; el mismo valor en una sección larga
   se estiraba de más. En vh mide siempre lo mismo, y es lo que se percibe. */
.galeria::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    linear-gradient(to bottom, var(--noche) 0%, rgba(21, 10, 33, 0.55) 34%, transparent 100%)
      top / 100% 38vh no-repeat,
    linear-gradient(to top,    var(--noche) 0%, rgba(21, 10, 33, 0.55) 34%, transparent 100%)
      bottom / 100% 38vh no-repeat;
}

/* Sobre las nubes, el título en color papel desaparecía del todo, y el morado
   claro tampoco aguantaba: el fondo aquí es claro, no oscuro como en el resto
   de secciones. Los dos van en morado oscuro y con bastante más cuerpo.

   El hangul llega hasta 0,26 de opacidad y no menos, porque justo detrás está
   el logo ARMY de las nubes: con la marca de agua muy tenue, 그대 y el logo se
   mezclaban y no se leía ninguno de los dos. */
.galeria .titulo__ko { color: rgba(52, 26, 78, 0.26); }
.galeria .titulo__es { color: #3D1F5C; }

.galeria > .titulo,
.galeria > .triptico {
  position: relative;
  z-index: 1;
}


/* ── El tríptico ──────────────────────────────────────────────────────────
   Las tres piezas a la vez, una al lado de otra, con el vídeo en medio.

   Empezó siendo un carrusel con flechas y puntos. Con solo tres piezas, un
   carrusel esconde dos tercios de lo que hay que enseñar y obliga a tocar algo
   para verlo: aquí se ven las tres de un vistazo y el vídeo corre solo. */
.triptico {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* Separación amplia entre las tres. Antes iban casi pegadas y las de los
     lados parecían un accidente del recorte en vez de tres piezas puestas a
     propósito. */
  gap: clamp(1rem, 4vw, 2.75rem);
  align-items: center;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  /* Más ancho que las 52rem de antes: las fotos son lo que hay que mirar en
     esta sección, y a lo ancho de la pantalla se ven bastante mejor. */
  max-width: 64rem;
}

.pieza {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: clamp(0.5rem, 2vw, 0.9rem);
  background: rgba(253, 246, 242, 0.4);
  box-shadow:
    0 1px 2px rgba(43, 27, 54, 0.2),
    0 18px 40px -20px rgba(43, 27, 54, 0.55);
}

/* La del medio es el vídeo, y en un tríptico el centro es el eje: va algo más
   grande y por delante de las otras dos. */
.pieza--eje {
  transform: scale(1.09);
  z-index: 1;
  box-shadow:
    0 1px 2px rgba(43, 27, 54, 0.24),
    0 24px 50px -20px rgba(43, 27, 54, 0.65);
}

.pieza__medio {
  width: 100%;
  height: 100%;
  display: block;
  /* El vídeo es 9:16 y las fotos ya vienen recortadas a 4:5, así que esto solo
     recorta el vídeo. */
  object-fit: cover;
  object-position: center;
}

.pieza__pie {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 1.8rem 0.5rem 0.55rem;
  font-family: var(--sans);
  font-size: 0.7rem;
  color: #FFFFFF;
  background: linear-gradient(to top, rgba(21, 10, 33, 0.85), transparent);
  text-align: center;
}



/* ═══ 4. La carta ════════════════════════════════════════════════════════ */

.carta {
  position: relative;
  padding: var(--aire) var(--margen) calc(var(--aire) * 1.2);
  overflow: hidden;
  isolation: isolate;
  background: var(--noche);
}

/* Los siete sobre el cielo estrellado, de cabecera de la sección.

   Ocupa una pantalla y se funde hacia abajo; NO cubre la sección entera. Esta
   sección mide unos 5.000 px de alto (son 965 palabras), y estirando la foto a
   todo eso `cover` la ampliaba tanto que solo se veía una franja de cielo: los
   siete están en la parte baja del original y quedaban fuera de cuadro. Se
   pagaba el peso de una foto para no verla.

   Anclada abajo (`center bottom`) para que se les vea a ellos, que es el
   motivo de la foto.

   El original mide 415x739: es pequeño y al ampliarlo se ablanda. Se sostiene
   porque es casi todo negro; si aparece una versión más grande, cambiarla. */
.carta__cielo {
  position: absolute;
  top: -6%;
  left: 0;
  right: 0;
  height: 106svh;
  z-index: -2;
  background: url('fondo/siete-830.webp') center bottom / cover no-repeat;
  mask-image: linear-gradient(to bottom, #000 0%, #000 52%, transparent 96%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 52%, transparent 96%);
}

@media (min-width: 48rem) {
  .carta__cielo {
    background-image: url('fondo/siete-1400.webp');
    /* En apaisado la foto se amplía mucho más y solo cabe una franja de su
       altura. Anclada al borde de abajo, esa franja les cortaba por la cintura
       y se veían solo piernas y zapatillas. Al 78% entran las caras. */
    background-position: center 78%;
  }
}

.carta::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Velo flojo a propósito: la carta se lee sobre la hoja de papel, no sobre la
     foto, así que aquí solo hace falta lo justo para coser el borde de arriba
     con la sección de las nubes y para que la foto no le robe la vista al
     texto. Abajo no hace falta nada: a esa altura la foto ya se ha desvanecido
     con su propia máscara y solo queda noche. */
  background:
    linear-gradient(to bottom, var(--noche) 0%, rgba(21, 10, 33, 0.5) 40%, rgba(21, 10, 33, 0.3) 100%)
      top / 100% 46vh no-repeat,
    linear-gradient(rgba(21, 10, 33, 0.3), rgba(21, 10, 33, 0.3));
}

/* Sobre la noche, la marca de agua del título va en morado apagado. */
.carta .titulo__ko { color: rgba(195, 166, 240, 0.16); }
.carta .titulo__es { color: var(--bomb); }

.carta > .titulo { position: relative; }

/* La hoja de papel. Es la pieza que hace que esta sección funcione: el fondo
   es una foto oscura, pero la carta se lee sobre papel, en tinta oscura y al
   ancho de siempre. 965 palabras en texto claro sobre una foto cansan de
   verdad, y esta es la sección que hay que poder leer del tirón.

   La sombra es lo que la separa del cielo: sin ella el papel parece un
   rectángulo pegado y no una hoja apoyada encima. */
.carta__hoja {
  /* Red de seguridad: la carta se ve SIEMPRE, pase lo que pase con el reveal.
     Ya se quedó invisible una vez porque el observador dejó de notificar un
     elemento de 5.600 px, y esto es lo único de la página que no puede fallar.
     Si alguien vuelve a meter `.carta__hoja` en la lista de reveal, estas dos
     líneas lo neutralizan. */
  opacity: 1 !important;
  transform: none !important;

  position: relative;
  max-width: 34rem;      /* ~62 caracteres por línea: el ancho que se lee sin cansarse. */
  margin-inline: auto;
  padding: clamp(2.25rem, 8vw, 4rem) clamp(1.5rem, 6vw, 3.25rem);
  background: var(--hanji);
  color: var(--tinta);
  border-radius: 3px;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.35),
    0 34px 80px -34px rgba(0, 0, 0, 0.8);
}

.carta__hoja p {
  margin: 0 0 1.7em;
  line-height: 1.9;
  text-wrap: pretty;
  hyphens: auto;
}

/* Las frases que Cristian dejó solas en su propio párrafo. Son el latido del
   texto: se sacan del cuerpo, se centran y se ponen en morado. */
.carta__golpe {
  margin: 2.6em 0 2.6em !important;
  font-size: clamp(1.3rem, 1.1rem + 1.2vw, 1.85rem);
  line-height: 1.45;
  text-align: center;
  color: var(--borahae);
  text-wrap: balance;
}

.carta__golpe::after {
  content: '';
  display: block;
  width: 2.5rem;
  height: 1px;
  margin: 1.6rem auto 0;
  background: var(--hanji-linea);
}

.carta__quiero {
  margin: 2.2em 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.85em;
  font-size: clamp(1.05rem, 1rem + 0.5vw, 1.28rem);
  text-align: center;
}

.carta__quiero li {
  color: var(--tinta);
}


/* ═══ 6. El cierre ═══════════════════════════════════════════════════════ */

.cierre {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--aire) var(--margen);
  overflow: hidden;
  text-align: center;
  color: var(--hanji);
  background:
    radial-gradient(100% 70% at 50% 100%, #4A2570 0%, transparent 65%),
    radial-gradient(120% 80% at 50% -10%, #32195180 0%, transparent 60%),
    var(--noche);
}

/* El mismo estadio de la portada, otra vez abajo: la carta abre y cierra en el
   mismo sitio. Aquí se le da algo menos de altura y se hunde un poco más en el
   velo, porque lo que manda en esta pantalla es el 보라해. */
.cierre::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  aspect-ratio: 800 / 632;
  background: url('fondo/estadio-800.webp') center / 100% 100% no-repeat;
  mask-image: linear-gradient(to bottom, transparent 0%, #000 40%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 40%);
  opacity: 0.75;
}

.cierre::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom,
    var(--noche) 0%,
    rgba(21, 10, 33, 0.9) 30%,
    rgba(21, 10, 33, 0.68) 58%,
    rgba(21, 10, 33, 0.45) 82%,
    rgba(21, 10, 33, 0.35) 100%);
}

@media (min-width: 48rem) {
  .cierre::before {
    aspect-ratio: auto;
    height: 62%;
    background-image: url('fondo/estadio-1600.webp');
    background-size: cover;
    background-position: center 62%;
  }
}

/* Las luces y el contenido, por encima de la foto y del velo. */
.cierre > .mar { z-index: 2; }

.cierre > .cierre__corazon,
.cierre > .cierre__ko,
.cierre > .cierre__glosa,
.cierre > .cierre__linea,
.cierre > .cierre__firma {
  position: relative;
  z-index: 3;
}

/* En el cierre las luces están más densas y más brillantes: es el estadio
   entero encendido, no las primeras lámparas. */
.mar--lleno .luz {
  filter: blur(0.5px) saturate(1.15);
}

.cierre__corazon {
  width: clamp(3.5rem, 12vw, 5rem);
  height: clamp(3.5rem, 12vw, 5rem);
  margin-bottom: clamp(1.75rem, 5vh, 2.75rem);
  /* Como máscara y no como imagen de fondo: así el corazón toma el color de
     aquí y puede ir más brillante que el del SVG, que está pensado para el
     favicon sobre fondo claro. Sobre la noche, aquel se apagaba. */
  background-color: var(--borahae-vivo);
  mask: url('corazon.svg') center / contain no-repeat;
  -webkit-mask: url('corazon.svg') center / contain no-repeat;
  filter: drop-shadow(0 0 26px rgba(155, 111, 224, 0.9));
  animation: latir 2.4s ease-in-out infinite;
}

/* Un latido de corazón de verdad son dos golpes seguidos y una pausa larga,
   no un pulso regular. */
@keyframes latir {
  0%, 100%  { transform: scale(1); }
  14%       { transform: scale(1.16); }
  28%       { transform: scale(1); }
  42%       { transform: scale(1.1); }
  56%       { transform: scale(1); }
}

.cierre__ko {
  margin: 0;
  font-family: var(--display);
  font-size: clamp(3.5rem, 19vw, 10rem);
  line-height: 0.9;
  color: #FFFFFF;
  text-shadow:
    0 0 30px rgba(155, 111, 224, 0.6),
    0 0 100px rgba(123, 78, 196, 0.45);
}

.cierre__glosa {
  margin: 1.5rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.cierre__romaja {
  font-family: var(--sans);
  font-size: 0.78rem;
  letter-spacing: 0.44em;
  text-transform: uppercase;
  text-indent: 0.44em;
  color: var(--bomb);
}

.cierre__sentido {
  font-family: var(--serif);
  font-size: clamp(1.05rem, 3.5vw, 1.35rem);
  color: rgba(253, 246, 242, 0.88);
}

.cierre__linea {
  margin: clamp(3rem, 9vh, 4.5rem) 0 0;
  max-width: 26rem;
  font-size: clamp(1rem, 3vw, 1.15rem);
  line-height: 1.7;
  color: rgba(253, 246, 242, 0.82);
  text-wrap: balance;
}

.cierre__firma {
  margin: 1.5rem 0 0;
  font-size: clamp(1.15rem, 4vw, 1.5rem);
  color: var(--bomb);
  text-wrap: balance;
}


/* ═══ El paso de una sección a otra ══════════════════════════════════════

   Dos cosas distintas, y conviene no confundirlas:

   1. LA COSTURA. Cada sección se funde por arriba y por abajo con el color de
      su vecina, con los degradados que están más arriba en este fichero
      (`.galeria::before`, `.carta::before`, los velos de portada y cierre).
      Eso es CSS de toda la vida y funciona en cualquier navegador. Es lo que
      quita los cortes secos entre un fondo y el siguiente.

   2. LA PROFUNDIDAD, aquí abajo. Los fondos de foto se mueven algo más
      despacio que el texto conforme ella baja, así que las secciones parecen
      capas a distintas distancias en vez de bloques apilados. Es lo que hace
      que el paso de una a otra se sienta como un viaje continuo.

   La profundidad va detrás de un @supports a propósito: las animaciones ligadas
   al scroll son recientes y Safari tardó en llevarlas. Donde no existan, no
   pasa nada -- los fondos se quedan quietos y la costura sigue estando. Es una
   mejora que suma, nunca algo de lo que la página dependa. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    .galeria__nubes,
    .carta__cielo,
    .razones::before {
      animation: deriva linear both;
      /* La animación se liga a la vista del elemento: avanza según cuánto de
         la sección se ha cruzado, no según el scroll global. */
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
      will-change: transform;
    }

    /* El recorrido es corto -- un 7% -- porque el parallax se nota mucho antes
       de lo que parece, y pasado ese punto marea en vez de dar profundidad. */
    @keyframes deriva {
      from { transform: translateY(-7%); }
      to   { transform: translateY(7%); }
    }

    /* El estadio de la portada y del cierre se queda quieto: está anclado al
       borde de abajo haciendo de horizonte, y un horizonte que se mueve deja
       de ser un horizonte. */
  }
}


/* ═══ Pantallas estrechas ════════════════════════════════════════════════ */

@media (max-width: 30rem) {
  /* En el móvil el título en hangul se comía el ancho y el rótulo en
     español se le montaba encima en dos líneas. */
  .titulo__es {
    margin-top: -1.2rem;
    letter-spacing: 0.22em;
    text-indent: 0.22em;
  }

}


/* ═══ Si el sistema pide menos movimiento, se apaga todo ═════════════════
   No es un detalle de accesibilidad de trámite: hay gente a la que el
   movimiento le provoca mareo de verdad. La página entera funciona igual
   quieta, solo que se ve todo desde el principio. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .aparece {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .luz,
  .portada__bajar-linea,
  .cierre__corazon,
  .galeria__nubes,
  .carta__cielo {
    animation: none;
  }

  /* El vídeo del tríptico no se para: es el contenido, no un adorno -- y sin
     él, esa pieza sería un rectángulo congelado en medio de las fotos. Lo que
     se quita aquí es el movimiento decorativo, no el que lleva significado. */
}
