/* ══════════════════════════════════════════════════════════════════════
   12 · HACES DE LUZ
   ══════════════════════════════════════════════════════════════════════

   QUÉ ES ESTE ARCHIVO
   Los rayos de luz que entran en diagonal desde arriba, como el sol
   colándose entre las nubes de una tarde. Bañan el relicario, las
   enredaderas y las molduras del marco.

   EL TRUCO: "screen" EN VEZ DE PINTAR ENCIMA
   Una capa clara puesta encima de la página la ensucia: apaga los negros
   y todo queda lechoso. Con mix-blend-mode: screen la capa SUMA luz en
   lugar de taparla, que es exactamente lo que hace un rayo de sol real.
   Los negros siguen siendo negros y solo se encienden las zonas que ya
   tenían algo de brillo: el oro de las molduras, los pétalos, las gemas.

   POR QUÉ VAN TAN ARRIBA (z-index 70)
   Porque tienen que bañar TAMBIÉN el marco victoriano y las enredaderas,
   que viven en 60. Si fueran por debajo, la luz pasaría por detrás de las
   rosas y el efecto se perdería justo donde más se luce.

   ÍNDICE
     1. La capa que los contiene
     2. Cada haz
     3. Accesibilidad
   ══════════════════════════════════════════════════════════════════════ */


/* ─── 0. PENUMBRA DE PROFUNDIDAD ───────────────────────────────────────
   La luz reina arriba, sobre el relicario; a medida que se baja, la
   página se hunde en penumbra, como el agua del océano: cuanto más hondo,
   más oscuro. Este velo es lo que oscurece —pero NUNCA llega al negro,
   solo se apaga—.

   Cubre el documento entero (position: absolute; inset: 0, igual que el
   marco victoriano) y su color va de transparente arriba a un casi-negro
   CÁLIDO abajo. Va por encima del marco y las enredaderas (z-index 65)
   para hundirlas también en la sombra, pero por debajo de los haces de
   luz (70): así la luz que todavía llega arriba se dibuja por encima del
   velo, y abajo, donde la luz ya no alcanza, manda la penumbra.

   El tope de oscuridad es moderado a propósito (elegancia por encima del
   efecto): el formulario y el pie quedan más tenues, nunca ilegibles. */
#penumbra-profunda {
  position: absolute;
  inset: 0;
  z-index: 65;
  pointer-events: none;
  /* Transparente en la portada; la penumbra entra recién más abajo y
     crece con la profundidad. El color es un negro cálido (tira a
     borgoña muy oscuro), no un gris neutro, para no enfriar la paleta. */
  /* Cuanto más hondo, más oscuro —pero NUNCA negro total—. La franja de
     abajo se profundizó a pedido: el pie y las últimas secciones quedan
     bien en sombra, y son la LUZ DE LAS VELAS (candelabros + cirios de
     piso, que van por encima de este velo, z66) la que abre los claros
     donde hay texto y botones. Tope ~.62 para que se lea sin esfuerzo entre
     charco y charco de luz. */
  /* DOS capas: primero el TINTE DE LA HORA y debajo la penumbra de siempre.

     El tinte es lo que hace que la SALA entera cambie de temperatura, no
     solo la ventana. Este velo cubre el documento completo, así que teñirlo
     a él es la forma más barata y más envolvente de que la escena sea de
     tarde dorada o de madrugada azul: una sola capa que ya existía, sin
     añadir ninguna nueva.

     Lo escribe codigo/22-luz-de-la-hora.js una vez cada diez minutos. El
     valor de reserva es transparente, así que sin ese módulo se ve como
     siempre. */
  background:
    linear-gradient(var(--tinte-del-velo, transparent), var(--tinte-del-velo, transparent)),
    linear-gradient(
      to bottom,
      rgba(8, 4, 4, 0)   0,
      rgba(8, 4, 4, 0)   22vh,
      rgba(7, 4, 4, .26) 90vh,
      rgba(5, 3, 3, .50) 170vh,
      rgba(4, 2, 2, .62) 100%);
}

/* Con menos movimiento el velo se mantiene (es estático, no molesta), pero
   se atenúa un poco para no oscurecer de más a quien ya pidió sobriedad. */
@media (prefers-reduced-motion: reduce) {
  #penumbra-profunda { opacity: .7; }
}


/* ─── 0B. CANDELABROS DE LA PROFUNDIDAD ────────────────────────────────
   Cuando la luz del día ya no llega, la opulencia queda iluminada por
   CANDELABROS de pared: apliques de latón que salen de los laterales
   sosteniendo velas, como en una mansión antigua de noche.
   codigo/19-velas.js los dibuja, los ubica y los anima.

   ⚠️ EL ORDEN DE LAS CAPAS ES LO QUE HACE QUE FUNCIONEN.
   Antes la pieza iba en z-index 62 y su resplandor en 58, los dos POR
   DEBAJO del velo de penumbra (#penumbra-profunda, z 65). Resultado: el
   velo —que en el fondo llega a ~40 % de negro— le comía la luz, y el mapa
   se veía casi negro por más que se subiera el brillo. Además, al estar en
   62 la pieza quedaba ENCIMA de las enredaderas (que viven en ~60), como
   pegada sobre las rosas.

   Ahora cada capa va donde corresponde:

     · #apliques (z-index 57) — la PIEZA de latón, por DEBAJO del marco
       (60). Las enredaderas y las molduras le pasan por delante, así el
       candelabro queda montado en la pared y las rosas trepan sobre él.
       Al estar bajo el velo, el metal se ensombrece con la profundidad,
       que es lo correcto.

     · #luz-de-velas (z-index 66) — el RESPLANDOR, por ENCIMA del velo (65)
       y por debajo de los haces (70). Su luz ya no se cancela: baña el
       mapa, el texto y las rosas.

   Es también lo físicamente correcto: el objeto vive dentro de la escena y
   se oscurece con ella, pero la luz que emite ilumina la habitación. */

/* ─── EL LIENZO DE LUZ ─────────────────────────────────────────────────
   Un solo <canvas> que dibuja TODOS los resplandores de las velas, en vez
   de los ~104 divs con mezcla que había antes. Lo crea y lo pinta
   codigo/23-lienzo-de-luz.js.

   POR QUÉ NO LLEVA `mix-blend-mode`
   Porque no lo necesita: dentro del canvas la luz se suma con
   `globalCompositeOperation = 'lighter'`, que es la misma matemática que
   hacía el `screen` —y lo que hace la luz de verdad— pero SIN costarle una
   capa al compositor. Ese era el problema: diez capas de mezcla apiladas
   obligaban al navegador a leer de vuelta el fondo y le impedían fusionar
   nada, y entre "Layerize" y "Commit" se llevaban la mitad del tiempo.

   `position: fixed` porque el canvas cubre solo la ventana, no el
   documento entero; el JS le resta el scroll a cada luz. Así el lienzo
   mide 1920×1080 en vez de 1920×5592, que es una quinta parte de píxeles.

   z-index 66: el mismo que tenía #luz-de-velas, para conservar el orden de
   la escena (por encima del velo de penumbra, por debajo de los haces). */
#lienzo-de-luz {
  position: fixed;
  inset: 0;
  z-index: 66;
  pointer-events: none;
}

/* La PIEZA de latón, integrada en la pared (debajo de rosas y molduras). */
#apliques {
  position: absolute;
  inset: 0;
  z-index: 57;
  pointer-events: none;
  overflow: hidden;
}
.aplique {
  position: absolute;
  /* Cada candelabro se ubica y se refleja (lado derecho) desde el JS.
     ⚠️ SIN filtro CSS acá (nada de drop-shadow): la llama titila DENTRO de
     este contenedor, y un filtro obligaría a re-rasterizar todo el
     candelabro en cada cuadro —caro, sobre todo sin placa de video—. */
}
/* La llama titila: el JS le cambia opacidad y un leve escalado. El origen
   abajo hace que crezca desde la mecha, como una llama real. */
.llama {
  transform-box: fill-box;
  transform-origin: 50% 90%;
  /* ⚡ ACÁ TAMPOCO VA `will-change`, POR LA MISMA RAZÓN QUE EN .vela.
     `will-change` es una PISTA para que el navegador reserve una capa de
     GPU, no una optimización mágica: la documentación de Chrome dice
     expresamente que no se ponga en muchos elementos, porque cada capa hay
     que recorrerla y administrarla en CADA cuadro. Eso es la fase
     "Layerize", que llegó a comerse el 31 % del perfil.

     Al medir la página viva aparecieron 179 elementos promovidos entre
     velas, llamas, pétalos, motas, haces y plantas. Se podaron casi todos.
     Las llamas, además, están dentro de un contenedor que se mezcla con el
     fondo, así que su capa nunca pudo aprovecharse. Se ven exactamente
     igual sin ella. */
}

/* El RESPLANDOR de cada llama, por encima del velo de penumbra.
   ⚠️ ACÁ NO VA `mix-blend-mode`. Esta capa es `absolute; inset: 0`, o sea
   que mide TODO el documento (en una pantalla ancha, más de diez millones
   de píxeles). Poner la mezcla acá obligaba al navegador a leer, mezclar y
   reescribir esa superficie entera CADA vez que una vela titilaba: en un
   perfil real, "Commit" (composición) se llevaba el 32 % del tiempo.
   La mezcla ahora va en cada .vela (unos cientos de píxeles cada una), que
   da el mismo resultado —cada luz suma sobre lo que tiene debajo— pero
   sobre un área ínfima en comparación. El área de esta capa se acota,
   además, desde codigo/19-velas.js. */
#luz-de-velas {
  position: absolute;
  inset: 0;
  z-index: 66;
  pointer-events: none;
  overflow: hidden;
}

/* Cada vela emite DOS resplandores superpuestos (los crea el JS):
     · .vela--nucleo  → chico y brillante, el corazón de la llama.
     · .vela--derrame → ancho y suave, el que de verdad ilumina la sección.
   Separarlos permite tener un centro nítido y una caída larga sin recurrir
   a filter: blur (que sin placa de video es carísimo). */
/* LA MEZCLA VIVE ACÁ: una capa por PIEZA (candelabro o cúmulo de cirios).
   Se midieron los dos extremos y los dos eran peores:
     · mezcla en la capa que cubre todo el documento → "Commit" 25,6 %
       (millones de píxeles a releer y remezclar en cada titileo).
     · mezcla en cada .vela → el navegador arma una capa POR ELEMENTO, y son
       52: "Layerize" saltó de 5,8 % a 22,3 % y "Pre-paint" de 4,1 % a 18,1 %.
   Con una capa por pieza son 8, cada una del tamaño de su candelabro más el
   margen de su derrame. El resultado en pantalla es el mismo: cada luz sigue
   sumando claridad sobre lo que tiene debajo.
   El JS (codigo/19-velas.js) le da posición y tamaño a cada uno. */
.luz-de-pieza {
  position: absolute;
  pointer-events: none;
  mix-blend-mode: screen;

  /* ⛔ SIN `content-visibility`, aunque parezca el lugar perfecto.
     Estas son las capas más caras de la web —`mix-blend-mode` obliga al
     compositor a leer de vuelta el fondo y le impide fusionar nada de lo
     que hay debajo—, y saltear las que no se ven parecía gratis.

     Pero `content-visibility` recorta al borde de la caja, y en este
     proyecto ya rompió el dibujo tres veces (ver .marco__ramillete y
     .marco__planta en estilos/02-marco-victoriano.css). No se arriesga otra
     vez con la luz de las velas.

     El costo se bajó por el camino seguro: ajustando la caja de mezcla al
     resplandor real en vez de al candelabro entero. Cuatro de estas cajas
     tenían el 87 % de su área vacía y el compositor la leía igual. Ver
     acomodarTodo() en codigo/19-velas.js: la caja es ahora la unión de los
     centros de llama ± el radio máximo del derrame, así que por definición
     no puede recortar la luz. */
}

.vela {
  position: absolute;
  border-radius: 50%;
  /* ⚡ SIN `will-change`, Y ES DELIBERADO.
     Cada .vela vive DENTRO de un .luz-de-pieza, que se mezcla con el fondo
     (mix-blend-mode: screen). Un elemento que se mezcla NO PUEDE componerse
     por separado: el navegador necesita el fondo para calcularlo, así que
     la capa que se le reservaba había que volver a fundirla igual. Eran 52
     capas de puro trabajo perdido. Ver la nota completa en .llama. */
  opacity: 0;              /* el JS le da su valor; sin JS, apagado */
}

.vela--nucleo {
  background: radial-gradient(circle,
    rgba(255, 226, 160, .95)  0%,
    rgba(255, 190, 105, .55) 18%,
    rgba(232, 150, 70,  .22) 42%,
    transparent 70%);
}

.vela--derrame {
  background: radial-gradient(circle,
    rgba(255, 198, 120, .40)  0%,
    rgba(236, 160, 82,  .26) 22%,
    rgba(208, 130, 60,  .15) 42%,
    rgba(170, 100, 46,  .07) 62%,
    transparent 80%);
}

/* Cuando un derrame queda MUY cerca de una caja de texto, el JS lo saca del
   contenedor de mezcla de su pieza y lo manda a #apliques (bajo el velo de
   penumbra), para que no encandile la lectura. Ahí ya no le llega el screen
   del contenedor —queda como un rescoldo DETRÁS de la caja, no como un
   lavado encima—; esta regla lo deja explícito por las dudas. */
.vela--detras {
  mix-blend-mode: normal;
}

@media (prefers-reduced-motion: reduce) {
  /* Sin titileo: velas encendidas y quietas (nunca apagadas: son la luz
     de la profundidad y sin ellas el fondo queda negro).
     ⚠️ El derrame NO se fuerza con !important: su opacidad la fija el JS en
     acomodarTodo() ya rebajada según lo cerca que esté de la caja de texto
     (ver 19-velas.js), y un !important acá le ganaría y volvería a lavar la
     lectura. El núcleo y la llama sí quedan clavados: no se atenúan. */
  .vela--nucleo  { opacity: .85 !important; }
  .llama { opacity: 1 !important; transform: none !important; }
}

/* (Acá había una regla que le quitaba el will-change a .vela y .llama solo
   en media y baja. Ya no hace falta: se lo quitamos a TODOS los niveles en
   sus propias reglas, porque medir la página mostró que esas capas nunca
   se aprovechaban —las velas se mezclan con el fondo, y eso impide
   componerlas por separado—.) */


/* ─── 1. LA CAPA ───────────────────────────────────────────────────────
   Ocupa exactamente la ventana y recorta lo que se sale (overflow:
   hidden). Los haces sí son más largos que ella y nacen fuera de la
   vista: al quedar recortados por la capa, no se les ve ni el principio
   ni el final, que es lo que los hace leer como rayos y no como barras.

   ⚠️ La capa NO puede ser más ancha que la ventana. Al estar en position:
   fixed, el overflow-x: hidden del body no la recorta —los elementos
   fijos se posicionan contra la ventana, no contra el body— y aparecía
   una barra de desplazamiento horizontal en el celular.
   ---------------------------------------------------------------------- */
#haces-de-luz {
  position: fixed;
  inset: 0;
  z-index: 70;
  pointer-events: none;
  mix-blend-mode: screen;
  overflow: hidden;

  /* ⚠️ LA LUZ BAÑA EL AMBIENTE, PERO NO EL MARCO VICTORIANO.
     El relicario, las ramas y las rosas SÍ tienen que encenderse con la
     luz; el marco dorado del borde NO —ya es todo oro, y sumarle luz lo
     vuelve un exceso—. Pero como las rosas trepan POR ENCIMA del marco,
     los dos comparten capa y no se pueden separar por orden de dibujo.

     La salida es esta máscara: la luz se muestra plena en el interior y
     se desvanece sobre la banda del borde (donde vive el marco). Son dos
     degradados —uno horizontal, otro vertical— y se combinan con
     "intersect", así la luz solo aparece donde AMBOS ejes están dentro:
     el centro. En los bordes y las esquinas se apaga sola.

     La banda es algo más ancha que el marco (1,4×) para que el marco
     quede bien dentro de la zona apagada y la transición no se corte
     justo en su filo. */
  --banda-de-luz: calc(var(--marco-grosor) * 1.4);
  -webkit-mask:
    linear-gradient(to right,  transparent 0, #000 var(--banda-de-luz),
                    #000 calc(100% - var(--banda-de-luz)), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 var(--banda-de-luz),
                    #000 calc(100% - var(--banda-de-luz)), transparent 100%);
  -webkit-mask-composite: source-in;
          mask:
    linear-gradient(to right,  transparent 0, #000 var(--banda-de-luz),
                    #000 calc(100% - var(--banda-de-luz)), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 var(--banda-de-luz),
                    #000 calc(100% - var(--banda-de-luz)), transparent 100%);
          mask-composite: intersect;
}


/* ─── 2. CADA HAZ ──────────────────────────────────────────────────────
   Una banda vertical muy alargada, girada en diagonal. El degradado la
   hace nacer de la nada, alcanzar su máximo hacia el primer tercio y
   apagarse abajo: así el rayo tiene dirección, no es una franja pareja.

   Los degradados laterales (los dos ::before/::after no hacen falta:
   basta con que el propio fondo sea un degradado horizontal difuso, que
   es lo que le da el borde suave de un haz de polvo en suspensión).

   El JS (codigo/14-haces-de-luz.js) les cambia despacio el ancho, la
   opacidad y la posición. Acá solo se define su forma en reposo.
   ---------------------------------------------------------------------- */
.haz {
  position: absolute;
  /* Nace bien arriba y muere bien abajo, fuera de la capa: así la capa lo
     recorta y el rayo no tiene extremos visibles. */
  top: -45%;
  height: 190%;
  width: 12vw;

  /* ⚡ RENDIMIENTO: antes el haz era una banda recta + filter: blur(26px)
     para suavizar los bordes. Ese blur enorme, en 5 bandas que se animan,
     se recalcula en CADA cuadro y sin placa de video lo hace la CPU: era
     uno de los mayores costos de la web.

     Ahora el borde suave viene del PROPIO degradado —una elipse radial que
     nace clara arriba y se desvanece a la nada— sin ningún filtro. Se ve
     igual (un rayo de polvo en suspensión) y no cuesta prácticamente nada. */
  /* ⚠️ ACÁ NO VA `var()` DENTRO DEL DEGRADADO, aunque el color cambie con
     la hora del día. Se probó y costó caro: `14-haces-de-luz.js` escribe
     --luz-intensidad en estas capas cada 65 ms, y escribir una propiedad
     personalizada invalida el estilo de TODO el subárbol. Con `var()` en el
     fondo, cada una de esas escrituras obligaba a volver a resolver los
     degradados de los 5 haces y las 32 motas: "Recalculate style" saltó del
     13 % al 21 % del perfil.

     La luz por hora se aplica igual, pero al revés: codigo/22-luz-de-la-hora.js
     escribe el degradado COMPLETO, ya armado, una vez cada diez minutos. El
     valor de abajo es el de las 18:00 —la luz de tarde de siempre— y queda
     como reserva por si ese módulo no llegara a cargar. */
  background:
    radial-gradient(ellipse 62% 46% at 50% 24%,
      rgba(244, 226, 160, .50)  0%,
      rgba(219, 183, 110, .30) 38%,
      rgba(201, 168, 76,  .10) 62%,
      transparent 80%);

  /* Inclinación: entra desde arriba a la derecha, como un sol de tarde */
  transform-origin: 50% 0;
  transform: rotate(18deg);

  opacity: 0;            /* el JS le da su valor; sin JS no molesta */
  will-change: transform, opacity;
}

/* Cada haz arranca en un sitio distinto. El JS los mueve a partir de acá. */
.haz:nth-child(1) { left:  6%; }
.haz:nth-child(2) { left: 24%; }
.haz:nth-child(3) { left: 45%; }
.haz:nth-child(4) { left: 63%; }
.haz:nth-child(5) { left: 82%; }


/* ─── 3. ACCESIBILIDAD ─────────────────────────────────────────────────
   Luz que respira lentamente sobre toda la pantalla es justo el tipo de
   movimiento que molesta a quien pidió reducirlo. Se apaga por completo.
   ---------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  #haces-de-luz { display: none; }
}

/* En pantallas chicas la luz tapa más de lo que aporta: se atenúa. */
@media (max-width: 700px) {
  #haces-de-luz { opacity: .55; }
}


/* ─── 4. MOTAS DE POLVO ────────────────────────────────────────────────
   Partículas mínimas suspendidas en la luz. Solo con los haces, la luz
   es una mancha; con polvo flotando dentro, se vuelve VOLUMÉTRICA —se ve
   el aire, como en un rayo de sol que entra por una ventana—.

   Van en su propia capa, apenas por debajo de los haces (z-index 69), y
   también en screen para sumar luz. Su brillo está atado a --luz-
   intensidad: aparecen cuando la luz entra y se apagan con ella.

   Las crea y les da sus tamaños y recorridos codigo/18-motas-de-polvo.js.
   ---------------------------------------------------------------------- */
#motas-de-polvo {
  position: fixed;
  inset: 0;
  z-index: 69;
  pointer-events: none;
  mix-blend-mode: screen;
  overflow: hidden;
  opacity: var(--luz-intensidad);
  transition: opacity .4s linear;
}

.mota {
  position: absolute;
  border-radius: 50%;
  /* El polvo brilla con la luz que lo atraviesa, así que su color también
     cambia con la hora — pero SIN `var()` acá dentro, por el mismo motivo
     que en .haz (ver la nota de arriba: estas 32 motas re-resolvían su
     degradado 15 veces por segundo). Lo escribe 22-luz-de-la-hora.js ya
     armado, cada diez minutos. */
  background: radial-gradient(circle,
    rgba(255, 246, 214, .95) 0%,
    rgba(244, 226, 160, .55) 42%,
    transparent 72%);
  opacity: 0;
  /* ⚡ SIN `will-change`: acá era literalmente redundante.
     Esta animación es de CSS y solo toca `transform` y `opacity`. Chrome
     detecta ese caso solo y la manda al compositor por su cuenta —no hace
     falta pedírselo—. El `will-change` que había acá no aportaba nada y sí
     sumaba 32 capas más que "Layerize" tenía que administrar por cuadro. */
  animation: flotar-mota var(--mota-dur, 26s) linear var(--mota-delay, 0s) infinite;
}

/* Cada mota nace, deriva despacio en diagonal (como el polvo cae siguiendo
   la corriente de aire de la luz) y se apaga, para reaparecer arriba. */
@keyframes flotar-mota {
  0%   { transform: translate(0, 0);                                opacity: 0; }
  12%  {                                                            opacity: var(--mota-op, .6); }
  88%  {                                                            opacity: var(--mota-op, .6); }
  100% { transform: translate(var(--mota-dx, -30px), var(--mota-dy, 90px)); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  #motas-de-polvo { display: none; }
}

/* CALIDAD GRÁFICA ADAPTATIVA: codigo/21-monitor-de-rendimiento.js marca el
   <html> con "calidad-media" o "calidad-baja" (alta = ninguna) según lo que
   el equipo puede sostener de verdad.

   ⚡ BAJA YA NO ES "APAGADO". Antes acá se escondían los haces Y las motas
   por completo, y el resultado era un nivel sin atmósfera: la penumbra
   quedaba muerta, sin polvo en suspensión ni luz entrando. Ahora baja
   conserva UN par de haces y su polvo (18-motas-de-polvo.js siembra pocas),
   que es lo que vuelve volumétrica la luz. Se puede permitir porque el
   costo se fue a otro lado: se les quita la capa de GPU dedicada (abajo) y
   se recuperaron capas de las 24 que gastaban los SVG de las plantas
   (ver estilos/02-marco-victoriano.css).

     · calidad-media → 4 de los 5 haces.
     · calidad-baja  → 2 de los 5 haces, con las motas puestas pero sin capa
       de compositor propia.
   Los candelabros, las velas y las joyas no se tocan en ningún nivel. */
html.calidad-media #haces-de-luz .haz:nth-child(5) { display: none; }

html.calidad-baja #haces-de-luz .haz:nth-child(3),
html.calidad-baja #haces-de-luz .haz:nth-child(4),
html.calidad-baja #haces-de-luz .haz:nth-child(5) { display: none; }

/* Sin capa de GPU propia para el adorno animado en calidad baja: el iGPU de
   un equipo modesto sufre más sosteniendo texturas que pintando estas formas
   simples junto con el resto. */
html.calidad-baja .haz,
html.calidad-baja .mota {
  will-change: auto;
}


/* ─── 5. VELO DE REVELADO ──────────────────────────────────────────────
   El baño de luz de "encender las luces" al abrir el sobre. Sube, llena
   la pantalla y se apaga, todo una sola vez, mientras la música entra
   como eco lejano (ver codigo/10-reproductor-de-musica.js) y los haces
   rampan de 0 a su intensidad ambiente (codigo/14-haces-de-luz.js).

   Va en screen para que sume luz cálida sin ensuciar, y por encima de los
   haces (z-index 71) para que sea el gesto que revela.
   ---------------------------------------------------------------------- */
#velo-de-revelado {
  position: fixed;
  inset: 0;
  z-index: 71;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0;

  /* ⚡ APAGADO POR DEFECTO, Y ES UN ARREGLO DE RENDIMIENTO REAL.
     Este velo dura 2,9 segundos UNA vez, al abrir el sobre… pero antes se
     quedaba en el árbol para siempre: una capa de mezcla del tamaño de toda
     la pantalla, con opacidad 0, sin dibujar nada y costando igual.

     Y `mix-blend-mode` no es una capa cualquiera: obliga al compositor a
     LEER DE VUELTA el fondo y le impide fusionar nada de lo que hay debajo.
     Con `display: none` desaparece del árbol de capas en cuanto termina su
     momento. Se enciende solo mientras el body tiene la clase .revelando. */
  display: none;
  background:
    radial-gradient(ellipse 95% 75% at 50% 40%,
      rgba(255, 240, 205, .55) 0%,
      rgba(230, 180, 120, .22) 42%,
      transparent 72%);
}
/* Solo existe mientras dura el revelado. Al quitarse la clase .revelando
   (lo hace codigo/03-sobre-de-apertura.js al terminar), vuelve a
   display:none y su capa de mezcla deja de existir. */
body.revelando #velo-de-revelado {
  display: block;
  animation: bano-de-revelado 2.9s var(--curva-elegante) forwards;
}
@keyframes bano-de-revelado {
  0%   { opacity: 0; }
  38%  { opacity: 1; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  #velo-de-revelado { display: none; }
}
