/* FUTURE atmosphere primitives - shared by every Filament panel (loaded
   next to future-theme.css by App\Support\FutureTheme::customStylesheet)
   and by the standalone login, 2FA and error pages.

   The room is deep space with the museum standing in it: a torus whose
   skin is cut through with lines of script lit electric blue from inside, a
   band of light travelling slowly round the ring. Overhead, a sky full of
   stars - fine dust and brighter stars twinkling out of step, a falling
   star now and then - and two orbits crossing it, the ellipse of the mark
   drawn in light. The mark itself stays polished steel.

   .mn-room     the room behind the page (markup: FutureTheme::roomBackdrop)
   .mn-torus    the museum: the steel ring, its lit script, the light
                travelling round it
   .mn-orbit    a tilted ellipse across the sky carrying one point of light
   .mn-stars    the starfield: fine dust and, --bright, the brighter stars
   .mn-comet    a falling star crossing the top of the sky every so often
   .mn-mark     the steel mark / the sidebar lockup
   .mn-shine    a highlight sweeping across steel, masked to the artwork
                (markup: FutureTheme::logo / ::shine)
   .mn-ripple   the press bloom added by FutureTheme's ripple script

   Colors come from the same --mn-* channels as future-theme.css; standalone
   pages declare them themselves. Motion: transform/opacity only on anything
   large, and all of it stops under prefers-reduced-motion. */

:root {
    /* Electric blue: the light the building is lit with (primary), its
       near-white core (primary-2), deep cobalt (accent) and a brighter blue
       for small lit details (accent-bright). */
    --mn-primary: 140, 184, 255;
    --mn-primary-2: 222, 235, 255;
    --mn-accent: 70, 100, 170;
    --mn-accent-bright: 160, 200, 255;
    --mn-concrete-950: 4, 6, 12;

    /* Lit glass: the metal every filled control and every figure is set in -
       a blue-white highlight down to cobalt. */
    --mn-chrome-hi: 240, 246, 255;
    --mn-chrome: 200, 220, 255;
    --mn-chrome-mid: 130, 170, 240;
    --mn-chrome-lo: 70, 110, 200;

    /* Lumen: the light of the script windows - the one light source in the
       room that isn't a star. */
    --mn-lumen: 190, 220, 255;

    /* Iris: neon running from cyan through blue into violet. Only ever a
       hairline (the topbar edge, the "you are here" rail, the title rule, the
       progress bar); surfaces stay night. */
    --mn-iris-1: 100, 200, 255;
    --mn-iris-2: 120, 140, 255;
    --mn-iris-3: 190, 120, 255;
    --mn-iris: linear-gradient(90deg, rgb(var(--mn-iris-1)), rgb(var(--mn-iris-2)) 50%, rgb(var(--mn-iris-3)));

    /* Decorated boundaries. Where a page needs one - the foot of the
       sidebar, the bottom of a hero panel, an empty table - a line of light
       script runs along it over a hairline horizon. Every tile is seamless
       under repeat-x. */
    --mn-band: url("/images/future-band.svg?v=2");
    --mn-band-deep: url("/images/future-band-deep.svg?v=2");
    --mn-line: url("/images/future-line.svg?v=2");
    --mn-lines: url("/images/future-lines.svg?v=2");

    /* The museum, the sky and the orbits. */
    --mn-torus: url("/images/future-torus.svg?v=2");
    --mn-stars: url("/images/future-stars.svg?v=2");
    --mn-stars-bright: url("/images/future-stars-bright.svg?v=1");
    --mn-orbits: url("/images/future-orbits.svg?v=2");

    /* Fine grain, so large flat dark panels never band. */
    --mn-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* Generic drift/breathe, shared by the lit edges in future-theme.css and
   future-pages.css. The distance in the name is the tile width the
   animation is paired with, so a strip loops without a visible jump. */
@keyframes mn-drift-800 { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-800px, 0, 0); } }
@keyframes mn-drift-800-rev { from { transform: translate3d(-800px, 0, 0); } to { transform: translate3d(0, 0, 0); } }
@keyframes mn-drift-120 { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-120px, 0, 0); } }
@keyframes mn-swell { 0%, 100% { translate: 0 0; } 50% { translate: 0 4px; } }
@keyframes mn-turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* ---------- The room ---------- */
.mn-room {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
    /* Its own layer, sealed off: nothing in the room can make the browser
       re-lay-out or repaint the page, and scrolling never repaints the room. */
    contain: strict;
    transform: translateZ(0);
    background:
        /* the building's blue glow low on the horizon, under the ring */
        radial-gradient(1200px 520px at 82% 112%, rgba(90, 150, 255, 0.13), transparent 62%),
        /* a faint nebula of violet high on the left */
        radial-gradient(900px 560px at 8% -12%, rgba(120, 110, 255, 0.10), transparent 64%),
        radial-gradient(1100px 640px at 60% -30%, rgba(80, 140, 255, 0.08), transparent 64%),
        linear-gradient(180deg, rgb(8, 12, 30) 0%, rgb(var(--mn-concrete-950)) 58%, rgb(2, 3, 6) 100%);
}

/* The air: two slow, out-of-phase blooms so the light never pulses in
   lockstep. */
.mn-room-haze {
    position: absolute;
    inset: -10vh -10vw;
    background:
        radial-gradient(40% 36% at 74% 6%, rgba(var(--mn-primary-2), 0.07), transparent 70%),
        radial-gradient(40% 34% at 86% 86%, rgba(var(--mn-lumen), 0.06), transparent 70%),
        radial-gradient(36% 30% at 6% 92%, rgba(var(--mn-chrome-lo), 0.08), transparent 72%);
    will-change: opacity, transform;
    animation: mn-haze 26s ease-in-out infinite alternate;
}

@keyframes mn-haze {
    0% { opacity: 0.6; transform: translate3d(-1.2%, 1%, 0) scale(1); }
    100% { opacity: 1; transform: translate3d(1.2%, -1%, 0) scale(1.04); }
}

/* Plain opacity, no blend mode: an overlay blend over the animated haze had
   to be recomputed for the whole screen on every frame. */
.mn-room-grain {
    position: absolute;
    inset: 0;
    background-image: var(--mn-grain);
    background-size: 160px 160px;
    opacity: 0.025;
}

/* ---------- Stars ---------- */
/* The whole sky: fine dust in one layer, brighter stars (some with a
   four-point glint) in another, each twinkling by opacity alone and out of
   step with the other, so the sky never pulses as one. They thin out toward
   the bottom, where the ring stands, and sit behind every card. */
.mn-stars {
    position: absolute;
    inset: 0;
    background: var(--mn-stars) repeat 0 0 / 420px 420px;
    opacity: 0.7;
    -webkit-mask-image: linear-gradient(180deg, #000 45%, rgba(0, 0, 0, 0.35) 100%);
    mask-image: linear-gradient(180deg, #000 45%, rgba(0, 0, 0, 0.35) 100%);
    will-change: opacity;
    animation: mn-twinkle 7s ease-in-out infinite alternate;
}

.mn-stars--bright {
    background: var(--mn-stars-bright) repeat 130px 60px / 760px 760px;
    animation-name: mn-twinkle-bright;
    animation-duration: 5.5s;
    animation-delay: -2s;
}

@keyframes mn-twinkle {
    from { opacity: 0.5; }
    to { opacity: 0.85; }
}

@keyframes mn-twinkle-bright {
    0%, 100% { opacity: 0.55; }
    40% { opacity: 1; }
    70% { opacity: 0.7; }
}

/* A falling star: a short streak of light crossing the top of the sky once
   every 11 seconds, visible for the first tenth of that - the rest of the
   time it waits off-screen. Transform and opacity only. */
.mn-comet {
    position: absolute;
    top: 9vh;
    left: 58vw;
    width: 150px;
    height: 1.5px;
    border-radius: 999px;
    background: linear-gradient(90deg, transparent, rgba(var(--mn-lumen), 0.5) 60%, rgb(255, 255, 255));
    box-shadow: 0 0 8px 1px rgba(var(--mn-iris-1), 0.45);
    opacity: 0;
    transform: rotate(158deg) translateX(0);
    transform-origin: 100% 50%;
    will-change: transform, opacity;
    animation: mn-comet 11s cubic-bezier(0.3, 0, 0.6, 1) infinite 3s;
}

@keyframes mn-comet {
    0% { opacity: 0; transform: rotate(158deg) translateX(0); }
    1.5% { opacity: 1; }
    9% { opacity: 0; transform: rotate(158deg) translateX(38vw); }
    100% { opacity: 0; transform: rotate(158deg) translateX(38vw); }
}

/* ---------- Orbits ---------- */
/* A circle squashed into a tilted ellipse (the mark's own angle), with a
   point of light riding it. The ring turns, not the dot, so the whole path
   is one compositor-only rotation; the squash makes the dot a short streak,
   which is what a light on a fast orbit looks like anyway. */
.mn-orbit {
    position: absolute;
    border-radius: 50%;
    border: 1px solid rgba(var(--mn-chrome-mid), 0.16);
}

.mn-orbit i {
    position: absolute;
    inset: -1px;
    border-radius: 50%;
    will-change: transform;
    animation: mn-turn 90s linear infinite;
}

.mn-orbit i::before {
    content: '';
    position: absolute;
    top: -3px;
    left: calc(50% - 3px);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: rgb(var(--mn-lumen));
    box-shadow: 0 0 10px 3px rgba(var(--mn-lumen), 0.55), 0 0 26px 8px rgba(var(--mn-iris-1), 0.18);
}

.mn-orbit--a {
    width: 150vw;
    aspect-ratio: 1;
    top: -118vw;
    left: -46vw;
    transform: rotate(-12deg) scaleY(0.34);
    transform-origin: 50% 100%;
}

.mn-orbit--b {
    width: 96vw;
    aspect-ratio: 1;
    top: -74vw;
    left: -8vw;
    border-color: rgba(var(--mn-chrome-mid), 0.10);
    transform: rotate(-9deg) scaleY(0.3);
    transform-origin: 50% 100%;
}

.mn-orbit--b i {
    animation-duration: 140s;
    animation-direction: reverse;
}

/* ---------- The torus ---------- */
/* The museum stands in the lower right, a third of it past the edge of the
   screen, fading into the night toward the top left so it only ever fills
   margins the reading column leaves empty. */
.mn-torus {
    position: absolute;
    right: -16vw;
    bottom: -30vh;
    width: clamp(760px, 82vw, 1560px);
    aspect-ratio: 1600 / 1000;
    opacity: 0.5;
    -webkit-mask-image: radial-gradient(70% 70% at 70% 72%, #000 40%, transparent 100%);
    mask-image: radial-gradient(70% 70% at 70% 72%, #000 40%, transparent 100%);
}

.mn-torus-art {
    position: absolute;
    inset: 0;
    background: var(--mn-torus) center / contain no-repeat;
    will-change: transform;
    animation: mn-float 18s ease-in-out infinite alternate;
}

@keyframes mn-float {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-0.6%, -1.4%, 0); }
}

/* Light travelling round the ring: a beam turning about the ring's centre,
   seen only through the artwork's own alpha - so it brightens the script
   windows as it passes and never the sky around them. The mask is static;
   only the beam inside it rotates. */
.mn-torus-light {
    position: absolute;
    inset: 0;
    -webkit-mask: var(--mn-torus) center / contain no-repeat;
    mask: var(--mn-torus) center / contain no-repeat;
    animation: mn-float 18s ease-in-out infinite alternate;
}

.mn-torus-light i {
    position: absolute;
    left: 50%;
    top: 52%;
    width: 120%;
    aspect-ratio: 1;
    translate: -50% -50%;
    background: conic-gradient(from 0deg, transparent 0deg, rgba(var(--mn-lumen), 0.95) 26deg, rgba(var(--mn-lumen), 0.2) 52deg, transparent 70deg, transparent 360deg);
    will-change: transform;
    animation: mn-turn 32s linear infinite;
}

/* ---------- Steel ---------- */
/* A highlight travelling across the metal every few seconds. It is masked to
   the artwork's own alpha (--mn-art, set inline next to the <img>), so it
   lights the ring and never the box around it. */
.mn-mark {
    position: relative;
    display: inline-block;
    line-height: 0;
}

.mn-mark img {
    display: block;
    max-width: 100%;
}

/* The sidebar lockup: the mark beside the wordmark. Filament hands the
   wrapper a fixed height (->brandLogoHeight), so the mark scales off that
   height and the wordmark is sized to sit level with it. */
.mn-lockup {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.95rem;
    height: 100%;
}

.mn-lockup .mn-mark {
    display: block;
    height: 78%;
    flex-shrink: 0;
}

.mn-lockup .mn-mark-img {
    width: auto;
    height: 100%;
    object-fit: contain;
    filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.55)) drop-shadow(0 0 18px rgba(var(--mn-chrome-mid), 0.2));
}

/* The wordmark, set in type: the logo's wide, evenly spaced capitals in
   steel. Letter-spacing also trails the last letter, so the negative end
   margin pulls the word back onto its optical centre. */
.mn-wordmark {
    font-family: 'Unbounded', 'Onest', sans-serif;
    font-weight: 500;
    font-size: 1.02rem;
    letter-spacing: 0.42em;
    margin-inline-end: -0.42em;
    line-height: 1;
    text-transform: uppercase;
    white-space: nowrap;
    background: linear-gradient(
        176deg,
        rgb(var(--mn-chrome-hi)) 0%,
        rgb(var(--mn-chrome)) 34%,
        rgb(var(--mn-chrome-mid)) 62%,
        rgb(var(--mn-chrome-hi)) 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
}

.mn-shine {
    isolation: isolate;
}

.mn-shine::after,
.mn-shine-pass {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(
        100deg,
        transparent 38%,
        rgba(var(--mn-chrome-hi), 0.0) 44%,
        rgba(var(--mn-chrome-hi), 0.9) 50%,
        rgba(var(--mn-chrome-hi), 0.0) 56%,
        transparent 62%
    );
    background-size: 260% 100%;
    background-repeat: no-repeat;
    -webkit-mask-image: var(--mn-art);
    mask-image: var(--mn-art);
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    mix-blend-mode: screen;
    animation: mn-sweep 7s cubic-bezier(0.5, 0, 0.3, 1) infinite;
}

@keyframes mn-sweep {
    0%, 62% { background-position: 180% 0; }
    88%, 100% { background-position: -80% 0; }
}

/* Headings and figures set in the same steel as the wordmark. */
.mn-chrome-text {
    background: linear-gradient(
        176deg,
        rgb(var(--mn-chrome-hi)) 0%,
        rgb(var(--mn-chrome)) 26%,
        rgb(var(--mn-chrome-lo)) 52%,
        rgb(var(--mn-chrome)) 70%,
        rgb(var(--mn-chrome-hi)) 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
}

/* ---------- Ripple ---------- */
/* On a steel button a white bloom would vanish, so the press shows as a
   ring of light spreading out from the finger: bright rim, clear centre. */
.mn-ripple {
    position: absolute;
    z-index: 0;
    border-radius: 50%;
    pointer-events: none;
    background: radial-gradient(circle, transparent 30%, rgba(255, 255, 255, 0.34) 52%, rgba(var(--mn-chrome-lo), 0.18) 60%, transparent 70%);
    transform: scale(0);
    animation: mn-ripple 760ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes mn-ripple {
    to { transform: scale(1); opacity: 0; }
}

/* ---------- Mobile: quieter room ---------- */
@media (max-width: 767px) {
    /* On a phone the reading column is the whole screen - the ring moves up
       behind the header, small and faint, and only one orbit stays. */
    .mn-torus {
        width: 150vw;
        right: -70vw;
        bottom: auto;
        top: -8vh;
        opacity: 0.26;
    }

    .mn-torus-light,
    .mn-orbit--b,
    .mn-room-grain {
        display: none;
    }

    .mn-stars--bright {
        background-size: 560px 560px;
    }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
    .mn-room *,
    .mn-mark,
    .mn-shine::after {
        animation: none !important;
    }

    .mn-shine::after,
    .mn-shine-pass,
    .mn-torus-light,
    .mn-ripple {
        display: none;
    }
}
