/*
 * Formulaires — habillage par défaut du moteur `assets/js/form-engine.js`.
 *
 * Cette feuille donne à `.c-form__*` une apparence correcte sans intervention :
 * un formulaire posé sur une page neuve est lisible, utilisable au clavier et
 * conforme au contraste, avant même que le site ne l'habille.
 *
 * Elle est chargée **avant** la feuille de la maquette : un site qui définit
 * ses propres valeurs l'emporte, sans avoir à défaire quoi que ce soit ici.
 *
 * Tout est exprimé en tokens — aucune valeur en dur.
 */

/* ------------------------------------------------------------------ */
/* Le formulaire remplit la boîte qu'on lui donne                       */
/* ------------------------------------------------------------------ */

/*
 * Cette feuille ne déclarait **aucune largeur** pour le formulaire lui-même, et
 * un `<form>` est un bloc : il remplit son parent — sauf si ce parent ne l'étire
 * pas.
 *
 * C'est le cas de la moitié des conteneurs qu'on écrit. Bricks pose ses blocs en
 * `display: flex; flex-direction: column`, et `align-items: flex-start` ou
 * `center` — deux réglages parfaitement ordinaires, posés pour le reste du
 * contenu — retirent l'étirement du seul axe qui compte ici. Le formulaire tombe
 * alors à la largeur de son contenu.
 *
 * Mesuré le 04/08/2026 : conteneur de 476 px, formulaire de 273,5 px, sur un
 * `align-items: flex-start` qui n'avait rien à voir avec le formulaire. Rien ne le
 * signalait — la page s'affiche, les champs fonctionnent, le formulaire est
 * simplement deux fois trop étroit.
 *
 * **Un composant déposé dans un conteneur arbitraire ne doit pas dépendre de
 * l'alignement de son hôte.** La largeur est donc déclarée ici, une fois, plutôt
 * que rattrapée site par site — et `align-self: stretch` couvre le cas où le
 * parent est une grille ou un flex dont on ne sait rien.
 */
.c-form__form {
  width: 100%;
  align-self: stretch;
}

/* ------------------------------------------------------------------ */
/* Grille                                                              */
/* ------------------------------------------------------------------ */

.c-form__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-s);
}

/* Un champ déclaré `full` traverse la grille, comme le bloc d'actions. Une
   zone de texte y passe d'office : deux colonnes ne lui suffisent jamais. */
.c-form__field--full,
.c-form__field--textarea,
.c-form__actions {
  grid-column: 1 / -1;
}

@media (max-width: 768px) {
  .c-form__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ------------------------------------------------------------------ */
/* Champ                                                               */
/* ------------------------------------------------------------------ */

.c-form__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  min-width: 0;
}

.c-form__label {
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-s);
  color: var(--color-text-strong);
}

/* On signale le facultatif, pas l'obligatoire : une mention plutôt qu'une
   forêt d'astérisques. Le poids et la couleur la mettent en retrait. */
.c-form__optional {
  font-weight: var(--font-weight-regular);
  color: var(--color-text-muted);
}

.c-form__control {
  width: 100%;
  padding: var(--space-xs) var(--space-s);
  font-family: inherit;
  font-size: inherit;
  color: var(--color-text-base);
  background: var(--color-surface-page);
  border: 1px solid var(--color-border-base);
  border-radius: var(--radius-m);
  transition: border-color var(--motion-duration-fast) var(--motion-easing-standard),
              box-shadow var(--motion-duration-fast) var(--motion-easing-standard);
}

/*
 * Hauteur de ligne native, imposée à Bricks.
 *
 * Bricks applique `line-height: 40px` à `input:not([type="submit"]), select,
 * textarea` — soit 0-1-1, plus fort qu'une classe. Chaque champ y gagne une
 * dizaine de pixels, sans que rien dans le thème ne l'explique. Le sélecteur
 * doublé monte à 0-2-0 et rend la main au navigateur, qui sait dimensionner un
 * champ mieux qu'une valeur fixe.
 */
.c-form__control.c-form__control {
  line-height: normal;
}

.c-form__control::placeholder {
  color: var(--color-text-muted);
}

/* `:focus-visible` seul laisserait un champ cliqué à la souris sans repère
   visible : sur une saisie, on veut voir où l'on écrit dans les deux cas. */
.c-form__control:focus {
  outline: none;
  border-color: var(--color-border-focus);
  box-shadow: 0 0 0 3px var(--color-brand-100);
}

/* La hauteur d'une zone de texte vient de son attribut `rows`, réglé dans la
   définition du formulaire — pas d'un minimum arbitraire posé ici. */
.c-form__field--textarea .c-form__control {
  resize: vertical;
}

/* La flèche native d'un `select` varie d'un système à l'autre : on la dessine.
   Sur le fond du champ plutôt que sur un pseudo-élément, pour qu'une feuille
   de site puisse la remplacer d'une seule déclaration. */
/* `select` et non `.c-form__control` : le bouton de l'habillage porte la même
   classe, et recevait donc ce chevron **en plus** du sien — deux flèches côte
   à côte, visibles sur la première capture. */
.c-form__field--select select.c-form__control {
  appearance: none;
  padding-right: var(--space-xl);
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cpath d='M3 5l4 4 4-4' stroke='%23606772' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-s) center;
}

/*
 * Une case **unique** se lit « case puis intitulé », sur une seule ligne.
 *
 * `:has()` restreint la règle à ce cas : un groupe de cases porte
 * `c-form__choices`, et la mise en ligne y poussait l'intitulé du groupe à
 * droite des options, sur une colonne étroite. Visible sur la capture, et
 * invisible en relecture du sélecteur seul.
 */
/*
 * Classe doublée — 0-3-0 — pour que le modificateur batte la classe de base
 * quoi qu'en fasse la feuille d'un site. Une maquette portée écrit couramment
 * `.c-form__field.c-form__field { flex-direction: column }` : le doublement y
 * sert à battre les panneaux de Bricks, il vaut 0-2-0, et il est enfilé après
 * `form.css`. À égalité, `column` gagnait et la case de consentement passait
 * au-dessus de son intitulé au lieu d'être à côté.
 */
.c-form__field--checkbox.c-form__field--checkbox:not(:has(.c-form__choices)) {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-2xs);
}

/*
 * Une case unique porte souvent un texte d'aide — c'est le cas de tout
 * consentement rédigé. Sur une seule ligne, ce paragraphe se rangeait à droite
 * de l'intitulé et les deux se partageaient la largeur : mesuré à 193 px pour
 * l'intitulé et 420 px pour l'aide, en travers de la carte. `wrap` ci-dessus et
 * cette base pleine largeur le renvoient sous la ligne « case puis intitulé »,
 * qui reste intacte.
 */
.c-form__field--checkbox:not(:has(.c-form__choices)) > .c-form__help,
.c-form__field--checkbox:not(:has(.c-form__choices)) > .c-form__error {
  flex: 1 0 100%;
}

/* Base nulle : l'intitulé tient sur la ligne de la case et enroule son propre
   texte. Sans elle, sa largeur minimale dépasse la place restante en mobile et
   c'est l'intitulé entier qui passe à la ligne — la case reste seule au-dessus. */
.c-form__field--checkbox:not(:has(.c-form__choices)) > .c-form__label {
  flex: 1 1 0;
  min-inline-size: 0;
}

.c-form__field--checkbox .c-form__control {
  flex: 0 0 auto;
  inline-size: var(--space-s);
  block-size: var(--space-s);
  margin-top: 0.125em;
  padding: 0;
  accent-color: var(--color-brand-500);
}

.c-form__field--checkbox .c-form__label {
  font-weight: var(--font-weight-regular);
}

/* ------------------------------------------------------------------ */
/* Choix — boutons radio et cases à cocher                             */
/* ------------------------------------------------------------------ */

/*
 * Le contrôle natif est masqué, jamais retiré.
 *
 * Ni le rond d'un bouton radio ni la coche d'une case ne sont stylables : le
 * navigateur les dessine, et `accent-color` ne change que leur couleur. On les
 * masque donc à l'œil et on trace le marqueur à côté, en CSS.
 *
 * Ce qui reste natif — et c'est tout l'intérêt : le clavier, la navigation par
 * flèches à l'intérieur d'un groupe, le regroupement par `name`, la validation
 * du navigateur, l'envoi du formulaire. Un `div` portant `role="radio"` oblige
 * à tout réimplémenter, et personne ne le fait entièrement.
 */
.c-form__choices {
  display: flex;
  flex-direction: column;
  inline-size: 100%;
}

.c-form__choice {
  position: relative;
  display: flex;
  /*
   * Les options se touchent : leur bordure est commune. Sans cette remise à
   * zéro, la marge que le socle pose sur tout `label` — cinq pixels, mesurés —
   * les décolle et fait apparaître une double bordure entre chacune.
   */
  margin: 0;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-s);
  font-weight: var(--font-weight-regular);
  cursor: pointer;
  background: var(--color-surface-page);
  border: 1px solid var(--color-border-base);
  transition:
    background-color var(--motion-duration-fast) var(--motion-easing-standard),
    border-color var(--motion-duration-fast) var(--motion-easing-standard),
    color var(--motion-duration-fast) var(--motion-easing-standard);
}

/* Les options se touchent : une seule bordure entre deux voisines, et les
   angles arrondis seulement en haut et en bas du groupe. */
.c-form__choices .c-form__choice + .c-form__choice {
  border-block-start-width: 0;
}

.c-form__choices .c-form__choice:first-child {
  border-start-start-radius: var(--radius-s);
  border-start-end-radius: var(--radius-s);
}

.c-form__choices .c-form__choice:last-child {
  border-end-start-radius: var(--radius-s);
  border-end-end-radius: var(--radius-s);
}

/*
 * Masqué, mais toujours dans le flux du document.
 *
 * `display: none` le retirerait de l'ordre de tabulation et de l'arbre
 * d'accessibilité : le champ deviendrait inatteignable au clavier et muet pour
 * un lecteur d'écran. On le réduit donc à un point, sans l'effacer.
 */
.c-form__choice-input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.c-form__choice-text {
  flex: 1 1 auto;
  min-inline-size: 0;
  /* Explicite : sans elle, l'intitulé hérite du gris posé sur le libellé du
     champ — un texte de choix illisible, et pourtant cliquable. */
  color: var(--color-text-strong);
}

.c-form__choice-mark {
  position: relative;
  flex: 0 0 auto;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  border: 2px solid var(--color-border-strong);
  transition: border-color var(--motion-duration-fast) var(--motion-easing-standard);
}

/* La forme dit le comportement : un rond ne se coche que seul, un carré non. */
.c-form__choice--radio .c-form__choice-mark { border-radius: var(--radius-full); }
.c-form__choice--check .c-form__choice-mark { border-radius: var(--radius-s); }

.c-form__choice-mark::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: inherit;
  background: var(--color-brand-500);
  transform: scale(0);
  transition: transform var(--motion-duration-fast) var(--motion-easing-spring);
}

.c-form__choice:hover {
  border-color: var(--color-brand-300);
  z-index: 1;
}

.c-form__choice:has(.c-form__choice-input:checked) {
  color: var(--color-brand-700);
  background: var(--color-brand-50);
  border-color: var(--color-brand-500);
  z-index: 2;
}

.c-form__choice:has(.c-form__choice-input:checked) .c-form__choice-mark {
  border-color: var(--color-brand-500);
}

.c-form__choice:has(.c-form__choice-input:checked) .c-form__choice-mark::after {
  transform: scale(1);
}

/*
 * Le focus se voit sur l'option entière, pas sur un contrôle invisible.
 *
 * Sans cette règle, tabuler dans le groupe ne montre rien du tout : le
 * navigateur pose son contour sur l'`<input>`, qui fait un pixel de côté.
 */
.c-form__choice:has(.c-form__choice-input:focus-visible) {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
  z-index: 3;
}

.c-form__field.is-invalid .c-form__choice {
  border-color: var(--color-feedback-danger);
}

@media (prefers-reduced-motion: reduce) {
  .c-form__choice,
  .c-form__choice-mark,
  .c-form__choice-mark::after {
    transition: none;
  }
}

/* ------------------------------------------------------------------ */
/* Select — habillage posé sur le contrôle natif                       */
/* ------------------------------------------------------------------ */

/*
 * Le `<select>` reste dans la page et garde la valeur ; l'habillage se
 * superpose. Tant que le script n'a pas tourné, c'est le natif qu'on voit —
 * le formulaire reste donc utilisable si le JavaScript ne s'exécute pas.
 */
.c-form__select {
  position: relative;
}

.c-form__select-native {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  opacity: 0;
  pointer-events: none;
}

.c-form__select-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2xs);
  inline-size: 100%;
  text-align: start;
  cursor: pointer;
}

.c-form__select-button.is-placeholder .c-form__select-value {
  color: var(--color-text-muted);
}

.c-form__select-value {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.c-form__select-chevron {
  flex: 0 0 auto;
  inline-size: 0.5rem;
  block-size: 0.5rem;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: translateY(-25%) rotate(45deg);
  transition: transform var(--motion-duration-fast) var(--motion-easing-standard);
}

.c-form__select[data-open="true"] .c-form__select-chevron {
  transform: translateY(25%) rotate(-135deg);
}

.c-form__select-list {
  position: absolute;
  z-index: var(--layer-dropdown);
  inset-inline: 0;
  inset-block-start: calc(100% + var(--space-3xs));
  max-block-size: 16rem;
  margin: 0;
  padding: var(--space-3xs);
  overflow-y: auto;
  list-style: none;
  background: var(--color-surface-page);
  border: 1px solid var(--color-border-base);
  border-radius: var(--radius-s);
  box-shadow: var(--shadow-m);
}

.c-form__select-option {
  padding: var(--space-2xs) var(--space-xs);
  border-radius: var(--radius-s);
  cursor: pointer;
}

/* `is-active` suit le clavier, `aria-selected` dit le choix retenu : deux
   états distincts, qui coexistent pendant qu'on parcourt la liste. */
.c-form__select-option.is-active {
  background: var(--color-surface-sunken);
}

.c-form__select-option[aria-selected="true"] {
  font-weight: var(--font-weight-semibold);
  color: var(--color-brand-700);
}

@media (prefers-reduced-motion: reduce) {
  .c-form__select-chevron {
    transition: none;
  }
}

/* Pièce jointe. Le bouton du sélecteur est dessiné par le système et n'accepte
   presque rien : on habille le champ, pas le bouton, et on lui rend le
   remplissage vertical qu'un `input[type=file]` n'a pas de lui-même. */
.c-form__field--file .c-form__control {
  padding: var(--space-2xs) var(--space-xs);
  cursor: pointer;
}

.c-form__field--file .c-form__control::file-selector-button {
  margin-right: var(--space-xs);
  padding: var(--space-3xs) var(--space-xs);
  font: inherit;
  color: var(--color-text-strong);
  cursor: pointer;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border-base);
  border-radius: var(--radius-s);
}

/* Le nom du fichier choisi. Écrit par le moteur, il reste vide tant que rien
   n'est joint — d'où `:empty`, sans quoi une ligne vide creuserait un écart
   sous chaque champ de fichier. */
.c-form__file-name {
  font-size: var(--font-size-s);
  color: var(--color-text-muted);
}

.c-form__file-name:empty {
  display: none;
}

.c-form__field--hidden {
  display: none;
}

/* Champ-piège : hors de l'écran, pas `display:none` — certains robots savent
   ignorer ce qui est masqué, beaucoup moins ce qui est simplement ailleurs. */
.c-form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.c-form__help {
  font-size: var(--font-size-s);
  color: var(--color-text-muted);
}

/* ------------------------------------------------------------------ */
/* Erreurs                                                             */
/* ------------------------------------------------------------------ */

.c-form__error {
  font-size: var(--font-size-s);
  color: var(--color-feedback-danger);
}

.c-form__error[hidden] {
  display: none;
}

/* La couleur ne porte jamais seule l'information : le champ change aussi de
   trait, et le message écrit reste la source. */
.c-form__field.is-invalid .c-form__control {
  border-color: var(--color-feedback-danger);
}

/* ------------------------------------------------------------------ */
/* Actions                                                             */
/* ------------------------------------------------------------------ */

/* Actions en colonne : le bouton d'abord, puis le statut et la mention. Une
   rangée obligerait à arbitrer entre l'alignement des boutons et le retour à
   la ligne de la mention — la colonne n'a pas ce problème. */
.c-form__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.c-form__submit {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
}

.c-form__submit[disabled] {
  opacity: 0.6;
  cursor: progress;
}

.c-form__note,
.c-form__step,
.c-form__status {
  font-size: var(--font-size-s);
  color: var(--color-text-muted);
}

.c-form__status:empty {
  display: none;
}

.c-form__status.is-error {
  color: var(--color-feedback-danger);
}

.c-form__success {
  font-size: var(--font-size-l);
  color: var(--color-text-strong);
}

/* Choix multiple : chaque ligne porte sa case, comme un groupe de cases à
   cocher. Sans marqueur, rien ne distingue « survolé » de « retenu » une fois
   la liste refermée puis rouverte. */
.c-form__select-option--check {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.c-form__select-option--check::before {
  content: "";
  flex: 0 0 auto;
  inline-size: 1.125rem;
  block-size: 1.125rem;
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius-s);
  transition: background-color var(--motion-duration-fast) var(--motion-easing-standard),
              border-color var(--motion-duration-fast) var(--motion-easing-standard);
}

.c-form__select-option--check[aria-selected="true"]::before {
  background: var(--color-brand-500);
  border-color: var(--color-brand-500);
  /* La coche est dessinée dans la case, pas ajoutée à côté : un caractère
     « ✓ » dépendrait de la police et n'est pas garanti. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' stroke='%23fff' stroke-width='2.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
}

/* En choix multiple, la ligne retenue ne passe pas en gras : la case le dit
   déjà, et le gras ferait sauter la largeur du texte à chaque clic. */
.c-form__select-option--check[aria-selected="true"] {
  font-weight: inherit;
  color: inherit;
}

@media (prefers-reduced-motion: reduce) {
  .c-form__select-option--check::before { transition: none; }
}
