/* ============================================================
   Puck Flip — Primitives d'accessibilité (socle partagé)

   Chargée juste APRÈS tokens.css par les QUATRE porteurs : layout.php,
   layout_public.php, login.php et quick_check.php.

   POURQUOI UNE FEUILLE SÉPARÉE : login.php et quick_check.php sont rendues par
   renderStandalone(), sans layout. Elles ne chargent donc ni app.css ni public.css,
   et aucune règle d'accessibilité partagée ne les atteignait — c'est ainsi que le
   sélecteur de langue de /login est resté à 16x24 alors qu'il était corrigé partout
   ailleurs, et que les cases à cocher de /quick-check faisaient 16x16.

   RÈGLE : ce fichier ne contient QUE des correctifs d'accessibilité mesurés. Aucune
   décision de direction visuelle — couleurs, tailles de police, espacements
   appartiennent à tokens.css et aux feuilles de composants.

   Chaque bloc cite la violation qui le justifie (mesure axe-core, WCAG 2.2 AA).
   ============================================================ */

/* ---- Anneau de focus global -----------------------------------------------
   Définition unique. Elle vivait en triple (layout.php, public.css, login.php),
   avec le risque qu'une copie dérive. Chargée avant les feuilles de composants :
   une page peut encore la renforcer, jamais l'effacer silencieusement.

   Ne JAMAIS ajouter `outline: none` sans indicateur de remplacement à >= 3:1.
   L'ancienne règle `input:focus { outline: none }` (spécificité 0,1,1) battait ce
   sélecteur (0,1,0) et ne laissait qu'une ombre à 1,40:1 : la tabulation dans un
   formulaire était aveugle. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ---- Cibles tactiles ------------------------------------------------------
   WCAG 2.5.8 (AA, 2.2) : 24x24 CSS px minimum, sauf lien au fil d'une phrase.

   Cases et boutons radio mesurés 13x13 (/pricing), 16x16 (/quick-check) et
   20x20 (/listings). 18px en pointeur fin garde la proportion dans une cellule
   de tableau ; 24px dès que le pointeur est grossier, seuil normatif. */
input[type="checkbox"],
input[type="radio"] {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  accent-color: var(--primary);
}
@media (pointer: coarse) {
  input[type="checkbox"],
  input[type="radio"] {
    width: 24px;
    height: 24px;
  }
}

/* Sélecteur de langue : fragment partagé par les trois layouts, mesuré 16x24.
   inline-flex + min-* crée la cible sans modifier l'aspect de la pilule. */
.lang-switch a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  min-height: 24px;
}

/* ---- Champ obligatoire ----------------------------------------------------
   WCAG 3.3.2 : un champ requis signalé par un seul astérisque coloré n'informe
   ni les personnes qui ne perçoivent pas la couleur, ni les lecteurs d'écran si
   le glyphe est décoratif. Le libellé porte donc le mot, masqué à l'œil. */
label .required {
  color: var(--danger-text);
  margin-left: 2px;
}
label .required::after {
  content: ' (obligatoire)';
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- Message d'erreur de champ -------------------------------------------
   WCAG 3.3.1 : l'erreur doit être identifiée en texte, associée au champ par
   aria-describedby, et ne pas reposer sur la couleur seule — d'où le glyphe. */
.field__error,
.form-error {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-1);
  margin-top: var(--sp-1);
  font-size: var(--fs-sm);
  color: var(--danger-text);
}
.field__error::before,
.form-error::before {
  content: '▲';
  font-size: 0.7em;
  line-height: 1.7;
  flex-shrink: 0;
}

/* Champ invalide. Le sélecteur cible aria-invalid plutôt qu'une classe : l'état
   doit être exposé aux technologies d'assistance pour être stylé, ce qui rend le
   balisage accessible par construction. */
[aria-invalid="true"] {
  border-color: var(--danger) !important;
}

/* ---- Utilitaire : accessible mais non visible -----------------------------
   Nécessaire aux <caption> de tableau, aux titres de page rendus par le layout
   et aux libellés que le design ne peut pas afficher. */
.u-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Variante révélée à la tabulation, pour un lien d'évitement. */
.u-sr-only-focusable:not(:focus):not(:focus-within) {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Mouvement ------------------------------------------------------------
   WCAG 2.3.3 : filet de sécurité global. Les vues portent 44 blocs <style>
   locaux dont tous n'honorent pas la préférence système ; cette règle les couvre
   sans avoir à les auditer un par un. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- Cibles tactiles compactes -------------------------------------------
   WCAG 2.5.8 exige 24x24 CSS px. Certains liens d'action tiennent en 22-23px de
   haut parce que leur hauteur suit le texte, et les agrandir deplacerait la
   ligne qui les contient. Le pseudo-element etend la cible reelle sans changer
   un seul pixel a l'ecran : il n'a ni fond, ni bordure, ni contenu.

   Ne pas appliquer a un lien deja porteur d'un ::before, ni a un lien noye dans
   une phrase (l'exception « inline » de 2.5.8 s'y applique deja). */
.u-hit-24 {
  position: relative;
}

.u-hit-24::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 24px;
}

/* ---- PIED DE PAGE LEGAL (fragments/legal_footer.php) ------------------------
   Rendu par les DEUX layouts, qui chargent des feuilles disjointes : public.css
   pour la vitrine, app.css pour l'application. La taille de cible ne peut donc pas
   vivre dans l'une des deux — mesure axe : 139x15px, refuse en target-size.

   Ce sont des entrees de <nav> et un lien de contact, donc des cibles autonomes :
   l'exception « lien dans une phrase » de WCAG 2.5.8 ne s'applique pas. La boite
   grandit d'elle-meme plutot que par un ::before, dont l'audit doutait. */
.footer-legal a,
.footer-operator a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}
