
/* 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
   ----------------------------------------------------------------------
   Every portal router forces InteractiveWebAssembly with prerender:false,
   so the routed body region renders NOTHING until dotnet.wasm downloads
   and boots. The layout chrome around it is static SSR and paints on the
   first byte, so a cold Azure start shows a finished header above a blank
   void, which reads as a broken app rather than a slow one.

   BootCurtain.razor is static SSR markup sitting next to the island. It
   needs no runtime to appear and no script to leave: removal is
   STRUCTURAL, not timed. The moment the island paints its first ELEMENT
   into .vems-boot-host, the :has() rule below hides the curtain. Blazor's
   island boundaries are HTML comments, which "> *" does not match, so the
   curtain survives exactly as long as the region 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-boot-curtain:has(~ .vems-boot-host > *) {
    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;
    }
}
