/* Escena de fondo "luxury medical" — capas SVG + CSS.
   Solo se animan transform y opacity. Cada capa es un wrapper (.sl) que
   recibe el parallax y un hijo (svg) que lleva la animacion propia, para
   que las dos transformaciones no se pisen. */

.scene {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  isolation: isolate;
  /* Variante clara por defecto */
  --sc-light: var(--bg-light, #E5DABE);
  --sc-top: #D9CEBA; --sc-mid: var(--esc-bg, var(--bg-main, #D0C7B8)); --sc-bot: #C6BCAB;
  --sc-vineta: rgba(176, 145, 95, .2);
}

/* Relleno base en su propia capa (no en .scene) para poder bajarle la
   opacidad sin afectar rays/particulas/embers/etc, que tienen sus propios
   --esc-op-*. Con --esc-bg-op en 0 se ve lo que haya detras de la escena
   (ej. HeroVideoBackdrop). */
.scene::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(130% 100% at 10% 4%, var(--sc-light) 0%, transparent 66%),
    linear-gradient(170deg, var(--sc-top) 0%, var(--sc-mid) 48%, var(--sc-bot) 100%);
  /* El relleno adelgaza SOLO sobre la portada. La escena es fixed —cubre
     siempre la ventana— mientras que el video es absolute y se va con el
     scroll, asi que una opacidad fija adelgazaba tambien el 75% de pagina que
     no tiene video detras y la desteñia contra el blanco del documento.
     --esc-bg-scroll va de 0 (arriba del todo) a 1 (pasada la portada); lo
     mueve scene.js. Si el JS no corre, vale 0 y esto es exactamente la
     opacidad de antes. */
  opacity: calc(
    var(--esc-op-bg, 1) + (1 - var(--esc-op-bg, 1)) * var(--esc-bg-scroll, 0)
  );
}

/* Wrapper de capa. Ya no lleva parallax de raton: mover el transform de las
   12 capas en cada pointermove obligaba a re-rasterizar las que llevan filtro
   o mascara — 36 filtros y 4 mascaras en la escena — y eso tiraba fotogramas
   y se veia como un parpadeo general. La escena tiene movimiento propio de
   sobra. Sin transform tampoco hace falta promocionar capas con will-change. */
.scene .sl {
  position: absolute;
}
.scene .sl > svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* ── Posicion de cada capa ─────────────────────────────────────── */
.sl-ambient  { inset: -6%;
               /* El resplandor calido de abajo (ag-warm) tambien lavaba la
                  caustica. Se disuelve donde empieza el suelo: la capa va de
                  -6% a 106% de la escena, asi que el 80% cae en su 77%. */
               -webkit-mask-image: linear-gradient(to bottom,
                 #000 0%, #000 66%, rgba(0,0,0,.4) 72%, transparent 77%);
               mask-image: linear-gradient(to bottom,
                 #000 0%, #000 66%, rgba(0,0,0,.4) 72%, transparent 77%); }
.sl-rays     { inset: -10% -6% -6% -14%; }   /* sin parallax de raton */
.sl-bokeh    { inset: -4%; }
.sl-network  { inset: 0; }   /* canvas: coordenadas = las de la escena */
.sl-part-far { inset: -2%; }
.sl-part-mid { inset: -3%; }
.sl-part-near{ inset: -5%; }
.sl-embers   { inset: -2%; }

/* HUD: el centro del dibujo (punto 880,700 del viewBox 900x1080) se ancla a
   --hud-x/--hud-y, medidos sobre la referencia. El bloom cuelga de las mismas
   variables para que su posicion no se despegue del centro de los anillos. */
.scene       { --hud-x: 95%; --hud-y: 68.8%; --hud-h: 63vh;
               --hud-w: calc(var(--hud-h) * .8333); --bloom: calc(var(--hud-h) * .19); }
.sl-hud      { width: var(--hud-w); height: var(--hud-h);
               left: calc(var(--hud-x) - var(--hud-w) * .9778);
               top:  calc(var(--hud-y) - var(--hud-h) * .6481); }

.sl-hud > svg{ position: absolute; inset: 0; }
.sl-bloom    { width: var(--bloom); height: var(--bloom);
               left: calc(var(--hud-x) - var(--bloom) / 2);
               top:  calc(var(--hud-y) - var(--bloom) / 2); }

.sl-horizon  { left: -2%; right: -2%; top: 72.2%; height: 28%;
               /* El halo se disuelve antes de llegar al suelo: la franja de
                  caustica empieza en el 80% de la escena, que es el 28% de
                  esta capa. Sin esto el resplandor lava la luz del suelo. */
               -webkit-mask-image: linear-gradient(to bottom,
                 #000 0%, #000 10%, rgba(0,0,0,.3) 19%, transparent 28%);
               mask-image: linear-gradient(to bottom,
                 #000 0%, #000 10%, rgba(0,0,0,.3) 19%, transparent 28%); }
.sl-floor    { left: 0; right: 0; top: 80%; height: 20%; }

/* Orden de pintado */
.sl-ambient  { z-index: 1 }
.sl-rays     { z-index: 2 }
.sl-network  { z-index: 3 }
.sl-part-far { z-index: 3 }
.sl-floor    { z-index: 4 }
.sl-horizon  { z-index: 1 }   /* al fondo, por detras del suelo */
.sl-hud      { z-index: 6 }
.sl-bloom    { z-index: 7 }
.sl-bokeh    { z-index: 8 }
.sl-part-mid { z-index: 8 }
.sl-part-near{ z-index: 9 }
.sl-embers   { z-index: 9 }

/* Vineta calida + bloom global */
.scene::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 10;
  background: radial-gradient(120% 100% at 50% 45%, transparent 55%, var(--sc-vineta) 100%);
}

/* Variante oscura. Solo cambian los tokens del suelo: los SVG de la carpeta
   dark/ ya vienen con la paleta dorada, y los modulos de canvas reciben su
   color al montarse. */
.scene.is-dark {
  --sc-light: #3A2E1C;
  --sc-top: #1E1913; --sc-mid: var(--esc-bg, #151109); --sc-bot: #0C0906;
  --sc-vineta: rgba(0, 0, 0, .45);
  /* Sobre carbon el bloom del radar se pierde: mismo dibujo, mas tamano. */
  --bloom: calc(var(--hud-h) * .32);
}


/* ── Peso de cada capa ─────────────────────────────────────────
   Valores elegidos en el panel de ajustes del preview. La variante clara es
   la base y la oscura los sobreescribe. Solo se usa opacity: por encima del
   100% haria falta un filtro de brillo, y meter un filtro en una capa animada
   obliga a re-rasterizarla en cada fotograma — el mismo problema que nos dio
   el parallax. Los excesos elegidos (103-106%) quedan por debajo de lo
   distinguible, asi que no compensan ese coste. */
.sl-rays                                   { opacity: var(--esc-op-rays,  .94) }
.sl-part-far, .sl-part-mid, .sl-part-near  { opacity: var(--esc-op-part,  .88) }
.sl-bokeh                                  { opacity: var(--esc-op-bokeh, .79) }
.sl-embers                                 { opacity: var(--esc-op-emb,   1) }
.sl-hud, .sl-bloom                         { opacity: var(--esc-op-hud,   1) }
.sl-network                                { opacity: var(--esc-op-net,   1) }
.sl-ambient, .sl-horizon                   { opacity: var(--esc-op-amb,   .90) }
.sl-floor                                  { opacity: var(--esc-op-flo,   1) }

/* La oscura usa LA MISMA variable con otro valor por defecto: asi el control
   del tema manda en las dos variantes y cada una conserva su punto de partida.
   Si la regla oscura fijara un numero, ganaria por especificidad y el panel no
   haria nada al estar el sitio en oscuro. */
.scene.is-dark .sl-rays                                  { opacity: var(--esc-op-rays,  .54) }
.scene.is-dark .sl-part-far,
.scene.is-dark .sl-part-mid,
.scene.is-dark .sl-part-near                             { opacity: var(--esc-op-part,  .30) }
.scene.is-dark .sl-bokeh                                 { opacity: var(--esc-op-bokeh, .42) }
.scene.is-dark .sl-embers                                { opacity: var(--esc-op-emb,   .48) }
.scene.is-dark .sl-hud, .scene.is-dark .sl-bloom         { opacity: var(--esc-op-hud,   .94) }
.scene.is-dark .sl-ambient, .scene.is-dark .sl-horizon   { opacity: var(--esc-op-amb,   .60) }
.scene.is-dark .sl-network                               { opacity: var(--esc-op-net,   .63) }
.scene.is-dark .sl-floor                                 { opacity: var(--esc-op-flo,   .60) }

/* ── Animaciones ───────────────────────────────────────────────── */
@keyframes sc-breathe { 0%, 100% { opacity: .82; transform: scale(1) }
                        50%      { opacity: 1;   transform: scale(1.03) } }
@keyframes sc-bokeh   { 0%, 100% { transform: translate(-22px,  13px) }
                        50%      { transform: translate( 22px, -13px) } }
@keyframes sc-drift   { 0%, 100% { transform: translate(0, 0) }
                        50%      { transform: translate(1.2%, -1.6%) } }
@keyframes sc-drift2  { 0%, 100% { transform: translate(0, 0) }
                        50%      { transform: translate(-1%, 1.3%) } }
@keyframes sc-luz     { 0%, 100% { opacity: .84 } 50% { opacity: 1 } }
@keyframes sc-pulse   { 0%, 100% { opacity: .85 } 50% { opacity: 1 } }
@keyframes sc-spin    { to { transform: rotate(360deg) } }
@keyframes sc-spin-r  { to { transform: rotate(-360deg) } }
@keyframes sc-bloom   { 0%, 100% { transform: scale(.92); opacity: .72 }
                        50%      { transform: scale(1.08); opacity: 1 } }
@keyframes sc-floor   { 0%, 100% { transform: scaleY(1) translateY(0) }
                        50%      { transform: scaleY(1.025) translateY(5px) } }

/* Estas dos capas latian pero no se movian: solo animaban opacidad, y por eso
   se leian como estampadas. Ahora ademas derivan.
   El vaiven va en 'translate'/'rotate' — propiedades individuales — para que
   COMPONGA con el 'transform'/'scale' que ya animan los latidos en vez de
   pisarlo. Y los periodos no son multiplos entre si: si latido y deriva
   coincidieran, el conjunto respiraria como un metronomo. */
.sl-ambient  > svg { animation: sc-breathe 16s ease-in-out infinite,
                                sc-vaiven-glow 27s ease-in-out infinite }
/* El abanico pivota sobre la esquina del sol, no sobre el centro de la capa:
   asi el giro abre y cierra el abanico desde su origen, que es como se mueve
   una luz de verdad. El desplazamiento crece con la distancia al sol y es cero
   en el sol mismo, o sea que por mucho que derive nunca pierde el foco. */
.sl-rays     > svg { transform-origin: 0 0;
                     animation: sc-luz 19s ease-in-out infinite,
                                sc-vaiven-rayos 31s ease-in-out infinite }
/* El bokeh son los circulos grandes y difusos, y es el caso raro de la escena:
   precisamente por ser enormes y sin borde, un recorrido que en cualquier otro
   elemento se veria de sobra en ellos no se aprecia. Necesitan bastante mas
   que el resto para leerse como que flotan.
   Y va en px, no en %: un 1.2% son 29 px en un monitor ancho pero 4 en un
   telefono. La deriva se desvanecia justo en la pantalla pequena, que es donde
   ademas hay menos cosas moviendose para disimularlo. */
.sl-bokeh    > svg { animation: sc-bokeh 40s ease-in-out infinite }
.sl-network  > svg { animation: sc-drift2 28s ease-in-out infinite }
.sl-part-far > svg { animation: sc-drift2 46s ease-in-out infinite }
.sl-part-mid > svg { animation: sc-drift 38s ease-in-out infinite }
.sl-part-near> svg { animation: sc-drift 26s ease-in-out infinite }
.sl-horizon  > svg { animation: sc-pulse 11s ease-in-out infinite }
.sl-floor    > svg { animation: sc-floor 26s ease-in-out infinite; transform-origin: 50% 0% }
.sl-bloom    > svg { animation: sc-bloom 6s ease-in-out infinite }

/* Grupos internos del HUD: contrarrotan a velocidades muy distintas.
   transform-box:view-box para que el origen sea el centro real del dibujo. */
.sl-hud [id^="hud-"], .sl-hud [id^="orbit-"] {
  transform-box: view-box;
  transform-origin: 880px 700px;
}
#hud-ring-back   { animation: sc-spin   100s linear infinite }
#hud-ring-middle { animation: sc-spin-r  75s linear infinite }
#hud-ring-front  { animation: sc-spin   130s linear infinite }
#hud-arcs        { animation: sc-spin-r  55s linear infinite }
#hud-nodes       { animation: sc-spin    88s linear infinite }
#orbit-arcs      { animation: sc-spin-r  64s linear infinite }
#orbit-nodes     { animation: sc-spin   110s linear infinite }
/* Capa 02 · rayos solares. El abanico pivota sobre el sol (-180,-140) y las
   burbujas del flare derivan, ambos siguiendo el puntero. Van por las
   propiedades individuales rotate/translate para no chocar con el transform
   que ya animan los keyframes del wrapper. */
/* Capa 02 · el abanico ya no reacciona al puntero: respira solo. El grupo
   entero deriva muy despacio y ademas cada haz oscila por su cuenta con un
   periodo distinto — es esa desincronia la que lo hace parecer natural en vez
   de un pendulo rigido. */
/* Capa 02 · nada se anima elemento a elemento.
   Animar hijos sueltos de un SVG obliga a repintar la capa entera en cada
   fotograma, con filtro o sin el; solo es barato animar la capa completa.
   Aqui eso costaba especialmente caro porque los haces llevan un desenfoque:
   moverlos por dentro obligaba ademas a recalcular el filtro.
   El abanico y las burbujas quedan quietos y la capa entera respira. */
/* Cada burbuja parpadea por su cuenta: duraciones primas entre si y desfases
   escalonados, para que el grupo no lata al unisono. El keyframe anima opacity
   y el brillo propio de cada burbuja va en fill-opacity — si fueran la misma
   propiedad la animacion pisaria el valor autorado y todas latirian igual. */
/* Antes parpadeaban las 21 burbujas por separado: 21 elementos animados que
   repintaban la capa entera en cada fotograma. Ahora respira el grupo. */
/* Las burbujas bascualan alrededor del sol, igual que el abanico, pero EN
   SENTIDO CONTRARIO y con otro periodo. Esa diferencia es justo lo que se
   percibe como movimiento: si todo derivara rigido en bloque, el ojo lo leeria
   como una capa quieta que alguien empuja, no como luz. */
#flare-halos { transform-box: view-box; transform-origin: -180px -140px;
               animation: sc-flicker2 6.4s ease-in-out infinite,
                          sc-vaiven-flare 23s ease-in-out infinite }
#flare-star  { transform-box: view-box; transform-origin: -180px -140px;
               animation: sc-flare 4.4s ease-in-out infinite,
                          sc-vaiven-star 17s ease-in-out infinite }

/* Capa 11 · brasas. Suben desde el horizonte describiendo una espiral: el
   avance vertical es constante y la X es una senoidal muestreada en 8 pasos.
   Nacen y mueren en fade, y el --del negativo de cada una las reparte por
   todo el recorrido ya en el primer frame — nunca aparece un grupo de golpe.
   El titileo va en un <g> interior porque la subida ya usa opacity: en la
   misma propiedad una animacion pisaria a la otra en vez de multiplicarla. */
.ember { transform-box: view-box;
         animation: sc-ember var(--dur, 32s) linear infinite;
         animation-delay: var(--del, 0s) }
/* El titileo por brasa eran otros 35 elementos animados. La subida ya cambia
   la opacidad al nacer y al morir, que es lo que se percibe. */
@keyframes sc-ember {
    0%    { translate: 0 0; opacity: 0 }
   10%    { opacity: 1 }
   12.5%  { translate: calc(var(--amp) *  .71) calc(var(--rise) * .125) }
   25%    { translate: var(--amp)              calc(var(--rise) * .25) }
   37.5%  { translate: calc(var(--amp) *  .71) calc(var(--rise) * .375) }
   50%    { translate: 0                       calc(var(--rise) * .5) }
   62.5%  { translate: calc(var(--amp) * -.71) calc(var(--rise) * .625) }
   75%    { translate: calc(var(--amp) * -1)   calc(var(--rise) * .75) }
   87.5%  { translate: calc(var(--amp) * -.71) calc(var(--rise) * .875) }
   88%    { opacity: 1 }
  100%    { translate: 0 var(--rise); opacity: 0 }
}
@keyframes sc-flicker2 { 0%, 100% { opacity: .55 } 37% { opacity: 1 } 72% { opacity: .78 } }
@keyframes sc-flare    { 0%, 100% { opacity: .68; scale: .95 } 50% { opacity: 1; scale: 1.06 } }

/* Vaivenes. Amplitudes deliberadamente minusculas: el giro se mide en decimas
   de grado porque, al pivotar sobre el sol, lo que el ojo ve al otro extremo
   del abanico son unos 9 px. Mas que eso deja de ser luz y parece un carrusel.
   Los cuatro periodos son primos entre si (31 · 27 · 23 · 17) para que las
   fases no vuelvan a coincidir: el ciclo conjunto tarda horas en repetirse. */
@keyframes sc-vaiven-rayos { 0%, 100% { rotate: -.22deg; translate:   0    0   }
                             50%      { rotate:  .22deg; translate:  10px  6px } }
@keyframes sc-vaiven-glow  { 0%, 100% { translate:   0    0   }
                             50%      { translate:  16px 10px } }
/* Medido a 2420 px de ancho, con .30deg y 8px el flare recorria 38 px contra
   los 17 del abanico: el doble que todo lo demas, que ya no es tenue. Ajustado
   para que siga siendo el que mas se mueve — hace falta para que se note el
   desfase contra los haces — pero sin destacar. */
@keyframes sc-vaiven-flare { 0%, 100% { rotate:  .20deg; translate:  -5px  3px }
                             50%      { rotate: -.20deg; translate:   5px -3px } }
@keyframes sc-vaiven-star  { 0%, 100% { translate:  -5px  3px }
                             50%      { translate:   5px -3px } }

@media (max-width: 768px) {
  .scene { --hud-x: 88%; --hud-y: 62%; --hud-h: 46vh; }
  .sl-bloom { display: none }
  /* Antes aqui se atenuaban particulas y bokeh a .7 en movil. Ahora su peso
     lo gobierna el tema por capa, asi que una regla fija los pisaria: si en
     movil hace falta menos, se baja desde el panel. */
}


/* Modo ligero (lo marca scene.js): de 35 brasas a 12. Cada brasa animada
   repinta la capa entera en cada fotograma, asi que recortar el numero es la
   forma directa de bajar el coste sin tocar el efecto. */
.scene.ligero #embers .ember:nth-child(n+13) { display: none }

/* En movil se apagan solo las derivas que no se perciben: las tres capas de
   particulas se desplazan menos de 1 px por segundo, asi que lo unico que
   aportaban era promocionar una capa a pantalla completa.
   El bokeh estaba aqui y se ha sacado: al medirlo era la unica capa con CERO
   desplazamiento en movil, y siendo los circulos mas grandes de la escena era
   justo la que se leia como estampada. Mover una capa entera es la forma
   barata de moverse — el compositor la desplaza sin repintarla — asi que se
   queda, y lo que cuesta es un lienzo mas que componer, no dibujo nuevo.
   Los resplandores y el flare SI se quedan: son lo que hace que la luz
   parezca viva, y su coste es acotado — dos capas promocionadas y tres grupos
   animados dentro de ellas. Lo caro nunca fue esto, sino las capas que se
   repintan enteras: la constelacion y el HUD, que si se van. */
.scene.ligero .sl-part-far > svg,
.scene.ligero .sl-part-mid > svg,
.scene.ligero .sl-part-near> svg { animation: none }

/* Constelacion, HUD y estrella fuera en movil. La constelacion es un canvas a
   pantalla completa repintandose, y el HUD siete grupos girando que repintan
   su capa en cada fotograma: entre los dos se llevaban lo que quedaba del
   presupuesto. */
.scene.ligero .sl-network,
.scene.ligero .sl-hud,
.scene.ligero .sl-bloom { display: none }

@media (prefers-reduced-motion: reduce) {
  .scene .sl, .scene .sl > svg, .scene [id] { animation: none !important; transition: none !important }
  .ember { translate: none !important; opacity: 1 !important }
}
