/* =============================================================================
   style.css — l'APPARENCE du formulaire
   =============================================================================
   Parti pris : minimaliste. Une seule couleur d'accent, beaucoup d'espace,
   des animations courtes et discrètes. Une animation minimaliste doit se
   SENTIR plus qu'elle ne se VOIT : elle explique un changement (une étape
   arrive, une erreur apparaît), elle ne décore pas.

   ORGANISATION DU FICHIER (du plus général au plus précis) :
     1. Variables (couleurs, espacements, durées)
     2. Thème sombre
     3. Base (box-sizing, body)
     4. Mise en page (conteneur, carte)
     5. Indicateur de progression
     6. Étapes (fieldset)
     7. Champs (label, input, aide, erreur)
     8. Boutons
     9. Message global + spinner (servira à l'étape 6)
    10. Animations (@keyframes)
    11. Accessibilité : mouvement réduit

   CE FICHIER NE CONTIENT AUCUNE LOGIQUE. Il réagit à des attributs que le
   JS posera à l'étape 4 :
     - hidden              sur une étape    → étape masquée
     - aria-current="step" sur un <li>      → étape en cours
     - data-fait           sur un <li>      → étape terminée
     - aria-invalid="true" sur un <input>   → champ en erreur
   Le JS change l'ÉTAT, le CSS décide de l'APPARENCE de cet état. Chacun
   son métier : le JS ne touche jamais à une couleur.
   ============================================================================= */


/* =============================================================================
   1. VARIABLES — "custom properties"
   =============================================================================
   Une variable CSS se déclare avec deux tirets (--nom) et s'utilise avec
   var(--nom). On les déclare sur :root (= la balise <html>) pour qu'elles
   soient disponibles PARTOUT dans la page.
   POURQUOI ? Si tu veux changer la couleur d'accent, tu la changes ICI, une
   seule fois, au lieu de la chercher dans 15 règles. C'est la même idée que
   le fichier de config PHP : une seule source de vérité.
   ============================================================================= */
:root {
  /* --- Couleurs ---
     Le nom décrit le RÔLE (fond, texte, accent), jamais la teinte (bleu,
     gris). Ainsi, en thème sombre, "--texte" peut devenir clair sans que
     son nom devienne un mensonge. */
  --fond:          #f5f4f0;   /* fond de page : blanc cassé, plus doux que #fff */
  --surface:       #ffffff;   /* la carte qui porte le formulaire */
  --texte:         #1d1d1f;   /* presque noir : le noir pur (#000) fatigue l'œil */
  --texte-discret: #6e6e73;   /* consignes, étapes inactives */
  --bordure:       #dcdad4;
  --accent:        #2f5d50;   /* vert sapin : la SEULE couleur "forte" de l'interface */
  --accent-doux:   #e3ece8;   /* version très claire de l'accent, pour les fonds */
  --sur-accent:    #ffffff;   /* texte posé SUR l'accent (boutons) */
  --erreur:        #b42318;
  --erreur-doux:   #fdecea;
  --succes:        #1f7a4d;
  --succes-doux:   #e6f4ec;
  --attention:      #8a5a00;  /* ambre : ni succès, ni erreur (demande annulée...) */
  --attention-doux: #fdf3e1;

  /* --- Espacements ---
     Une échelle fixe (4, 8, 12, 16, 24, 32, 48 px) plutôt que des valeurs
     au hasard. Le regard perçoit cette régularité comme de l'ordre, même
     sans savoir pourquoi : c'est un des secrets du design "propre". */
  --esp-1: 0.25rem;  /*  4px */
  --esp-2: 0.5rem;   /*  8px */
  --esp-3: 0.75rem;  /* 12px */
  --esp-4: 1rem;     /* 16px */
  --esp-5: 1.5rem;   /* 24px */
  --esp-6: 2rem;     /* 32px */
  --esp-7: 3rem;     /* 48px */
  /* POURQUOI rem et pas px ? 1rem = la taille de police choisie par
     l'utilisateur dans son navigateur (16px par défaut). Une personne
     malvoyante qui règle 20px verra tout l'espacement grandir avec le texte,
     au lieu d'un texte énorme dans des cases trop petites. */

  --rayon: 10px;     /* arrondi des coins : discret, pas "bulle" */

  /* --- Mouvement ---
     Des durées courtes : au-delà de ~400 ms, une animation d'interface
     donne l'impression que le site est LENT. */
  --duree-rapide: 150ms;
  --duree:        320ms;
  /* Courbe "ease-out" personnalisée : démarre vite, freine en douceur à la
     fin. C'est le mouvement des objets réels qui s'arrêtent : il paraît
     naturel. Une animation "linear" paraît mécanique. */
  --courbe: cubic-bezier(0.22, 1, 0.36, 1);

  /* Police système : celle du système d'exploitation (San Francisco sur Mac,
     Segoe UI sur Windows, Roboto sur Android).
     POURQUOI pas une police Google Fonts ? Zéro téléchargement, donc
     affichage immédiat, et aucune requête vers un service tiers (= rien à
     déclarer au titre du RGPD). Pour un design minimaliste, c'est idéal. */
  --police: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Indique au navigateur que la page sait s'afficher en clair ET en
     sombre : il adapte alors aussi les barres de défilement et les
     éléments natifs. */
  color-scheme: light dark;
}


/* =============================================================================
   2. THÈME SOMBRE
   =============================================================================
   @media (prefers-color-scheme: dark) s'active quand le SYSTÈME de
   l'utilisateur est en mode sombre. On redéfinit seulement les variables :
   toutes les règles qui les utilisent suivent automatiquement. C'est la
   démonstration de la puissance des variables : 15 lignes pour un thème
   complet.
   ============================================================================= */
@media (prefers-color-scheme: dark) {
  :root {
    --fond:          #141414;
    --surface:       #1e1e1f;
    --texte:         #ececec;
    --texte-discret: #9a9a9f;
    --bordure:       #38383b;
    --accent:        #7cc4ab;   /* l'accent s'éclaircit pour rester lisible sur fond sombre */
    --accent-doux:   #1f2e29;
    --sur-accent:    #0f1a16;
    --erreur:        #f2877c;
    --erreur-doux:   #2e1a18;
    --succes:        #6fcf97;
    --succes-doux:   #17271e;
    --attention:      #f0c46b;
    --attention-doux: #2e2614;
  }
}


/* =============================================================================
   3. BASE
   ============================================================================= */

/* box-sizing: border-box — LA règle à mettre dans tous tes projets.
   Par défaut (content-box), width: 300px + padding: 20px donne une boîte de
   340px : le padding s'AJOUTE à la largeur. Avec border-box, la boîte fait
   300px, padding compris. Beaucoup plus intuitif.
   *::before et *::after : les pseudo-éléments (contenus générés par le CSS)
   ne sont pas couverts par * seul. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* L'attribut HTML "hidden" signifie "masqué". Mais il perd face à toute
   règle CSS qui définit display. Exemple : .etape { display: grid } placé
   plus bas RÉAFFICHERAIT une étape cachée par le JS. Le !important garantit
   que hidden gagne toujours. C'est un des rares usages légitimes de
   !important : on l'utilise pour faire respecter une règle, pas pour
   gagner une bataille de priorité. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;                       /* le navigateur ajoute 8px par défaut */
  min-height: 100vh;               /* au moins toute la hauteur de l'écran */
  background: var(--fond);
  color: var(--texte);
  font-family: var(--police);
  font-size: 1rem;
  line-height: 1.5;                /* interligne aéré = lecture confortable */
  /* Lissage des polices sur Mac : texte plus fin et plus net. */
  -webkit-font-smoothing: antialiased;

  /* Centrage de la carte dans la page avec grid :
     place-items: center = centré horizontalement ET verticalement. */
  display: grid;
  place-items: center;
  padding: var(--esp-5) var(--esp-4);
}


/* =============================================================================
   4. MISE EN PAGE
   ============================================================================= */
.conteneur {
  /* width: 100% + max-width : la carte prend toute la largeur sur mobile,
     mais jamais plus de 30rem (480px) sur grand écran. Une ligne de
     formulaire trop large est difficile à suivre des yeux. */
  width: 100%;
  max-width: 30rem;
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: calc(var(--rayon) * 1.6);
  padding: var(--esp-6);
  /* Ombre très légère et très diffuse : elle décolle la carte du fond sans
     attirer l'attention. Deux ombres superposées (une nette, une floue)
     imitent la lumière réelle. */
  box-shadow:
    0 1px 2px rgb(0 0 0 / 0.04),
    0 8px 24px rgb(0 0 0 / 0.04);
}

h1 {
  margin: 0 0 var(--esp-5);
  font-size: 1.375rem;
  font-weight: 600;
  /* letter-spacing négatif sur les titres : les grandes lettres paraissent
     trop espacées naturellement, on les resserre légèrement. */
  letter-spacing: -0.01em;
}

/* Sur petit écran, on récupère de la place : moins de marge intérieure. */
@media (max-width: 30rem) {
  .conteneur {
    padding: var(--esp-5) var(--esp-4);
  }
}


/* =============================================================================
   5. INDICATEUR DE PROGRESSION
   =============================================================================
   Rendu visé :   (1)───(2)───(3)
                Identité  Vérif.  Sécurité
   Les numéros ne sont PAS dans le HTML : ils sont générés par un "compteur"
   CSS. Le HTML garde le sens (une liste ordonnée), le CSS ajoute le décor.
   ============================================================================= */
.progression {
  list-style: none;                /* on retire les "1." "2." natifs */
  margin: 0 0 var(--esp-6);
  padding: 0;
  display: flex;
  counter-reset: etape;            /* crée un compteur nommé "etape", à 0 */
}

.progression li {
  flex: 1;                         /* les 3 étapes se partagent la largeur */
  position: relative;              /* repère pour positionner le trait (::after) */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--esp-2);
  font-size: 0.8125rem;
  color: var(--texte-discret);
  counter-increment: etape;        /* +1 à chaque <li> */
  transition: color var(--duree) var(--courbe);
}

/* La pastille numérotée. ::before crée un élément "virtuel" avant le
   contenu du <li>. */
.progression li::before {
  content: counter(etape);         /* affiche la valeur du compteur : 1, 2, 3 */
  position: relative;
  z-index: 1;                      /* passe AU-DESSUS du trait de liaison */
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;              /* carré + 50% = cercle */
  border: 1.5px solid var(--bordure);
  background: var(--surface);
  font-weight: 600;
  /* On anime les couleurs, pas la taille : changer une couleur ne force
     pas le navigateur à recalculer la mise en page. C'est plus fluide. */
  transition:
    background-color var(--duree) var(--courbe),
    border-color     var(--duree) var(--courbe),
    color            var(--duree) var(--courbe);
}

/* Le trait qui relie une pastille à la suivante.
   :not(:last-child) : pas de trait après la dernière étape. */
.progression li:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 1rem;                       /* au milieu vertical de la pastille (2rem / 2) */
  left: calc(50% + 1rem);          /* part du bord droit de la pastille... */
  right: calc(-50% + 1rem);        /* ...jusqu'au bord gauche de la suivante */
  height: 1.5px;
  background: var(--bordure);
  /* Le trait se "remplit" de couleur de gauche à droite quand l'étape est
     terminée : on utilise un dégradé deux fois plus large que le trait, et
     on fait glisser sa position. */
  background-image: linear-gradient(to right, var(--accent) 50%, var(--bordure) 50%);
  background-size: 200% 100%;
  background-position: 100% 0;     /* au départ, on voit la moitié grise */
  transition: background-position var(--duree) var(--courbe);
}

/* --- Étape EN COURS ---
   On cible l'attribut ARIA directement : le même attribut sert au lecteur
   d'écran ET au style. Impossible d'avoir un affichage qui ment à
   l'accessibilité (classe "active" oubliée, par exemple). */
.progression li[aria-current="step"] {
  color: var(--texte);
  font-weight: 500;
}

.progression li[aria-current="step"]::before {
  border-color: var(--accent);
  color: var(--accent);
  /* Halo léger autour de la pastille active. */
  box-shadow: 0 0 0 4px var(--accent-doux);
}

/* --- Étape TERMINÉE --- (attribut data-fait posé par le JS) */
.progression li[data-fait]::before {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--sur-accent);
}

.progression li[data-fait]::after {
  background-position: 0 0;        /* le trait se remplit d'accent */
}


/* =============================================================================
   6. LES ÉTAPES (fieldset)
   ============================================================================= */
.etape {
  /* Un <fieldset> a un style natif : bordure grise, marges, padding.
     On remet tout à zéro pour repartir d'une page blanche. */
  border: 0;
  margin: 0;
  padding: 0;
  /* PIÈGE CONNU : par défaut, un fieldset refuse de rétrécir sous la
     largeur de son contenu (min-width: min-content). Sur mobile, un long
     texte le fait déborder de l'écran. min-width: 0 corrige ce bug. */
  min-width: 0;

  display: grid;
  gap: var(--esp-5);               /* espace régulier entre les champs */

  /* L'ANIMATION D'ENTRÉE : chaque fois qu'une étape passe de "hidden" à
     visible, elle passe de display:none à display:grid, et le navigateur
     REJOUE son animation. Le JS n'a rien à faire de plus : le simple fait
     d'enlever hidden déclenche l'animation. */
  animation: apparition var(--duree) var(--courbe);
}

.etape legend {
  padding: 0;
  margin-bottom: var(--esp-3);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--texte-discret);
  /* Petit libellé en capitales espacées : discret, mais structure la page. */
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* --- Les icônes Flaticon sous le titre de l'étape 2 --------------------------
   Une icône UIcons est un CARACTÈRE de police : on la règle donc comme du
   texte, avec font-size (taille) et color (couleur).
   display: flex range les deux <i> côte à côte ; gap les espace. */
.icones {
  display: flex;
  gap: var(--esp-2);
  margin-bottom: var(--esp-4);
}

.icones .fi {
  /* Une petite pastille ronde autour de chaque icône : discret, et dans
     les couleurs de l'interface (vert d'accent sur fond vert très clair). */
  display: inline-grid;
  place-items: center;              /* centre l'icône dans la pastille */
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--accent-doux);
  color: var(--accent);
  font-size: 1.125rem;              /* la taille de l'icône elle-même */
  line-height: 1;                   /* évite un décalage vertical de la police */
}


/* =============================================================================
   7. LES CHAMPS
   ============================================================================= */
.champ {
  display: grid;
  gap: var(--esp-2);
}

label {
  font-size: 0.9375rem;
  font-weight: 500;
}

/* La consigne (ex. "16 chiffres..."). Elle est placée APRÈS le label dans le
   HTML, mais on veut la voir sous le champ, près de l'erreur. "order"
   change l'ordre d'AFFICHAGE dans une grille sans changer l'ordre du HTML
   (qui reste logique pour les lecteurs d'écran). */
.aide {
  order: 1;
  margin: 0;
  font-size: 0.8125rem;
  color: var(--texte-discret);
}

input {
  width: 100%;
  padding: var(--esp-3) var(--esp-4);
  /* font: inherit — sans ça, les champs utilisent une police système plus
     petite que le reste de la page. Un oubli très courant. */
  font: inherit;
  /* 16px minimum : en dessous, Safari sur iPhone ZOOME automatiquement
     quand on touche le champ. 1rem = 16px, on est tranquilles. */
  font-size: 1rem;
  color: var(--texte);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  /* outline: none retire le contour bleu natif au focus...
     ATTENTION : ne JAMAIS faire ça sans le remplacer par un autre indicateur
     visible (voir :focus-visible juste après). Sans repère de focus, une
     personne qui navigue au clavier ne sait plus où elle est. */
  outline: none;
  transition:
    border-color var(--duree-rapide) ease,
    box-shadow   var(--duree-rapide) ease;
}

input::placeholder {
  color: var(--texte-discret);
  opacity: 0.6;                    /* l'exemple doit se distinguer d'une vraie saisie */
}

input:hover {
  border-color: var(--texte-discret);
}

/* Le focus : bordure d'accent + halo doux. C'est notre remplaçant du
   contour natif retiré plus haut. */
input:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-doux);
}

/* Le numéro de série en chiffres "tabulaires" (tous de la même largeur) :
   les groupes "1234 5678 9012 3456" restent alignés pendant la frappe au lieu de
   bouger à chaque chiffre. Idem pour la date. */
#numero_serie,
#date_expiration {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

/* type="number" ajoute de petites flèches haut/bas. Inutiles pour un quota
   et visuellement bruyantes : on les retire. Le préfixe -webkit- vise
   Chrome/Safari/Edge, -moz- vise Firefox. */
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* --- Champ en erreur ---
   Le JS posera aria-invalid="true" sur le champ. Comme pour aria-current,
   l'attribut sert À LA FOIS au lecteur d'écran ("invalide") et au style.
   POURQUOI pas :invalid ? Parce que :invalid s'applique dès le chargement :
   un champ obligatoire encore vide serait rouge avant même que
   l'utilisateur ait tapé quoi que ce soit. Agressif. On préfère que le JS
   décide QUAND montrer l'erreur (au clic sur "Suivant"). */
input[aria-invalid="true"] {
  border-color: var(--erreur);
}
input[aria-invalid="true"]:focus-visible {
  box-shadow: 0 0 0 4px var(--erreur-doux);
}

/* Le message d'erreur sous le champ. */
.erreur {
  order: 2;                        /* toujours en dernier, sous la consigne */
  margin: 0;
  font-size: 0.8125rem;
  color: var(--erreur);
  animation: apparition var(--duree-rapide) var(--courbe);
}

/* :empty = "ne contient rien". Une erreur vide ne doit prendre AUCUNE
   place : sinon l'espace (gap) de la grille creuserait un trou sous chaque
   champ. Dès que le JS y écrit un texte, :empty ne s'applique plus, le
   message apparaît... et l'animation se joue. */
.erreur:empty {
  display: none;
}


/* =============================================================================
   8. BOUTONS
   ============================================================================= */
.actions {
  display: flex;
  gap: var(--esp-3);
  margin-top: var(--esp-2);
}

button {
  font: inherit;
  font-weight: 500;
  padding: var(--esp-3) var(--esp-5);
  border-radius: var(--rayon);
  border: 1px solid transparent;
  cursor: pointer;                 /* la petite main : "c'est cliquable" */
  /* Hauteur minimale de 44px : la taille recommandée pour qu'une zone
     tactile soit facile à toucher avec le doigt. */
  min-height: 2.75rem;
  outline: none;
  transition:
    background-color var(--duree-rapide) ease,
    border-color     var(--duree-rapide) ease,
    transform        var(--duree-rapide) ease,
    box-shadow       var(--duree-rapide) ease;
}

/* Bouton PRINCIPAL ("Suivant", "Envoyer") : l'action qu'on veut voir
   faire. Il est plein, en couleur d'accent, et poussé à droite.
   Sélecteur : tout bouton dont data-action vaut "suivant", ou le bouton
   d'envoi. Le style découle du RÔLE du bouton, sans classe à ajouter. */
button[data-action="suivant"],
button[type="submit"] {
  margin-left: auto;               /* pousse le bouton tout à droite */
  background: var(--accent);
  color: var(--sur-accent);
}

/* Bouton SECONDAIRE ("Précédent") : discret, contour seulement. On ne doit
   pas hésiter entre les deux : un seul bouton attire l'œil. */
button[data-action="precedent"] {
  background: transparent;
  color: var(--texte);
  border-color: var(--bordure);
}

/* filter: brightness() fonce légèrement le bouton au survol, quelle que
   soit sa couleur (pratique : marche aussi en thème sombre). */
button:hover {
  filter: brightness(0.94);
}
button[data-action="precedent"]:hover {
  border-color: var(--texte-discret);
}

/* :active = pendant que le bouton est enfoncé. Un enfoncement de 2% :
   imperceptible consciemment, mais le bouton "répond" sous le doigt. C'est
   ce genre de détail qui rend une interface agréable. */
button:active {
  transform: scale(0.98);
}

button:focus-visible {
  box-shadow: 0 0 0 4px var(--accent-doux);
}

/* Bouton désactivé (le JS le désactivera pendant l'envoi, à l'étape 6,
   pour empêcher un double clic = double enregistrement en base). */
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}


/* =============================================================================
   9. MESSAGE GLOBAL + SPINNER (utilisés à l'étape 6)
   =============================================================================
   Le JS ajoutera une de ces classes à #message-global selon la réponse du
   serveur :
     .message--chargement  → envoi en cours (avec spinner)
     .message--succes      → demande enregistrée
     .message--erreur      → échec (serveur injoignable, erreur PHP...)
   Convention de nommage "bloc--variante" (méthode BEM) : on lit tout de
   suite que c'est une VARIANTE du message.
   ============================================================================= */
#message-global:empty {
  display: none;
}

#message-global {
  display: flex;
  align-items: center;
  gap: var(--esp-3);
  margin-bottom: var(--esp-5);
  padding: var(--esp-4);
  border-radius: var(--rayon);
  font-size: 0.9375rem;
  background: var(--accent-doux);
  animation: apparition var(--duree) var(--courbe);
}

/* POURQUOI "#message-global.message--succes" et pas juste ".message--succes" ?
   À cause de la SPÉCIFICITÉ : quand deux règles se contredisent, la plus
   "précise" gagne. Un id (#) pèse plus lourd qu'une classe (.) : la règle
   #message-global ci-dessus imposerait son fond même avec la classe. En
   combinant id + classe, notre règle devient plus précise et gagne. C'est
   la bonne façon de faire, plutôt que d'ajouter !important partout. */
#message-global.message--succes {
  background: var(--succes-doux);
  color: var(--succes);
}

#message-global.message--erreur {
  background: var(--erreur-doux);
  color: var(--erreur);
}

/* "Attention" : la demande a été annulée (10 minutes sans décision), ou
   validée sans compte à créditer (page admin). Pas une erreur de
   l'utilisateur, pas un succès non plus : une couleur ambre, entre les deux. */
#message-global.message--attention {
  background: var(--attention-doux);
  color: var(--attention);
}

/* Le succès porte une petite coche dans un cercle, générée en CSS (aucune
   image). Elle "apparaît" avec un léger effet d'échelle : le seul moment
   un peu festif de l'interface, et il reste discret. */
#message-global.message--succes::before {
  content: "✓";
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--succes);
  color: var(--surface);
  font-weight: 700;
  animation: coche 420ms var(--courbe);
}

/* Le JS met le focus sur le message de succès pour que les lecteurs
   d'écran le lisent. Ce focus est donné PAR SCRIPT (l'élément n'est pas
   atteignable avec Tab), le contour de focus n'aide donc personne ici. */
#message-global:focus {
  outline: none;
}

/* Pendant l'envoi, le JS rend le formulaire "inert" (plus aucune
   interaction possible). On le montre en l'estompant : l'utilisateur
   comprend qu'il doit attendre, sans qu'on ait besoin de l'écrire. */
form[inert] {
  opacity: 0.5;
  transition: opacity var(--duree) var(--courbe);
}

/* Le spinner : un simple cercle dont un quart de la bordure est coloré, qui
   tourne sur lui-même. Aucune image : 100% CSS.
   Le JS l'insérera ainsi : <span class="spinner" aria-hidden="true"></span>
   aria-hidden : c'est un décor, le lecteur d'écran lira le TEXTE du message
   ("Envoi en cours..."), pas le spinner. */
.spinner {
  flex-shrink: 0;                  /* ne s'écrase pas si le texte est long */
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  border: 2px solid var(--bordure);
  border-top-color: var(--accent);
  animation: rotation 0.8s linear infinite;
  /* Ici "linear" est voulu : une rotation continue doit avoir une vitesse
     constante, sinon le spinner semble hoqueter à chaque tour. */
}


/* Le lien "Nouvelle demande" ajouté par le JS à la fin du message final.
   margin-left: auto le pousse à droite du message (le message est en flex). */
.message__lien {
  margin-left: auto;
  color: inherit;
  font-weight: 500;
  white-space: nowrap;
}


/* =============================================================================
   9 bis. L'ÉCRAN D'ATTENTE (après l'envoi, pendant 10 minutes maximum)
   =============================================================================
   Le formulaire disparaît ; à sa place : un grand spinner, une phrase, le
   temps restant et une fine barre qui se vide. Tout est centré, sans cadre :
   le minimalisme, c'est aussi savoir ne RIEN ajouter. */
.attente {
  display: grid;
  justify-items: center;
  gap: var(--esp-3);
  padding: var(--esp-6) 0 var(--esp-4);
  text-align: center;
  animation: apparition var(--duree) var(--courbe);
}

/* [hidden] doit toujours gagner sur display: grid ci-dessus. Sans cette
   règle, "hidden" n'aurait aucun effet (display: grid l'écraserait). */
.attente[hidden] {
  display: none;
}

/* Les contenus possibles de l'écran d'attente (spinner, bloc du code NPI,
   bloc du code NSS) : centrés de la même façon. [hidden] doit gagner sur
   display. */
.attente__bloc {
  display: grid;
  justify-items: center;
  gap: var(--esp-3);
  width: 100%;
  animation: apparition var(--duree) var(--courbe);
}
.attente__bloc[hidden] {
  display: none;
}

/* Le champ du code (NPI, NSS) : centré, pas trop large, lettres espacées pour
   bien lire chaque caractère du code. */
.champ--code {
  width: min(16rem, 100%);
  margin: var(--esp-2) 0 0;
  text-align: left;
}
.champ--code input {
  text-align: center;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

/* Le formulaire à l'intérieur de chaque bloc de code : mêmes alignements
   que le bloc lui-même (titre, texte, champ et bouton centrés). */
.formulaire-code {
  display: grid;
  justify-items: center;
  gap: var(--esp-3);
  width: 100%;
}

/* Le bouton "Envoyer le code" : style principal, mais centré (le
   margin-left: auto des boutons d'envoi le pousserait à droite). */
.formulaire-code button {
  margin-left: 0;
}

/* Variante plus grande du spinner du message global. Même animation. */
.spinner--grand {
  width: 2.75rem;
  height: 2.75rem;
  border-width: 3px;
  margin-bottom: var(--esp-2);
}

.attente__titre {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
}

.attente__texte {
  margin: 0;
  max-width: 22rem;
  color: var(--texte-discret);
  font-size: 0.9375rem;
}

/* Le minuteur "9:42" : chiffres de largeur fixe, pour qu'il ne "tremble"
   pas quand les chiffres changent (le 1 est plus étroit que le 8). */
.attente__minuteur {
  margin: var(--esp-2) 0 0;
  font-size: 0.8125rem;
  color: var(--texte-discret);
  font-variant-numeric: tabular-nums;
}

/* La barre de temps : un rail gris, et un remplissage vert qui se vide.
   Le JS ne change que la LARGEUR en % ; la transition rend la descente
   fluide entre deux mises à jour au lieu de sauter par à-coups. */
.attente__barre {
  width: min(16rem, 100%);
  height: 3px;
  border-radius: 3px;
  background: var(--bordure);
  overflow: hidden;
}

.attente__barre span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: width 1s linear;
}


/* =============================================================================
   10. ANIMATIONS
   =============================================================================
   @keyframes décrit les étapes d'une animation ; la propriété "animation"
   (plus haut) l'applique à un élément avec une durée et une courbe.
   ============================================================================= */

/* Apparition : léger fondu + montée de 8px. Assez pour que l'œil
   remarque l'arrivée d'un contenu, trop peu pour distraire.
   On n'anime que opacity et transform : ce sont les deux propriétés que le
   navigateur sait animer sans recalculer la mise en page (il délègue à la
   carte graphique). Résultat : 60 images par seconde, même sur un vieux
   téléphone. Animer margin ou top, au contraire, saccade. */
@keyframes apparition {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* La coche du succès : part d'un peu plus petit et "se pose". */
@keyframes coche {
  from {
    opacity: 0;
    transform: scale(0.6);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes rotation {
  to {
    transform: rotate(360deg);
  }
}


/* =============================================================================
   11. ACCESSIBILITÉ : MOUVEMENT RÉDUIT
   =============================================================================
   Certaines personnes (troubles vestibulaires, migraines) ont activé dans
   leur système l'option "réduire les animations". Les mouvements à l'écran
   peuvent leur donner des vertiges. On respecte ce choix en coupant
   presque toutes les animations.
   On garde 0.01ms plutôt que 0 : certains scripts attendent la fin d'une
   animation (événement "animationend") ; avec 0, cet événement pourrait ne
   jamais se déclencher.
   Le spinner, lui, continue de tourner, mais plus lentement : c'est une
   INFORMATION ("ça charge"), pas une décoration.
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .spinner {
    animation-duration: 1.6s !important;
    animation-iteration-count: infinite !important;
  }
}


/* =============================================================================
   12. CRÉDIT DES ICÔNES (condition de la licence Flaticon)
   ============================================================================= */
.credit {
  margin: var(--esp-4) 0 0;
  text-align: center;
  font-size: 0.75rem;
  color: var(--texte-discret);
}

.credit a {
  color: inherit;
}
