.ambient{
  position:fixed; inset:0; z-index:0; pointer-events:none;
  background:
    radial-gradient(ellipse 42% 32% at 10% 18%, rgba(199,123,58,.08), transparent 70%),
    radial-gradient(ellipse 36% 28% at 90% 35%, rgba(199,123,58,.06), transparent 70%),
    radial-gradient(ellipse 46% 34% at 25% 82%, rgba(199,123,58,.07), transparent 70%),
    radial-gradient(ellipse 40% 30% at 80% 95%, rgba(199,123,58,.055), transparent 70%);
  animation:ambientDrift 42s ease-in-out infinite alternate;
}
/* roaming shadows — clouds passing somewhere above the forest; almost imperceptible */
.ambient::before{
  content:""; position:absolute; inset:-20%;
  background:
    radial-gradient(ellipse 38% 30% at 30% 30%, rgba(0,0,0,.16), transparent 70%),
    radial-gradient(ellipse 44% 34% at 75% 65%, rgba(0,0,0,.13), transparent 72%);
  animation:shadowRoam 74s ease-in-out infinite alternate;
}
/* thin travelling smoke shared by every dark chapter — one continuous environment */
.ambient::after{
  content:""; position:absolute; inset:-15%;
  mix-blend-mode:screen; opacity:.5;
  background:
    radial-gradient(ellipse 50% 18% at 60% 22%, rgba(170,160,148,.07), transparent 70%),
    radial-gradient(ellipse 60% 22% at 25% 70%, rgba(170,160,148,.06), transparent 72%),
    radial-gradient(ellipse 44% 16% at 85% 88%, rgba(170,160,148,.05), transparent 70%);
  animation:smokeRoam 58s ease-in-out infinite alternate;
}
@keyframes ambientDrift{0%{transform:translate(0,0) scale(1)}100%{transform:translate(-2.5%,2%) scale(1.04)}}
@keyframes shadowRoam{0%{transform:translate(0,0) rotate(0deg)}100%{transform:translate(3%,-2%) rotate(1.2deg)}}
@keyframes smokeRoam{0%{transform:translate(-2%,1%) scale(1)}100%{transform:translate(2.5%,-1.5%) scale(1.05)}}
html.reduced .ambient, html.reduced .ambient::before, html.reduced .ambient::after{animation:none}
/* mobile: fixed full-screen blend-mode overlays force per-frame full repaints on
   Android Chrome — grain reads as lightning flashes, scroll goes heavy */
@media(max-width:768px){
  .grain{display:none}
  .ambient{animation:none}
  .ambient::before,.ambient::after{animation:none}
}

.grain{
  position:fixed; inset:-100%; pointer-events:none; z-index:900; opacity:.05; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 8s steps(5) infinite;
}
@keyframes grain{0%,100%{transform:translate(0,0)}25%{transform:translate(-4%,3%)}50%{transform:translate(3%,-5%)}75%{transform:translate(-3%,4%)}}

.vignette{position:fixed;inset:0;pointer-events:none;z-index:850;
  box-shadow:inset 0 0 22vw 4vw rgba(0,0,0,.55);}

/* ---------- reveal on scroll ---------- */
.reveal{opacity:0; transform:translateY(18px); transition:opacity .6s var(--ease), transform .6s var(--ease)}
.reveal.in{opacity:1; transform:translateY(0)}
.reveal-line{position:relative; overflow:hidden}
.reveal-line > span{display:inline-block; transform:translateY(105%); transition:transform .6s var(--ease)}
.reveal-line.in > span{transform:translateY(0)}

/* ---------- ember particles ---------- */
.ember-particle{position:absolute; bottom:-2%; width:3px; height:3px; border-radius:50%; background:var(--ember); opacity:0; box-shadow:0 0 22px 4px rgba(199,123,58,.55); animation:rise linear infinite}
@keyframes rise{
  0%{opacity:0; transform:translateY(0) translateX(0) scale(.6)}
  10%{opacity:1; transform:translateY(-8vh) translateX(0) scale(1)}
  85%{opacity:.55}
  100%{opacity:0; transform:translateY(-100vh) translateX(var(--drift,20px)) scale(.7)}
}
