/* =====================================================================
   Live Weather Theme — Monir Hasan
   A fixed "sky" layer behind the whole site that reflects the visitor's
   real local time of day and the current weather conditions.

   Readability first, but not at the sky's expense. The page text is
   #eef2fb, which needs a background luminance under about 0.16 to clear
   WCAG AA. The old scrim pushed it down to roughly 0.02 — five times darker
   than it had to be — which is why every theme looked like the same black
   page. The scrim now aims just inside the limit instead of far past it, so
   the sky is genuinely visible and the contrast still passes.

   What makes a painted sky read as a real one, in order of how much it
   matters: a horizon, light coming from where the sun actually is, and a
   vertical colour structure that goes zenith -> mid -> warm haze rather
   than a flat two-tone fade. All three are built below.

   State is driven by two attributes set on <html> by weather.js:
     data-sky     = dawn | morning | day | afternoon | sunset | dusk | night
     data-weather = clear | cloudy | overcast | fog | drizzle | rain | snow | thunder
   ===================================================================== */

.sky {
    position: fixed;
    inset: 0;
    z-index: -3;
    overflow: hidden;
    pointer-events: none;
    contain: strict;
}

/* ---------- Stacking order inside the sky ----------
   The scrim is a dark sheet that guarantees text contrast, so it has to sit
   above the weather. Lightning is the one exception: it must
   flash ABOVE the scrim, otherwise the scrim swallows it and a thunderstorm
   looks like an ordinary grey sky. That was the bug. The flash peaks briefly
   and blends rather than covers, so text stays readable through a strike. */
.sky-gradient { z-index: 0; }
.sky-stars    { z-index: 1; }
.sky-sun,
.sky-moon     { z-index: 2; }
.sky-clouds   { z-index: 3; }
.sky-rain,
.sky-snow,
.sky-splash,
.sky-fog      { z-index: 4; }
.sky-scrim    { z-index: 5; }
.sky-flash    { z-index: 6; }
.sky-bolt     { z-index: 7; }

/* ---------- Base gradient: time of day ----------
   Each phase is three stacked background layers on ONE element, not three
   elements. Background layers cost the compositor almost nothing; extra
   animated divs cost style and layout on every frame, and this page already
   carries ~170 particles.

     layer 1 (top)  sun glow      light spilling from where the sun actually is
     layer 2        horizon haze  the bright band that makes a sky feel deep
     layer 3        base ramp     zenith -> mid -> horizon -> below-horizon

   The five-stop base ramp is the part that reads as real. A sky is never a
   two-tone fade: it is darkest and most saturated straight up, and turns
   pale and warm as it approaches the horizon, because you are looking
   through more air. */
.sky-gradient {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, #070a14 0%, #0b1020 60%, #070a14 100%);
    transition: background 2.5s ease;
}

[data-sky="dawn"] .sky-gradient {
    background:
        radial-gradient(ellipse 70% 45% at 84% 58%, rgba(255, 150, 120, 0.30), transparent 68%),
        linear-gradient(180deg, transparent 50%, rgba(255, 170, 140, 0.16) 76%, rgba(255, 190, 160, 0.10) 88%, transparent 100%),
        linear-gradient(180deg, #0d1730 0%, #1e2145 28%, #3a2b4e 54%, #6b4050 78%, #241a2a 100%);
}
[data-sky="morning"] .sky-gradient {
    background:
        radial-gradient(ellipse 60% 40% at 84% 34%, rgba(255, 225, 180, 0.24), transparent 66%),
        linear-gradient(180deg, transparent 52%, rgba(190, 215, 235, 0.16) 80%, transparent 100%),
        linear-gradient(180deg, #0d2444 0%, #17406a 30%, #2a628c 58%, #5c8caa 82%, #16202f 100%);
}
[data-sky="day"] .sky-gradient {
    background:
        radial-gradient(ellipse 55% 38% at 84% 13%, rgba(255, 244, 214, 0.28), transparent 64%),
        linear-gradient(180deg, transparent 50%, rgba(196, 224, 240, 0.18) 80%, transparent 100%),
        linear-gradient(180deg, #0a2b52 0%, #12457a 30%, #1e6499 58%, #5793b6 82%, #16283c 100%);
}
[data-sky="afternoon"] .sky-gradient {
    background:
        radial-gradient(ellipse 58% 40% at 84% 26%, rgba(255, 232, 190, 0.24), transparent 66%),
        linear-gradient(180deg, transparent 50%, rgba(224, 216, 210, 0.16) 80%, transparent 100%),
        linear-gradient(180deg, #0e2740 0%, #1a3f5e 30%, #2d5c7c 58%, #6a8ea3 82%, #151d2b 100%);
}
[data-sky="sunset"] .sky-gradient {
    background:
        radial-gradient(ellipse 75% 45% at 84% 62%, rgba(255, 150, 90, 0.38), transparent 66%),
        linear-gradient(180deg, transparent 44%, rgba(255, 120, 80, 0.22) 72%, rgba(255, 170, 110, 0.16) 86%, transparent 100%),
        linear-gradient(180deg, #101a38 0%, #2e2350 26%, #6a3556 52%, #a85440 78%, #2a1820 100%);
}
[data-sky="dusk"] .sky-gradient {
    background:
        radial-gradient(ellipse 80% 35% at 70% 88%, rgba(190, 110, 120, 0.20), transparent 70%),
        linear-gradient(180deg, transparent 58%, rgba(140, 140, 200, 0.12) 84%, transparent 100%),
        linear-gradient(180deg, #060a1c 0%, #101433 30%, #1e1b45 58%, #3a2a4e 84%, #0d0b1a 100%);
}
[data-sky="night"] .sky-gradient {
    background:
        radial-gradient(ellipse 90% 30% at 50% 96%, rgba(60, 90, 140, 0.22), transparent 72%),
        linear-gradient(180deg, transparent 62%, rgba(70, 100, 150, 0.10) 88%, transparent 100%),
        linear-gradient(180deg, #03050d 0%, #060a1a 32%, #0a1026 62%, #101a33 88%, #060a14 100%);
}

/* Heavier cloud cover mutes and greys the whole sky. */
[data-weather="overcast"] .sky-gradient,
[data-weather="rain"] .sky-gradient,
[data-weather="thunder"] .sky-gradient { filter: saturate(0.55) brightness(0.72); }
[data-weather="fog"] .sky-gradient { filter: saturate(0.35) brightness(0.85) blur(2px); }

/* ---------- Scrim: guarantees text contrast over any sky ----------
   Measured, not guessed. The page text is #eef2fb, which needs the surface
   behind it under about 0.16 relative luminance for WCAG AA. The previous
   scrim reached 0.53 alpha at the very top of the screen and 0.96 at the
   bottom, which put the composite near 0.02 — five times darker than
   required, and the reason every theme looked like the same black page.

   These values land the brightest phase (Bright Day) at roughly 5:1 behind
   the hero text while letting the actual sky through at the top. */
.sky-scrim {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(180deg,
            rgba(7, 10, 20, 0.30) 0%,
            rgba(7, 10, 20, 0.46) 34%,
            rgba(7, 10, 20, 0.68) 68%,
            rgba(7, 10, 20, 0.82) 100%),
        radial-gradient(ellipse 120% 70% at 50% 0%, rgba(7, 10, 20, 0) 0%, rgba(7, 10, 20, 0.25) 70%, rgba(7, 10, 20, 0.45) 100%);
}

/* ---------- Sun ----------
   The sun moves with transform, not `top`. Animating `top` forces the browser
   to re-lay-out and re-paint the sun on every frame of the 2.5s transition,
   which Lighthouse reports as a non-composited animation and which also
   registered as a small layout shift. transform runs on the compositor: no
   layout, no paint, no shift.

   --sun-y is a plain number, multiplied by --sky-h to get a length. --sky-h is
   1vh on the real page; the admin preview tiles are 116px tall, so they set
   --sky-h: 1.16px and the same numbers land in the same relative spots. */
.sky-sun {
    position: absolute;
    top: 0;
    right: 16%;
    width: 120px;
    height: 120px;
    border-radius: 50%;
    opacity: 0;
    background: radial-gradient(circle at 50% 50%, rgba(255, 236, 190, 0.95), rgba(255, 190, 110, 0.5) 45%, transparent 70%);
    filter: blur(2px);
    transform: translate3d(0, calc(var(--sun-y, 16) * var(--sky-h, 1vh)), 0);
    transition: opacity 2.5s ease, transform 2.5s ease, background 2.5s ease;
}
[data-sky="dawn"]      .sky-sun { opacity: 0.5; --sun-y: 58; background: radial-gradient(circle, rgba(255, 190, 150, 0.85), rgba(255, 130, 110, 0.4) 45%, transparent 70%); }
[data-sky="morning"]   .sky-sun { opacity: 0.65; --sun-y: 34; }
[data-sky="day"]       .sky-sun { opacity: 0.75; --sun-y: 13; }
[data-sky="afternoon"] .sky-sun { opacity: 0.6; --sun-y: 26; }
[data-sky="sunset"]    .sky-sun { opacity: 0.55; --sun-y: 62; background: radial-gradient(circle, rgba(255, 170, 120, 0.9), rgba(230, 90, 80, 0.45) 45%, transparent 70%); }

/* The sun is hidden when the sky is covered. */
[data-weather="overcast"] .sky-sun,
[data-weather="rain"] .sky-sun,
[data-weather="snow"] .sky-sun,
[data-weather="thunder"] .sky-sun,
[data-weather="fog"] .sky-sun { opacity: 0.12; }

/* ---------- Moon (night, only when the sky is reasonably clear) ---------- */
.sky-moon {
    position: absolute;
    top: 14%;
    right: 18%;
    width: 84px;
    height: 84px;
    border-radius: 50%;
    opacity: 0;
    background: radial-gradient(circle at 36% 34%, #fdfbf2 0%, #e8ecf7 55%, #c3cbdd 100%);
    box-shadow:
        0 0 32px rgba(210, 226, 255, 0.5),
        0 0 90px rgba(150, 190, 255, 0.28);
    transition: opacity 2.5s ease;
}
/* Crescent shade — a darker disc offset over the moon. */
.sky-moon::after {
    content: '';
    position: absolute;
    top: -12%;
    right: -16%;
    width: 84%;
    height: 108%;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 50%, #060a16 60%, rgba(6, 10, 22, 0.85) 100%);
}
[data-sky="dusk"]  .sky-moon,
[data-sky="night"] .sky-moon { opacity: 0.9; }
[data-sky="dawn"]  .sky-moon { opacity: 0.35; }

[data-weather="overcast"] .sky-moon,
[data-weather="rain"] .sky-moon,
[data-weather="thunder"] .sky-moon,
[data-weather="fog"] .sky-moon { opacity: 0.1; }

/* ---------- Stars ---------- */
.sky-stars {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 2.5s ease;
}

/* The Milky Way. A real dark sky is not evenly speckled — it has a bright,
   dusty band running across it, and that band is most of what makes a night
   sky read as photographic rather than as dots on black.

   It is a pseudo-element, not a div: no extra node, and because nothing
   animates it, the browser paints it once and never touches it again. It
   inherits the parent's opacity, so it appears and hides with the stars. */
.sky-stars::before {
    content: '';
    position: absolute;
    top: -18%;
    left: -30%;
    width: 160%;
    height: 90%;
    transform: rotate(-24deg);
    background:
        radial-gradient(ellipse 42% 46% at 34% 52%, rgba(198, 214, 255, 0.16), transparent 70%),
        radial-gradient(ellipse 34% 40% at 68% 46%, rgba(226, 210, 255, 0.13), transparent 72%),
        linear-gradient(180deg,
            transparent 34%,
            rgba(186, 202, 246, 0.05) 44%,
            rgba(214, 224, 255, 0.11) 50%,
            rgba(186, 202, 246, 0.05) 57%,
            transparent 68%);
    /* One blur on one element that never moves is cheap. One blur per particle
       is not — which is why the drops and flakes no longer have one. */
    filter: blur(14px);
}
[data-sky="dusk"]  .sky-stars { opacity: 0.5; }
[data-sky="night"] .sky-stars { opacity: 1; }
[data-sky="dawn"]  .sky-stars { opacity: 0.3; }

/* Clouds hide the stars — "stars only when the sky is clear". */
[data-weather="overcast"] .sky-stars,
[data-weather="rain"] .sky-stars,
[data-weather="thunder"] .sky-stars,
[data-weather="snow"] .sky-stars,
[data-weather="fog"] .sky-stars { opacity: 0.06 !important; }
[data-weather="cloudy"] .sky-stars { opacity: 0.45; }

/* Real stars are not white. They run from cool blue-white through yellow to
   faint orange, and that spread of colour is the second thing (after the
   Milky Way) that separates a night sky from a field of identical dots.
   --tint is set per star in weather.js. */
.star {
    position: absolute;
    border-radius: 50%;
    background: var(--tint, #fff);
    animation: twinkle var(--dur, 4s) ease-in-out var(--delay, 0s) infinite;
}

@keyframes twinkle {
    0%, 100% { opacity: 0.15; transform: scale(0.8); }
    50%      { opacity: 1;    transform: scale(1.15); }
}

/* A slow shooting star on clear nights. */
.shooting-star {
    position: absolute;
    width: 130px;
    height: 1.5px;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0), #fff, rgba(255, 255, 255, 0));
    opacity: 0;
    animation: shoot 9s ease-in var(--delay, 4s) infinite;
}

@keyframes shoot {
    0%       { opacity: 0; transform: translate(0, 0) rotate(18deg) scaleX(0.2); }
    3%       { opacity: 1; }
    12%      { opacity: 0; transform: translate(340px, 150px) rotate(18deg) scaleX(1); }
    100%     { opacity: 0; transform: translate(340px, 150px) rotate(18deg) scaleX(1); }
}

/* ---------- Clouds ---------- */
.sky-clouds {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 2.5s ease;
}
[data-weather="cloudy"]   .sky-clouds { opacity: 0.5; }
[data-weather="overcast"] .sky-clouds { opacity: 0.85; }
[data-weather="rain"]     .sky-clouds { opacity: 0.9; }
[data-weather="drizzle"]  .sky-clouds { opacity: 0.7; }
[data-weather="snow"]     .sky-clouds { opacity: 0.8; }
[data-weather="thunder"]  .sky-clouds { opacity: 0.95; }
[data-weather="fog"]      .sky-clouds { opacity: 0.6; }

/* A single blurred ellipse reads as a smudge. Four overlapping lobes of
   different sizes, with a flatter and darker base, reads as a cloud: puffy
   on top, heavy and flat underneath, the way real cumulus sits. */
.cloud {
    position: absolute;
    border-radius: 999px;
    background:
        radial-gradient(ellipse 40% 76% at 26% 52%, rgba(198, 212, 236, 0.46), transparent 72%),
        radial-gradient(ellipse 34% 96% at 50% 38%, rgba(208, 221, 243, 0.50), transparent 74%),
        radial-gradient(ellipse 42% 68% at 74% 54%, rgba(190, 205, 230, 0.42), transparent 72%),
        radial-gradient(ellipse 78% 42% at 50% 74%, rgba(150, 168, 200, 0.30), transparent 78%);
    filter: blur(13px);
    animation: drift var(--dur, 90s) linear var(--delay, 0s) infinite;
}
/* Night clouds are darker so they read as silhouettes, not glowing blobs. */
[data-sky="night"] .cloud,
[data-sky="dusk"] .cloud {
    background:
        radial-gradient(ellipse 40% 76% at 26% 52%, rgba(96, 112, 145, 0.42), transparent 72%),
        radial-gradient(ellipse 34% 96% at 50% 38%, rgba(104, 120, 154, 0.46), transparent 74%),
        radial-gradient(ellipse 42% 68% at 74% 54%, rgba(92, 106, 138, 0.40), transparent 72%),
        radial-gradient(ellipse 78% 42% at 50% 74%, rgba(50, 62, 88, 0.30), transparent 78%);
}
/* Rain-bearing cloud: darker, denser, less blurred at the base. */
[data-weather="rain"] .cloud,
[data-weather="overcast"] .cloud { filter: blur(12px) brightness(0.66); }
[data-weather="thunder"] .cloud   { filter: blur(11px) brightness(0.5) contrast(1.15); }

@keyframes drift {
    from { transform: translateX(-30vw); }
    to   { transform: translateX(130vw); }
}

/* ---------- Rain ----------
   Rain never falls straight down and it is never all the same distance away.
   Three things make it read as real:
     1. One shared wind angle. Every drop leans and travels the same way, so
        the eye reads "wind", not "random streaks".
     2. Depth. Far drops are thin, short, pale and slow; near drops are thick,
        long, bright and fast. JS assigns each drop a layer.
     3. It lands. Splash rings at the bottom finish the illusion.

   The container is wider than the screen because slanted drops have to enter
   from off the left edge, or the top-left corner stays permanently dry. */
.sky-rain {
    position: absolute;
    inset: -12% -22% 0 -22%;
    opacity: 0;
    transition: opacity 1.2s ease;
}
[data-weather="rain"]    .sky-rain { opacity: 1; }
[data-weather="drizzle"] .sky-rain { opacity: 0.55; }
[data-weather="thunder"] .sky-rain { opacity: 1; }

/* No filter: blur() here, deliberately. A blur forces the browser to give that
   one element its own render surface, and there are up to 130 drops — that
   alone was a measurable slice of the main-thread style-and-layout time. The
   softness of a distant drop is carried by the gradient instead: far drops are
   sub-pixel thin and low-opacity, which the antialiaser already renders soft.
   Same look, no extra surfaces. */
.raindrop {
    position: absolute;
    top: 0;
    width: var(--w, 1.5px);
    height: var(--len, 78px);
    border-radius: 999px;
    /* Faint tail, bright head — a drop smeared by its own speed. */
    background: linear-gradient(180deg,
        rgba(174, 208, 255, 0) 0%,
        rgba(190, 220, 255, 0.32) 45%,
        rgba(228, 241, 255, 0.92) 100%);
    animation: fall var(--dur, 0.8s) linear var(--delay, 0s) infinite;
}
[data-weather="drizzle"] .raindrop { height: calc(var(--len, 78px) * 0.45); opacity: 0.7; }
/* A downpour: heavier and brighter. Done with a brighter gradient rather than
   filter: brightness(), for the same render-surface reason. */
[data-weather="thunder"] .raindrop {
    background: linear-gradient(180deg,
        rgba(198, 226, 255, 0) 0%,
        rgba(214, 235, 255, 0.4) 45%,
        rgba(255, 255, 255, 1) 100%);
}

/* --tilt is negative because a positive (clockwise) rotation would lean the
   streak against its own direction of travel. --drift is in vh, not vw, so
   the slant angle stays the same on a phone and on a widescreen monitor. */
@keyframes fall {
    from { transform: translate3d(0, -18vh, 0) rotate(var(--tilt, -8deg)); }
    to   { transform: translate3d(var(--drift, 20vh), 118vh, 0) rotate(var(--tilt, -8deg)); }
}

/* Splash rings where the rain meets the bottom of the screen. */
.sky-splash {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 14vh;
    opacity: 0;
    transition: opacity 1.2s ease;
}
[data-weather="rain"]    .sky-splash { opacity: 0.85; }
[data-weather="thunder"] .sky-splash { opacity: 1; }
[data-weather="drizzle"] .sky-splash { opacity: 0.4; }

.splash {
    position: absolute;
    bottom: var(--y, 3vh);
    width: var(--size, 26px);
    height: calc(var(--size, 26px) * 0.32);
    border-radius: 50%;
    border: 1px solid rgba(196, 224, 255, 0.55);
    border-top-color: transparent;
    opacity: 0;
    animation: splash-ring var(--dur, 1.4s) ease-out var(--delay, 0s) infinite;
}

@keyframes splash-ring {
    0%   { opacity: 0;    transform: scale(0.15); }
    10%  { opacity: 0.7; }
    60%  { opacity: 0.18; }
    100% { opacity: 0;    transform: scale(1.3); }
}

/* ---------- Snow ---------- */
.sky-snow {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 1.2s ease;
}
[data-weather="snow"] .sky-snow { opacity: 1; }

/* The soft halo used to be a box-shadow plus a blur filter — two things that
   each cost the compositor real work, on every flake. A radial gradient that
   fades to transparent gives the same soft-edged flake as part of the
   element's own paint, for free. */
.snowflake {
    position: absolute;
    top: -6%;
    background: radial-gradient(circle at 50% 50%,
        rgba(255, 255, 255, 0.95) 0%,
        rgba(255, 255, 255, 0.72) 38%,
        rgba(220, 236, 255, 0.22) 68%,
        rgba(220, 236, 255, 0) 100%);
    animation: snowfall var(--dur, 12s) linear var(--delay, 0s) infinite;
}

/* Snow does not fall, it wanders down. Four sway points instead of one give
   each flake a drifting S-path; --sway is set per flake so near flakes swing
   wide and distant ones barely move.

   There used to be a rotate() on each step. A round flake looks identical at
   every angle, so it was interpolating a rotation nobody could see. */
@keyframes snowfall {
    0%   { transform: translate3d(0, -8vh, 0); }
    25%  { transform: translate3d(var(--sway, 24px), 22vh, 0); }
    50%  { transform: translate3d(calc(var(--sway, 24px) * -0.8), 52vh, 0); }
    75%  { transform: translate3d(calc(var(--sway, 24px) * 0.6), 82vh, 0); }
    100% { transform: translate3d(0, 112vh, 0); }
}

/* ---------- Fog ---------- */
.sky-fog {
    position: absolute;
    inset: 0;
    opacity: 0;
    background:
        linear-gradient(180deg, transparent 0%, rgba(190, 202, 222, 0.12) 45%, rgba(190, 202, 222, 0.18) 72%, transparent 100%);
    transition: opacity 2s ease;
}
/* Two banks of mist sliding past each other at different speeds. A single
   layer moving as one block looks like a sheet of grey; two layers at
   different rates read as depth, which is what real fog does. */
.sky-fog::before,
.sky-fog::after {
    content: '';
    position: absolute;
    inset: -20% -40%;
    background:
        radial-gradient(ellipse 55% 30% at 22% 62%, rgba(206, 216, 234, 0.22), transparent 70%),
        radial-gradient(ellipse 48% 24% at 68% 48%, rgba(196, 208, 228, 0.18), transparent 72%),
        radial-gradient(ellipse 62% 22% at 46% 80%, rgba(186, 198, 220, 0.20), transparent 74%);
    filter: blur(16px);
}
.sky-fog::after {
    inset: -10% -40% 10%;
    opacity: 0.7;
    filter: blur(26px);
}
[data-weather="fog"] .sky-fog { opacity: 1; }
[data-weather="fog"] .sky-fog::before { animation: fog-drift 44s ease-in-out infinite; }
[data-weather="fog"] .sky-fog::after  { animation: fog-drift 68s ease-in-out -22s infinite reverse; }
/* A thinner haze also hangs around during rain and snow. */
[data-weather="rain"] .sky-fog,
[data-weather="snow"] .sky-fog,
[data-weather="thunder"] .sky-fog { opacity: 0.4; }

@keyframes fog-drift {
    0%, 100% { transform: translate3d(-6%, 0, 0); }
    50%      { transform: translate3d(6%, 1.5%, 0); }
}

/* ---------- Lightning ----------
   Two parts, because real lightning has two: the sheet flash that lights the
   whole cloud base, and the bolt itself. The flash uses screen blending so it
   BRIGHTENS the scrim above it instead of painting a pale film over it — that
   is what makes a strike feel like light rather than a flat white rectangle.
   Peaks last 40-90ms, so text never becomes unreadable. */
.sky-flash {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse 70% 42% at var(--x, 62%) 6%, rgba(232, 243, 255, 0.95) 0%, rgba(190, 214, 255, 0.42) 34%, transparent 70%),
        linear-gradient(180deg, rgba(206, 228, 255, 0.3) 0%, transparent 55%);
    mix-blend-mode: screen;
    opacity: 0;
}
[data-weather="thunder"] .sky-flash { animation: lightning 9s linear infinite; }

/* Uneven on purpose. An evenly spaced flicker reads as a blinking light;
   lightning stutters — bright, nearly out, brighter, then a slow decay. */
@keyframes lightning {
    0%, 0.9%   { opacity: 0; }
    1.2%       { opacity: 0.8; }
    1.8%       { opacity: 0.1; }
    2.3%       { opacity: 1; }
    3%         { opacity: 0.16; }
    3.6%       { opacity: 0.55; }
    4.8%       { opacity: 0.06; }
    6%         { opacity: 0; }
    45%        { opacity: 0; }
    45.7%      { opacity: 0.45; }
    46.4%      { opacity: 0.05; }
    47%        { opacity: 0.3; }
    48.4%      { opacity: 0; }
    100%       { opacity: 0; }
}

/* The bolt. A forked zig-zag cut out of a bright vertical gradient with a
   glow bled around it, so it looks lit rather than drawn. */
.sky-bolt {
    position: absolute;
    top: -3%;
    left: var(--x, 58%);
    width: 120px;
    height: 66vh;
    opacity: 0;
    background: linear-gradient(180deg, #ffffff 0%, #e6f1ff 42%, #b9d4ff 78%, rgba(170, 205, 255, 0) 100%);
    clip-path: polygon(
        55% 0%, 38% 31%, 50% 31%, 30% 63%, 44% 63%, 24% 100%,
        39% 62%, 27% 62%, 47% 30%, 35% 30%, 63% 0%);
    filter:
        drop-shadow(0 0 12px rgba(200, 226, 255, 0.95))
        drop-shadow(0 0 40px rgba(120, 170, 255, 0.6));
    transform: scale(var(--scale, 1));
    transform-origin: 50% 0;
}
[data-weather="thunder"] .sky-bolt { animation: bolt-strike var(--dur, 9s) linear var(--delay, 0s) infinite; }

@keyframes bolt-strike {
    0%, 1%   { opacity: 0; }
    1.25%    { opacity: 1; }
    1.8%     { opacity: 0.08; }
    2.3%     { opacity: 0.95; }
    2.9%     { opacity: 0.12; }
    3.4%     { opacity: 0.5; }
    4.2%     { opacity: 0; }
    100%     { opacity: 0; }
}

/* ---------- Weather badge (optional, bottom-left) ---------- */
.weather-badge {
    position: fixed;
    left: 16px;
    bottom: 16px;
    z-index: 120;
    display: none;
    align-items: center;
    gap: 9px;
    padding: 8px 15px;
    border-radius: 999px;
    background: rgba(10, 14, 24, 0.66);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.09));
    color: var(--text, #eef2fb);
    font-size: 0.82rem;
    line-height: 1;
    box-shadow: 0 10px 30px -14px rgba(0, 0, 0, 0.8);
}
.weather-badge.visible { display: inline-flex; }
.weather-badge .wb-icon { font-size: 1.05rem; }
.weather-badge .wb-sep { opacity: 0.35; }
.weather-badge .wb-place { color: var(--muted, #96a2bd); }

@media (max-width: 900px) {
    /* Keep clear of the floating chat / back-to-top controls on phones. */
    .weather-badge { left: 12px; bottom: 12px; font-size: 0.76rem; padding: 7px 12px; }
    .weather-badge .wb-place { display: none; }
}

/* Dim the site's ambient brand orbs so they don't fight the sky. */
body.weather-active::before { opacity: 0.22; }
body.weather-active::after  { opacity: 0.18; }

/* ---------- Motion & data preferences ---------- */
@media (prefers-reduced-motion: reduce) {
    .star, .shooting-star, .cloud, .raindrop, .snowflake, .splash,
    .sky-fog, .sky-fog::before, .sky-fog::after,
    .sky-flash, .sky-bolt { animation: none !important; }
    .sky-gradient, .sky-sun, .sky-moon, .sky-stars, .sky-clouds { transition: none !important; }
    /* With the animation off a raindrop would sit frozen at the top of the
       screen as a bare line, so hide the falling particles outright. */
    .raindrop, .snowflake, .splash, .sky-bolt { display: none !important; }
    /* The gradient, sun, moon and stars still change with the time of day —
       only the motion is removed. */
}

/* Admin pages keep their light UI: never paint the sky there. */
.admin-body .sky,
.admin-body .weather-badge { display: none !important; }
