
/* Scale & rotate pulse spinner */
.spinner-scale-rotate {
    width: 33.6px;
    height: 33.6px;
    animation: scale-rotate 2s infinite linear;
    background-color: #325d88;
    border-radius: 50%;
}

@keyframes scale-rotate {
    0% {
        transform: scale(0) rotate(-45deg) translateY(0);
    }

    50% {
        transform: scale(1.25) rotate(960deg) translateY(100%);
    }

    100% {
        transform: scale(0) rotate(2000deg) translateY(0);
    }
}

/* Multi-div bouncing dots spinner */
.spinner-multi-div {
    display: flex;
    gap: 8px;
}

    .spinner-multi-div > div {
        width: 8px;
        height: 8px;
        background-color: #325d88;
        border-radius: 50%;
        animation: multi-bounce 1.4s infinite ease-in-out both;
    }

        .spinner-multi-div > div:nth-child(1) {
            animation-delay: -0.32s;
        }

        .spinner-multi-div > div:nth-child(2) {
            animation-delay: -0.16s;
        }

@keyframes multi-bounce {
    0%, 80%, 100% {
        transform: scale(0);
    }

    40% {
        transform: scale(1);
    }
}

/* Skewing spinner */
.spinner-skew {
    width: 56px;
    height: 56px;
    animation: skew-spin 2s infinite ease;
    border-radius: 50%;
    background-color: #325d88;
}

@keyframes skew-spin {
    10% {
        transform: skewX(60deg);
    }

    20% {
        transform: skewX(-60deg);
    }

    30% {
        transform: skewX(0deg);
    }

    40% {
        transform: skewY(60deg);
    }

    50% {
        transform: skewY(-60deg);
    }

    60% {
        transform: skewY(0);
    }
}

/* 3D cube spinner */
.spinner-3d {
    width: 44.8px;
    height: 44.8px;
    animation: spinner-3d-spin 2s infinite ease;
    transform-style: preserve-3d;
}

    .spinner-3d > div {
        background-color: rgba(50,93,136,0.2);
        height: 100%;
        position: absolute;
        width: 100%;
        border: 2.2px solid #325d88;
    }

        .spinner-3d > div:nth-of-type(1) {
            transform: translateZ(-22.4px) rotateY(180deg);
        }

        .spinner-3d > div:nth-of-type(2) {
            transform: rotateY(-270deg) translateX(50%);
            transform-origin: top right;
        }

        .spinner-3d > div:nth-of-type(3) {
            transform: rotateY(270deg) translateX(-50%);
            transform-origin: center left;
        }

        .spinner-3d > div:nth-of-type(4) {
            transform: rotateX(90deg) translateY(-50%);
            transform-origin: top center;
        }

        .spinner-3d > div:nth-of-type(5) {
            transform: rotateX(-90deg) translateY(50%);
            transform-origin: bottom center;
        }

        .spinner-3d > div:nth-of-type(6) {
            transform: translateZ(22.4px);
        }

@keyframes spinner-3d-spin {
    0% {
        transform: rotate(45deg) rotateX(-25deg) rotateY(25deg);
    }

    50% {
        transform: rotate(45deg) rotateX(-385deg) rotateY(25deg);
    }

    100% {
        transform: rotate(45deg) rotateX(-385deg) rotateY(385deg);
    }
}

/* Concentric rings spinner */
.spinner-concentric {
    width: 56px;
    height: 56px;
    display: grid;
    border: 4.5px solid transparent;
    border-radius: 50%;
    border-right-color: #325d88;
    animation: spinner-a4dj62 1s infinite linear;
}

    .spinner-concentric::before,
    .spinner-concentric::after {
        content: "";
        grid-area: 1/1;
        margin: 2.2px;
        border: inherit;
        border-radius: 50%;
        animation: spinner-a4dj62 2s infinite;
    }

    .spinner-concentric::after {
        margin: 8.9px;
        animation-duration: 3s;
    }

@keyframes spinner-a4dj62 {
    100% {
        transform: rotate(1turn);
    }
}

.spinner-scale-rotate {
    width: 33.6px;
    height: 33.6px;
    animation: scale-rotate 2s infinite linear;
    background-color: #325d88;
    border-radius: 50%;
}

@keyframes scale-rotate {
    0% {
        transform: scale(0) rotate(-45deg) translateY(0);
    }

    50% {
        transform: scale(1.25) rotate(960deg) translateY(100%);
    }

    100% {
        transform: scale(0) rotate(2000deg) translateY(0);
    }
}

.spinner-multi-div {
    display: flex;
    gap: 8px;
}

    .spinner-multi-div > div {
        width: 8px;
        height: 8px;
        background-color: #325d88;
        border-radius: 50%;
        animation: multi-bounce 1.4s infinite ease-in-out both;
    }

        .spinner-multi-div > div:nth-child(1) {
            animation-delay: -0.32s;
        }

        .spinner-multi-div > div:nth-child(2) {
            animation-delay: -0.16s;
        }

@keyframes multi-bounce {
    0%, 80%, 100% {
        transform: scale(0);
    }

    40% {
        transform: scale(1);
    }
}

.spinner-skew {
    width: 56px;
    height: 56px;
    animation: skew-spin 2s infinite ease;
    border-radius: 50%;
    background-color: #325d88;
}

@keyframes skew-spin {
    10% {
        transform: skewX(60deg);
    }

    20% {
        transform: skewX(-60deg);
    }

    30% {
        transform: skewX(0deg);
    }

    40% {
        transform: skewY(60deg);
    }

    50% {
        transform: skewY(-60deg);
    }

    60% {
        transform: skewY(0);
    }
}

.spinner-3d {
    width: 44.8px;
    height: 44.8px;
    animation: spinner-3d-spin 2s infinite ease;
    transform-style: preserve-3d;
    position: relative;
}

    .spinner-3d > div {
        background-color: rgba(50,93,136,0.2);
        height: 100%;
        position: absolute;
        width: 100%;
        border: 2.2px solid #325d88;
    }

        .spinner-3d > div:nth-of-type(1) {
            transform: translateZ(-22.4px) rotateY(180deg);
        }

        .spinner-3d > div:nth-of-type(2) {
            transform: rotateY(-270deg) translateX(50%);
            transform-origin: top right;
        }

        .spinner-3d > div:nth-of-type(3) {
            transform: rotateY(270deg) translateX(-50%);
            transform-origin: center left;
        }

        .spinner-3d > div:nth-of-type(4) {
            transform: rotateX(90deg) translateY(-50%);
            transform-origin: top center;
        }

        .spinner-3d > div:nth-of-type(5) {
            transform: rotateX(-90deg) translateY(50%);
            transform-origin: bottom center;
        }

        .spinner-3d > div:nth-of-type(6) {
            transform: translateZ(22.4px);
        }

@keyframes spinner-3d-spin {
    0% {
        transform: rotate(45deg) rotateX(-25deg) rotateY(25deg);
    }

    50% {
        transform: rotate(45deg) rotateX(-385deg) rotateY(25deg);
    }

    100% {
        transform: rotate(45deg) rotateX(-385deg) rotateY(385deg);
    }
}

.spinner {
    width: 56px;
    height: 56px;
    border: 11.2px #325d88 double;
    border-left-style: solid;
    border-radius: 50%;
    animation: spinner-aib1d7 0.75s infinite linear;
}

@keyframes spinner-aib1d7 {
    to {
        transform: rotate(360deg);
    }
}

.spinner-conic {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    padding: 1.1px;
    background: conic-gradient(#0000 10%,#325d88) content-box;
    -webkit-mask: repeating-conic-gradient(#0000 0deg,#000 1deg 20deg,#0000 21deg 36deg), radial-gradient(farthest-side,#0000 calc(100% - 9px),#000 calc(100% - 9px));
    -webkit-mask-composite: destination-in;
    mask-composite: intersect;
    animation: spinner-d55elj 1s infinite steps(10);
}

@keyframes spinner-d55elj {
    to {
        transform: rotate(1turn);
    }
}

.spinner-orbit {
    --d: 24.6px;
    width: 4.5px;
    height: 4.5px;
    border-radius: 50%;
    color: #325d88;
    box-shadow: calc(1*var(--d)) calc(0*var(--d)) 0 0, calc(0.707*var(--d)) calc(0.707*var(--d)) 0 1.1px, calc(0*var(--d)) calc(1*var(--d)) 0 2.2px, calc(-0.707*var(--d)) calc(0.707*var(--d)) 0 3.4px, calc(-1*var(--d)) calc(0*var(--d)) 0 4.5px, calc(-0.707*var(--d)) calc(-0.707*var(--d))0 5.6px, calc(0*var(--d)) calc(-1*var(--d)) 0 6.7px;
    animation: spinner-a90wxe 1s infinite steps(8);
}

@keyframes spinner-a90wxe {
    100% {
        transform: rotate(1turn);
    }
}

.spinner-radiate {
    position: relative;
    width: 9px;
    height: 9px;
}
.spinner-radiate div {
    position: absolute;
    width: 50%;
    height: 150%;
    background: #325d88;
    transform: rotate(calc(var(--rotation) * 1deg)) translate(0, calc(var(--translation) * 1%));
    animation: spinner-fzua35 1s calc(var(--delay) * 1s) infinite ease;
}
.spinner-radiate div:nth-child(1) { --delay: 0.1; --rotation: 36; --translation: 150; }
.spinner-radiate div:nth-child(2) { --delay: 0.2; --rotation: 72; --translation: 150; }
.spinner-radiate div:nth-child(3) { --delay: 0.3; --rotation: 108; --translation: 150; }
.spinner-radiate div:nth-child(4) { --delay: 0.4; --rotation: 144; --translation: 150; }
.spinner-radiate div:nth-child(5) { --delay: 0.5; --rotation: 180; --translation: 150; }
.spinner-radiate div:nth-child(6) { --delay: 0.6; --rotation: 216; --translation: 150; }
.spinner-radiate div:nth-child(7) { --delay: 0.7; --rotation: 252; --translation: 150; }
.spinner-radiate div:nth-child(8) { --delay: 0.8; --rotation: 288; --translation: 150; }
.spinner-radiate div:nth-child(9) { --delay: 0.9; --rotation: 324; --translation: 150; }
.spinner-radiate div:nth-child(10) { --delay: 1; --rotation: 360; --translation: 150; }
@keyframes spinner-fzua35 {
    0%, 10%, 20%, 30%, 50%, 60%, 70%, 80%, 90%, 100% {
        transform: rotate(calc(var(--rotation) * 1deg)) translate(0, calc(var(--translation) * 1%));
    }
    50% {
        transform: rotate(calc(var(--rotation) * 1deg)) translate(0, calc(var(--translation) * 1.5%));
    }
}

.spinner-shadow-pulse {
    position: relative;
    width: 22.4px;
    height: 22.4px;
}

    .spinner-shadow-pulse::before,
    .spinner-shadow-pulse::after {
        content: '';
        width: 100%;
        height: 100%;
        display: block;
        animation: spinner-b4c8mmmd 0.5s backwards, spinner-49opz7md 1.25s 0.5s infinite ease;
        border: 5.6px solid #325d88;
        border-radius: 50%;
        box-shadow: 0 -33.6px 0 -5.6px #325d88;
        position: absolute;
    }

    .spinner-shadow-pulse::after {
        animation-delay: 0s, 1.25s;
    }

@keyframes spinner-b4c8mmmd {
    from {
        box-shadow: 0 0 0 -5.6px #325d88;
    }
}

@keyframes spinner-49opz7md {
    to {
        transform: rotate(360deg);
    }
}

.spinner-dual-orbit {
    position: relative;
    width: 56px;
    height: 56px;
}

    .spinner-dual-orbit > div {
        width: 100%;
        height: 100%;
        border-radius: 50%;
        border: 13.4px solid rgba(50, 93, 136, 0.1);
        position: absolute;
        top: 0;
        left: 0;
        animation: spinner-g7vlvwmd 0.65s linear infinite;
        z-index: 0;
    }

        .spinner-dual-orbit > div::before {
            content: '';
            height: 13.4px;
            width: 13.4px;
            border-radius: 50%;
            background: #325d88;
            position: absolute;
            top: 50%;
            animation: spinner-h1vps1md 1.3s infinite reverse steps(1);
            transform: translate(calc(2 * var(--translate-2)), calc(var(--translate) * 1%));
            z-index: 1;
        }

        .spinner-dual-orbit > div:nth-of-type(1) {
            --translate: -50;
            --translate-2: calc(56px / 8);
        }

            .spinner-dual-orbit > div:nth-of-type(1)::before {
                right: 0;
            }

        .spinner-dual-orbit > div:nth-of-type(2) {
            --translate: 50;
            --translate-2: calc(-56px / 8);
            animation-delay: 0.65s;
            animation-direction: reverse;
            transform: translate(21.3px, 0);
        }

            .spinner-dual-orbit > div:nth-of-type(2)::before {
                left: 0;
                transform: translate(calc(-56px / 4), -50%);
                animation-direction: normal;
            }

@keyframes spinner-h1vps1md {
    0% {
        opacity: 0;
    }

    50% {
        opacity: 1;
    }
}

@keyframes spinner-g7vlvwmd {
    from {
        transform: translate(calc(var(--translate) * 1%), 0) translate(calc(var(--translate-2)), 0) rotate(0deg);
    }

    to {
        transform: translate(calc(var(--translate) * 1%), 0) translate(calc(var(--translate-2)), 0) rotate(360deg);
    }
}
.spinner-tri-ring {
    width: 56px;
    height: 56px;
    display: grid;
    border: 4.5px solid #0000;
    border-radius: 50%;
    border-color: #325d88 #0000;
    animation: spinner-e04l1k 1s infinite linear;
}

    .spinner-tri-ring::before,
    .spinner-tri-ring::after {
        content: "";
        grid-area: 1/1;
        margin: 2.2px;
        border: inherit;
        border-radius: 50%;
    }

    .spinner-tri-ring::before {
        border-color: #325d88 #0000;
        animation: inherit;
        animation-duration: 0.5s;
        animation-direction: reverse;
    }

    .spinner-tri-ring::after {
        margin: 8.9px;
    }

@keyframes spinner-e04l1k {
    100% {
        transform: rotate(1turn);
    }
}
.spinner-comet {
    position: relative;
    width: 15.7px;
    height: 15.7px;
}

    .spinner-comet div {
        width: 100%;
        height: 100%;
        border-radius: 50%;
        position: absolute;
        top: 0;
        left: 0;
        animation: spinner-4t3wzl 1.25s infinite backwards;
    }

        .spinner-comet div:nth-child(1) {
            animation-delay: 0.15s;
            background-color: rgba(50, 93, 136, 0.9);
        }

        .spinner-comet div:nth-child(2) {
            animation-delay: 0.3s;
            background-color: rgba(50, 93, 136, 0.7);
        }

        .spinner-comet div:nth-child(3) {
            animation-delay: 0.45s;
            background-color: rgba(50, 93, 136, 0.5);
        }

        .spinner-comet div:nth-child(4) {
            animation-delay: 0.6s;
            background-color: rgba(50, 93, 136, 0.3);
        }

        .spinner-comet div:nth-child(5) {
            animation-delay: 0.75s;
            background-color: rgba(50, 93, 136, 0.1);
        }

@keyframes spinner-4t3wzl {
    0% {
        transform: rotate(0deg) translateY(-200%);
    }

    60%, 100% {
        transform: rotate(360deg) translateY(-200%);
    }
}

/* ======================================================================
   WASM boot curtain
   ----------------------------------------------------------------------
   The whole page is one InteractiveWebAssembly root at prerender:false,
   so NOTHING paints until dotnet.wasm downloads and boots, chrome
   included. A cold Azure start would otherwise show a blank void, which
   reads as a broken app rather than a slow one.

   BootCurtain.razor renders in App.razor, OUTSIDE that root. It needs no
   runtime to appear and no script to leave: removal is STRUCTURAL, not
   timed. The moment the root paints its first ELEMENT into
   .vems-app-root, the :has() rule below hides it. Blazor's render-mode
   boundaries are HTML comments, which "> *" does not match, so the
   curtain survives exactly as long as the root is genuinely empty. A boot
   that never completes therefore keeps the curtain up instead of falling
   back to the blank screen this exists to prevent.

   Layout lives here rather than in Tailwind utilities on purpose. The
   Tailwind build runs with important:true, so a "flex" class would emit
   "display: flex !important" and win against the hide rule.
   ====================================================================== */
.vems-boot-curtain {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    height: 100%;
    padding: 1rem;
    text-align: center;
    opacity: 0;
    /* Held invisible through the delay, so a warm start (island paints in
       well under half a second) never flashes a spinner at all. The
       curtain costs nothing unless the wait is real. */
    animation: vems-boot-curtain-in 200ms ease-out 500ms forwards;
}

/* .vems-app-root is display:contents, a DOM marker with no layout of its own, so the hide
   stays structural. The curtain sizes itself from .vems-app-boot rather than a body region. */
.vems-app-boot {
    display: flex;
    height: 100vh;
}

.vems-app-root {
    display: contents;
}

.vems-app-boot:has(~ .vems-app-root > *) {
    display: none;
}

/* A cold start and a broken boot look identical for the first few
   seconds. Past 15s they should not: this line says the wait is expected
   and names the cause. */
.vems-boot-curtain__slow {
    max-width: 22rem;
    opacity: 0;
    animation: vems-boot-curtain-in 300ms ease-out 15s forwards;
}

@keyframes vems-boot-curtain-in {
    to {
        opacity: 1;
    }
}
