/*
 * AURA — couche de composants
 * ===========================
 *
 * Aucune valeur brute ici : tout vient de `tokens.css`. Un `#hex` ou un `12px`
 * écrit dans ce fichier est un bogue, et `stylelint` le refuse.
 *
 * Nommage BEM : `.aura-bloc__element--variante`. Un seul système, documenté,
 * plutôt qu'un mélange de BEM et de `@layer` que personne ne saurait trancher
 * six mois plus tard.
 *
 * Les composants marqués « spécifique AURA » portent la valeur du produit :
 * ils rendent visible ce que le backend garantit — provenance des preuves,
 * distinction entre absence et zéro, traçabilité d'un verdict.
 */

/* ══════════════════════════════════════════════════════════════════════════
   Icônes
   ══════════════════════════════════════════════════════════════════════════

   Le sprite SVG vendorisé (`static/vendor/icones.svg`) remplace la police
   d'icônes complète (~2000 glyphes pour une centaine réellement utilisés,
   134 Ko de police pour un sprite déjà subsetté à 52 Ko). Le motif est celui
   documenté par Bootstrap Icons pour son propre sprite : `fill: currentcolor`
   fait suivre la couleur du texte comme le faisait la police, `1em` fait
   suivre sa taille — `text-success`, `fs-5`, `display-4` continuent de
   s'appliquer sans changement sur les gabarits. `flex-shrink: 0` : sans lui,
   une icône dans un conteneur flex trop étroit (`.pillar-stat`, boutons)
   perd sa largeur au profit du texte voisin, alors que sa hauteur reste fixe
   — le même correctif que porte la propre classe `.bi` de Bootstrap. */

.bi {
  display: inline-block;
  flex-shrink: 0;
  width: 1em;
  height: 1em;
  vertical-align: -0.125em;
  fill: currentcolor;
}

/* ══════════════════════════════════════════════════════════════════════════
   Boutons
   ══════════════════════════════════════════════════════════════════════════ */

.aura-btn {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
  justify-content: center;
  padding: var(--space-3) var(--space-5);
  font-family: var(--font-body);
  font-size: var(--text-small);
  font-weight: var(--weight-semibold);
  line-height: 1;
  color: var(--text-main);
  text-decoration: none;
  cursor: pointer;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

.aura-btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.aura-btn[disabled],
.aura-btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.5;
}

/*
 * L'action dominante. **Un seul élément or par écran** : s'il y en a deux,
 * l'un des deux n'est pas l'action principale.
 */
.aura-btn--primary {
  color: var(--text-on-accent);
  background: var(--accent-gold);
}

.aura-btn--primary:hover {
  background: var(--accent-gold-hover);
}

.aura-btn--secondary {
  border-color: var(--border-strong);
}

.aura-btn--secondary:hover {
  background: var(--bg-card-hover);
}

.aura-btn--ghost {
  padding-inline: var(--space-3);
  color: var(--text-secondary);
}

.aura-btn--ghost:hover {
  color: var(--text-main);
  background: var(--bg-card-hover);
}

.aura-btn--danger {
  color: var(--danger);
  border-color: var(--danger);
}

.aura-btn--danger:hover {
  color: var(--text-main);
  background: var(--danger);
}

/* Un bouton en cours d'action doit le dire, et refuser un second clic. */
.aura-btn[aria-busy="true"] {
  pointer-events: none;
  opacity: 0.7;
}

/* ══════════════════════════════════════════════════════════════════════════
   Cartes et surfaces
   ══════════════════════════════════════════════════════════════════════════ */

.aura-card {
  padding: var(--space-5);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.aura-card__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-h4);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-heading);
}

.aura-card__meta {
  font-size: var(--text-small);
  color: var(--text-secondary);
}

/* ══════════════════════════════════════════════════════════════════════════
   EvidenceBadge — spécifique AURA
   ══════════════════════════════════════════════════════════════════════════

   Nature d'une preuve : mesurée, estimée, déclarée, ou non évaluée.

   **Jamais la couleur seule.** Chaque variante combine une couleur, une forme
   de bordure et un libellé écrit. Un daltonien, une impression en noir et
   blanc, un écran mal réglé : dans les trois cas l'information survit.

   Présenter une estimation comme une mesure dans un dossier opposable serait
   une faute — c'est la règle §1.1 du plan, rendue visuelle.
   ═══════════════════════════════════════════════════════════════════════════ */

.aura-evidence {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-tiny);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  border: 1px solid;
  border-radius: var(--radius-pill);
}

.aura-evidence__mark {
  font-size: var(--text-small);
  line-height: 1;
}

.aura-evidence--measured {
  color: var(--evidence-measured);
  background: var(--evidence-measured-bg);
  border-color: var(--evidence-measured);
}

.aura-evidence--estimated {
  color: var(--evidence-estimated);
  background: var(--evidence-estimated-bg);
  /* Bordure discontinue : l'incertitude est lisible sans la couleur. */
  border-style: dashed;
  border-color: var(--evidence-estimated);
}

.aura-evidence--declared {
  color: var(--evidence-declared);
  background: var(--evidence-declared-bg);
  border-color: var(--evidence-declared);
}

.aura-evidence--none {
  color: var(--evidence-none);
  background: var(--evidence-none-bg);
  border-style: dotted;
  border-color: var(--evidence-none);
}

/* ══════════════════════════════════════════════════════════════════════════
   MetricCard — spécifique AURA
   ══════════════════════════════════════════════════════════════════════════

   Un indicateur qui **sait afficher l'absence**. Une valeur non mesurée
   s'affiche `—` accompagné de « non mesuré », jamais `0` : un zéro se lit
   « mesuré, et vaut zéro », ce qui est faux et flatteur.
   ═══════════════════════════════════════════════════════════════════════════ */

.aura-metric {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.aura-metric__label {
  font-size: var(--text-tiny);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.aura-metric__value {
  font-family: var(--font-display);
  font-size: var(--text-h1);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  color: var(--text-main);
}

/* La valeur absente n'est pas grisée par pudeur : elle est marquée comme un
   état à part entière, de premier rang. */
.aura-metric__value--absent {
  font-family: var(--font-body);
  font-size: var(--text-h2);
  color: var(--text-muted);
}

.aura-metric__note {
  font-size: var(--text-tiny);
  color: var(--text-muted);
}

/* ══════════════════════════════════════════════════════════════════════════
   CoverageBar — spécifique AURA
   ══════════════════════════════════════════════════════════════════════════

   Couverture d'une exigence, en **trois segments distincts** : satisfait, non
   satisfait, et non évalué.

   Le troisième ne doit jamais être fondu dans le deuxième. « Non évalué »
   n'est pas un échec : c'est une lacune de la mesure, et la couverture ne vaut
   que pour ce qui a été examiné.
   ═══════════════════════════════════════════════════════════════════════════ */

.aura-coverage {
  display: flex;
  gap: 2px;
  height: var(--space-2);
  overflow: hidden;
  background: var(--bg-base);
  border-radius: var(--radius-pill);
}

.aura-coverage__segment {
  height: 100%;
}

.aura-coverage__segment--satisfied {
  background: var(--success);
}

.aura-coverage__segment--unsatisfied {
  background: var(--danger);
}

/* Hachure : « non évalué » se distingue des deux autres même en niveaux de
   gris, et même pour un daltonien rouge-vert. */
.aura-coverage__segment--unassessed {
  background: repeating-linear-gradient(
    45deg,
    var(--evidence-none-bg),
    var(--evidence-none-bg) 3px,
    var(--bg-card-hover) 3px,
    var(--bg-card-hover) 6px
  );
}

.aura-coverage__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-3);
  font-size: var(--text-tiny);
  color: var(--text-secondary);
}

.aura-coverage__key {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
}

.aura-coverage__swatch {
  width: var(--space-3);
  height: var(--space-3);
  border-radius: var(--radius-sm);
}

/* ══════════════════════════════════════════════════════════════════════════
   RiskVerdict et DecisionTrace — spécifique AURA
   ══════════════════════════════════════════════════════════════════════════

   La classification est produite par un arbre de règles déterministe. Sa trace
   est ce qui la rend défendable devant un auditeur : il faut la **montrer**,
   pas la cacher derrière un score.
   ═══════════════════════════════════════════════════════════════════════════ */

.aura-verdict {
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius-lg);
}

.aura-verdict--high-risk {
  background: var(--warning-bg);
  border-left-color: var(--warning);
}

.aura-verdict--minimal {
  background: var(--success-bg);
  border-left-color: var(--success);
}

/*
 * Article 5. Ce n'est pas un badge rouge parmi d'autres : un système relevant
 * d'une pratique interdite ne s'audite pas, il se retire du marché. L'écran
 * correspondant est un arrêt, pas une étape.
 */
.aura-verdict--prohibited {
  background: var(--danger-bg);
  border: 2px solid var(--danger);
  border-left-width: 4px;
}

.aura-verdict__category {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-h2);
  line-height: var(--leading-heading);
}

.aura-trace {
  width: 100%;
  font-size: var(--text-small);
  border-collapse: collapse;
}

.aura-trace th,
.aura-trace td {
  padding: var(--space-3);
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
}

.aura-trace th {
  font-size: var(--text-tiny);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* La règle décisive porte une flèche en plus de son fond : la ligne reste
   repérable sans la couleur. */
.aura-trace__row--decisive {
  font-weight: var(--weight-semibold);
  background: var(--bg-card-hover);
}

.aura-trace__rule {
  font-family: var(--font-mono);
  font-size: var(--text-tiny);
  color: var(--accent-gold);
}

/* ══════════════════════════════════════════════════════════════════════════
   ProvenanceFooter — spécifique AURA
   ══════════════════════════════════════════════════════════════════════════

   Empreinte SHA-256, méthode et version de scoring, bouton copier. C'est ce
   qui permet à un auditeur de vérifier le document qu'on lui remet sans accès
   à la base — l'argument principal du produit.
   ═══════════════════════════════════════════════════════════════════════════ */

.aura-provenance {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-tiny);
  color: var(--text-secondary);
  background: var(--bg-base);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.aura-provenance__hash {
  font-family: var(--font-mono);
  color: var(--text-main);
  overflow-wrap: anywhere;
}

/* ══════════════════════════════════════════════════════════════════════════
   EmptyState — obligatoire sur toute liste
   ══════════════════════════════════════════════════════════════════════════

   Icône, titre, explication, **une seule action**. Un tableau de zéros sans
   marche à suivre décourage ; c'est le défaut de l'écran d'accueil actuel.
   ═══════════════════════════════════════════════════════════════════════════ */

.aura-empty {
  padding: var(--space-8) var(--space-5);
  text-align: center;
}

.aura-empty__icon {
  margin-bottom: var(--space-4);
  font-size: var(--text-h1);
  color: var(--text-muted);
}

.aura-empty__title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-h3);
}

.aura-empty__text {
  max-width: var(--prose-max);
  margin: 0 auto var(--space-5);
  color: var(--text-secondary);
}

/* ══════════════════════════════════════════════════════════════════════════
   RunProgress
   ══════════════════════════════════════════════════════════════════════════ */

.aura-progress {
  height: var(--space-2);
  overflow: hidden;
  background: var(--bg-base);
  border-radius: var(--radius-pill);
}

.aura-progress__fill {
  height: 100%;
  background: var(--primary-fill);
  transition: width var(--duration-slow) var(--ease-out);
}

/* ══════════════════════════════════════════════════════════════════════════
   Jauge de biais — divergente, centrée sur zéro

   Un score de biais BBQ va de -1 à +1 et zéro est le centre, pas l'origine.
   Contrairement à `.aura-progress`, le remplissage part donc du milieu de la
   piste plutôt que de son bord gauche : partir de 0 % laisserait croire
   qu'un score négatif est un manque, alors qu'il désigne un penchant à
   l'encontre du stéréotype, tout autant un penchant que le positif.
   ══════════════════════════════════════════════════════════════════════════ */

.biais-jauge {
  position: relative;
  height: var(--space-2);
  background: var(--bg-base);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

/* Largeur minimale de la colonne qui porte la jauge, pour qu'elle reste
   lisible dans un tableau — évite un `style="min-width"` en ligne. */
.colonne-effect-size {
  min-width: 12rem;
}

.biais-jauge__centre {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background: var(--border-strong);
}

.biais-jauge__remplissage {
  position: absolute;
  top: 0;
  bottom: 0;
  background: var(--primary-fill);
  transition:
    left var(--duration-slow) var(--ease-out),
    width var(--duration-slow) var(--ease-out);
}

/*
 * Position et largeur du remplissage, par pas de 5 points — jamais posées en
 * attribut `style`, que `core/tests/test_styles_en_ligne.py` interdit
 * d'augmenter. Les deux échelles s'arrêtent à 50 : le centre de la jauge est
 * à 50 %, et rien ne va plus loin dans un sens ou dans l'autre.
 */
.biais-jauge__remplissage--gauche-0 {
  left: 0%;
}
.biais-jauge__remplissage--gauche-5 {
  left: 5%;
}
.biais-jauge__remplissage--gauche-10 {
  left: 10%;
}
.biais-jauge__remplissage--gauche-15 {
  left: 15%;
}
.biais-jauge__remplissage--gauche-20 {
  left: 20%;
}
.biais-jauge__remplissage--gauche-25 {
  left: 25%;
}
.biais-jauge__remplissage--gauche-30 {
  left: 30%;
}
.biais-jauge__remplissage--gauche-35 {
  left: 35%;
}
.biais-jauge__remplissage--gauche-40 {
  left: 40%;
}
.biais-jauge__remplissage--gauche-45 {
  left: 45%;
}
.biais-jauge__remplissage--gauche-50 {
  left: 50%;
}

.biais-jauge__remplissage--largeur-0 {
  width: 0%;
}
.biais-jauge__remplissage--largeur-5 {
  width: 5%;
}
.biais-jauge__remplissage--largeur-10 {
  width: 10%;
}
.biais-jauge__remplissage--largeur-15 {
  width: 15%;
}
.biais-jauge__remplissage--largeur-20 {
  width: 20%;
}
.biais-jauge__remplissage--largeur-25 {
  width: 25%;
}
.biais-jauge__remplissage--largeur-30 {
  width: 30%;
}
.biais-jauge__remplissage--largeur-35 {
  width: 35%;
}
.biais-jauge__remplissage--largeur-40 {
  width: 40%;
}
.biais-jauge__remplissage--largeur-45 {
  width: 45%;
}
.biais-jauge__remplissage--largeur-50 {
  width: 50%;
}

/* ══════════════════════════════════════════════════════════════════════════
   Badges et puces
   ══════════════════════════════════════════════════════════════════════════ */

.aura-badge {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-tiny);
  font-weight: var(--weight-medium);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
}

.aura-badge--success {
  color: var(--success);
  background: var(--success-bg);
  border-color: var(--success);
}

.aura-badge--danger {
  color: var(--danger);
  background: var(--danger-bg);
  border-color: var(--danger);
}

.aura-badge--warning {
  color: var(--warning);
  background: var(--warning-bg);
  border-color: var(--warning);
}

.aura-badge--neutral {
  color: var(--text-secondary);
}

/* ══════════════════════════════════════════════════════════════════════════
   Formulaires
   ══════════════════════════════════════════════════════════════════════════ */

.aura-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.aura-field__label {
  font-size: var(--text-small);
  font-weight: var(--weight-medium);
}

.aura-field__control {
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-body);
  font-size: var(--text-body);
  color: var(--text-main);
  background: var(--bg-base);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
}

.aura-field__control:focus-visible {
  border-color: var(--accent-gold);
  outline: none;
  box-shadow: var(--focus-ring);
}

.aura-field__help {
  font-size: var(--text-tiny);
  color: var(--text-muted);
}

/*
 * L'erreur n'est jamais portée par la seule couleur : le message est écrit,
 * relié au champ par `aria-describedby`, et précédé d'un symbole.
 */
.aura-field__error {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  font-size: var(--text-tiny);
  color: var(--danger);
}

.aura-field__control[aria-invalid="true"] {
  border-color: var(--danger);
}

/* ── Lien d'évitement ─────────────────────────────────────────────────────
 *
 * Premier élément focusable de chaque page. Il reste hors de l'écran tant
 * qu'il n'a pas le focus : visible, il n'aurait aucun sens pour qui navigue à
 * la souris ; absent, il obligerait à traverser toute la navigation au clavier
 * à chaque page — une quinzaine de tabulations sur les écrans d'application.
 *
 * `clip-path` plutôt que `display: none`, qui retirerait l'élément de l'ordre
 * de tabulation et le rendrait donc inatteignable.
 */
.aura-evitement {
  position: absolute;
  z-index: 2000;
  inset-inline-start: var(--space-3);
  padding: var(--space-3) var(--space-4);
  color: var(--text-on-accent);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  background: var(--primary-fill);
  border-radius: var(--radius-md);
  transform: translateY(-200%);
  transition: transform var(--duration-fast) var(--ease-out);
}

.aura-evitement:focus {
  transform: translateY(var(--space-3));
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* ── Sélecteur de langue ──────────────────────────────────────────────────
 *
 * Un formulaire, non un lien : changer de langue modifie un état côté serveur.
 * Il reste utilisable sans JavaScript — le bouton envoie le choix.
 */
.selecteur-langue {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.selecteur-langue__champ {
  padding: var(--space-2) var(--space-3);
  font-family: inherit;
  font-size: var(--text-small);
  color: var(--text-main);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}

.selecteur-langue__champ:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

.selecteur-langue__valider {
  padding: var(--space-2) var(--space-3);
  font-family: inherit;
  font-size: var(--text-small);
  color: var(--text-secondary);
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}

.selecteur-langue__valider:hover {
  color: var(--text-main);
  border-color: var(--border-strong);
}

.selecteur-langue__valider:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/*
 * Avec JavaScript, le changement est immédiat et le bouton devient superflu.
 * `hidden` n'est posé que par le script : sans lui, le bouton reste.
 */
.selecteur-langue__valider[hidden] {
  display: none;
}

/*
 * État de la preuve de travail du formulaire d'inscription.
 *
 * Discret par construction : ce n'est pas une action de l'utilisateur, c'est
 * un compte rendu. Le lecteur d'écran l'entend par `aria-live`, l'œil le
 * remarque à peine — et c'est voulu.
 */
.captcha-etat {
  margin: 0.5rem 0 0;
  font-size: 0.875rem;
  color: var(--text-muted);
  min-height: 1.25rem;
}

.captcha-etat.captcha-verifie {
  color: var(--success);
}

/*
 * Ce que fait chaque usage LLM, sur l'écran de configuration.
 *
 * Ces phrases ne sont pas de l'aide contextuelle facultative : leur absence a
 * failli faire auditer le mauvais modèle. Elles se lisent avant le choix, pas
 * après.
 */
.usage-description {
  color: var(--text-muted);
  max-width: 60ch;
  margin-bottom: 1.5rem;
}

.usages-explications dt {
  font-weight: 600;
  margin-top: 0.75rem;
}

.usages-explications dd {
  color: var(--text-muted);
  max-width: 70ch;
  margin-bottom: 0;
}

/*
 * Enrôlement de la double authentification.
 *
 * Le code à scanner est rendu en SVG côté serveur : il ne charge rien, ne
 * dépend d'aucun script, et reste net à toute taille.
 */
.qr-enrolement svg {
  width: 200px;
  height: 200px;
  background: #fff;
  padding: 0.5rem;
  border-radius: 0.25rem;
}

.etapes-mfa > li {
  margin-bottom: 1.5rem;
}

.cle-manuelle {
  user-select: all;
  word-break: break-all;
}

.codes-de-secours {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
  gap: 0.5rem;
  font-size: 1.125rem;
}

/*
 * Deux classes qui remplacent des attributs `style` du gabarit de profil.
 *
 * Le cliquet de `test_styles_en_ligne.py` ne laisse le compte que décroître :
 * ajouter un style en ligne oblige à garder `unsafe-inline` dans `style-src`.
 */
.champ-etroit {
  max-width: 480px;
}

.btn-texte-clair {
  color: #fff;
}
