/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  RE-FONDO · LA ATMÓSFERA                    Tu Plantilla v2 · 17-ago-2026 ║
   ║  css/re-fondo.css — CARGAR AL FINAL (después de escala.css)               ║
   ╠══════════════════════════════════════════════════════════════════════════╣
   ║  EL PROBLEMA MEDIDO                                                       ║
   ║  lienzo.js:178-180 hace `s.style.backgroundColor = s.dataset.bg` sobre     ║
   ║  cada [data-bg]: 16 colores planos pintados INLINE. Los negros se repiten  ║
   ║  literalmente — #060608 en c01, t02, t06, f02, z02 y el footer — así que   ║
   ║  el acto oscuro es el MISMO negro durante ~21 pantallas. Ningún gradiente  ║
   ║  de ambiente en toda la hoja: lo único que hay es la retícula de puntos    ║
   ║  de base.css:107-108 (26×26px) y los decorados por sección (.tp-deco,      ║
   ║  .sfrio-deco, .tpz-deco), que son FORMAS, no LUZ.                          ║
   ║                                                                            ║
   ║  EL CRITERIO                                                              ║
   ║  1) No puedo cambiar el color de una sección: el inline style de           ║
   ║     lienzo.js gana a cualquier hoja sin !important, y ponerle !important   ║
   ║     a 16 fondos sería declararle la guerra al pintor. Entonces la          ║
   ║     atmósfera se SUMA en capas translúcidas encima del color, nunca lo     ║
   ║     reemplaza. El color sigue siendo de el cliente.                            ║
   ║  2) Dos capas fijas de luz + una de grano + una de profundidad. Fijas a    ║
   ║     propósito: al no moverse, el contenido pasa por debajo y la luz        ║
   ║     "viaja" sin que nada se anime — es el efecto más barato que existe     ║
   ║     (cero repintado, cero rAF, cero JS) y funciona igual sin GSAP.         ║
   ║  3) La temperatura no inventa colores: la paleta de este proyecto es       ║
   ║     azul/negro/blanco/crema y nada más (scenery-cierre.css:9). Así que     ║
   ║     "cálido" = crema #f4efe6 y "frío" = azul #2440ff / glow #6d86ff. La    ║
   ║     temperatura es la PROPORCIÓN entre esas dos luces, no un tono nuevo.   ║
   ║  4) La costura: el divisor de scenery-cierre.js ya trae el COLOR de la     ║
   ║     sección siguiente. Mi costura trae su LUZ, y va DEBAJO del divisor,    ║
   ║     de modo que la cuña opaca me recorta el resplandor. La costura toma    ║
   ║     forma sin que yo dibuje una segunda forma que pueda pelearse con la    ║
   ║     primera. Complementar = dejar que el otro recorte.                     ║
   ║                                                                            ║
   ║  DÓNDE ME METO (mapa de z-index verificado, no supuesto)                   ║
   ║    fondo de sección (inline)  ← más abajo                                  ║
   ║    ▸ mis lavados de sección   z:0   (nuevo)                                ║
   ║    ▸ mi costura               z:0   (nuevo)                                ║
   ║    .tpz-divisor              z:1   scenery-cierre.css:28  ← me recorta     ║
   ║    .tp-deco/.sfrio-deco/.t06-deco z:1                                      ║
   ║    .lienzo                    z:1   chrome.css:9                           ║
   ║    ▸ mis 2 luces + grano      z:1   (nuevo, después en el árbol)           ║
   ║    .section>.container        z:2   chrome.css:10   ← el texto NUNCA queda  ║
   ║    .c02 z:2 · .footer z:2 · tab-rail z:5 · nav z:150 · popup z:200            debajo de mi luz
   ║                                                                            ║
   ║  LO QUE NO TOCO (regla 1)                                                 ║
   ║  t03-sietedias, t04b-chat, f02-calc y f01-como no aparecen en NINGUNA      ║
   ║  lista de este archivo. Por eso las agrupaciones son listas de ids a mano  ║
   ║  y no [data-theme="light"], que habría sido la mitad de código pero        ║
   ║  barría justo esas cuatro. Les llega solo la capa fija global, que no      ║
   ║  declara nada sobre sus selectores ni sus hijos. (Y f02 ya tiene su propio ║
   ║  glow azul: .sfrio-glow, scenery-frio.css:41.)                            ║
   ║                                                                            ║
   ║  PROHIBICIONES RESPETADAS                                                 ║
   ║  · cero mix-blend-mode (el grano es gris medio semitransparente: aclara    ║
   ║    sobre negro y oscurece sobre crema por matemática de alfa, sin blend).  ║
   ║  · cero will-change permanente · cero filter/backdrop-filter/blur nuevo.   ║
   ║  · los @keyframes llevan valores literales, jamás var() dentro de un       ║
   ║    transform (el navegador no reevalúa la variable y el estado final       ║
   ║    queda pegado).                                                          ║
   ║  · espaciado: solo --s1..--s8 (4·8·14·20·28·40·56·80) o sumas de esos      ║
   ║    pasos. Los %/vmax/vh de este archivo son POSICIÓN DE LUZ y sangrado de  ║
   ║    capa decorativa, no distancia entre cosas que se leen.                  ║
   ║                                                                            ║
   ║  COLISIÓN QUE DECLARO EN VEZ DE ESCONDER                                   ║
   ║  El prefijo pedido (.re-) lo aplico a variables (--re-*) y keyframes       ║
   ║  (re-*), pero no puedo prefijar las CAJAS: sin tocar el HTML, las únicas   ║
   ║  cajas nuevas posibles son pseudo-elementos. Ocupo 4 globales             ║
   ║  (html::before/after, body::before/after) y ::before/::after de 11         ║
   ║  secciones + el footer. Verifiqué con grep que hoy no existe NI UNO de     ║
   ║  esos pseudos en css/ ni en js/: están libres. Si otra sesión los          ║
   ║  necesita, este es el archivo con el que va a chocar.                      ║
   ╚══════════════════════════════════════════════════════════════════════════╝ */


/* ═══════════════════════════════════════════════════════════════════════════
   0 · TOKENS DE ATMÓSFERA
   Los alfas son bajos a propósito y todos verificados contra el peor caso:
   sobre #ffffff (t05) y sobre #060608 (c01/t02/t06/z02). Nada supera .20,
   porque una capa a ancho completo con más alfa deja de ser atmósfera y
   empieza a ser un velo que te apaga la tipografía.
   ═══════════════════════════════════════════════════════════════════════════ */
:root{
  /* Las dos únicas temperaturas que la paleta permite */
  --re-calida:      rgba(244,239,230,.13);   /* crema #f4efe6 — luz de lámpara */
  --re-calida-baja: rgba(244,239,230,.085);
  --re-fria:        rgba(36,64,255,.19);     /* azul #2440ff — luz de pantalla */
  --re-fria-baja:   rgba(109,134,255,.13);   /* glow #6d86ff — el rebote */
  --re-hondo:       rgba(27,49,201,.11);     /* azul-deep #1b31c9 — la sombra */

  /* Altura de la costura. El divisor mide 70px (scenery-cierre.css:29) y en
     .subsec 42px (:32); la luz tiene que ser MÁS ALTA que la cuña para que se
     lea como resplandor que se filtra desde el otro lado y no como un borde.
     80+40 = 120px, y 56px para las subsecciones. Todo sumas de la escala. */
  --re-costura:      calc(var(--s8) + var(--s6));
  --re-costura-mini: var(--s7);
}
/* Mismo corte que usa escala.css:89 para bajar un paso en teléfono. Allá el
   divisor cae a 44px y 28px (scenery-cierre.css:34-35), así que la costura
   baja al paso inmediatamente superior a esas medidas. */
@media(max-width:760px){
  :root{
    --re-costura:      var(--s8);
    --re-costura-mini: var(--s6);
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   1 · PROFUNDIDAD — html::before
   Una viñeta, pero AZUL (--azul-deep), no negra. Es el único truco que se
   lee bien en los tres actos con una sola declaración: sobre el negro hunde
   las esquinas y da bóveda; sobre la crema se lee como la sombra fría del
   papel al borde de la hoja. Una viñeta negra habría ensuciado la crema, que
   es justo el color que el cliente no quiere ver sucio.
   Va en html y no en body porque body ya carga las dos luces, y quería la
   profundidad DEBAJO de ellas (html::before es el primer hijo del árbol).
   ═══════════════════════════════════════════════════════════════════════════ */
html::before{
  content:"";
  position:fixed;
  inset:0;
  z-index:1;                 /* misma banda que .lienzo: sobre el color, bajo el texto */
  pointer-events:none;
  background:radial-gradient(125% 95% at 50% 40%,
              transparent 45%,
              rgba(27,49,201,.05) 76%,
              rgba(27,49,201,.11) 100%);
}


/* ═══════════════════════════════════════════════════════════════════════════
   2 · LAS DOS LUCES QUE VIAJAN — body::before (cálida) · body::after (fría)
   Van en BODY, no en html, por un motivo funcional: lienzo.js:124 escribe
   `document.body.dataset.acto`, y las custom properties/estados de body los
   ve un pseudo de body pero JAMÁS uno de html (las variables bajan, no suben).
   Sin GSAP ese atributo no existe nunca (lienzo.js:9 hace return), así que la
   mezcla por defecto que queda escrita aquí tiene que verse bien sola.

   El sangrado (inset negativo) está calculado contra el recorrido de los
   keyframes del bloque 3: el viaje máximo es 9vh / 5vw y el sangrado es
   12vh / 8vw — la capa nunca puede mostrar su propio borde al desplazarse.
   ═══════════════════════════════════════════════════════════════════════════ */
body::before,
body::after{
  content:"";
  position:fixed;
  inset:-12vh -8vw;
  z-index:1;
  pointer-events:none;
  /* el cambio de acto es un fundido de LUZ, no un salto de color: por eso lo
     que cambia es opacity (compositable) y no los gradientes (que no
     interpolan y darían un corte seco a mitad de scroll) */
  transition:opacity 1.1s linear;
}

/* Luz cálida: crema. Sobre los negros es una lámpara; sobre las secciones
   crema es casi invisible — y está bien, porque a las secciones claras la
   luz se la da su propio lavado (bloque 5), que sí puede usar blanco. */
body::before{
  opacity:.62;               /* mezcla sin JS: tibia, el término medio honesto */
  background:
    radial-gradient(46vmax 34vmax at 16% 18%, var(--re-calida), transparent 68%),
    radial-gradient(38vmax 30vmax at 88% 74%, var(--re-calida-baja), transparent 66%);
}

/* Luz fría: azul + glow, colocada en las esquinas OPUESTAS a la cálida.
   Cruzadas, las dos capas dibujan una diagonal de temperatura en pantalla:
   el ojo siempre tiene un lado tibio y uno frío al que agarrarse, que es lo
   que hace que un fondo se sienta "profundo" y no "pintado". */
body::after{
  opacity:.55;
  background:
    radial-gradient(52vmax 40vmax at 82% 12%, var(--re-fria), transparent 66%),
    radial-gradient(40vmax 32vmax at 10% 82%, var(--re-fria-baja), transparent 64%);
}

/* ── La temperatura del acto ──────────────────────────────────────────────
   Los tres actos existen en el HTML (data-acto en c01-hero, t01-equipo,
   f01-como y otra vez caliente en z02-cierre). El arco es el del funnel de
   el cliente y también funciona como arco visual:
     caliente → póster negro, azul dominante y un hilo de crema: promesa
     tibio    → confianza: crema arriba manda, el azul se retira al piso
     frío     → el plano técnico: azul al máximo, la crema casi apagada
   z02 vuelve a "caliente" en el HTML, así que el cierre recupera el clima
   exacto del hero. Eso no lo invento yo: ya estaba en el marcado, y aquí por
   fin se ve. Valores literales, sin var() encadenado: un fundido de opacidad
   tiene que ser inmune a cualquier redefinición aguas arriba. */
body[data-acto="caliente"]::before{opacity:.45}
body[data-acto="caliente"]::after {opacity:.90}
body[data-acto="tibio"]::before   {opacity:1}
body[data-acto="tibio"]::after    {opacity:.40}
body[data-acto="frio"]::before    {opacity:.22}
body[data-acto="frio"]::after     {opacity:1}


/* ═══════════════════════════════════════════════════════════════════════════
   3 · EL VIAJE CON EL SCROLL (mejora progresiva)
   Las capas fijas ya "viajan" porque el contenido pasa por debajo. Esto le
   suma una deriva real ligada al scroll, sin una línea de JS y sin rAF —
   que además es la única forma de que no muera con la pestaña oculta (bug
   conocido de este proyecto).
   El @supports pide las DOS cosas que necesita la receta: si un navegador
   soporta animation-timeline pero no animation-duration:auto, la duración se
   quedaría en 0s y la luz se congelaría en el fotograma final. Fallando el
   test no pasa nada: quedan las luces fijas, que es un estado terminado.
   Solo transform. Sin will-change: la capa ya es su propia capa de
   composición por ser fixed con gradiente.
   ═══════════════════════════════════════════════════════════════════════════ */
@supports (animation-timeline:scroll()) and (animation-duration:auto){
  body::before,
  body::after{
    animation-duration:auto;
    animation-timing-function:linear;
    animation-fill-mode:both;
    animation-timeline:scroll(root block);
  }
  body::before{animation-name:re-viaje-calida}
  body::after {animation-name:re-viaje-fria}
}
/* Recorridos cruzados: la cálida sube y se va a la izquierda, la fría baja y
   se va a la derecha. En 21 pantallas de scroll eso significa que la luz de
   la primera pantalla NO es la luz de la última, que es exactamente lo que
   faltaba. Valores literales (regla 5): si aquí hubiera var(--algo), el
   estado final se quedaría clavado en el valor de la primera resolución. */
@keyframes re-viaje-calida{
  from{transform:translate3d(0,0,0)}
  55% {transform:translate3d(-3vw,-5vh,0)}
  to  {transform:translate3d(-4vw,-9vh,0)}
}
@keyframes re-viaje-fria{
  from{transform:translate3d(0,3vh,0)}
  55% {transform:translate3d(3vw,-1vh,0)}
  to  {transform:translate3d(5vw,-6vh,0)}
}


/* ═══════════════════════════════════════════════════════════════════════════
   4 · GRANO FINO — html::after
   Va en html::after y no en body porque html::after es el ÚLTIMO hijo del
   árbol: el grano queda por encima de las dos luces y de las piezas del
   lienzo (les da textura, es lo que quiero) y sigue por debajo de todo
   .container z:2 (nunca ensucia una letra, que es lo que no quiero).
   Sin mix-blend-mode: el ruido es gris medio con alfa ~.5 de fábrica, así
   que a .05 de capa aclara los negros y oscurece la crema por simple
   composición alfa. Un blend en una capa fija a pantalla completa es
   justamente lo que en otra página de este proyecto dejó todo negro.
   180px de baldosa con stitchTiles: se rasteriza UNA vez, se repite, y al
   ser fixed no repinta al scrollear.
   ═══════════════════════════════════════════════════════════════════════════ */
html::after{
  content:"";
  position:fixed;
  inset:0;
  z-index:1;
  pointer-events:none;
  opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='re-grano'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23re-grano)'/%3E%3C/svg%3E");
  background-size:180px 180px;   /* en px CSS: el grano no crece con el dpr */
}


/* ═══════════════════════════════════════════════════════════════════════════
   5 · TEMPERATURA POR SECCIÓN — ::before, z-index:0
   Aquí se resuelve el hallazgo grave: cuatro secciones con el MISMO #060608
   seguidas (c01, t02, t06, z02, más f02 que no toco). No puedo cambiarles el
   color, así que a cada una le pongo una luz distinta y de distinta
   temperatura: el negro es el mismo, la NOCHE es distinta.
   z-index:0 = encima del fondo inline de la sección (y de su retícula de
   puntos), debajo de su decorado z:1 y muy debajo del contenido z:2.
   ═══════════════════════════════════════════════════════════════════════════ */
:is(#c01-hero,#t02-garantia,#t06-portafolio,#z02-cierre,#f03-planes,
    #t01-equipo,#t04-mantencion,#t05-resenas,#f04-comparacion,#f05-packredes,
    #z01-faq)::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
}

/* ── LAS CUATRO NOCHES (#060608, una luz para cada una) ─────────────────── */

/* c01-hero · la noche del póster. Sienta lo que ya existe: la dona crema
   recortada arriba-izquierda (.c01-arc--tl) y la azul abajo-derecha, que ya
   trae box-shadow 90px azul (sections.css:39). Mi luz continúa esas dos
   fuentes fuera del recorte, así que las donas dejan de flotar sobre negro
   plano y empiezan a estar DENTRO de algo. */
/* ⚠ RETIRADO AL INTEGRAR (17-ago) · Aquí había un `#c01-hero::before` con
   su lavado de luz. re-hero.css declara EXACTAMENTE el mismo pseudo con la
   misma especificidad (1,0,1) para arreglar un problema de legibilidad
   medido (el anillo crema pasando por detrás del titular). Uno de los dos
   desaparecía en silencio; gana re-hero porque su motivo es un bug real y
   no un adorno. El hero queda fuera del alcance de este archivo. */


/* t02-garantia · la noche TIBIA. Es la sección de la confianza y el sello
   50/50 centrado: la clave entra desde arriba en crema y el azul se va al
   piso. Comparada con c01 (azul dominante), el mismo #060608 se lee más
   cálido — y eso es precisamente el punto: dos negros idénticos, dos climas. */
#t02-garantia::before{
  background:
    radial-gradient(90% 55% at 50% 0%,   rgba(244,239,230,.055), transparent 68%),
    radial-gradient(60% 40% at 50% 100%, rgba(36,64,255,.10),    transparent 70%);
}

/* t06-portafolio · la noche ÍNDIGO. Los tres teléfonos con páginas vivas
   piden contraluz: charco azul justo detrás de ellos (a 58% de alto, donde
   están las pantallas) y un rebote glow arriba-derecha que acompaña al arco
   blanco 7% que ya vive ahí (.t06-arc--a). Los teléfonos quedan retroiluminados
   en vez de pegados sobre un fondo. */
#t06-portafolio::before{
  background:
    radial-gradient(66% 46% at 50% 58%, rgba(36,64,255,.17),    transparent 66%),
    radial-gradient(50% 40% at 88% 10%, rgba(109,134,255,.10),  transparent 70%);
}

/* z02-cierre · la noche del AMANECER AL REVÉS: el azul entra desde abajo,
   por fuera del cuadro, como un horizonte. Se apoya en .tpz-horizonte
   (scenery-cierre.css:91, un arco de 240vw con borde superior blanco 8% al
   55% de alto): ese hilo blanco por fin tiene una atmósfera detrás que lo
   justifique. Y un halo crema tenue a la altura del titular fino, que es la
   voz elegante del ADN y merece luz propia. */
#z02-cierre::before{
  background:
    radial-gradient(120% 55% at 50% 108%, rgba(36,64,255,.20),   transparent 72%),
    radial-gradient(60% 40% at 50% 30%,   rgba(244,239,230,.05), transparent 70%);
}

/* ── LA NOCHE AZUL (#0b0d26 · f03-planes, el único acto-blue) ───────────── */
/* Es el póster de la oferta: luz blanca de cenital arriba (donde están las
   tres ventanas retro) y azul-deep hundido en el piso, para que la fila de
   bonos no termine en un vacío del mismo tono. */
#f03-planes::before{
  background:
    radial-gradient(90% 50% at 50% -5%,  rgba(255,255,255,.07), transparent 66%),
    radial-gradient(80% 55% at 50% 105%, rgba(27,49,201,.28),   transparent 70%);
}

/* ── EL PAPEL (secciones claras) ────────────────────────────────────────── */
/* Regla común: charco de luz blanca arriba + enfriamiento azul al pie. Ese
   simple gradiente vertical le da a cada sección clara un arriba y un abajo;
   antes eran planos absolutos (#fbfaf6, #eef1fb, #fafaf8 sin un solo
   gradiente en toda la hoja) y encadenadas se leían como una única hoja
   infinita. El azul del pie es además el aviso de que viene la noche. */
:is(#t01-equipo,#t04-mantencion,#f04-comparacion,#f05-packredes)::before{
  background:
    radial-gradient(100% 55% at 50% -8%,  rgba(255,255,255,.55), transparent 62%),
    radial-gradient(120% 70% at 50% 112%, rgba(36,64,255,.05),   transparent 68%);
}

/* t05-resenas es #ffffff: el charco blanco ahí no existe (blanco sobre
   blanco). Se invierte el truco — se le da BASE crema (--bg-2 #ece6d9) para
   que el blanco puro se lea como papel y no como pantalla apagada. */
#t05-resenas::before{
  background:
    radial-gradient(120% 70% at 50% 108%, rgba(236,230,217,.50), transparent 66%),
    radial-gradient(90%  50% at 50% 100%, rgba(36,64,255,.045),  transparent 60%);
}

/* z01-faq es la sección larga de lectura (26 preguntas, tab-rail sticky).
   Aquí la luz NO puede pasar por encima de un párrafo: solo un marco frío
   por los bordes, con el centro completamente limpio. La atmósfera se calla
   donde la gente está leyendo. */
#z01-faq::before{
  background:radial-gradient(140% 90% at 50% 50%,
              transparent 52%,
              rgba(36,64,255,.045) 100%);
}


/* ═══════════════════════════════════════════════════════════════════════════
   6 · LA COSTURA CON FORMA — ::after, z-index:0
   Cómo complementa sin pelear: scenery-cierre.js:33-56 recorre las [data-bg]
   vecinas y le cuelga a la sección A un .tpz-divisor (z:1, bottom:-1px, 70px)
   cuyo SVG va relleno con el color de la sección B — diagonal en los pares,
   onda en los impares, espejada en diagonales alternas. Mi costura va a
   z-index:0, o sea DEBAJO de esa cuña opaca. Resultado: el divisor me recorta
   el resplandor con su propia geometría, y la costura tiene la forma exacta
   del divisor sin que yo dibuje ni una curva. Si mañana cambian los paths, mi
   luz cambia con ellos.

   Y el criterio de color es el gemelo del suyo: el divisor trae el COLOR de
   lo que viene; la costura trae su LUZ.

   Fronteras reales, contadas sobre el DOM: 12 divisores (t01→t02, t02→t03,
   t03→t04, t04b→t05, t05→t06, t06→f01, f01→f02, f02→f03, f03→f04, f04→f05,
   f05→z01, z01→z02) y 3 fronteras SIN divisor, porque el JS las salta:
     · c01→t01: entre medio va el marquee c02 (sin data-bg) — ya divide él.
     · t04→t04b: mismo #eef1fb en las dos, no hay cambio de color.
     · z02→footer: el footer está fuera de <main>.
   En esas tres mi banda se ve entera, sin cuña que la recorte, y funciona
   igual: es un respiro de luz antes del cambio. Ninguna queda huérfana.
   ═══════════════════════════════════════════════════════════════════════════ */
:is(#c01-hero,#t01-equipo,#t02-garantia,#t04-mantencion,#t05-resenas,
    #t06-portafolio,#f03-planes,#f04-comparacion,#f05-packredes,
    #z01-faq,#z02-cierre)::after{
  content:"";
  position:absolute;
  left:0;
  right:0;
  bottom:0;
  height:var(--re-costura);
  z-index:0;
  pointer-events:none;
}
/* .subsec trae padding-block var(--s6) hacia abajo y divisor de 42/28px: con
   los 120px de la costura normal el resplandor le llegaría al contenido. */
:is(#f04-comparacion,#f05-packredes)::after{height:var(--re-costura-mini)}

/* Los cortes de cada gradiente están en 0% y 38%: a poco más de un tercio de
   subida ya va por la mitad. Así el brillo vive en la banda del divisor y no
   se estira hasta la última tarjeta. */

/* → hacia la NOCHE: se hunde. El negro que viene se filtra hacia arriba. */
:is(#t01-equipo,#t05-resenas,#z01-faq)::after{
  background:linear-gradient(to top,
              rgba(9,9,14,.12) 0%,
              rgba(27,49,201,.05) 38%,
              transparent 100%);
}
/* → hacia el AZUL: cinta y azul-noche piden azul franco. c01 remata contra el
   marquee (#2440ff con borde negro 2px, base.css:335) y z02 contra el borde
   superior azul de 2px del footer (chrome.css:125): en los dos casos la
   costura es el resplandor que anuncia ese azul antes de que aparezca. */
:is(#c01-hero,#t02-garantia,#z02-cierre)::after{
  background:linear-gradient(to top,
              rgba(36,64,255,.17) 0%,
              rgba(36,64,255,.07) 38%,
              transparent 100%);
}
/* → hacia el PAPEL: amanece. t06→f01 y f03→f04 son los dos saltos
   noche→claro más bruscos de la página; aquí la crema sube desde el borde. */
:is(#t06-portafolio,#f03-planes)::after{
  background:linear-gradient(to top,
              rgba(244,239,230,.16) 0%,
              rgba(244,239,230,.06) 38%,
              transparent 100%);
}
/* → claro a claro (t04→t04b mismo color sin divisor, f04→f05, f05→z01):
   un susurro. Si aquí hubiera contraste, inventaría una frontera donde el
   diseño decidió que no la hubiera. */
:is(#t04-mantencion,#f04-comparacion,#f05-packredes)::after{
  background:linear-gradient(to top,
              rgba(36,64,255,.055) 0%,
              transparent 100%);
}


/* ═══════════════════════════════════════════════════════════════════════════
   7 · EL FOOTER — el agujero que había que tapar
   chrome.css:125 declara .footer{position:relative;z-index:2}: el footer
   pinta su #060608 ENCIMA de mis capas fijas z:1. Sin esto, la atmósfera se
   corta de golpe en el borde superior del footer y se ve el escalón.
   z-index:-1 y no 0 a propósito: el footer SÍ es contexto de apilamiento
   (tiene z-index), así que -1 lo deja sobre su propio fondo y debajo de todo
   su contenido en flujo. Con 0 me pondría encima de los enlaces.
   ═══════════════════════════════════════════════════════════════════════════ */
.footer::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background:
    radial-gradient(100% 60% at 50% 0%,   rgba(36,64,255,.14),   transparent 68%),
    radial-gradient(70%  50% at 15% 100%, rgba(244,239,230,.04), transparent 70%);
}


/* ═══════════════════════════════════════════════════════════════════════════
   8 · CONVIVENCIA
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── t03 pineado: la atmósfera se aparta ────────────────────────────────────
   sections.js:313 pone html.t03-pinned mientras el ScrollTrigger de los 7
   días tiene la sección tomada, y sections.css:1267-1270 ya usa ese estado
   para apagar .lienzo y .wsp-bubble en móvil porque las piezas sueltas
   ensuciaban la escena. Mi luz hace exactamente lo mismo que .lienzo, así
   que toma exactamente la misma decisión: se retira. No estoy tocando t03
   ni sus hijos — estoy reaccionando a una clase de <html> que t03 ya publica.
   Especificidad: html.t03-pinned body::before = (0,1,2) > body[data-acto]::before
   = (0,1,1), así que gana sin !important. */
html.t03-pinned body::before,
html.t03-pinned body::after{opacity:.18}
@media(max-width:1079px){
  /* en móvil la escena de los 7 días es de pantalla completa y el cliente la ama
     tal cual: cero luz encima, igual que el lienzo */
  html.t03-pinned body::before,
  html.t03-pinned body::after{opacity:0}
}

/* ── Teléfono: menos capas de composición ──────────────────────────────────
   Cada capa fija a pantalla completa es una textura en memoria de la GPU
   (en un 390×844 @3x son ~12 MB cada una). En desktop van cuatro; en
   teléfono se apaga la de profundidad y quedan tres: las dos luces —que son
   las que cuentan la historia— y el grano. La viñeta es la que menos aporta
   en una pantalla angosta, donde los bordes están siempre a la vista y el
   ojo la lee como suciedad, no como bóveda. */
@media(max-width:760px){
  html::before{display:none}
}

/* ── Movimiento reducido ───────────────────────────────────────────────────
   OJO, esto no es decorativo: base.css:363-367 hace
   *,*::before,*::after{animation-duration:.01ms!important}. Sobre una
   animación de scroll timeline eso NO la detiene — le fija una duración
   ridícula y la deja clavada en el ÚLTIMO fotograma, así que la luz
   aparecería en su posición final desde el primer scroll. Hay que anularla
   por NOMBRE. Las luces quedan fijas, el grano queda, la atmósfera completa
   sigue existiendo: nadie pierde el diseño por pedir menos movimiento. */
@media(prefers-reduced-motion:reduce){
  body::before,
  body::after{
    animation-name:none;
    transition:none;
  }
}

/* ── Sin JS / sin GSAP ─────────────────────────────────────────────────────
   Sin GSAP no hay data-acto (lienzo.js:9 hace return antes de escribirlo) y
   la mezcla se queda en el .62/.55 por defecto, que es la tibia. html.no-gsap
   lo hace explícito para que el estado sin motor sea una decisión escrita y
   no un accidente heredado. Nada de esta capa necesita JS para existir. */
html.no-gsap body::before{opacity:.62}
html.no-gsap body::after {opacity:.55}

/* ── Impresión ─────────────────────────────────────────────────────────────
   Nadie quiere gastar tóner en atmósfera. */
@media print{
  html::before,html::after,
  body::before,body::after,
  .footer::before,
  :is(#c01-hero,#t01-equipo,#t02-garantia,#t04-mantencion,#t05-resenas,
      #t06-portafolio,#f03-planes,#f04-comparacion,#f05-packredes,
      #z01-faq,#z02-cierre)::before,
  :is(#c01-hero,#t01-equipo,#t02-garantia,#t04-mantencion,#t05-resenas,
      #t06-portafolio,#f03-planes,#f04-comparacion,#f05-packredes,
      #z01-faq,#z02-cierre)::after{display:none}
}
