/* ═══ DOTD atmosphere · layer styles ═══════════════════════════════════════════
   The module builds its own DOM inside the mount element. This file styles it.
   Four of the seven layers are pure CSS and cost nothing per frame; the other
   three share one canvas. See assets/atmos.js.
   ------------------------------------------------------------------------- */

.atmos{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0;
  /* state response — the scene knows when the server is down (2s, never instant) */
  transition:filter 2s var(--ease-breathe,cubic-bezier(.45,0,.55,1)),
             opacity 2s var(--ease-breathe,cubic-bezier(.45,0,.55,1))}
.atmos>*{position:absolute;inset:0}

/* 1 · void wash */
.atmos-sky{
  background:
    radial-gradient(120% 80% at 50% 34%, var(--night-3,#041C3C) 0%, var(--night-1,#041424) 38%, var(--void,#040C1C) 74%),
    linear-gradient(180deg, var(--void,#040C1C) 0%, #04121C 62%, #04161A 100%);
}

/* 2 · stars  3 · treeline  5 · dust — one canvas, one RAF */
.atmos-canvas{width:100%;height:100%;display:block}

/* 4 · ground fog */
.atmos-fog{
  background:
    radial-gradient(150% 44% at 22% 108%, rgba(4,28,44,.62), transparent 70%),
    radial-gradient(140% 40% at 78% 112%, rgba(4,36,52,.44), transparent 72%);
  animation:atmosFog 34s cubic-bezier(.45,0,.55,1) infinite alternate;
}
@keyframes atmosFog{from{transform:translate3d(-2.5%,0,0)}to{transform:translate3d(2.5%,-1.5%,0) scaleY(1.06)}}

/* 6 · film grain — stepped to ≈12fps on purpose. Below frame rate reads as film;
       at frame rate it reads as sensor noise. Most mood per millisecond on the page,
       which is why the quality ladder freezes it last rather than dropping it. */
.atmos-grain{
  opacity:.16;mix-blend-mode:screen;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  animation:atmosGrain .83s steps(1,end) infinite;
}
@keyframes atmosGrain{
  0%{background-position:0 0}          12.5%{background-position:-32px 14px}
  25%{background-position:24px -28px}  37.5%{background-position:-18px -34px}
  50%{background-position:36px 22px}   62.5%{background-position:-40px 8px}
  75%{background-position:14px 38px}   87.5%{background-position:-26px -12px}
}

/* 7 · vignette */
.atmos-vignette{
  background:radial-gradient(108% 92% at 50% 46%, transparent 44%, rgba(2,6,14,.62) 88%, rgba(1,4,10,.86) 100%);
}

/* ── no quality switches here, by design ────────────────────────────────────
   Every layer is present on every device. Adaptation happens in JS, and only
   to the NUMBER of stars and motes — never by hiding a layer. If you are ever
   tempted to add a `display:none` for performance, lower the density instead. */

/* ── server state ───────────────────────────────────────────────────────────
   down: the page feels offline before you have read the word.
   unknown: nothing changes — we do not perform an outage we have not confirmed. */
.atmos[data-state="down"]{filter:saturate(.35) brightness(.72)}

/* ── reduced motion ─────────────────────────────────────────────────────────
   Everything stops; nothing disappears. It becomes a painting, not a blank page. */
@media (prefers-reduced-motion:reduce){
  .atmos-fog,.atmos-grain{animation:none}
}
