/*
    world.css — Milestone 18, Phase B: the Living World parallax background.

    Renders inside the pre-existing #particles-js hook (position:fixed; inset:0; z-index:-1;
    already on every page via includes/header.php). Layer order back-to-front:
    celestial -> clouds -> far-ridge -> hills -> forest -> ground -> fauna -> scrim.

    THREE HARD CONSTRAINTS — breaking any of these silently wrecks the page, not just the effect:

    1. Never set a `background` on `html`. `body`'s background propagates up to the canvas, and
       that propagation is the ONLY reason a z-index:-1 child (#particles-js) paints above the
       canvas instead of being clipped by it. This is why the world is visible on home.php/
       pricing.php despite neither using the `.z-1` Bootstrap utility the other ~29 pages wrap
       their content in. Do not "fix" that inconsistency — it isn't one.
    2. Never put `transform` / `filter` / `backdrop-filter` / `contain: paint` on `body` or
       `.main-content`. Any one of those makes that element a new containing block for its fixed
       descendants, which simultaneously breaks the world, the `fixed-top` navbar, AND every
       Bootstrap modal (modals are `position: fixed` too).
    3. A CSS animation on `transform` overrides an inline `transform`. That's why the cloud-drift
       keyframe below targets the CHILD <svg>, never the parent `.world-layer` div — the parent is
       what world-background.js writes `translate3d(...)` onto every frame for the parallax
       effect, and a competing CSS animation on that same element would just win outright.
*/

#particles-js {
    /* The sky itself is a plain CSS gradient between two custom properties, not part of any SVG —
       includes/world-background.php sets both inline for first paint (Asia/Bangkok server time,
       zero flash), world-background.js re-lerps them every 60s afterward via the same anchor
       table mirrored in both languages. */
    background: linear-gradient(180deg, var(--world-sky-top, #8FD8F5) 0%, var(--world-sky-bottom, #C9EEFF) 100%);
    overflow: hidden;
    transition: background 3s ease;
}

.world {
    position: absolute;
    inset: 0;
}

.world-layer {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.world-layer svg {
    display: block;
    width: 100%;
    height: 100%;
}

/* The 5 layers world-background.js writes a per-frame translate3d() onto for mouse/scroll
   parallax. will-change is declared statically here, once, never toggled per-frame — toggling it
   defeats its own purpose (the browser would keep re-promoting/demoting the layer to its own
   compositor tile instead of leaving it promoted). Celestial and ground are deliberately excluded:
   celestial's sun/moon position is time-driven, not mouse-driven, and ground is the foreground
   anchor the rest of the scene parallaxes against. */
.world-layer--clouds,
.world-layer--far-ridge,
.world-layer--hills,
.world-layer--forest,
.world-layer--fauna {
    will-change: transform;
}

/* --- Celestial: sky gradient (via #particles-js background above) + sun/moon/stars ---
   Position AND opacity are both driven by CSS custom properties lerped from the same anchor
   table in PHP (first paint) and JS (every 60s after) — this is the "sun arcs across the sky"
   motion the plan asked for, without a per-frame animation loop for something that only needs to
   visibly move a few times an hour. */
.sun-block,
.moon-block {
    position: absolute;
    width: 40px;
    height: 40px;
    left: var(--world-sun-x, 50%);
    top: var(--world-sun-y, 10%);
    transition: left 60s linear, top 60s linear, opacity 3s ease;
}
.moon-block {
    left: var(--world-moon-x, 50%);
    top: var(--world-moon-y, 10%);
}
.sun-block { opacity: var(--world-sun-opacity, 0); }
.moon-block { opacity: var(--world-moon-opacity, 0); }

/* --world-star-opacity is the day/night dimmer (near-0 at noon, ~0.9 at night, from the same
   lerped anchor table as the sky). The twinkle keyframe multiplies it down to 40% at its dimmest
   point via calc() rather than animating between two fixed numbers, so a single set of keyframes
   still respects the current time of day with zero JS DOM changes. */
.star {
    opacity: var(--world-star-opacity, 0);
    transition: opacity 3s ease;
    animation: star-twinkle 3s ease-in-out infinite;
}
.star:nth-child(2n) { animation-duration: 4s; animation-delay: -1s; }
.star:nth-child(3n) { animation-duration: 2.4s; animation-delay: -2s; }
@keyframes star-twinkle {
    0%, 100% { opacity: var(--world-star-opacity, 0); }
    50%      { opacity: calc(var(--world-star-opacity, 0) * 0.4); }
}

/* --- Clouds: drift horizontally, forever, via a CSS animation on the child <svg> (constraint 3) --- */
.world-layer--clouds svg {
    animation: cloud-drift 90s linear infinite;
}
@keyframes cloud-drift {
    from { transform: translateX(-15%); }
    to   { transform: translateX(15%); }
}

/* --- Fauna: birds by day, fireflies by night --- */
.fauna-bird,
.fauna-firefly {
    position: absolute;
}
.fauna-bird {
    animation: bird-flutter 6s ease-in-out infinite;
    transform-origin: center;
}
.fauna-bird:nth-child(2) { animation-delay: -2s; animation-duration: 7s; }
.fauna-bird:nth-child(3) { animation-delay: -4s; animation-duration: 5s; }
@keyframes bird-flutter {
    0%, 100% { transform: translate(0, 0); }
    50%      { transform: translate(-24px, -10px); }
}
.fauna-firefly {
    animation: firefly-flicker 2.6s ease-in-out infinite;
}
.fauna-firefly:nth-child(2n) { animation-delay: -1s; animation-duration: 3.2s; }
.fauna-firefly:nth-child(3n) { animation-delay: -1.7s; animation-duration: 2s; }
@keyframes firefly-flicker {
    0%, 100% { opacity: 0.15; transform: translate(0, 0); }
    50%      { opacity: 1;    transform: translate(6px, -8px); }
}
/* .world[data-night] is set once, server-side, by world-background.php from the same lerped
   sun/moon opacity used for the sky and re-evaluated by world-background.js's 60s timer — birds
   swap for fireflies at the same threshold the stars start fading in at (sun opacity < 0.5). */
.world[data-night="0"] .fauna-firefly { display: none; }
.world[data-night="1"] .fauna-bird { display: none; }

/* --- Scrim: static (non-parallax) vignette so foreground text/cards stay legible over a busier
   background — the world's horizon and detail stay in the lower third and outer 15% precisely so
   this scrim only ever has to soften edges, never cover the interesting part of the scene. --- */
.world-layer--scrim {
    background: linear-gradient(
        180deg,
        rgba(255, 247, 230, 0.35) 0%,
        rgba(255, 247, 230, 0.05) 18%,
        rgba(255, 247, 230, 0.05) 70%,
        rgba(255, 247, 230, 0.45) 100%
    );
    pointer-events: none;
}

/* --- Reduced motion: stop ALL animation (parallax, drift, twinkle, flutter) but KEEP the world
   and the day/night colour — world-background.js checks this same query before ever installing
   its mousemove/scroll listeners or starting its rAF loop, so this isn't just a CSS fallback, the
   JS work never happens at all. --- */
@media (prefers-reduced-motion: reduce) {
    .world-layer--clouds svg,
    .star,
    .fauna-bird,
    .fauna-firefly {
        animation: none !important;
    }
}

/* --- Lite mode: applied by world-background.js on low-end/small-viewport devices. Drops the two
   most decorative, least-load-bearing layers (celestial's stars/fauna) and removes will-change
   promotion from the remaining moving layers, trading a slightly flatter scene for meaningfully
   less compositor/paint work. --- */
.world--lite .world-layer--fauna,
.world--lite .star {
    display: none;
}
.world--lite .world-layer--clouds,
.world--lite .world-layer--far-ridge,
.world--lite .world-layer--hills,
.world--lite .world-layer--forest {
    will-change: auto;
}

/* --- The 4 auth pages' old blurred-glass ambient orbs (assets/css/dashboard.css's .bg-orb) are
   visually incompatible with the new world scenery and were the single most expensive element on
   those pages (a 400px, filter:blur(80px) circle). Hidden wherever the world is present. See
   assets/css/dashboard.css's own .bg-orb rule for the definition being overridden. --- */
.bg-orb {
    display: none;
}
