/* The sky: soft bokeh clouds, for the surfaces that want something behind frosted glass.

   ONE DEFINITION, FOUR SURFACES. It began inline in PublicPortal's own <style> for the join page
   and was then asked for behind the login screen, the TOTP screen and the console's sidebar. Four
   copies of a gradient and a keyframe drift apart one edit at a time, and the drift is invisible --
   nothing fails, the pages simply stop matching -- so it is a file, and the clouds are custom
   properties so the two variants below cannot disagree about what a cloud looks like.

   WHY IT EXISTS AT ALL. backdrop-filter blurs what is BEHIND an element, so a frosted card over a
   flat colour reads as a flat tint and the effect is wasted. This is the thing being frosted.

   ONE CLASS PER VARIANT, NOT TWO COMPOSED. The first version of this file split "where it goes"
   (.sky) from "what it looks like" (.sky-bg) and asked callers to wear both. Both set `position`,
   both were single-class selectors, and .sky-bg came second in the file -- so it won, the layer
   became a zero-height relative block, its pseudo-elements had no area to paint in, and the clouds
   disappeared from every surface at once. Reported as "the cloudy bokeh wallpaper is now gone from
   all screens". There is nothing to compose now: one class does one job completely.

   NO IMAGES, NO SCRIPT, NO BLUR FILTER. Radial gradients with transparent falloff are already
   soft, which is what makes this affordable on the console beside a live video stream. An earlier
   version used solid circles under filter: blur(70px) -- it looked the same and cost a large
   blurred layer per shape.
*/

:root {
    /* The clouds, once. Sizes in rem so they scale with the root font rather than with whatever
       box they land in: the same cloud over a full page and in a narrow sidebar. */
    --sky-cloud-a: radial-gradient(38rem 24rem at 18% 14%, rgba(23, 186, 232, .22), transparent 70%);
    --sky-cloud-b: radial-gradient(34rem 24rem at 84% 24%, rgba(90, 140, 255, .18), transparent 70%);
    --sky-cloud-c: radial-gradient(28rem 20rem at 62% 82%, rgba(53, 193, 122, .10), transparent 70%);

    /* What they sit on: a little lighter towards the top, like a sky. */
    --sky-base: radial-gradient(120% 80% at 50% -10%, #1d2e3d 0%, #141f2a 55%, #0f1821 100%);
}

/* ---- a full page: the join screen, the login screen, the TOTP screen ---------------------------

   FIXED AND FULL-VIEWPORT, which is both halves of its job: it gives the clouds a box the size of
   the screen to live in, and it stays out of its parent's flow so it cannot push a centred card
   around. pointer-events: none so it never takes a click meant for the page.

   Used as <div class="sky" aria-hidden="true"></div> with no contents. Whatever sits above it
   needs position: relative and a z-index -- see the note on .card in AuthEndpoints. */
.sky {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;

    background: var(--sky-base);
}

.sky::before,
.sky::after {
    content: "";
    position: absolute;

    /* Oversized on purpose: these move, and a layer that stopped at the edges would show its own
       corner sliding into view. The overflow: hidden above crops them back to the screen. */
    inset: -25%;
}

/* Two of the three travel together, which gives the drift some depth without a third animation:
   a cloud mass rather than three circles taking turns. */
.sky::before {
    background: var(--sky-cloud-a), var(--sky-cloud-c);
    animation: sky-drift-a 72s ease-in-out infinite alternate;
}

.sky::after {
    background: var(--sky-cloud-b);
    animation: sky-drift-b 94s ease-in-out infinite alternate;
}

/* Long, and deliberately not multiples of each other: two loops with tidy round durations
   visibly resynchronise every couple of minutes. */
@keyframes sky-drift-a {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(5rem, 3rem, 0) scale(1.12); }
}

@keyframes sky-drift-b {
    from { transform: translate3d(0, 0, 0) scale(1.08); }
    to   { transform: translate3d(-6rem, -4rem, 0) scale(1); }
}

/* STOPS WHEN ASKED TO. Drifting shapes behind a text field are close to the definition of what
   this setting exists to turn off, and one of the pages wearing it is the one somebody is sent to
   while something has already gone wrong for them. The sky stays; it holds still. */
@media (prefers-reduced-motion: reduce) {
    .sky::before,
    .sky::after { animation: none; }
}

/* ---- anywhere else: read the properties -------------------------------------------------------

   There is no second class in this file, and the reason is worth the paragraph.

   The console wanted these clouds behind one of its grid columns, so this file offered a class for
   it and the column wore it -- and nothing appeared. A Blazor scoped stylesheet appends an
   attribute to its own selectors, so that column's rule compiles to ".col-b[b-xxxxxxx]", which
   outranks a plain class from a plain stylesheet. The "background" SHORTHAND it already set then
   reset background-image to none, and won. Every rule was correct on its own.

   Custom properties do not lose that fight, because they are not in it. --sky-cloud-a/b/c and
   --sky-base are declared on :root above and inherit everywhere, so any stylesheet -- scoped or
   not -- can paint the same clouds while the values still live only here:

       background-image: var(--sky-cloud-a), var(--sky-cloud-b), var(--sky-cloud-c), var(--sky-base);
       background-repeat: no-repeat;

   See .col-b in Home.razor.css, which is exactly that. Use background-image rather than the
   shorthand, so a colour added later cannot wipe the clouds out without anybody noticing -- which
   is the mistake above, one step removed.

   A SCROLLING HOST IS SAFE painted this way. background-attachment defaults to "scroll", which
   despite its name keeps a background fixed to the element's own box while the content moves past
   it. "fixed" is the one to avoid here: it anchors to the VIEWPORT and resolves the clouds'
   percentage positions against the screen, which leaves most of them outside a narrow column. */
