/* ---------------------------------------------------------
   Eight28 Globe Loader — shared styles

   Used by TWO loader instances:
     1. Boot loader (App.razor body) — fixed overlay shown
        from page first byte until Blazor mounts. Rings + halo
        only, no canvas globe (no JS dependency, paints instantly).
     2. Runtime loader (Components/GlobalLoading.razor) — shown
        when GlobalBusyState.IsBusy. Adds the canvas globe driven
        by /js/globe-loader.js.

   Both render the same .globe-loader composition; this file is
   their single source of truth for the inner visual. The runtime
   backdrop chrome (.global-loading-backdrop) lives in the scoped
   Globalloading.razor.css alongside the Blazor component.
--------------------------------------------------------- */

/* ---------- boot-loader overlay ---------- */
/*
   Visible by default. JS in App.razor (set in GlobalLoading's
   first OnAfterRender) flips body[data-blazor-ready] which
   fades and hides this layer. forceLoad navigations reset the
   page so the loader reappears on every full reload.
*/
.boot-loader {
    position: fixed;
    inset: 0;
    z-index: 10000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-background-page, #FAFBFC);
    transition: opacity 250ms ease-out, visibility 250ms ease-out;
}

body[data-blazor-ready="true"] .boot-loader {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

/* ---------- globe-loader composition (shared) ---------- */

.globe-loader {
    position: relative;
    width: 200px;
    height: 200px;
    display: grid;
    place-items: center;
}

.globe-loader__globe {
    width: 120px;
    height: 120px;
    display: block;
    border-radius: 50%;
}

.globe-loader__whirl {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.globe-loader__ring {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
    transform-origin: 50% 50%;
}

.globe-loader__ring--outer { animation: globe-loader-spin 6s linear infinite; }
.globe-loader__ring--mid   { animation: globe-loader-spin 4s linear infinite reverse; }
.globe-loader__ring--inner { animation: globe-loader-spin 2.4s linear infinite; }
.globe-loader__ring--sweep { animation: globe-loader-spin 3s cubic-bezier(.6,.1,.4,.9) infinite; }

@keyframes globe-loader-spin {
    to { transform: rotate(360deg); }
}

/* Soft pulsing halo behind the globe — uses color-mix so the
   tint always tracks the current --color-primary. */
.globe-loader__halo {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 50%,
        color-mix(in srgb, var(--color-primary, #009cbd) 8%, transparent) 0%,
        color-mix(in srgb, var(--color-primary, #009cbd) 8%, transparent) 38%,
        transparent 62%);
    animation: globe-loader-pulse 3s ease-in-out infinite;
}

@keyframes globe-loader-pulse {
    0%, 100% { opacity: 0.55; transform: scale(1); }
    50%      { opacity: 1;    transform: scale(1.04); }
}

/* ---------- accessibility ---------- */

@media (prefers-reduced-motion: reduce) {
    .globe-loader__ring,
    .globe-loader__halo {
        animation: none;
    }

    .boot-loader {
        transition: none;
    }
}
