/**
 * INDICATEUR DE CHARGEMENT GLOBAL - voir static/js/loading_indicator.js
 * pour le detail complet de la demande (Cedric, 28 septembre 2026) et du
 * mecanisme.
 *
 * REVU LE 28 SEPTEMBRE 2026 (retour de recette, iPhone) : « sur iPhone,
 * je n'ai pas la barre bleue fine [...] je pense qu'il faut mettre une
 * icone de chargement au milieu de l'ecran (un peu en transparence). une
 * icone animee au lieu de la barre bleue ». La barre fine du haut est
 * retiree - une icone centree la remplace. Rien d'autre ne change : le
 * delai, les regles de declenchement et l'API `track()` sont dans
 * static/js/loading_indicator.js et n'ont pas bouge.
 *
 * TROIS ELEMENTS, TOUS CREES PAR LE JAVASCRIPT (toujours presents dans le
 * DOM, juste masques par `hidden` tant qu'aucune attente n'est engagee) :
 *
 *   .ds-loading-indicator    - le conteneur POSITIONNE (centre de la zone
 *                              visible - voir le fichier JS pour le calcul
 *                              visualViewport/zoom), porte role="status"/
 *                              aria-live="polite" : c'est LUI que le
 *                              lecteur d'ecran annonce.
 *   .ds-loading-icon         - le petit fond rond semi-transparent.
 *   .ds-loading-icon-glyph   - le glyphe anime a l'interieur.
 *   .ds-loading-status-text  - le texte, silencieux a l'oeil par defaut
 *                              (technique « sr-only »), SAUF sous
 *                              `prefers-reduced-motion: reduce` ou il
 *                              devient visible SOUS l'icone (qui devient
 *                              alors immobile) - voir plus bas pourquoi.
 *
 * UN SEUL CONTENEUR POSITIONNE, PAS DEUX
 * -------------------------------------------
 * L'icone et le texte voyagent ENSEMBLE (une seule mise en page flex, en
 * colonne) sous un seul element que le JavaScript positionne. Deux
 * elements positionnes separement auraient exige de dupliquer le calcul
 * de centrage a chaque endroit ou il change (redimensionnement, clavier
 * virtuel, cran de zoom) - une seule source, un seul point de calcul.
 *
 * UNITES DE TAILLE : EN PX, JAMAIS EN UNITE DE FENETRE
 * ---------------------------------------------------------
 * `tests/test_unites_ecran_sous_zoom_20260924.py` interdit les unites de
 * fenetre (`vw`/`vh`/...) sur les proprietes de taille et de position :
 * calculees AVANT le zoom du produit, elles ne designeraient plus la
 * fraction d'ecran qu'elles annoncent des que l'utilisateur change de
 * cran. Toutes les tailles ci-dessous sont en `px`. Le centrage lui-meme
 * n'utilise que `top`/`left` en pourcentage (relatifs au bloc contenant
 * d'un `position: fixed`, donc insensibles au meme defaut) et une
 * position ABSOLUE en px ecrite par le JavaScript - jamais `vw`/`vh`.
 *
 * NI L'UN NI L'AUTRE NE GENE LA SAISIE : `pointer-events: none` sur le
 * conteneur entier, aucun voile plein ecran, aucune capture de focus.
 *
 * PAS SEULEMENT LA COULEUR : le glyphe porte une FORME (un arc qui
 * tourne) en plus de sa couleur, et l'element occupe (`.ds-loading-busy`)
 * change d'OPACITE, jamais seulement de teinte - un signal qui ne
 * disparaitrait qu'en couleur resterait invisible a un daltonien (voir
 * les six formes d'icone du module d'impression, meme principe).
 *
 * LE FOND SEMI-TRANSPARENT MARCHE SUR CLAIR COMME SUR SOMBRE
 * ------------------------------------------------------------
 * Ce produit n'a pas de bascule sombre/clair (`prefers-color-scheme`
 * n'est utilise nulle part dans `app.css`) : l'icone recouvre tantot un
 * fond blanc (`--surface`), tantot l'entete bleu nuit. Plutot que
 * detecter ce qu'il y a dessous, le fond de l'icone est lui-meme sombre
 * et translucide (`--navy-900` a ~78 % d'opacite) avec un glyphe blanc -
 * il fournit son PROPRE contraste, et reste lisible sur les deux.
 */

.ds-loading-indicator {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 100000;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.ds-loading-indicator[hidden] {
  display: none;
}

.ds-loading-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: rgba(11, 29, 51, .78);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-soft, 0 18px 45px rgba(16, 24, 40, .10));
}

.ds-loading-icon-glyph {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 4px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  animation: ds-loading-tourner .8s linear infinite;
}

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

/* `.ds-loading-status-text` : masque a l'oeil par defaut (technique
   « sr-only » standard, identique a `.sr-only` de app.css - redefinie ici
   plutot que partagee pour que ce fichier reste lisible et deployable
   seul), lu par un lecteur d'ecran grace a role="status"/aria-live="polite"
   pose sur `.ds-loading-indicator`. */
.ds-loading-status-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Un element declencheur (lien, bouton, formulaire) « en cours » - PAS
   l'indicateur global : ceci reste inchange par la revue du 28.09.2026. */
.ds-loading-busy {
  opacity: .6;
}

/* En plus de `.ds-loading-busy` pour tout ce qui n'a pas de `disabled`
   natif (un lien, une ligne de tableau...) : le clic ne doit plus
   atteindre l'element pendant qu'il est occupe. */
.ds-loading-locked {
  pointer-events: none;
}

.ds-loading-spinner {
  display: inline-block;
  width: 13px;
  height: 13px;
  margin-inline-start: 8px;
  vertical-align: -2px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .45);
  border-top-color: currentColor;
  animation: ds-loading-tourner .7s linear infinite;
}

/* Curseur "en cours" pendant que l'indicateur global est visible - pose
   sur <html> plutot que sur chaque element, pour qu'un curseur explicite
   deja pose plus bas (ex. `cursor: pointer` d'un bouton) continue d'y
   gagner par specificite : ce n'est qu'un repere sur le reste de la
   page. */
html.ds-loading-active {
  cursor: progress;
}

@media (prefers-reduced-motion: reduce) {
  /* L'icone reste, IMMOBILE (aucune animation) plutot que masquee :
     "pas d'animation" ne veut pas dire "pas de repere du tout". */
  .ds-loading-icon-glyph,
  .ds-loading-spinner {
    animation: none;
  }

  /* Sans mouvement, l'icone seule ne dit plus grand-chose a un
     utilisateur voyant : le texte devient visible SOUS elle (le
     conteneur est deja en colonne) - meme principe que la barre fixe +
     texte d'avant le 28.09.2026, applique a l'icone centree. */
  .ds-loading-status-text {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    padding: 5px 14px;
    overflow: visible;
    clip: auto;
    white-space: normal;
    border: 0;
    border-radius: 999px;
    background: rgba(11, 29, 51, .78);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    text-align: center;
  }
}

@media print {
  .ds-loading-indicator {
    display: none !important;
  }
}
