/* ---- Loading feedback (navigation + form submits) ----
 * A slim top progress bar plus a full-screen overlay preloader. Shared by the
 * customer app, marketing pages and admin panel. Self-contained: uses literal
 * brand colours so it works regardless of which stylesheet is in scope.
 */

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

/* Slim top progress bar shown while a page or form is loading. */
.route-progress {
    position: fixed;
    top: 0;
    left: 0;
    height: 3px;
    width: 0;
    background: linear-gradient(90deg, #990011, #bd0018);
    box-shadow: 0 0 10px rgba(189, 0, 24, .5);
    border-radius: 0 3px 3px 0;
    z-index: 10000;
    opacity: 0;
    pointer-events: none;
    transition: width .25s ease, opacity .3s ease;
}

.route-progress.is-active {
    opacity: 1;
}

/* Blocking overlay for major page navigations so users get an obvious
 * "loading" cue and cannot multi-tap the same destination. */
.route-overlay {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(252, 246, 245, .74);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    z-index: 9998;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .18s ease;
}

.route-overlay.is-active {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}

.route-overlay-spinner {
    width: 46px;
    height: 46px;
    border-radius: 50%;
    border: 3px solid rgba(153, 0, 17, .18);
    border-top-color: #990011;
    animation: sb-spin .7s linear infinite;
}

.route-overlay-label {
    position: absolute;
    margin-top: 86px;
    font-size: 13px;
    font-weight: 800;
    color: #990011;
    letter-spacing: .02em;
}

/* ---- Pull-to-refresh (mobile app) ---- */
.pull-refresh {
    position: fixed;
    top: 14px;
    left: 50%;
    transform: translateX(-50%) translateY(-56px);
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 8px 22px rgba(61, 30, 33, .2);
    opacity: 0;
    z-index: 60;
    pointer-events: none;
}

.pull-refresh.is-animating {
    transition: transform .25s ease, opacity .25s ease;
}

.pull-refresh-spinner {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 2.5px solid rgba(153, 0, 17, .22);
    border-top-color: #990011;
    transition: transform .15s ease;
}

/* Past the trigger threshold: hint that releasing will refresh. */
.pull-refresh.is-armed .pull-refresh-spinner {
    transform: rotate(180deg);
    border-top-color: #bd0018;
}

.pull-refresh.is-refreshing .pull-refresh-spinner {
    animation: sb-spin .7s linear infinite;
}

/* Keep the browser's own pull-to-refresh/overscroll out of the way.
 * Applied to the real scrollers only: the legacy app's inner `.screen-content`,
 * and the document element for the dashboard (which scrolls the window). It must
 * NOT sit on `body.dashboard-body`: with `overflow-x: clip/hidden` the body can
 * become a non-scrollable scroll container, and `contain` there blocks wheel
 * scroll from chaining to the real scroller (scrollbar drag still worked). */
.app-body .screen-content,
html {
    overscroll-behavior-y: contain;
}

@media (prefers-reduced-motion: reduce) {
    .route-overlay-spinner,
    .pull-refresh.is-refreshing .pull-refresh-spinner {
        animation-duration: 1.2s;
    }
}
