/* Composants : les briques qui portent le parcours de demande de devis. */

/* ---------------------------------------------------------------- Boutons ---- */

.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sima-esp-2);
  min-height: var(--sima-touche-min);
  padding: var(--sima-esp-3) var(--sima-esp-6);
  border: 1px solid transparent;
  border-radius: var(--sima-rayon-champ);
  font-family: var(--sima-police-texte);
  font-size: var(--sima-corps);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--sima-transition),
    border-color var(--sima-transition),
    transform var(--sima-transition);
}

/*
 * L'action principale du site, et la seule qui porte le rouge.
 * Regle a tenir : UN SEUL bouton rouge par ecran. S'il sert au bouton, aux titres, aux
 * liens et aux en-tetes de tableau, il ne signale plus rien.
 */
.bouton--principal {
  background: var(--sima-rouge);
  border-color: var(--sima-rouge);
  color: var(--sima-blanc);
}

.bouton--principal:hover {
  background: var(--sima-rouge-fonce);
  border-color: var(--sima-rouge-fonce);
  color: var(--sima-blanc);
}

.bouton--principal:active {
  transform: translateY(1px);
}

.bouton--secondaire {
  background: var(--sima-fond);
  border-color: var(--sima-bordure);
  color: var(--sima-texte);
}

.bouton--secondaire:hover {
  border-color: var(--sima-texte);
  color: var(--sima-texte);
}

.bouton--acier {
  background: var(--sima-acier);
  border-color: var(--sima-acier);
  color: var(--sima-blanc);
}

.bouton--acier:hover {
  background: #23405a;
  color: var(--sima-blanc);
}

.bouton--pleine-largeur {
  width: 100%;
}

.bouton[disabled],
.bouton[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

@media (max-width: 768px) {
  .bouton {
    min-height: 56px;
  }
}

/* ------------------------------------------------------- Mention de tarif ---- */

/*
 * « Tarif sur demande » est OBLIGATOIRE et ne disparait jamais.
 * Sur l'ancien site, le visiteur voyait une quantite et un bouton « Ajouter au panier »
 * sans prix : il en deduisait une erreur du site, pas une intention.
 */
.tarif-sur-demande {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sima-esp-2);
  font-weight: 600;
  color: var(--sima-acier);
}

.tarif-sur-demande__delai {
  font-weight: 400;
  font-size: var(--sima-petit);
  color: var(--sima-texte-2);
}

/* ------------------------------------------------------------ Carte produit -- */

/*
 * `auto-fill` et non `auto-fit`.
 *
 * `auto-fit` effondre les pistes vides et repartit la place sur celles qui restent :
 * une famille filtree a un seul resultat affichait une carte large de toute la page,
 * avec une photographie de produit etiree sur quatre colonnes. Une carte doit garder la
 * meme taille qu'il y en ait 1, 4 ou 20 - c'est ce qui fait qu'une grille se lit.
 *
 * `auto-fill` laisse donc des pistes vides a droite d'une derniere ligne incomplete.
 * C'est le comportement voulu, pas un trou a boucher.
 *
 * Les pistes restent flexibles : c'est la CARTE qui est plafonnee, pas la piste.
 *
 * Une premiere version bornait la piste - `minmax(236px, 320px)` - pour pouvoir centrer
 * la grille. L'effet etait tout autre : quand la fonction max est definie, la
 * specification calcule le nombre de repetitions sur ELLE et non sur le minimum. Le
 * catalogue tombait a trois colonnes en 1920 px, la ou la charte en vise quatre des
 * 1560 px, et les tuiles a une seule colonne en 768 px.
 *
 * Avec `1fr` le compte des colonnes redevient juste, et `max-inline-size` sur la carte
 * garde la taille constante voulue plus haut. La marge automatique centre la carte dans
 * sa piste : sans elle, l'ecart se reporterait entierement a droite de chaque carte.
 */
.grille-produits {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 236px), 1fr));
  gap: var(--sima-esp-6);
  list-style: none;
  padding: 0;
  margin: 0;
}

.carte {
  display: flex;
  flex-direction: column;
  background: var(--sima-fond);
  /* Une ombre des le repos. Sans elle, une grille de 24 cartes se lit comme un tableau
     quadrille : la bordure dessine la grille au lieu de detourer l'objet. */
  border: 1px solid var(--sima-bordure-tenue);
  border-radius: var(--sima-rayon-carte);
  box-shadow: var(--sima-ombre-1);
  overflow: hidden;
  transition:
    border-color var(--sima-transition),
    box-shadow var(--sima-transition),
    transform var(--sima-transition);
}

.carte:hover {
  border-color: var(--sima-bordure);
  box-shadow: var(--sima-ombre-2);
  /* `prefers-reduced-motion` ramene la transition a 0 ms, le deplacement devient alors
     instantane plutot qu'anime. */
  transform: translateY(-3px);
}

/*
 * Le rang : une machine par ligne, sur toute la largeur.
 *
 * Mesure prise chez le concurrent que le client a cite : image a ~38 % de la largeur
 * utile, texte a ~56 %, gouttiere large, et un pas vertical CONSTANT quelle que soit la
 * longueur du texte. Le texte est cale en haut et la colonne droite reste creuse : c'est
 * ce vide qui distingue une mise en avant d'une liste. Le remplir annulerait l'effet.
 *
 * Pas de carte, pas d'ombre, pas d'angle arrondi : un filet fin separe les rangs. Une
 * grille de cartes dit « stock » ; un rang dit « voici cette machine ».
 */
.grille-produits--rangs {
  display: block;
}

.grille-produits--rangs .carte--rang {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: var(--sima-esp-8);
  align-items: start;
  max-inline-size: none;
  margin-inline: 0;
  padding-block: var(--sima-esp-6);
  border: 0;
  border-block-end: 1px solid rgb(44 74 99 / 20%);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

.grille-produits--rangs .carte--rang:hover {
  /* Le rang ne se souleve pas : il n'est pas une carte. */
  transform: none;
  box-shadow: none;
}

.grille-produits--rangs .carte--rang .carte__visuel {
  border-radius: var(--sima-rayon-carte);
}

.grille-produits--rangs .carte--rang .carte__phrase {
  margin-block-start: var(--sima-esp-3);
  color: var(--sima-texte-3);
  max-inline-size: 62ch;
}

/*
 * Sous 900 px, le rang redevient une carte empilee.
 *
 * Chez le concurrent, le rang mobile fait 463 px de haut et quatorze machines
 * demandent 6 500 px de defilement. Une image en 4:3 pleine largeur, le nom, les
 * chiffres, et rien d'autre : la phrase disparait, elle ne se lit pas a cette taille.
 */
@media (max-width: 900px) {
  .grille-produits--rangs .carte--rang {
    grid-template-columns: 1fr;
    gap: var(--sima-esp-4);
  }

  .grille-produits--rangs .carte--rang .carte__phrase {
    display: none;
  }
}

.carte__visuel {
  /* Le rapport des sources, et non un carre.
   *
   * Le carre avait ete choisi pour donner de la presence a la machine dans une grille a
   * quatre colonnes. Mesure : une source 4:3 posee dans un cadre carre en `contain`
   * laisse environ 25 % de vide en haut et en bas, et porte la carte a 502 px de haut
   * pour 288 de large. La presence recherchee etait donc surtout du blanc, et la grille
   * s'en trouvait etiree.
   *
   * Fond blanc et marge interieure conserves : un packshot colle dans une boite grise
   * sans marge, c'est la signature visuelle de PrestaShop 1.6, exactement ce dont on
   * sort. */
  aspect-ratio: var(--sima-ratio-produit);
  background: var(--sima-fond);
  padding: var(--sima-esp-4);
  overflow: hidden;
}

/*
 * `sima_image()` rend un `<picture>`, pas un `<img>` nu.
 *
 * Sans cette regle, le `height: 100%` de l'image se resolvait contre le `<picture>`,
 * lui-meme en hauteur automatique : le pourcentage devenait `auto` et `object-fit`
 * cessait de s'appliquer. Une photo carree s'affichait donc a 240x240 dans un cadre de
 * 240x180 - soixante pixels de machine rognes en bas, sur toutes les vignettes du
 * catalogue, et une hauteur d'image differente d'une carte a l'autre.
 *
 * C'etait un bug, pas un choix esthetique, et il expliquait une bonne part du « ca fait
 * vieux ».
 */
.carte__visuel picture {
  display: block;
  width: 100%;
  height: 100%;
}

.carte__visuel img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: transform 250ms ease-out;
}

.carte:hover .carte__visuel img {
  transform: scale(1.04);
}

.carte__corps {
  display: flex;
  flex-direction: column;
  gap: var(--sima-esp-3);
  /* 16 px sur une carte de 278 px, c'etait la densite qui faisait bon marche. */
  padding: var(--sima-esp-6);
  flex: 1;
}

.carte__marque {
  font-size: var(--sima-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--sima-texte-3);
}

.carte__titre {
  font-family: var(--sima-police-titre);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.2;
  margin: 0;
}

.carte__titre a {
  text-decoration: none;
}

.carte__titre a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.carte {
  max-inline-size: 320px;
  margin-inline: auto;
  position: relative;
}

/*
 * Les trois caracteristiques ne sont pas decoratives : ce sont celles qui permettent
 * d'eliminer un produit sans ouvrir sa fiche.
 */
/*
 * Les chiffres cles de la carte - largeur, puissance, poids.
 *
 * C'etait une phrase : « 2 200 W · 60 kg », alignee a gauche, a la suite du titre. Trois
 * defauts en un. Les valeurs ne s'alignaient pas d'une carte a l'autre, donc l'oeil ne
 * pouvait pas les comparer en balayant une grille - or c'est EXACTEMENT ce qu'on fait
 * devant un catalogue technique. Le point median les collait les unes aux autres. Et la
 * hauteur du bloc variait avec le nombre de valeurs, ce qui decalait tout ce qui suit.
 *
 * Elles forment desormais une bande : une cellule par valeur, centree, separee d'un
 * filet. `margin-top: auto` la pousse en bas du corps, juste au-dessus du pied - et
 * comme les cartes d'une meme rangee ont la meme hauteur, les bandes se retrouvent a la
 * meme ligne. C'est ce qui les rend comparables.
 */
.carte__cles {
  display: flex;
  align-items: center;
  margin: var(--sima-esp-4) 0 0;
  margin-top: auto;
  padding-block: var(--sima-esp-3);
  list-style: none;
  border-block: 1px solid var(--sima-bordure-tenue);
}

.carte__cle {
  flex: 1 1 0;
  min-width: 0;
  padding-inline: var(--sima-esp-2);
  text-align: center;
  font-size: var(--sima-petit);
  color: var(--sima-texte-2);
  /* Sans chiffres tabulaires, « 2 200 W » et « 60 kg » ne se superposent pas d'une carte
     a l'autre, et la colonne tremble. */
  font-variant-numeric: tabular-nums;
  line-height: 1.3;
}

.carte__cle + .carte__cle {
  border-inline-start: 1px solid var(--sima-bordure-tenue);
}

/* Sur un rang - les machines de l'accueil -, la bande ne s'etire pas sur toute la
   largeur : elle se range a gauche, au fil du texte, et reste lisible. */
.carte--rang .carte__cles {
  margin-top: var(--sima-esp-4);
  justify-content: flex-start;
}

.carte--rang .carte__cle {
  flex: 0 1 auto;
  min-width: 7rem;
}

.carte__pied {
  margin-top: auto;
  padding-top: var(--sima-esp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sima-esp-3);
}

.carte__pied .bouton {
  position: relative;
  z-index: 1;
}

/* -------------------------------------------------------- Selecteur d'axes ---- */

/*
 * Des pastilles, pas des listes deroulantes : on voit tout d'un coup et on tape du
 * doigt. Les 567 declinaisons de l'ancien catalogue etaient invisibles au visiteur.
 */
.axe {
  margin-bottom: var(--sima-esp-6);
}

.axe__nom {
  display: block;
  font-size: var(--sima-petit);
  font-weight: 600;
  margin-bottom: var(--sima-esp-2);
}

.pastilles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sima-esp-2);
  list-style: none;
  padding: 0;
  margin: 0;
}

.pastille {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--sima-touche-min);
  min-height: var(--sima-touche-min);
  padding: var(--sima-esp-2) var(--sima-esp-4);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  background: var(--sima-fond);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  cursor: pointer;
  transition:
    border-color var(--sima-transition),
    background-color var(--sima-transition);
}

.pastille:hover {
  border-color: var(--sima-acier);
}

.pastille[aria-pressed="true"],
.pastille--active {
  background: var(--sima-acier);
  border-color: var(--sima-acier);
  color: var(--sima-blanc);
}

/* Une combinaison inexistante est grisee, PAS masquee : l'artisan doit voir que le
   grain 24 existe, meme s'il n'est pas disponible dans cette dimension. */
.pastille[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  text-decoration: line-through;
}

.pastille--large {
  padding-inline: var(--sima-esp-6);
}

/* ---------------------------------------------------- Tableau technique ---- */

/*
 * Ce composant est celui que les assistants IA lisent. Il merite le soin qu'on met
 * d'habitude dans une page d'accueil.
 */
.caracteristiques {
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-carte);
  overflow: hidden;
}

.caracteristiques__groupe {
  border-top: 1px solid var(--sima-bordure);
}

.caracteristiques__groupe:first-child {
  border-top: 0;
}

.caracteristiques__entete {
  background: var(--sima-acier);
  color: var(--sima-blanc);
  padding: var(--sima-esp-2) var(--sima-esp-4);
  font-family: var(--sima-police-titre);
  font-size: 1.05rem;
  font-weight: 600;
  margin: 0;
}

.caracteristiques table {
  font-size: var(--sima-petit);
}

.caracteristiques th,
.caracteristiques td {
  padding: var(--sima-esp-3) var(--sima-esp-4);
  text-align: left;
  border-top: 1px solid var(--sima-bordure);
}

.caracteristiques tr:first-child th,
.caracteristiques tr:first-child td {
  border-top: 0;
}

.caracteristiques tbody tr:nth-child(even) {
  background: var(--sima-fond-2);
}

.caracteristiques th {
  font-weight: 500;
  color: var(--sima-texte-2);
  width: 45%;
}

.caracteristiques td {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Sur mobile, bascule en paires empilees : jamais de defilement horizontal. */
@media (max-width: 560px) {
  .caracteristiques th,
  .caracteristiques td {
    display: block;
    width: 100%;
  }

  .caracteristiques td {
    padding-top: 0;
    border-top: 0;
  }
}

/* ------------------------------------------------------------ Reassurance ---- */

/*
 * L'ancien bloc promettait « Commandez avant 12h pour un depart le jour meme » en gris
 * illisible, pour un site qui n'expedie rien. Une reassurance fausse coute plus qu'une
 * reassurance absente. Celui-ci ne dit que des choses vraies, avec un contraste verifie.
 */
.reassurance {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sima-esp-6);
  list-style: none;
  padding: 0;
  margin: 0;
}

.reassurance li {
  display: flex;
  gap: var(--sima-esp-3);
  align-items: flex-start;
  color: var(--sima-texte-2);
  font-size: var(--sima-petit);
  margin: 0;
}

.reassurance svg {
  flex: none;
  width: 24px;
  height: 24px;
  color: var(--sima-acier);
}

.reassurance strong {
  display: block;
  color: var(--sima-texte);
  font-size: var(--sima-corps);
}

/* ------------------------------------------------- Barre de demande mobile ---- */

/*
 * Barre fixe des qu'un article est dans la liste. Elle ne recouvre jamais un contenu
 * utile : l'espace est reserve dans la page.
 */
.barre-demande {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sima-esp-4);
  padding: var(--sima-esp-3) var(--sima-esp-4);
  background: var(--sima-fond-inverse);
  color: var(--sima-blanc);
  box-shadow: 0 -2px 12px rgba(22, 24, 28, 0.18);
}

.barre-demande__compte {
  font-weight: 600;
  font-size: var(--sima-petit);
}

body:has(.barre-demande) {
  padding-bottom: 76px;
}

@media (min-width: 1024px) {
  .barre-demande {
    display: none;
  }

  body:has(.barre-demande) {
    padding-bottom: 0;
  }
}

/* ------------------------------------------------------------ Formulaires ---- */

.champ {
  margin-bottom: var(--sima-esp-6);
}

.champ label {
  display: block;
  font-weight: 600;
  font-size: var(--sima-petit);
  margin-bottom: var(--sima-esp-2);
}

/*
 * Les contenus internes des champs natifs.
 *
 * La boite d'un champ etait bien a la charte, mais tout ce que le navigateur dessine
 * DEDANS ne l'etait pas : aucune de ces regles n'existait, et le releve du CSSOM le
 * confirmait - zero occurrence de `::file-selector-button`, `::-webkit-inner-spin-button`
 * ou `::-webkit-search-cancel-button` dans les cinq feuilles chargees.
 *
 * Le plus visible etait le champ de fichier : un bouton gris en Arial, borde en
 * `outset`, flottant dans un cadre SIMA. Six champs de dépôt du back-office - image,
 * document, logo de marque, visuel de famille, illustration de guide, depot de devis.
 */

.champ input[type="file"] {
  padding-block: var(--sima-esp-2);
  cursor: pointer;
}

.champ input[type="file"]::file-selector-button,
.champ input[type="file"]::-webkit-file-upload-button {
  margin-inline-end: var(--sima-esp-3);
  padding: var(--sima-esp-2) var(--sima-esp-4);
  border: 1px solid var(--sima-acier);
  border-radius: var(--sima-rayon-champ);
  background: var(--sima-fond);
  color: var(--sima-acier);
  font-family: inherit;
  font-size: var(--sima-petit);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--sima-transition), color var(--sima-transition);
}

.champ input[type="file"]:hover::file-selector-button,
.champ input[type="file"]:hover::-webkit-file-upload-button {
  background: var(--sima-acier);
  color: var(--sima-blanc);
}

/* Les fleches d'increment mangeaient la marge interieure droite du champ. */
.champ input[type="number"]::-webkit-inner-spin-button,
.champ input[type="number"]::-webkit-outer-spin-button {
  margin-inline-start: var(--sima-esp-2);
  opacity: 0.6;
}

.champ input[type="date"]::-webkit-calendar-picker-indicator,
.champ input[type="search"]::-webkit-search-cancel-button {
  cursor: pointer;
  opacity: 0.55;
  transition: opacity var(--sima-transition);
}

.champ input[type="date"]:hover::-webkit-calendar-picker-indicator,
.champ input[type="search"]:hover::-webkit-search-cancel-button {
  opacity: 1;
}

/*
 * Les etats. Aucun n'etait declare : un champ desactive avait l'air actif, et un champ
 * refuse par la validation du navigateur ne se signalait pas.
 */
.champ input:disabled,
.champ select:disabled,
.champ textarea:disabled {
  background: var(--sima-fond-2);
  color: var(--sima-texte-3);
  cursor: not-allowed;
}

.champ input:user-invalid,
.champ select:user-invalid,
.champ textarea:user-invalid {
  border-color: var(--sima-rouge);
}

.champ input,
.champ textarea,
.champ select {
  width: 100%;
  min-height: var(--sima-touche-min);
  padding: var(--sima-esp-3);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  background: var(--sima-fond);
  transition: border-color var(--sima-transition);
}

.champ input:hover,
.champ textarea:hover {
  border-color: var(--sima-bordure-forte);
}

.champ input:focus,
.champ textarea:focus {
  border-color: var(--sima-acier);
}

/*
 * Un groupe de choix a l'interieur d'un champ : « Livraison ou retrait », « Etat du sol ».
 *
 * Symfony rend ces options a plat, `input` puis `label`, sans conteneur par option. La
 * regle ci-dessus, qui donne 100 % de largeur et 44 px de haut a tout `input`, en faisait
 * trois disques vides empiles, chacun avec son intitule perdu dessous.
 *
 * Deux colonnes suffisent a les rapparier : la case, puis son intitule. C'est la grille
 * qui reforme les lignes, sans balise supplementaire a inserer dans le theme de
 * formulaire.
 */
.champ > div:has(> input[type="radio"]),
.champ > div:has(> input[type="checkbox"]) {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--sima-esp-3) var(--sima-esp-3);
  margin-top: var(--sima-esp-2);
}

.champ input[type="radio"],
.champ input[type="checkbox"] {
  width: auto;
  min-height: 0;
  min-width: 0;
  padding: 0;
  /* La zone tactile de 44 px vit sur l'intitule, qui est bien plus large que la case :
     c'est lui que le doigt vise. */
  accent-color: var(--sima-acier);
}

.champ > div > label {
  display: flex;
  align-items: center;
  min-height: var(--sima-touche-min);
  margin: 0;
  font-weight: 400;
  font-size: var(--sima-corps);
  cursor: pointer;
}

.champ__aide {
  display: block;
  margin-top: var(--sima-esp-2);
  font-size: var(--sima-petit);
  color: var(--sima-texte-2);
}

/* L'erreur n'est jamais portee par la seule couleur : elle est ecrite, et associee au
   champ par aria-describedby. */
.champ__erreur {
  display: flex;
  align-items: flex-start;
  gap: var(--sima-esp-2);
  margin-top: var(--sima-esp-2);
  padding: var(--sima-esp-2) var(--sima-esp-3);
  background: var(--sima-rouge-pale);
  border-left: 3px solid var(--sima-rouge);
  color: var(--sima-texte);
  font-size: var(--sima-petit);
}

.champ--erreur input,
.champ--erreur textarea {
  border-color: var(--sima-rouge);
}

.champ--case {
  display: flex;
  align-items: flex-start;
  gap: var(--sima-esp-3);
}

.champ--case input {
  width: 22px;
  min-height: 22px;
  height: 22px;
  margin-top: 3px;
  flex: none;
}

.champ--case label {
  margin: 0;
  font-weight: 500;
}

/* Champ leurre : premiere couche de protection, invisible a l'ecran et hors du flux de
   tabulation, mais rempli par les automates. */
.leurre {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------------------------------------------------------------- Messages ---- */

.message {
  padding: var(--sima-esp-4);
  border-radius: var(--sima-rayon-carte);
  border-left: 4px solid;
  margin-bottom: var(--sima-esp-6);
}

.message--succes {
  background: var(--sima-succes-pale);
  border-color: var(--sima-succes);
}

.message--erreur {
  background: var(--sima-rouge-pale);
  border-color: var(--sima-rouge);
}

.message--info {
  background: var(--sima-acier-pale);
  border-color: var(--sima-acier);
}

/* --------------------------------------------------------------- Etiquettes ---- */

.etiquette {
  display: inline-flex;
  align-items: center;
  gap: var(--sima-esp-1);
  padding: 2px var(--sima-esp-2);
  border-radius: var(--sima-rayon-champ);
  font-size: var(--sima-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.etiquette--acier {
  background: var(--sima-acier-pale);
  color: var(--sima-acier);
}

.etiquette--rouge {
  background: var(--sima-rouge-pale);
  color: var(--sima-rouge-fonce);
}

.etiquette--succes {
  background: var(--sima-succes-pale);
  color: var(--sima-succes);
}

.etiquette--gris {
  background: var(--sima-fond-2);
  color: var(--sima-texte-2);
}

/* -------------------------------------------------------------- Pagination ---- */

.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sima-esp-2);
  align-items: center;
  justify-content: center;
  list-style: none;
  padding: 0;
  margin: var(--sima-esp-12) 0 0;
}

.pagination a,
.pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--sima-touche-min);
  min-height: var(--sima-touche-min);
  padding-inline: var(--sima-esp-3);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.pagination [aria-current="page"] {
  background: var(--sima-acier);
  border-color: var(--sima-acier);
  color: var(--sima-blanc);
}

/* -------------------------------------------------------------- Fil d'Ariane -- */

.fil-ariane {
  padding-block: var(--sima-esp-4);
  font-size: var(--sima-petit);
  color: var(--sima-texte-2);
}

.fil-ariane ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sima-esp-2);
  list-style: none;
  padding: 0;
  margin: 0;
}

.fil-ariane li + li::before {
  content: "/";
  margin-right: var(--sima-esp-2);
  color: var(--sima-texte-3);
}

/* ------------------------------------------------- Bascule de profil ---- */

/*
 * Deux positions, un curseur qui glisse : le meme geste que le selecteur de langue.
 *
 * Le choix du profil commande sept champs. Pose en deux gros boutons radio empiles, il
 * demandait de trancher avant d'avoir montre qu'il y avait un choix, et rien ne disait
 * que le formulaire allait changer dessous.
 *
 * Les radios restent des radios, simplement masques a l'oeil : c'est leur valeur qui est
 * postee, et le curseur suit `:has(:checked)` et non un controleur. Sans JavaScript, la
 * bascule glisse quand meme - seuls les volets restent alors tous les deux visibles,
 * ce qui allonge le formulaire sans bloquer personne.
 */
.bascule {
  margin-bottom: var(--sima-esp-8);
}

.bascule__legende {
  display: block;
  padding: 0;
  margin-bottom: var(--sima-esp-3);
  font-weight: 600;
  font-size: var(--sima-petit);
}

.bascule__piste {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px;
  padding: 4px;
  background: var(--sima-fond-2);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
}

.bascule__onglet {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sima-esp-3) var(--sima-esp-4);
  border-radius: calc(var(--sima-rayon-champ) - 2px);
  text-align: center;
  cursor: pointer;
  transition: color var(--sima-transition);
}

.bascule__onglet strong {
  font-size: var(--sima-corps);
}

/* Le curseur glisse sous l'onglet coche. Deux positions, une seule regle. */
.bascule__curseur {
  position: absolute;
  z-index: 0;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: calc((100% - 8px - 2px) / 2);
  background: var(--sima-fond);
  border-radius: calc(var(--sima-rayon-champ) - 2px);
  box-shadow: var(--sima-ombre-1);
  transition: transform var(--sima-transition);
}

.bascule__piste:has(.bascule__radio:last-of-type:checked) .bascule__curseur {
  transform: translateX(calc(100% + 2px));
}

/*
 * Le focus se voit sur l'onglet, pas sur le radio : celui-ci est hors de l'ecran, et un
 * anneau de focus invisible revient a n'en pas avoir.
 */
.bascule__radio:focus-visible + .bascule__onglet {
  outline: 2px solid var(--sima-rouge);
  outline-offset: 2px;
}

.bascule__radio:checked + .bascule__onglet strong {
  color: var(--sima-texte);
}

.bascule__radio:not(:checked) + .bascule__onglet {
  color: var(--sima-texte-2);
}

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

/* ------------------------------------------------ Sections de formulaire ---- */

/*
 * Un formulaire de treize champs se remplit s'il s'annonce en trois etapes courtes ; le
 * meme, d'un seul tenant, se referme.
 */
.formulaire__section {
  margin-bottom: var(--sima-esp-8);
  padding-top: var(--sima-esp-6);
  border-top: 1px solid var(--sima-bordure);
}

.formulaire__titre {
  margin: 0 0 var(--sima-esp-4);
  font-size: 1.25rem;
}

/*
 * Les champs courts vont deux par ligne. Un code postal etale sur toute la largeur d'un
 * ecran d'atelier demande de viser une zone dix fois plus large que sa valeur, et donne
 * au formulaire une longueur qu'il n'a pas.
 *
 * `auto-fill` et non `auto-fit` : un champ seul sur sa ligne garde la moitie de la
 * largeur, il ne s'etire pas pour combler.
 */
.formulaire__grille {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
  gap: 0 var(--sima-esp-6);
}

/* Un champ long reprend toute la largeur : une adresse ou un message ne se saisit pas
   dans une demi-colonne. */
.formulaire__grille .champ:has(textarea),
.formulaire__grille .champ--large {
  grid-column: 1 / -1;
}

.formulaire__envoi {
  padding-top: var(--sima-esp-6);
  border-top: 1px solid var(--sima-bordure);
}

/* ---------------------------------------------- Recapitulatif de demande ---- */

/*
 * Ce que le visiteur a mis dix minutes a rassembler, et qu'il relit avant d'envoyer.
 *
 * Il tenait dans un bandeau d'information, avec une liste a puces : le meme traitement
 * visuel que « votre page a expire ».
 */
.recapitulatif {
  margin-bottom: var(--sima-esp-8);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  background: var(--sima-fond);
  overflow: hidden;
}

.recapitulatif__entete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sima-esp-3);
  padding: var(--sima-esp-4) var(--sima-esp-6);
  background: var(--sima-fond-2);
  border-bottom: 1px solid var(--sima-bordure);
}

.recapitulatif__titre {
  margin: 0;
  font-size: 1.1rem;
}

.recapitulatif__modifier {
  font-size: var(--sima-petit);
}

.recapitulatif__lignes {
  list-style: none;
  padding: 0;
  margin: 0;
}

.recapitulatif__ligne {
  display: flex;
  align-items: baseline;
  gap: var(--sima-esp-4);
  padding: var(--sima-esp-3) var(--sima-esp-6);
}

.recapitulatif__ligne + .recapitulatif__ligne {
  border-top: 1px solid var(--sima-bordure-tenue);
}

/* Les chiffres tabulaires alignent la colonne des quantites, qui se lit alors d'un coup
   d'oeil au lieu de danser d'une ligne a l'autre. */
.recapitulatif__quantite {
  flex: 0 0 auto;
  min-width: 2.5rem;
  padding: 2px var(--sima-esp-2);
  border-radius: var(--sima-rayon-champ);
  background: var(--sima-fond-2);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: center;
}

.recapitulatif__designation {
  display: flex;
  flex-direction: column;
}

/* ------------------------------------------------------ Sélecteur de langue ---- */

/*
 * Pilule à curseur coulissant, quatre positions.
 *
 * Reprend l'esprit de l'interrupteur de fx.diamontis.fr, adapté de deux à quatre
 * langues - Hagondange est à 25 km du Luxembourg et 40 km de la Sarre.
 *
 * Les langues prévues mais pas encore ouvertes restent visibles, en retrait : un artisan
 * luxembourgeois voit que sa langue arrive, et on ne lui sert pas du français sous une
 * URL luxembourgeoise.
 */
.selecteur-langue__piste {
  position: relative;
  /* Des colonnes egales : c'est ce qui permet au curseur de se deplacer d'un pas
     constant, sans mesurer la largeur de chaque libelle en JavaScript.

     Leur NOMBRE vient du gabarit, par `--n`. Il etait ecrit `4` en dur ici, et le jour
     ou l'espagnol est entre dans `Langues::TOUTES` la cinquieme langue est passee a la
     ligne, sous les quatre autres, avec un curseur qui ne visait plus la bonne. Un
     nombre en dur d'un cote d'une frontiere et une liste de l'autre : c'est le motif
     que les audits de ce projet relevent depuis le debut. */
  --n: 4;
  --gouttiere: 2px;
  --marge: 3px;

  display: grid;
  grid-template-columns: repeat(var(--n), minmax(0, 1fr));
  align-items: center;
  gap: var(--gouttiere);
  padding: var(--marge);
  margin: 0;
  list-style: none;
  background: var(--sima-fond-2);
  border: 1px solid var(--sima-bordure);
  border-radius: 999px;
}

/* Le nombre de langues, pose par le gabarit depuis `Langues::TOUTES`. La liste est
   fermee mais large : ajouter une langue ne demandera pas de revenir ici. */
.selecteur-langue__piste--n2 { --n: 2; }
.selecteur-langue__piste--n3 { --n: 3; }
.selecteur-langue__piste--n4 { --n: 4; }
.selecteur-langue__piste--n5 { --n: 5; }
.selecteur-langue__piste--n6 { --n: 6; }
.selecteur-langue__piste--n7 { --n: 7; }
.selecteur-langue__piste--n8 { --n: 8; }

.selecteur-langue__option {
  margin: 0;
  position: relative;
  z-index: 1;
}

/*
 * Le curseur qui glisse sous la langue courante.
 *
 * Sa position vient d'une classe posee par le gabarit, pas d'un attribut style : la CSP
 * refuse le style en ligne. Quatre langues, quatre classes - la liste est fermee, elle
 * suit `Langues::TOUTES`.
 *
 * Il est purement decoratif : l'information est portee par `aria-current` sur la langue
 * active. Sans CSS, la pilule reste une liste de liens parfaitement utilisable.
 */
.selecteur-langue__curseur {
  position: absolute;
  z-index: 0;
  top: var(--marge);
  bottom: var(--marge);
  left: var(--marge);
  /* `n` colonnes et `n - 1` gouttieres, a l'interieur des deux marges. */
  width: calc(
    (100% - 2 * var(--marge) - (var(--n) - 1) * var(--gouttiere)) / var(--n)
  );
  background: var(--sima-fond);
  border-radius: 999px;
  box-shadow: var(--sima-ombre-1);
  transition: transform var(--sima-transition);
  /* Le pas : une colonne, plus la gouttiere qui la suit. Une seule formule pour toutes
     les positions, la ou il y avait une regle par langue - donc une regle a ajouter a
     chaque langue, et celle de l'espagnol n'avait pas ete ecrite. */
  transform: translateX(
    calc(var(--pos, 0) * (100% + var(--gouttiere)))
  );
}

.selecteur-langue__piste--pos-0 { --pos: 0; }
.selecteur-langue__piste--pos-1 { --pos: 1; }
.selecteur-langue__piste--pos-2 { --pos: 2; }
.selecteur-langue__piste--pos-3 { --pos: 3; }
.selecteur-langue__piste--pos-4 { --pos: 4; }
.selecteur-langue__piste--pos-5 { --pos: 5; }
.selecteur-langue__piste--pos-6 { --pos: 6; }
.selecteur-langue__piste--pos-7 { --pos: 7; }

@media (prefers-reduced-motion: reduce) {
  .selecteur-langue__curseur {
    transition: none;
  }
}

.selecteur-langue__lien {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sima-esp-1);
  min-height: 34px;
  padding: 0 var(--sima-esp-2);
  border-radius: 999px;
  text-decoration: none;
  font-size: var(--sima-micro);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--sima-texte-2);
  transition:
    color var(--sima-transition),
    background-color var(--sima-transition);
}

.selecteur-langue__lien:hover {
  color: var(--sima-texte);
  background: var(--sima-fond);
}

/* Le fond blanc est celui du curseur, glisse dessous : le doubler ici le figerait. */
.selecteur-langue__lien--active {
  color: var(--sima-texte);
}

/* Une langue non ouverte n'est pas cachée : elle est visiblement inactive. */
.selecteur-langue__lien--indisponible {
  opacity: 0.4;
  cursor: not-allowed;
}

.selecteur-langue__lien--indisponible:hover {
  background: transparent;
  color: var(--sima-texte-2);
}

.selecteur-langue__drapeau {
  width: 18px;
  height: 12px;
  border-radius: 2px;
  flex: none;
  box-shadow: 0 0 0 1px rgba(22, 24, 28, 0.12);
}

.selecteur-langue__code {
  line-height: 1;
}

/* La zone tactile réelle atteint 44 px sans grossir la pilule : le pseudo-élément
   déborde au-dessus et au-dessous, invisible mais cliquable. */
.selecteur-langue__lien::before {
  content: "";
  position: absolute;
  inset: -5px 0;
}

@media (max-width: 768px) {
  .selecteur-langue__code {
    /* Sur mobile, le drapeau suffit : la place manque et le code est redondant
       avec l'attribut lang, lu par les lecteurs d'écran. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }

  .selecteur-langue__drapeau {
    width: 22px;
    height: 15px;
  }
}

/*
 * Le montant du devis, sur la page de suivi.
 *
 * C'est la seule information que le client cherche en ouvrant cette page : elle est
 * traitee comme telle.
 */
.devis__montant {
  display: flex;
  flex-direction: column;
  gap: var(--sima-esp-1);
  margin-block: var(--sima-esp-4);
}

.devis__montant strong {
  font-family: var(--sima-police-titre);
  font-size: 2rem;
  line-height: 1.1;
  color: var(--sima-texte);
}

/*
 * Questions frequentes.
 *
 * `details` natif : elles s'ouvrent sans JavaScript, et restent lisibles si le style ne
 * charge pas. Une question fermee reste visible - c'est elle qui informe, meme sans clic.
 */
.questions__item {
  border-bottom: 1px solid var(--sima-bordure);
  padding-block: var(--sima-esp-4);
}

.questions__item:first-child {
  border-top: 1px solid var(--sima-bordure);
}

.questions__item summary {
  font-family: var(--sima-police-titre);
  font-size: 1.15rem;
  font-weight: 600;
  cursor: pointer;
  /* La zone de clic atteint la hauteur tactile minimale sans grossir le texte. */
  min-height: var(--sima-touche-min);
  display: flex;
  align-items: center;
  gap: var(--sima-esp-3);
}

.questions__item summary:hover {
  color: var(--sima-acier);
}

.questions__item p {
  margin: var(--sima-esp-3) 0 0;
  color: var(--sima-texte-2);
  max-width: var(--sima-mesure);
}

/* ------------------------------------------------------- Oeil du mot de passe -- */

/*
 * Le bouton est pose par le controleur Stimulus, donc il n'existe que si le script a
 * repondu. La classe qui met le champ en position relative l'est aussi, pour la meme
 * raison : sans script, aucune regle ne s'applique et le champ reste ordinaire.
 */
.champ--avec-oeil {
  position: relative;
}

.champ--avec-oeil input {
  padding-right: 52px;
}

.champ__oeil {
  position: absolute;
  right: 4px;
  /* Le champ est precede de son etiquette : le bouton se cale sur le bas du bloc plutot
     que sur son milieu, sinon il flotte au niveau du texte de l'etiquette. */
  bottom: 0;
  width: 44px;
  height: var(--sima-touche-min);
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  border-radius: var(--sima-rayon-champ);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  opacity: 0.65;
  transition: opacity var(--sima-transition);
}

.champ__oeil:hover,
.champ__oeil:focus-visible {
  opacity: 1;
}

/* ------------------------------------------------- Champs restes sans style -- */

/*
 * Six classes etaient posees dans les gabarits sans qu'aucune regle ne leur reponde.
 *
 * Ce n'est pas une negligence anodine : `carte__quantite` habille le champ de quantite
 * de CHAQUE carte produit, donc vingt-quatre fois sur une page famille. Un `input
 * type="number"` nu mesure vingt-six pixels de haut, montre les fleches du systeme et
 * n'a ni rayon ni bordure de la charte - au milieu d'une interface entierement stylee.
 * C'est tres probablement l'ecran qui a fait dire au client « on a des input pas
 * stylises », et il avait raison.
 */

.carte__ajout {
  display: flex;
  gap: var(--sima-esp-2);
  align-items: stretch;
}

.carte__ajout .bouton {
  flex: 1;
}

.carte__quantite {
  width: 72px;
  min-height: 44px;
  padding: var(--sima-esp-2);
  text-align: center;
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  background: var(--sima-fond);
  font-family: inherit;
  font-size: var(--sima-corps);
  /* Les chiffres tabulaires evitent que la largeur saute entre 1 et 8. */
  font-variant-numeric: tabular-nums;
}

.carte__quantite:hover {
  border-color: var(--sima-bordure-forte);
}

.carte__quantite:focus {
  border-color: var(--sima-acier);
}

/*
 * Le selecteur de tri de la page famille.
 *
 * `appearance: none` retire le chrome du systeme, et le chevron est une image `data:`
 * inscrite dans la feuille : aucune ressource externe, donc rien a ouvrir dans la CSP.
 */
.champ-tri,
.champ select {
  appearance: none;
  min-height: var(--sima-touche-min);
  padding: var(--sima-esp-2) var(--sima-esp-8) var(--sima-esp-2) var(--sima-esp-3);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  background-color: var(--sima-fond);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%235b6470' stroke-width='2' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  font-family: inherit;
  font-size: var(--sima-corps);
  color: var(--sima-texte);
  cursor: pointer;
}

.champ-tri:hover,
.champ select:hover {
  border-color: var(--sima-bordure-forte);
}

.champ-tri:focus,
.champ select:focus {
  border-color: var(--sima-acier);
}

/* Les cases et les boutons radio restaient au bleu du systeme, a cote de libelles
   passes a l'acier : deux bleus qui se disputaient le meme composant. */
.champ input,
.champ select,
.champ textarea,
.filtres__option input {
  accent-color: var(--sima-acier);
}

.champ ::placeholder,
.champ input::placeholder,
.champ textarea::placeholder {
  /* 4,99:1 sur blanc : lisible, et distinct d'une valeur reellement saisie. */
  color: var(--sima-texte-3);
  opacity: 1;
}

/* ------------------------------------------------- Choix particulier / pro --- */

/*
 * Le tout premier champ du formulaire de demande, et il s'affichait en boutons radio
 * nus empiles. C'est l'ecran ou le visiteur decide de continuer ou de partir.
 */
.champ__legende {
  font-size: var(--sima-corps-large);
  font-weight: 700;
  padding: 0;
  margin-bottom: var(--sima-esp-3);
}

.profil-choix__options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--sima-esp-4);
}

.profil-choix__option {
  position: relative;
}

.profil-choix__option label {
  display: flex;
  flex-direction: column;
  gap: var(--sima-esp-1);
  min-height: 88px;
  padding: var(--sima-esp-4) var(--sima-esp-4) var(--sima-esp-4) 52px;
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-carte);
  background: var(--sima-fond);
  cursor: pointer;
  transition:
    border-color var(--sima-transition),
    background-color var(--sima-transition);
}

.profil-choix__option label:hover {
  border-color: var(--sima-bordure-forte);
}

/*
 * L'etat retenu ne tient pas a la seule couleur : l'ombre interieure double la bordure,
 * ce qui le rend perceptible sans distinguer les teintes.
 */
.profil-choix__option:has(input:checked) label {
  border-color: var(--sima-acier);
  box-shadow: inset 0 0 0 1px var(--sima-acier);
  background: var(--sima-acier-pale);
}

.profil-choix__option input {
  position: absolute;
  top: 22px;
  left: 18px;
  width: 20px;
  height: 20px;
  accent-color: var(--sima-acier);
}

/* Le contour de focus doit suivre la carte entiere, pas le seul bouton radio. */
.profil-choix__option:has(input:focus-visible) label {
  outline: 3px solid var(--sima-acier);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------ Icones --- */

/*
 * Font Awesome, auto-heberge et reduit aux seules icones employees.
 *
 * `app:icones:reduire` relit les gabarits, ne garde que les regles utiles et sous-ensemble
 * les polices. Le paquet complet declare des milliers d'icones pour 90 ko de CSS et
 * 119 ko de police : du poids charge, analyse, et jamais applique - en tete de page,
 * donc bloquant pour le rendu. A relancer apres tout ajout d'icone.
 *
 * Les icones sont TOUJOURS decoratives ici : chacune double un texte deja lisible, et
 * porte donc `aria-hidden`. Une icone seule, sans texte, exigerait une etiquette - et
 * sur un site consulte avec des gants sur un chantier, le texte vaut mieux.
 */
.fa-solid,
.fa-regular,
.fa-brands {
  /* La couleur suit le texte : une icone qui garde sa teinte propre au survol ou sur
     fond sombre se detache comme un corps etranger. */
  color: inherit;
}

.reassurance__icone {
  font-size: 1.5rem;
  color: var(--sima-acier);
}

.pied__puce {
  width: 1.25em;
  color: var(--sima-texte-3);
}

.pied__telephone .fa-solid {
  font-size: 0.8em;
  margin-right: var(--sima-esp-2);
  color: var(--sima-texte-3);
}

/* ------------------------------------------------------- Appels d'interet --- */

/*
 * L'animation sert le sens, jamais l'ornement.
 *
 * Chaque regle ci-dessous repond a une question du visiteur : ou vais-je en cliquant,
 * qu'est-ce qui vient de changer, qu'est-ce qui m'attend. Une animation qui ne repond a
 * rien fatigue au troisieme ecran.
 *
 * `prefers-reduced-motion` ramene `--sima-transition` a 0 ms, mais cela ne suffit pas
 * pour les animations nommees : elles sont coupees explicitement plus bas.
 */

/* La fleche avance : le bouton dit ou il mene avant qu'on clique. */
.bouton--principal .fa-arrow-right,
.bouton--acier .fa-arrow-right {
  transition: transform var(--sima-transition);
}

.bouton--principal:hover .fa-arrow-right,
.bouton--acier:hover .fa-arrow-right {
  transform: translateX(4px);
}

/*
 * Au survol, l'icone PREND LA PLACE du texte : le bouton dit « Ajouter », et sous le
 * curseur il ne montre plus que le geste - un plus, ou un oeil pour aller voir.
 *
 * Les deux se superposent au lieu de se suivre. L'icone est sortie du flux, donc le
 * bouton garde exactement la largeur de son libelle : rien ne bouge au moment ou le
 * curseur l'atteint, et sur une grille de 24 cartes une cible qui se deplace pendant
 * qu'on la vise se voit tout de suite.
 *
 * Le texte visible disparait, pas le nom accessible : l'`aria-label` du bouton porte le
 * nom du produit et ne change jamais.
 *
 * `:focus-visible` compte autant que `:hover`, sinon la bascule n'existe pas au clavier.
 *
 * Rien n'est prevu pour le tactile, et c'est voulu : sans survol, le bouton reste son
 * libelle. Y montrer l'icone d'emblee effacerait le mot sans que personne ne l'ait
 * demande.
 */
.bouton--revele {
  position: relative;
}

.bouton--revele > span,
.bouton--revele .bouton__revele {
  transition: opacity var(--sima-transition);
}

.bouton--revele .bouton__revele {
  position: absolute;
  /*
   * Le centrage se fait par translation et non par `inset: 0` : Font Awesome impose une
   * largeur de 1.25em a ses icones, qui empeche l'etirement et collait l'icone au bord
   * gauche du bouton. Une translation ne depend d'aucune largeur.
   */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
}

.bouton--revele:hover > span,
.bouton--revele:focus-visible > span {
  opacity: 0;
}

.bouton--revele:hover .bouton__revele,
.bouton--revele:focus-visible .bouton__revele {
  opacity: 1;
}

/*
 * Le temps de l'ajout et du retour « Ajoute », la bascule est neutralisee.
 *
 * La souris est encore sur le bouton qu'on vient de cliquer : sans cela, le seul retour
 * visuel d'un ajout sans rechargement resterait cache sous l'icone jusqu'a ce que le
 * visiteur pense a bouger la main.
 */
.bouton--revele.bouton--fige > span {
  opacity: 1;
}

.bouton--revele.bouton--fige .bouton__revele {
  opacity: 0;
}

/*
 * Le compteur de la liste de demande pulse UNE FOIS quand il change.
 *
 * C'est le seul retour visuel d'un ajout fait sans rechargement : sans lui, le visiteur
 * ne sait pas si son clic a porte, et il reclique. Une pulsation permanente, elle,
 * deviendrait un clignotant qu'on cesse de voir.
 */
@keyframes sima-pastille {
  0% { transform: scale(1); }
  40% { transform: scale(1.35); }
  100% { transform: scale(1); }
}

.entete__compteur {
  animation: sima-pastille 420ms ease-out;
}

/* L'icone du telephone frappe une fois a l'arrivee sur la page : le telephone EST le
   canal de ce metier, et l'ancien site le cachait en pied de page. */
@keyframes sima-sonne {
  0%, 70%, 100% { transform: rotate(0); }
  75% { transform: rotate(-12deg); }
  80% { transform: rotate(10deg); }
  85% { transform: rotate(-8deg); }
  90% { transform: rotate(6deg); }
}

.entete__telephone .fa-solid {
  animation: sima-sonne 2.4s ease-in-out 1s 1;
}

/*
 * Les cartes du catalogue apparaissent en cascade au premier affichage.
 *
 * Le decalage est plafonne a huit cartes : au-dela, la derniere ligne attendrait plus
 * d'une seconde, et l'effet passerait de vivant a lent.
 */
@keyframes sima-monte {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .grille-produits > li {
    animation: sima-monte 380ms ease-out backwards;
  }

  .grille-produits > li:nth-child(1) { animation-delay: 0ms; }
  .grille-produits > li:nth-child(2) { animation-delay: 40ms; }
  .grille-produits > li:nth-child(3) { animation-delay: 80ms; }
  .grille-produits > li:nth-child(4) { animation-delay: 120ms; }
  .grille-produits > li:nth-child(5) { animation-delay: 160ms; }
  .grille-produits > li:nth-child(6) { animation-delay: 200ms; }
  .grille-produits > li:nth-child(7) { animation-delay: 240ms; }
  .grille-produits > li:nth-child(n + 8) { animation-delay: 280ms; }
}

/*
 * Rien ne bouge pour qui a demande que rien ne bouge.
 *
 * La regle est volontairement brutale - `animation: none` sur tout - parce qu'une
 * animation oubliee ici est precisement celle qui declenche un malaise vestibulaire.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- Visionneuse ---- */

/*
 * Le bouton d'agrandissement, pose sur la vue principale.
 *
 * Il est visible en permanence et non au survol : au survol, il n'existe pas pour qui
 * navigue au doigt ni au clavier.
 */
.fiche__principal {
  position: relative;
}

.fiche__agrandir {
  position: absolute;
  inset-block-start: var(--sima-esp-3);
  inset-inline-end: var(--sima-esp-3);
  z-index: 1;
  display: grid;
  place-items: center;
  inline-size: var(--sima-touche-min);
  block-size: var(--sima-touche-min);
  border: 1px solid var(--sima-bordure);
  border-radius: var(--sima-rayon-champ);
  background: rgb(255 255 255 / 92%);
  color: var(--sima-texte);
  cursor: pointer;
  transition: background var(--sima-transition), color var(--sima-transition);
}

.fiche__agrandir:hover {
  background: var(--sima-acier);
  color: var(--sima-blanc);
}

/*
 * Le dialogue lui-meme.
 *
 * `<dialog>` porte `display: none` par defaut : il faut donc cibler `[open]` pour la
 * mise en page, sans quoi la grille s'applique aussi a l'etat ferme et le dialogue
 * occupe la page.
 */
.visionneuse {
  max-inline-size: min(96vw, 1400px);
  max-block-size: 94vh;
  padding: 0;
  border: 0;
  border-radius: var(--sima-rayon-carte);
  background: var(--sima-fond-inverse);
  color: var(--sima-blanc);
}

.visionneuse[open] {
  display: grid;
  grid-template-rows: auto 1fr auto;
}

.visionneuse::backdrop {
  background: rgb(0 0 0 / 82%);
}

.visionneuse__barre {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sima-esp-4);
  padding: var(--sima-esp-3) var(--sima-esp-4);
}

.visionneuse__compteur {
  font-size: var(--sima-petit);
  color: rgb(255 255 255 / 78%);
}

.visionneuse__fermer,
.visionneuse__pas {
  display: grid;
  place-items: center;
  inline-size: var(--sima-touche-min);
  block-size: var(--sima-touche-min);
  border: 0;
  border-radius: 50%;
  background: rgb(255 255 255 / 12%);
  color: var(--sima-blanc);
  cursor: pointer;
  transition: background var(--sima-transition);
}

.visionneuse__fermer:hover,
.visionneuse__pas:hover {
  background: rgb(255 255 255 / 24%);
}

.visionneuse__image {
  inline-size: 100%;
  block-size: 100%;
  max-block-size: 78vh;
  object-fit: contain;
}

.visionneuse__legende {
  margin: 0;
  padding: var(--sima-esp-3) var(--sima-esp-4);
  font-size: var(--sima-petit);
  color: rgb(255 255 255 / 78%);
  text-align: center;
}

.visionneuse__pas {
  position: absolute;
  inset-block-start: 50%;
  transform: translateY(-50%);
}

.visionneuse__pas--avant {
  inset-inline-start: var(--sima-esp-3);
}

.visionneuse__pas--apres {
  inset-inline-end: var(--sima-esp-3);
}

.visionneuse :focus-visible {
  outline: 3px solid var(--sima-blanc);
  outline-offset: 2px;
}

/* ------------------------------------------------- Tableau des declinaisons ---- */

/*
 * Replie par defaut : sur une fiche a vingt-quatre references, deplie il repousserait la
 * description hors de l'ecran. Le selecteur a pastilles reste le chemin principal.
 */
.declinaisons-tableau {
  margin-block-start: var(--sima-esp-4);
}

.declinaisons-tableau summary {
  cursor: pointer;
  padding-block: var(--sima-esp-2);
  font-size: var(--sima-petit);
  color: var(--sima-acier);
}

/* Le cadre defile seul : un tableau large ne doit pas faire defiler la page entiere. */
.declinaisons-tableau__cadre {
  overflow-x: auto;
  margin-block-start: var(--sima-esp-3);
}

.declinaisons-tableau table {
  width: 100%;
  border-collapse: collapse;
  /* 15 px et non 10 : le concurrent compose ce tableau en 10 px, et il est illisible. */
  font-size: var(--sima-petit);
}

.declinaisons-tableau th,
.declinaisons-tableau td {
  padding: var(--sima-esp-2) var(--sima-esp-3);
  border-block-end: 1px solid var(--sima-bordure);
  text-align: left;
  white-space: nowrap;
}

.declinaisons-tableau thead th {
  border-block-start: 3px solid var(--sima-rouge);
  color: var(--sima-acier);
  font-weight: 600;
}

.declinaisons-tableau tbody tr:hover {
  background: var(--sima-fond-2);
}


/* ============================================================ Thème et logo ==== */

/*
 * Le logo.
 *
 * Les quatre carres restent rouges dans les deux themes - c'est la marque. Les lettres,
 * elles, sont peintes en `currentColor` dans le SVG : il suffit de poser `color` ici
 * pour qu'elles suivent le fond sur lequel le logo est pose.
 */
.logo-sima {
  display: block;
  height: auto;
  color: var(--sima-logo-texte);
}

.entete__logo .logo-sima {
  width: 176px;
}

/*
 * L'interrupteur de theme.
 *
 * Une seule cible, trois etats. L'icone affichee dit l'etat COURANT : soleil en clair,
 * lune en sombre, disque a moitie plein quand on suit le systeme. Les trois sont dans le
 * gabarit et deux sont masquees - c'est ce qui evite un changement de police d'icone au
 * clic, et ce qui permet a `app:icones:reduire` de toutes les voir.
 */
.bascule-theme {
  display: flex;
  align-items: center;
}

.bascule-theme[hidden] {
  display: none;
}

.bascule-theme__bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--sima-touche-min);
  height: var(--sima-touche-min);
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  color: var(--sima-texte-2);
  cursor: pointer;
  transition:
    color var(--sima-transition),
    background-color var(--sima-transition),
    border-color var(--sima-transition);
}

.bascule-theme__bouton:hover {
  color: var(--sima-texte);
  background: var(--sima-fond-2);
  border-color: var(--sima-bordure);
}

/*
 * Les trois icones sont toutes dans le gabarit, deux sont masquees.
 *
 * Le selecteur porte le bouton EN PLUS de l'icone, et ce n'est pas du zele : la feuille
 * de Font Awesome est chargee apres celle-ci et pose `display` sur `.fa-solid`, a
 * specificite egale. A egalite, c'est la derniere declaree qui gagne - donc la sienne.
 * Un cran de specificite en plus tranche, sans dependre de l'ordre des feuilles.
 */
.bascule-theme__bouton .bascule-theme__icone {
  font-size: 1.05rem;
  line-height: 1;
  display: none;
}

/* Sans attribut, on suit le systeme : c'est l'etat par defaut, et l'icone le dit. */
.bascule-theme__bouton .bascule-theme__icone--systeme {
  display: inline-block;
}

:root[data-theme-choisi='clair'] .bascule-theme__bouton .bascule-theme__icone--systeme,
:root[data-theme-choisi='sombre'] .bascule-theme__bouton .bascule-theme__icone--systeme {
  display: none;
}

:root[data-theme-choisi='clair'] .bascule-theme__bouton .bascule-theme__icone--clair {
  display: inline-block;
}

:root[data-theme-choisi='sombre'] .bascule-theme__bouton .bascule-theme__icone--sombre {
  display: inline-block;
}


/* ================================================================== Icônes ====== */

/*
 * Les icones, partout ou elles accompagnent un texte.
 *
 * Une icone de police se pose sur la ligne de base, comme une lettre : son centre optique
 * tombe donc plus bas que celui du texte qu'elle accompagne, et l'ecart se voit d'autant
 * plus que le libelle est court. Une boite de largeur fixe, centree, la remet d'aplomb -
 * et, accessoirement, aligne verticalement les icones de plusieurs lignes entre elles,
 * puisqu'elles occupent toutes la meme largeur quel que soit leur glyphe.
 */
.bouton > .fa-solid,
.entete__telephone > .fa-solid,
.entete__demande > .fa-solid,
.pied__puce,
.lien-icone > .fa-solid {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25em;
  flex: none;
  line-height: 1;
}

/* Le conteneur doit centrer, sinon la boite de l'icone reste alignee sur la base. */
.bouton,
.entete__telephone,
.entete__demande,
.lien-icone {
  align-items: center;
}
