/*
 * ============================================================================
 * Confirmilya — Unified loading system (styles)
 * ============================================================================
 *
 * One visual language for every loading state in the application:
 *
 *   #loadingScreen / .ds-loader-overlay  full-page overlay
 *   .ds-loader-inline                    scoped to a single component
 *   .ds-loader-spinner                   the spinner itself (sm / md / lg)
 *   .ds-skeleton                         placeholder blocks
 *   .ds-btn-loading                      button submit state
 *
 * COMPATIBILITY NOTE
 * ------------------
 * Six pages already render `<div id="loadingScreen">` and hide it with
 * inline styles:
 *
 *     loadingScreen.style.opacity = '0';
 *     setTimeout(() => loadingScreen.style.display = 'none', 500);
 *
 * So #loadingScreen must default to visible, must animate on opacity, and must
 * stay hidden once JavaScript writes display:none. Those rules are preserved
 * verbatim below — this file changes how the overlay looks, never how it is
 * driven.
 */

/* ==========================================================================
   1. Spinner primitive
   ========================================================================== */

.ds-loader-spinner {
    --ds-spinner-size: 32px;
    --ds-spinner-thickness: 3px;
    --ds-spinner-track: rgba(26, 54, 93, 0.15);
    --ds-spinner-head: var(--ds-brand-700, #1a365d);

    width: var(--ds-spinner-size);
    height: var(--ds-spinner-size);
    border: var(--ds-spinner-thickness) solid var(--ds-spinner-track);
    border-top-color: var(--ds-spinner-head);
    border-radius: 50%;
    animation: ds-spin 720ms linear infinite;
    flex: none;
}

.ds-loader-spinner-sm { --ds-spinner-size: 16px; --ds-spinner-thickness: 2px; }
.ds-loader-spinner-lg { --ds-spinner-size: 48px; --ds-spinner-thickness: 4px; }

/* On dark backdrops (the full-page overlay) the spinner inverts. */
.ds-loader-spinner-inverse {
    --ds-spinner-track: rgba(255, 255, 255, 0.25);
    --ds-spinner-head: #ffffff;
}

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


/* ==========================================================================
   2. Full-page overlay
   ========================================================================== */

/* Shared appearance for the new overlay and the existing #loadingScreen. */
#loadingScreen,
.ds-loader-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--ds-z-loader, 9999);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 1rem;
    background: linear-gradient(135deg, #16305a 0%, #1a365d 55%, #0d7f6a 100%);
    color: #fff;
    opacity: 1;
    transition: opacity 400ms var(--ds-ease, cubic-bezier(0.4, 0, 0.2, 1));
}

/* The overlay is decorative while it blocks; announce it politely instead. */
#loadingScreen,
.ds-loader-overlay {
    -webkit-user-select: none;
    user-select: none;
}

/* Hidden state used by the unified API. Pages that instead write
   `style.display = 'none'` keep working because an inline style wins. */
.ds-loader-overlay[hidden],
.ds-loader-overlay.ds-is-hidden {
    display: none;
}

/* Fade-out helper: JS adds this, waits for the transition, then hides. */
.ds-loader-overlay.ds-is-leaving,
#loadingScreen.ds-is-leaving {
    opacity: 0;
    pointer-events: none;
}

.ds-loader-overlay-light {
    background: rgba(248, 250, 252, 0.88);
    backdrop-filter: blur(3px);
    color: var(--ds-text, #1a2233);
}

.ds-loader-brand {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    font-size: 1.05rem;
}

.ds-loader-message {
    font-size: 0.875rem;
    font-weight: 500;
    opacity: 0.85;
    text-align: center;
    max-width: 32ch;
    /* Reserve a line so showing a message cannot shift the spinner. */
    min-height: 1.25rem;
}


/* ==========================================================================
   3. Component-level loader
   ========================================================================== */

/* Wraps a region (table body, card, chart) without blocking the whole page.
   The host needs position:relative; the API sets that only when it is static,
   and restores it afterwards. */
.ds-loader-inline {
    position: absolute;
    inset: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 0.6rem;
    background: rgba(255, 255, 255, 0.72);
    backdrop-filter: blur(2px);
    border-radius: inherit;
    color: var(--ds-text-muted, #5a6577);
    font-size: 0.8125rem;
    font-weight: 500;
}

.ds-loader-inline[hidden] { display: none; }

/* A bar variant for narrow strips where a centred spinner looks heavy. */
.ds-loader-bar {
    position: relative;
    overflow: hidden;
    height: 3px;
    background: var(--ds-gray-200, #e5e9f0);
    border-radius: 999px;
}
.ds-loader-bar::after {
    content: '';
    position: absolute;
    inset: 0;
    width: 40%;
    border-radius: inherit;
    background: linear-gradient(90deg,
        var(--ds-brand-500, #2d5d9c),
        var(--ds-accent-500, #00d4aa));
    animation: ds-slide 1.1s var(--ds-ease, ease) infinite;
}

@keyframes ds-slide {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(250%); }
}


/* ==========================================================================
   4. Button submit state
   ========================================================================== */

/* The label is kept in place and faded, so the button never changes width and
   the surrounding layout cannot shift. */
.ds-btn-loading {
    position: relative;
    pointer-events: none;
    cursor: progress;
}

.ds-btn-loading > * {
    opacity: 0;
}

.ds-btn-loading::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1em;
    height: 1em;
    margin: -0.5em 0 0 -0.5em;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: ds-spin 640ms linear infinite;
    opacity: 0.9;
}

/* When the caller supplies text, show it instead of hiding everything. */
.ds-btn-loading.ds-btn-loading-text {
    color: transparent;
}


/* ==========================================================================
   5. Skeletons
   ========================================================================== */

.ds-skeleton {
    position: relative;
    overflow: hidden;
    background: var(--ds-gray-200, #e5e9f0);
    border-radius: var(--ds-radius-sm, 6px);
    /* Occupies space up front, which is what prevents the layout shift. */
    min-height: 1em;
}
.ds-skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg,
        transparent,
        rgba(255, 255, 255, 0.6),
        transparent);
    animation: ds-shimmer 1.4s infinite;
}
.ds-skeleton-text  { height: 0.85em; margin-bottom: 0.5em; }
.ds-skeleton-title { height: 1.4em; width: 45%; margin-bottom: 0.75em; }
.ds-skeleton-line-short { width: 60%; }
.ds-skeleton-circle { border-radius: 50%; }

@keyframes ds-shimmer {
    100% { transform: translateX(100%); }
}


/* ==========================================================================
   6. Accessibility & motion
   ========================================================================== */

/* Screen-reader-only text used to announce loading state. */
.ds-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* With reduced motion the spinner stops rotating and pulses gently instead,
   so the element still reads as "busy" without continuous movement. */
@media (prefers-reduced-motion: reduce) {
    .ds-loader-spinner,
    .ds-btn-loading::after {
        animation: ds-pulse 1.4s ease-in-out infinite;
        border-top-color: currentColor;
    }
    .ds-loader-spinner {
        border-top-color: var(--ds-spinner-head);
    }
    .ds-loader-bar::after,
    .ds-skeleton::after {
        animation: none;
    }
    .ds-skeleton::after { opacity: 0.4; }

    @keyframes ds-pulse {
        0%, 100% { opacity: 1; }
        50%      { opacity: 0.35; }
    }
}

/* Fallback: if scripting never runs, the overlay must not trap the user
   forever. It fades out on its own shortly after the document paints. */
@media (scripting: none) {
    #loadingScreen,
    .ds-loader-overlay {
        animation: ds-loader-failsafe 0.1s linear 4s forwards;
    }
}

@keyframes ds-loader-failsafe {
    to { opacity: 0; visibility: hidden; }
}
