/* =====================================================================
   Amrich UI — Weather scenes

   The particle canvas handles anything CONTINUOUS: rain streaks, snow,
   blossom, leaves, dust in the light. This file handles what is
   EPISODIC or STATIC — a lightning strike, a sun with turning rays,
   frost creeping in at the edges, a snow drift building along the
   bottom, a gust of wind through the blossom.

   That split is deliberate and it is the whole reason this layer is
   affordable. A pending requestAnimationFrame obliges the browser to run
   the full rendering lifecycle at every vsync whether anything changed or
   not, so a second animation loop would have cost as much as the first
   one did before it was fixed. Everything here is either a CSS animation
   on a transform/opacity — which the compositor owns and the main thread
   never sees — or a one-shot triggered by a `setTimeout` that fires every
   nine to twenty-four seconds. Between strikes, this file costs nothing
   at all.

   All of it lives behind the page content and is `pointer-events: none`,
   so nothing here can ever intercept a click.
   ===================================================================== */

.th-wx {
  position: fixed;
  inset: 0;
  z-index: -1;                 /* above the theme backdrop, below the page */
  pointer-events: none;
  overflow: hidden;
  contain: strict;             /* nothing in here can invalidate the page */
}

/* Scene modifiers are written `th-wx--<scene>` so they can never collide
   with an element class like `.th-wx-sun`. They did once, and the
   container took on the sun disc's own position and size. */

/* On a page with its own background the scene would be hidden behind it,
   so it moves in front — still under every bit of content. */
html.th-own-bg .th-wx { z-index: 0; }
html.th-own-bg .th-wx > * { opacity: .85; }

/* =====================================================================
   1. STORM  —  lightning, and rain hitting the bottom of the screen

   The flash and the bolt live in a SECOND layer that sits over the page,
   not under it. A white flash painted behind the content is invisible on
   a light page — white on white — and that is exactly how the first
   version failed. Real lightning lights up the room from in front of the
   furniture. This layer is pointer-events: none and is only opaque for
   about a tenth of a second at a time, so nothing is ever obscured for
   long enough to matter.
   ===================================================================== */
.th-wx-front {
  position: fixed;
  inset: 0;
  z-index: 2147481000;      /* over the page, under the mascot and the dock */
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}

.th-wx-flash {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70vmax 60vmax at 62% -14%, #ffffff, rgba(226, 244, 255, .65) 42%, rgba(200, 230, 255, .18) 68%, transparent 82%);
  opacity: 0;
}
.th-wx-bolt {
  position: absolute;
  top: -3%;
  left: 52%;
  width: 22vmin;
  height: 54vmin;
  opacity: 0;
  filter: drop-shadow(0 0 10px rgba(180, 222, 255, .95)) drop-shadow(0 0 26px rgba(140, 200, 255, .7));
}
.th-wx-bolt path { fill: #f7fcff; }
.th-wx-bolt .th-wx-fork { fill: none; }

/* One strike is a short, sharp double flicker — the way real lightning
   reads — then a long fade. It is triggered by adding a class, and the
   class is removed when the animation ends. */
.th-wx-strike .th-wx-flash { animation: thWxFlash 1.15s ease-out; }
.th-wx-strike .th-wx-bolt  { animation: thWxBolt  1.15s ease-out; }

/* Short, sharp, double flicker — then a long fade. Peaks are kept under
   0.6 so text stays readable straight through a strike. */
@keyframes thWxFlash {
  0%   { opacity: 0; }
  4%   { opacity: .58; }
  9%   { opacity: .08; }
  14%  { opacity: .5; }
  22%  { opacity: .16; }
  38%  { opacity: .26; }
  100% { opacity: 0; }
}
@keyframes thWxBolt {
  0%, 3%   { opacity: 0; transform: scaleY(.4); }
  5%       { opacity: 1; transform: scaleY(1); }
  10%      { opacity: .1; }
  15%      { opacity: .9; }
  24%      { opacity: 0; }
  100%     { opacity: 0; }
}

/* a second bolt on the other side, for variety */
.th-wx-bolt.th-wx-bolt-b { left: 21%; width: 16vmin; height: 40vmin; }
.th-wx-strike-b .th-wx-bolt-b { animation: thWxBolt 1.15s ease-out .09s; }
/* one bolt on its own should not always be in the same place */
.th-wx-front--storm .th-wx-bolt:first-of-type { left: calc(38% + 22vw * var(--th-bolt-x, .4)); }

/* Rain arriving. A row of splash marks along the bottom, each on its own
   offset, so the ground looks wet rather than the rain just stopping. */
.th-wx-splash {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 46px;
}
.th-wx-splash i {
  position: absolute;
  bottom: 4px;
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 1.5px solid rgba(180, 220, 240, .55);
  transform: scale(0);
  opacity: 0;
  animation: thWxSplash 1.5s linear infinite;
}
@keyframes thWxSplash {
  0%   { transform: scale(.1) scaleY(.35); opacity: .9; }
  60%  { opacity: .25; }
  100% { transform: scale(1.5) scaleY(.4); opacity: 0; }
}

/* The whole page dims slightly under a storm — overcast, not night. */
.th-wx-overcast {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(38, 58, 76, .30), rgba(38, 58, 76, .10) 55%, rgba(38, 58, 76, .04));
}
/* On a dark page the overcast would only make it muddier. */
html[data-th-dark="1"] .th-wx-overcast { opacity: .35; }

/* =====================================================================
   2. SUN  —  a disc with turning rays, warm haze, and a slow shimmer
   ===================================================================== */
.th-wx-sun {
  position: absolute;
  top: -14vmin;
  right: -10vmin;
  width: 52vmin;
  height: 52vmin;
}
.th-wx-sun-core {
  position: absolute;
  inset: 30%;
  border-radius: 50%;
  background: radial-gradient(circle, #fff8dc 0%, #ffd166 45%, rgba(255, 183, 3, .55) 70%, transparent 78%);
  animation: thWxPulse 6s ease-in-out infinite;
}
.th-wx-sun-glow {
  position: absolute;
  inset: -40%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 209, 102, .38) 0%, rgba(255, 183, 3, .16) 40%, transparent 68%);
}
/* The rays are one conic gradient masked into spokes, so twelve beams
   cost one element and one composited rotation. */
.th-wx-sun-rays {
  position: absolute;
  inset: -18%;
  border-radius: 50%;
  background: repeating-conic-gradient(from 0deg,
    rgba(255, 214, 120, .30) 0deg 3deg,
    transparent 3deg 15deg);
  -webkit-mask-image: radial-gradient(circle, transparent 26%, #000 40%, transparent 76%);
          mask-image: radial-gradient(circle, transparent 26%, #000 40%, transparent 76%);
  animation: thWxSpin 90s linear infinite;
}
@keyframes thWxSpin  { to { transform: rotate(360deg); } }
@keyframes thWxPulse { 0%, 100% { transform: scale(1); opacity: .95; } 50% { transform: scale(1.05); opacity: 1; } }

/* Heat. A very slow vertical drift on a warm wash — reads as haze rising
   off the ground without touching a single pixel of the page. */
.th-wx-heat {
  position: absolute;
  left: -10%; right: -10%; bottom: -12%;
  height: 46%;
  background: linear-gradient(0deg, rgba(255, 196, 90, .20), transparent 78%);
  animation: thWxHeat 9s ease-in-out infinite;
}
@keyframes thWxHeat {
  0%, 100% { transform: translateY(0) scaleY(1); opacity: .8; }
  50%      { transform: translateY(-2%) scaleY(1.06); opacity: 1; }
}

/* An occasional lens bloom sweeping across, triggered like the lightning */
.th-wx-bloom {
  position: absolute;
  top: 8%; right: 6%;
  width: 30vmin; height: 30vmin;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .55), transparent 62%);
  opacity: 0;
}
.th-wx-glint .th-wx-bloom { animation: thWxBloom 2.6s ease-in-out; }
@keyframes thWxBloom {
  0%, 100% { opacity: 0; transform: scale(.7); }
  40%      { opacity: .75; transform: scale(1.1); }
}

/* =====================================================================
   3. WINTER  —  frost at the edges, and a drift that builds
   ===================================================================== */
.th-wx-frost {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 90% at 50% 50%, transparent 52%, rgba(214, 240, 255, .55) 88%, rgba(235, 249, 255, .8) 100%);
}
/* Six frost ferns in the corners, drawn once as SVG and never animated */
.th-wx-fern {
  position: absolute;
  width: 26vmin; height: 26vmin;
  opacity: .5;
}
.th-wx-fern path { stroke: rgba(255, 255, 255, .95); fill: none; stroke-linecap: round; }
.th-wx-fern-tl { top: -1vmin; left: -1vmin; }
.th-wx-fern-tr { top: -1vmin; right: -1vmin; transform: scaleX(-1); }
.th-wx-fern-bl { bottom: -1vmin; left: -1vmin; transform: scaleY(-1); }
.th-wx-fern-br { bottom: -1vmin; right: -1vmin; transform: scale(-1); }

/* The drift. Its height is a CSS variable that weather.js nudges upward
   every few seconds while the page is open, so snow visibly settles. */
.th-wx-drift {
  position: absolute;
  left: -2%; right: -2%; bottom: 0;
  height: var(--th-drift, 10px);
  background: linear-gradient(180deg, rgba(255, 255, 255, .96), rgba(226, 243, 255, .9));
  border-radius: 50% 50% 0 0 / 26px 26px 0 0;
  transition: height 2.4s cubic-bezier(.22, 1, .36, 1);
  box-shadow: 0 -2px 10px rgba(180, 215, 240, .5);
}

/* =====================================================================
   4. BLOSSOM  —  a branch in flower, and a gust through it
   ===================================================================== */
.th-wx-branch {
  position: absolute;
  top: -2vmin;
  width: 46vmin;
  height: 30vmin;
  transform-origin: top left;
  animation: thWxSway 8s ease-in-out infinite;
}
.th-wx-branch-l { left: -3vmin; }
/* Mirrored about its CENTRE. About the right edge — which is what
   `transform-origin: top right` did — the mirror threw the drawing out
   past the edge of the screen and the branch simply was not there. */
.th-wx-branch-r { right: -3vmin; transform: scaleX(-1); transform-origin: center; animation-delay: -3s; }
@keyframes thWxSway {
  0%, 100% { transform: rotate(-.8deg); }
  50%      { transform: rotate(1.2deg); }
}
html .th-wx-branch-r { animation-name: thWxSwayFlip; transform-origin: center; }
@keyframes thWxSwayFlip {
  0%, 100% { transform: scaleX(-1) rotate(-.8deg); }
  50%      { transform: scaleX(-1) rotate(1.2deg); }
}

/* A gust: the branches lean hard for a moment. weather.js also tells the
   particle engine to push the petals sideways at the same time. */
.th-wx-gust .th-wx-branch   { animation: thWxGust 2.1s ease-in-out; }
.th-wx-gust .th-wx-branch-r { animation: thWxGustFlip 2.1s ease-in-out; transform-origin: center; }
@keyframes thWxGust {
  0%, 100% { transform: rotate(-.8deg); }
  22%      { transform: rotate(6deg); }
  55%      { transform: rotate(-2.4deg); }
}
@keyframes thWxGustFlip {
  0%, 100% { transform: scaleX(-1) rotate(-.8deg); }
  22%      { transform: scaleX(-1) rotate(6deg); }
  55%      { transform: scaleX(-1) rotate(-2.4deg); }
}

/* =====================================================================
   5. AUTUMN + EMBERS  —  low warm light, and rising sparks
   ===================================================================== */
.th-wx-warmth {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(80vmax 50vmax at 12% 104%, rgba(234, 88, 12, .16), transparent 68%),
    linear-gradient(200deg, rgba(251, 191, 36, .14), transparent 55%);
}
.th-wx-embers {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(50vmax 40vmax at 50% 108%, rgba(255, 138, 0, .22), transparent 70%);
}

/* =====================================================================
   6. WHEN NOT TO RUN
   ===================================================================== */
html[data-th-motion="off"] .th-wx,
html[data-th-motion="off"] .th-wx-front,
html[data-th-lite="1"] .th-wx,
html[data-th-lite="1"] .th-wx-front { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  /* the scenery stays, the movement does not */
  .th-wx *, .th-wx-front * { animation: none !important; transition: none !important; }
  .th-wx-front { display: none !important; }
  .th-wx-bloom { display: none !important; }
}

@media print { .th-wx, .th-wx-front { display: none !important; } }
.th-capturing .th-wx,
.th-capturing .th-wx-front { display: none !important; }

/* A phone gets the scene at a smaller scale — the sun and the branches are
   sized in vmin, so they would otherwise dominate a narrow screen. */
@media (max-width: 640px) {
  .th-wx-sun    { width: 68vmin; height: 68vmin; top: -18vmin; right: -20vmin; }
  .th-wx-branch { width: 62vmin; height: 34vmin; }
  .th-wx-fern   { width: 34vmin; height: 34vmin; }
}


/* =====================================================================
   7. TWO SCENES AT ONCE
   The festival's scene and the sky's are separate containers, so a theme
   change at midday does not restart the rain. The festival's sits behind
   the sky's, and is dialled back a little so weather stays legible on top.
   ===================================================================== */
.th-wx-fest { z-index: -1; }
.th-wx-sky  { z-index: -1; }
html.th-own-bg .th-wx-fest,
html.th-own-bg .th-wx-sky { z-index: 0; }
.th-wx-fest > * { opacity: .8; }

/* =====================================================================
   8. RAIN  (a wet day, without the theatrics)
   ===================================================================== */
.th-wx-overcast-soft { opacity: .62; }

/* =====================================================================
   9. NIGHT
   ===================================================================== */
.th-wx-nightfall {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(12, 20, 38, .45), rgba(12, 20, 38, .16) 55%, transparent);
}
.th-wx-moon {
  position: absolute;
  top: 6vmin; right: 9vmin;
  width: 18vmin; height: 18vmin;
  animation: thWxMoon 22s ease-in-out infinite;
}
.th-wx-moon-glow {
  position: absolute; inset: -70%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(226, 240, 255, .34) 0%, rgba(190, 215, 255, .12) 42%, transparent 70%);
}
.th-wx-moon-disc {
  position: absolute; inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 36% 32%, #ffffff 0%, #eef4ff 55%, #d7e3f5 100%);
  box-shadow: 0 0 6vmin rgba(214, 234, 255, .55);
  overflow: hidden;
}
.th-wx-moon-disc span {
  position: absolute;
  border-radius: 50%;
  background: rgba(186, 203, 226, .55);
}
@keyframes thWxMoon { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-1.2vmin); } }

/* =====================================================================
   10. FOG
   Three bands at different depths and speeds. One band is a smear;
   three are weather.
   ===================================================================== */
.th-wx-fogwash {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(226, 232, 238, .5), rgba(226, 232, 238, .22) 60%, rgba(226, 232, 238, .34));
}
.th-wx-fogband {
  position: absolute;
  left: -60%; right: -60%;
  height: 32%;
  background: radial-gradient(60% 100% at 30% 50%, rgba(255, 255, 255, .85), transparent 70%),
              radial-gradient(50% 100% at 72% 50%, rgba(255, 255, 255, .7), transparent 70%);
  filter: blur(6px);
}
.th-wx-fog1 { top: 12%; animation: thWxDrift 64s linear infinite; opacity: .6; }
.th-wx-fog2 { top: 42%; animation: thWxDrift 92s linear infinite reverse; opacity: .48; }
.th-wx-fog3 { top: 68%; animation: thWxDrift 118s linear infinite; opacity: .7; }
@keyframes thWxDrift { from { transform: translateX(-14%); } to { transform: translateX(14%); } }

/* =====================================================================
   11. OVERCAST
   ===================================================================== */
.th-wx-greywash {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(120, 138, 156, .26), rgba(120, 138, 156, .08) 60%, transparent);
}
.th-wx-cloud {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .75), rgba(255, 255, 255, .28) 55%, transparent 72%);
  filter: blur(2px);
}
.th-wx-cloud1 { top: -14vmin; left: -10vmin; width: 76vmin; height: 46vmin; animation: thWxDrift 130s linear infinite; }
.th-wx-cloud2 { top: 4vmin; right: -18vmin; width: 62vmin; height: 38vmin; animation: thWxDrift 172s linear infinite reverse; opacity: .8; }

/* =====================================================================
   12. WIND
   ===================================================================== */
.th-wx-windlines { position: absolute; inset: 0; }
.th-wx-windlines i {
  position: absolute;
  left: -45vmin;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(120, 150, 175, .75), transparent);
  animation: thWxBlow 4s linear infinite;
}
@keyframes thWxBlow {
  0%   { transform: translateX(0) scaleX(.6); opacity: 0; }
  12%  { opacity: 1; }
  80%  { opacity: .7; }
  100% { transform: translateX(160vw) scaleX(1.2); opacity: 0; }
}

/* =====================================================================
   13. FAIRY LIGHTS  (a festival scene, for Christmas)
   ===================================================================== */
.th-wx-fairy {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 5vmin;
  border-bottom: 2px solid rgba(90, 70, 50, .25);
  border-radius: 0 0 50% 50% / 0 0 100% 100%;
}
/* The glow is a static box-shadow and the TWINKLE is opacity plus scale.

   The first version animated the box-shadow itself, which measured at
   three and a half times the cost of everything else on the page put
   together: a shadow cannot be composited, so sixteen bulbs forced a
   full repaint on every frame, forever. Opacity and transform are handed
   to the compositor and cost the main thread nothing — and the effect is
   indistinguishable. */
.th-wx-fairy i {
  position: absolute;
  top: 3.4vmin;
  width: 1.5vmin; height: 1.5vmin;
  border-radius: 50%;
  box-shadow: 0 0 1.6vmin 0.3vmin currentColor;
  will-change: opacity, transform;
  animation: thWxBulb 2.8s ease-in-out infinite;
}
@keyframes thWxBulb {
  0%, 100% { opacity: .38; transform: scale(.86); }
  50%      { opacity: 1;   transform: scale(1.12); }
}

/* =====================================================================
   14. THE TINT
   The weather's only claim on colour. It is a wash over the backdrop, not
   a palette — the festival has to stay recognisable underneath it, so a
   rainy Diwali is still unmistakably Diwali.
   ===================================================================== */
html[data-th-tint] body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: .5;
}
html[data-th-tint="warm"]  body::after { background: linear-gradient(180deg, rgba(255, 236, 200, .55), rgba(255, 246, 226, .2)); }
html[data-th-tint="hot"]   body::after { background: linear-gradient(180deg, rgba(255, 214, 150, .7), rgba(255, 190, 120, .28)); }
html[data-th-tint="cool"]  body::after { background: linear-gradient(180deg, rgba(200, 222, 236, .6), rgba(214, 232, 244, .24)); }
html[data-th-tint="storm"] body::after { background: linear-gradient(180deg, rgba(150, 172, 192, .72), rgba(176, 194, 210, .3)); }
html[data-th-tint="grey"]  body::after { background: linear-gradient(180deg, rgba(196, 206, 216, .6), rgba(214, 222, 230, .26)); }
html[data-th-tint="frost"] body::after { background: linear-gradient(180deg, rgba(206, 232, 250, .62), rgba(226, 242, 255, .26)); }
html[data-th-tint="bloom"] body::after { background: linear-gradient(180deg, rgba(255, 224, 238, .55), rgba(255, 240, 248, .22)); }
html[data-th-tint="amber"] body::after { background: linear-gradient(180deg, rgba(255, 226, 186, .6), rgba(255, 240, 214, .24)); }
html[data-th-tint="night"] body::after { background: linear-gradient(180deg, rgba(120, 140, 180, .55), rgba(150, 168, 200, .3)); }

/* A dark page is already dark; multiplying a wash over it only makes it
   muddy, so it lightens instead and at a much lower strength. */
html[data-th-dark="1"][data-th-tint] body::after { mix-blend-mode: screen; opacity: .12; }

/* Battery saver keeps the tint — it is a static gradient and costs
   nothing — but loses everything that moves. */
html[data-th-lite="1"][data-th-tint] body::after { opacity: .35; }
