/* Voile d'attente commun à tout le site.
 *
 * Affiché pendant qu'un formulaire recharge la page, pour qu'une opération
 * longue (import, export, synchronisation, génération) ne se traduise pas par
 * une page figée où l'utilisateur reclique. Le déclenchement est décrit dans
 * static/js/busy_overlay.js.
 *
 * Le rendu suit le module visité : toutes les couleurs dérivent des variables
 * --module-* posées par le context processor `module_colors`. Chaque var()
 * porte son repli DxLean en dur (vert du logo), parce que les gabarits
 * autonomes — connexion, OAuth, ENSAM, portail QMS — ne chargent pas forcément
 * global-variables.css : le voile doit rester présentable sans lui.
 */
.dx-busy-overlay {
    --dxb-primary: var(--module-primary, var(--color-primary, #6bb442));
    --dxb-secondary: var(--module-secondary, var(--color-primary-hover, #3d9970));
    --dxb-primary-rgb: var(--module-primary-rgb, 107, 180, 66);

    /* Boîte par défaut : la fenêtre entière. Le script la restreint à la zone
       de contenu (voir measureRegion dans busy_overlay.js), pour que l'en-tête
       et la barre latérale restent lisibles et cliquables pendant l'attente —
       c'est le reste de la page qui travaille, pas eux. */
    position: fixed;
    inset: 0;
    z-index: 2000; /* au-dessus des modales Bootstrap (1055) et du chat assistant */
    display: none;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background:
        radial-gradient(circle at 50% 45%,
            rgba(var(--dxb-primary-rgb), .28) 0%,
            rgba(15, 23, 42, .62) 60%),
        rgba(15, 23, 42, .62);
    backdrop-filter: blur(3px);
}

.dx-busy-overlay.is-visible {
    display: flex;
    animation: dx-busy-fade .18s ease-out;
}

@keyframes dx-busy-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.dx-busy-card {
    position: relative;
    overflow: hidden;
    width: min(23rem, 100%);
    padding: 2rem 2.25rem 1.75rem;
    border-radius: var(--radius-lg, 14px);
    background: var(--color-surface, #fff);
    color: var(--color-text, #1f2937);
    box-shadow: 0 1.5rem 3rem rgba(15, 23, 42, .35);
    text-align: center;
}

/* Barre de progression indéterminée en tête de carte : la teinte du module y
   est la plus lisible, et le mouvement dit « ça travaille » mieux qu'un anneau
   seul. */
.dx-busy-sweep {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: rgba(var(--dxb-primary-rgb), .16);
    overflow: hidden;
}

.dx-busy-sweep::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: 40%;
    background: linear-gradient(90deg, var(--dxb-primary), var(--dxb-secondary));
    animation: dx-busy-sweep 1.5s ease-in-out infinite;
}

@keyframes dx-busy-sweep {
    0%   { left: -40%; }
    100% { left: 100%; }
}

.dx-busy-visual {
    position: relative;
    width: 3.25rem;
    height: 3.25rem;
    margin: 0 auto 1rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.dx-busy-ring {
    position: absolute;
    inset: 0;
    border: 3px solid rgba(var(--dxb-primary-rgb), .18);
    border-top-color: var(--dxb-primary);
    border-right-color: var(--dxb-secondary);
    border-radius: 50%;
    animation: dx-busy-spin .9s linear infinite;
}

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

/* Icône du module, immobile au centre de l'anneau qui tourne : c'est elle qui
   rend le voile reconnaissable d'un module à l'autre. */
.dx-busy-icon {
    width: 1.75rem;
    height: 1.75rem;
    object-fit: contain;
}

.dx-busy-module {
    margin-bottom: .35rem;
    font-family: var(--font-display, "Lexend Exa", system-ui, sans-serif);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--dxb-primary);
}

.dx-busy-message {
    margin-bottom: .35rem;
    font-family: var(--font-interface, "Inter", system-ui, -apple-system, "Segoe UI", sans-serif);
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.35;
}

.dx-busy-hint {
    margin-bottom: 0;
    font-family: var(--font-interface, "Inter", system-ui, -apple-system, "Segoe UI", sans-serif);
    font-size: .8125rem;
    color: var(--color-text-muted, #6b7280);
}

.dx-busy-dots::after {
    content: '';
    animation: dx-busy-dots 1.4s steps(4, end) infinite;
}

@keyframes dx-busy-dots {
    0%   { content: ''; }
    25%  { content: '.'; }
    50%  { content: '..'; }
    75%  { content: '...'; }
}

/* ── Contenu chargé en deux temps (voir dxsite/deferred.py) ─────────────────
   Même carte que le voile, mais posée dans le flux de la page au lieu de la
   recouvrir : à ce moment il n'y a encore rien à masquer. */
.dx-deferred {
    --dxb-primary: var(--module-primary, var(--color-primary, #6bb442));
    --dxb-secondary: var(--module-secondary, var(--color-primary-hover, #3d9970));
    --dxb-primary-rgb: var(--module-primary-rgb, 107, 180, 66);

    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 60vh;
    padding: 1.5rem;
}

/* Apparition retardée : sur une page qui revient en une demi-seconde, montrer
   puis retirer une carte de chargement fait clignoter l'écran pour rien. Même
   raison que le délai du voile des formulaires, appliqué ici en CSS puisque
   l'attente commence avant tout script. */
.dx-deferred-card {
    opacity: 0;
    animation: dx-deferred-appear .2s ease-out 350ms forwards;
    position: relative;
    overflow: hidden;
    width: min(23rem, 100%);
    padding: 2rem 2.25rem 1.75rem;
    border-radius: var(--radius-lg, 14px);
    background: var(--color-surface, #fff);
    color: var(--color-text, #1f2937);
    border: 1px solid rgba(var(--dxb-primary-rgb), .18);
    box-shadow: 0 .5rem 1.5rem rgba(15, 23, 42, .08);
    text-align: center;
}

@keyframes dx-deferred-appear {
    to { opacity: 1; }
}

/* Un échec doit rester lisible même si l'animation d'apparition est coupée. */
.dx-deferred.is-failed .dx-deferred-card {
    opacity: 1;
    animation: none;
}

.dx-deferred.is-failed .dx-busy-sweep,
.dx-deferred.is-failed .dx-busy-visual {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .dx-busy-overlay.is-visible { animation: none; }
    .dx-busy-ring { animation-duration: 2.4s; }
    .dx-busy-sweep::after { animation-duration: 3s; }
    .dx-busy-dots::after { animation: none; content: '…'; }
    /* Le retard reste — il évite un clignotement, ce n'est pas un effet — mais
       sans fondu. */
    .dx-deferred-card { animation-duration: 0s; }
}
