/* FICHIER GÉNÉRÉ par couleurs-extraire.py — charte.css sans ses couleurs.
   Ne pas éditer. Réservé aux pages *-test.php. */
/* =====================================================================
   Bati'Tools — charte.css
   Charte graphique commune : variables de design (couleurs, espacements,
   typographie, rayons, ombres) + mécanisme clair/sombre.

   Ce fichier ne contient QUE des tokens (variables). Il ne redéfinit pas
   encore les styles des boutons, cartes, formulaires, etc. — ça viendra
   page par page, à mesure qu'on migre chaque page dessus.

   Palette : reprise à l'identique de style-v0.css / base-v0.css
   (ambre #edb518 + rouge sombre #79031d), avec deux corrections de
   contraste repérées (texte d'erreur illisible sur fond rouge sombre,
   placeholder illisible dans les champs de saisie).
   ===================================================================== */

:root {
  /* ---------- Espacements ---------- */
  --space-1: 0.5rem; /* 8px */
  --space-2: 0.75rem; /* 12px */
  --space-3: 1rem; /* 16px */
  --space-4: 1.25rem; /* 20px */
  --space-5: 1.5rem; /* 24px */
  --space-6: 2rem; /* 32px */

  /* ---------- Rayons ---------- */
  --radius-sm: 8px;
  --radius-md: 10px;
  --radius-lg: 12px;

  /* ---------- Ombres ---------- */

  /* ---------- Typographie fluide ---------- */
  --fs-0: clamp(0.95rem, 0.8rem + 0.4vw, 1rem); /* texte courant */
  --fs-1: clamp(1.05rem, 0.9rem + 0.6vw, 1.1rem); /* texte un peu plus gros */
  --fs-2: clamp(1.25rem, 1.05rem + 0.8vw, 1.5rem); /* sous-titres */
  --fs-3: clamp(1.45rem, 1.2rem + 1.2vw, 1.9rem); /* titres */

  /* ---------- Couleurs — thème clair (par défaut) ---------- */
  /* §155 — LE NOM NU DÉSIGNE LE CAS COURANT, LE SUFFIXE MARQUE L'EXCEPTION.
     --encre et --encre-attenuee se posent sur --carte, qui est le fond de la
     quasi-totalité du texte du site ; --encre-sur-fond et
     --encre-attenuee-sur-fond se posent sur l'ambre de --fond. La charte
     faisait l'inverse d'un jeton à l'autre — --text valait pour la carte mais
     --muted pour le fond —, et c'est une des causes des erreurs de contraste
     relevées à l'audit du 19/09/2026. */
    /* arrière-plan global (ambre) */
    /* panneaux / cartes / boîtes de résultat (rouge sombre) */
    /* texte principal, posé sur --carte (cas courant) */
    /* texte À L'INTÉRIEUR des champs de saisie (fond clair) */
    /* fond des champs de saisie */
    /* texte secondaire posé sur --fond */
    /* texte PRINCIPAL posé directement sur --fond.
                                --encre (#f5f7f7) est prévu pour --carte (rouge
                                sombre) ; sur l'ambre de --fond il est presque
                                illisible. Même encre que --champ-encre, qui est
                                déjà l'encre sombre de la charte. Jeton INERTE
                                tant qu'une page ne l'emploie pas (NOTES §81.5). */
    /* séparateurs */
    /* couleur d'action principale (boutons, liens) */
    /* encre de succès posée sur --carte */
    /* texte d'erreur — corrigé : l'ancien #b3261e était
                                quasi illisible sur le fond --carte (rouge sur rouge) */
   /* corrigé : l'ancien #cccccc était illisible */

  /* Cartes des outils PRO (page d'accueil). Deux jetons plutot qu'un gradient
     en dur : en theme clair --action et --carte valent tous deux #79031d,
     un gradient calcule a partir d'eux serait donc plat. */
     /* rouge plus profond que --carte */
     /* ambre brule, tire vers --fond */
                                    /* sur le fond clair des champs (--champ-fond) */

  /* Libellés "entrée" / "sortie" des cartes d'outils (page d'accueil) */
    /* corrigé : l'ancien #798080 manquait de contraste sur --carte */

  /* Variante de --encre-attenuee-sur-fond lisible sur un fond --carte (ex: texte secondaire
     à l'intérieur d'une .card). --encre-attenuee-sur-fond seul est prévu pour un fond --fond clair
     et devient illisible sur --carte (rouge sombre) : voir règle .card .hint
     plus bas. Calculé à partir de --encre/--carte, donc reste correct
     automatiquement quel que soit le thème (clair/sombre/manuel). */

  /* ---------- Liseré des boutons (13/09/2026, NOTES §106) ----------
     Un bouton plein prend --action, qui vaut --carte en thème clair et une
     teinte sombre en thème sombre : sombre sur sombre, il disparaissait. Un
     bouton .btn-outline, transparent, disparaissait de même sur un fond de la
     couleur de sa bordure. On ne peut pas choisir en CSS « la couleur qui
     contraste avec celle du bouton », mais on peut poser DEUX liserés, un
     clair et un sombre : quel que soit le fond, l'un des deux tranche.
       --bouton-filet-clair : liseré intérieur clair (l'encre --encre, presque blanche
                    dans les deux thèmes) ;
       --bouton-halo-sombre : anneau extérieur sombre (l'encre --encre-sur-fond en clair ;
                    en sombre --encre-sur-fond est claire, d'où un noir voilé).
     Jetons DÉRIVÉS, définis une seule fois : ils suivent le thème par leurs
     sources, et changent avec la palette dans admin-palette.php. */

  /* ---------- États : succès, alerte, erreur ----------
     Ajoutés le 07/09/2026 (NOTES §81). Ils comblent un trou qui coûtait cher :
     `--etat-conforme-sur-carte` de la charte vaut #cccccc (un gris), si bien que 40 pages ont
     REDÉFINI `--etat-conforme-sur-carte` localement en vert pour dire « conforme ». Le même nom
     portait donc deux sens selon la page, et une page qui cesserait de le
     redéfinir passerait au gris sans que rien ne le signale.
     Chaque état vient par PAIRE — un texte et son fond —, parce qu'un vert
     lisible sur un fond clair ne l'est pas sur --carte (rouge sombre en
     thème clair) : c'est la leçon du §7.4. Les valeurs sont celles que les
     pages employaient déjà majoritairement, relevées au §81.3.
     Ces jetons sont INERTES tant qu'une page ne les emploie pas : ils
     n'écrasent rien. La migration est la fiche T-8. */

  /* Les bordures se DÉDUISENT de la paire : une valeur de moins à tenir, et
     elles suivent automatiquement le thème, comme --encre-attenuee. */

  /* ---------- §155 — LES QUATRE JETONS QUE LES PAGES RÉCLAMAIENT ----------
     L'audit des couleurs (19/09/2026) a trouvé le même manque réinventé
     séparément par six pages, chacune avec sa teinte : un quatrième état, qui
     n'est ni conforme, ni une alerte, ni une erreur, mais une INFORMATION —
     « ce texte s'applique », « plusieurs lectures sont possibles ». Faute de
     jeton, elles l'ont peint en #175cd3, #1d4ed8, #3b82f6, #35507a, #8ec5ff.
     La valeur retenue est celle de rubrique-ACT, la plus contrastée sur fond
     clair. Même paire texte + fond que les trois autres états, même filet
     déduit.
     --encre-sur-action comble l'autre manque : l'encre d'un bouton plein ou
     d'une pastille d'accent, que six pages écrivaient `color:#fff` à la main.
     Elle est écrite en clair plutôt que déduite de --encre À DESSEIN : c'est
     une encre de CONTRASTE, celle qu'on doit pouvoir corriger seule depuis
     admin-palette.php le jour où --action changera de clarté — or l'éditeur
     de palette ne sait modifier qu'une ligne `--jeton: #hex`. */

  /* L'orange du plot de chantier : la seule couleur du site dont la TEINTE
     est l'identité, d'où le seul nom qui dise une couleur et non un rôle.
     Écrite en dur jusqu'ici ici même (bandeau de travaux), dans
     01-inc/lien_accueil.php et dans rubrique-CVC/selectionEmetteurs.php.
     Déclarée dans :root SEULEMENT, et volontairement : une couleur de marque
     ne change pas avec le thème, et :root s'applique aussi sous
     html[data-theme="dark"]. */

  /* Fond de la pastille du logo. Sombre dans les DEUX thèmes, et ce n'est pas
     un oubli : le logo est blanc sur fond transparent, il disparaîtrait sur
     une pastille claire (voir l'en-tête de 01-inc/lien_accueil.php). Les deux
     valeurs ne diffèrent que d'un point de gris — vraisemblablement une
     divergence accidentelle, laissée telle quelle pour que cette étape ne
     change AUCUN pixel ; à unifier dans un second temps. */

  /* ---------- Mesures des champs / contrôles ---------- */
  --control-pad-y: 0.8rem;
  --control-pad-x: 0.9rem;
  --control-font: 1rem; /* ≥16px pour éviter le zoom auto sur iOS */

  --input-control-min-h:   2.5rem; /* ≈ 40px (densité compacte) */
  --input-control-ideal-h: 2.75rem; /* ≈ 44px (recommandé) */
  --input-control-max-h:   3rem; /* ≈ 48px (confort) */
  --input-control-px: 0.875rem;
  --input-control-py: 0.5rem;
  --input-control-radius: 0.5rem;
}

/* ---------- Couleurs — thème sombre (automatique, selon l'OS) ---------- */
@media (prefers-color-scheme: dark) {
  :root {

      /* en sombre, --fond est sombre : c'est --encre */

     /* bleu profond, cohérent avec --action #60a5fa */

  /* §156 — LE FOND D'ÉTAT SOMBRE SE MÉLANGE À `transparent`, PAS À --carte.
     C'est la charte qui s'aligne ici sur les pages, et non l'inverse : 89 des
     déclarations relevées dans le site écrivaient déjà `16%, transparent`.
     Elles ont raison. Un fond translucide se compose avec la surface qui le
     PORTE — une carte, le fond de page, un tableau — alors qu'un mélange
     figé sur var(--carte) n'est juste que posé sur une carte, et se voit
     partout ailleurs. Ce seul alignement a rendu 78 jetons du site
     strictement identiques à ceux-ci, donc migrables sans arbitrage. */
  /* États — thème sombre (NOTES §81). Les textes sont les valeurs déjà les
     plus répandues dans les pages ; les fonds se déduisent de --carte pour
     n'inventer aucune teinte de plus. */

  /* §155 — le quatrième état et l'encre de contraste, en sombre. Le fond se
     déduit de --carte comme les trois autres, pour n'inventer aucune teinte. */

  }
}

/* ---------- Bascule manuelle (indépendante des préférences OS) ----------
   Un bouton pourra plus tard poser data-theme="light" ou data-theme="dark"
   sur <html> (et retenir le choix, ex. via localStorage) pour forcer un
   thème quel que soit le réglage du système. Tant qu'aucun choix manuel
   n'est fait, c'est prefers-color-scheme ci-dessus qui décide. */
html[data-theme="light"] {

  /* Cartes des outils PRO (page d'accueil). Deux jetons plutot qu'un gradient
     en dur : en theme clair --action et --carte valent tous deux #79031d,
     un gradient calcule a partir d'eux serait donc plat. */
     /* rouge plus profond que --carte */
     /* ambre brule, tire vers --fond */

  /* États — mêmes valeurs que le :root clair (NOTES §81). */

}

html[data-theme="dark"] {

     /* bleu profond, cohérent avec --action #60a5fa */

  /* §156 — LE FOND D'ÉTAT SOMBRE SE MÉLANGE À `transparent`, PAS À --carte.
     C'est la charte qui s'aligne ici sur les pages, et non l'inverse : 89 des
     déclarations relevées dans le site écrivaient déjà `16%, transparent`.
     Elles ont raison. Un fond translucide se compose avec la surface qui le
     PORTE — une carte, le fond de page, un tableau — alors qu'un mélange
     figé sur var(--carte) n'est juste que posé sur une carte, et se voit
     partout ailleurs. Ce seul alignement a rendu 78 jetons du site
     strictement identiques à ceux-ci, donc migrables sans arbitrage. */
  /* États — thème sombre (NOTES §81). Les textes sont les valeurs déjà les
     plus répandues dans les pages ; les fonds se déduisent de --carte pour
     n'inventer aucune teinte de plus. */

  /* §155 — le quatrième état et l'encre de contraste, en sombre. Le fond se
     déduit de --carte comme les trois autres, pour n'inventer aucune teinte. */

}

/* =====================================================================
   §155 — ALIAS DE TRANSITION.  À SUPPRIMER, PAS À ENTRETENIR.
   ---------------------------------------------------------------------
   POURQUOI CE BLOC EXISTE. Les jetons de couleur de la charte ont été
   renommés en français le 19/09/2026 (audit dans laragon/Interne/_audit-css/,
   hors du dossier servi). 107 fichiers
   les consomment encore sous leurs anciens noms. Les reprendre tous dans la
   même nuit serait le seul moyen de s'en passer — et le meilleur moyen de
   casser une page sans s'en apercevoir. Ces alias laissent donc les deux
   vocabulaires coexister le temps de la bascule, fichier par fichier.

   POURQUOI UN SEUL BLOC SUFFIT, ET NON QUATRE. Un alias ne copie pas une
   VALEUR, il pointe vers un JETON : `--bg: var(--fond)` est résolu au moment
   où la page s'affiche, donc avec le --fond du thème actif. Le répéter dans
   les blocs sombres ne ferait que créer trois occasions de plus de les
   désynchroniser.

   POURQUOI ILS SONT INVISIBLES À L'ÉDITEUR DE PALETTE. admin-palette.php ne
   reconnaît que les lignes de la forme `--jeton: #hexadecimal;`. Une valeur
   `var(--…)` ne correspond pas : ces vingt-six lignes ne seront ni listées ni
   réécrites, et il n'y a rien à prévoir de ce côté.

   LE DANGER DE CE BLOC EST EXACTEMENT SON INTÉRÊT. Tant qu'il est là, un
   fichier non repris continue de fonctionner — donc rien ne signale qu'il
   reste à faire. Le décompte des fichiers encore sur les anciens noms se
   relit à tout moment :

       cd ../Interne/_audit-css && python3 audit.py plan && python3 audit.py docx

   DATE DE RETRAIT VISÉE : une fois les six étapes du plan de bascule closes.
   Le jour où ce bloc part, une page oubliée tombe en couleur par défaut —
   noir sur blanc —, ce qui se voit tout de suite. C'est voulu : un alias qui
   survit à sa raison d'être est une dette qu'on ne rembourse jamais.
   ===================================================================== */

/* =====================================================================
   Composants partagés
   Ajoutés au fur et à mesure des migrations de pages (première page :
   connexion.php). Un même type d'objet DOM = une même classe partout.
   ===================================================================== */

/* ---------- Base ---------- */
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  line-height: 1.5;
  /* Fond « croquis » : SVG transparent, une seule couleur, la teinte de fond
     reste donnée par bati-toolsColor.css (--fond). Tuile de 4096 x 2304 px affichée à 20 %,
     répétée automatiquement au-delà (écrans 5K / 8K). L'opacité se règle dans
     le SVG (attribut opacity du <g> racine) ou dans Interne/fond-sketch/fond-sketch.py. */
  background-image: url("../04-img/fond-sketch.svg");
  background-repeat: repeat;
  background-size: var(--fond-l) var(--fond-h);
  background-position: 0 0;
}
/* Dimensions affichées de la tuile du fond croquis (4096 x 2304 à 20 %).
   --fond-h est aussi lu par 05-js/fond-parallaxe.js : ne changer la taille qu'ici. */
:root { --fond-l: 819px; --fond-h: 461px; }

/* Parallaxe du fond : le fond défile 3 fois moins vite que le contenu.
   Activée seulement quand 05-js/fond-parallaxe.js pose la classe .fond-parallaxe
   sur <html> (sinon, et si l'utilisateur demande moins d'animations, le fond
   défile normalement avec la page, règle body ci-dessus).
   Le fond passe sur un calque fixe un peu plus haut que la fenêtre, que le
   script translate de -(défilement / 3) modulo la hauteur d'une tuile :
   translation seule = animation fluide, sans repeindre le SVG à chaque image. */
html.fond-parallaxe body {
  background-image: none;
  position: relative;
  z-index: 0;             /* contexte d'empilement : le calque z-index -1 reste au-dessus de la couleur du body */
}
html.fond-parallaxe body::before {
  content: "";
  position: fixed;
  top: 0; left: 0; right: 0;
  height: calc(100vh + var(--fond-h));
  z-index: -1;
  pointer-events: none;
  background-image: url("../04-img/fond-sketch.svg");
  background-repeat: repeat;
  background-size: var(--fond-l) var(--fond-h);
  background-position: 0 0;
  transform: translate3d(0, var(--fond-decalage, 0px), 0);
  will-change: transform;
}

/* ---------- Layout ---------- */
.container {
  max-width: 560px;
  margin: 0 auto;
  padding-inline: var(--space-3);
}
.container-wide {
  max-width: 1100px;
  margin: 0 auto;
  padding-inline: var(--space-3);
}
.row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* ---------- En-tête / pied de page de site ---------- */
.site-header, .site-footer {
  text-align: center;

  padding: var(--space-3) 0;
}
/* Ancre de positionnement du menu mobile : #primaryNav est en position
   absolute avec top:100%. Sans ce position:relative il se cale sur le bloc
   conteneur initial (la page entiere) et part tout en bas, hors ecran. */
.site-header { position: relative; }
.site-title {
  font-size: var(--fs-2);
  margin: 0;

}
.site-nav {
  display: flex;
  gap: var(--space-3);
  align-items: center;
}
.site-footer {
  margin-top: var(--space-6);
}
/* Pied de page simple (une seule ligne centrée) : connexion/déconnexion/inscription */
.site-footer > .container { text-align: center; }

/* ---------- Liens texte ---------- */
.link {

  text-decoration: underline;
}
.link:hover, .link:focus-visible { opacity: .8; }

/* Lien texte précédé d'une icône de rubrique (SVG inline, cf. bt_icone()).

   inline-flex et non flex : un lien reste dans le flux du texte, un flex le
   ferait passer en bloc sur toute la largeur de la colonne.

   Le soulignement est déplacé de <a> vers le <span> du libellé. Une règle
   text-decoration posée sur un ancêtre est tracée par-dessus les boîtes en
   ligne atomiques comme un <svg> et ne peut pas être annulée depuis
   l'enfant : gardé sur le <a>, le trait barrerait le pictogramme. */
.link-icone { display: inline-flex; align-items: center; gap: 0.4rem; text-decoration: none; }
.link-icone > span { text-decoration: underline; }
.link-icone svg { flex: none; width: 18px; height: 18px; }

/* ---------- Titres de section ---------- */
.h {
  font-size: var(--fs-2);
  margin: 0 0 var(--space-3);

}

/* ---------- Carte / panneau ---------- */
.card {

  padding: var(--space-5);
  border-radius: var(--radius-lg);

}

/* ---------- Boutons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--control-pad-y) var(--control-pad-x);
  font-size: var(--control-font);
  border: 1px solid; /* liseré clair, cf. --bouton-filet-clair */
          /* anneau sombre : l'un des deux tranche toujours */
  border-radius: var(--radius-md);

  text-decoration: none;
  cursor: pointer;
  transition: filter .15s ease, transform .05s ease;
}
.btn:hover { filter: brightness(1.1); }
.btn:active { transform: translateY(1px); }
.btn-outline {

  border: 1px solid;
          /* même anneau sombre que .btn (§106) */
}

/* ---------- Formulaires ---------- */
.form {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-3);
}
.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.field label { font-weight: 600; font-size: var(--fs-0); }

input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
select,
textarea {
  font: inherit;

  border: 1px solid;
  border-radius: var(--input-control-radius);
  padding: var(--input-control-py) var(--input-control-px);
  min-height: var(--input-control-ideal-h);
  width: 100%;
}
/* Le textarea hérite du même habillage que les autres champs ; seules
   les propriétés qui n'ont pas de sens sur un input mono-ligne sont
   ajoutées ici (redimensionnement vertical, hauteur de départ). */
textarea {
  resize: vertical;
  min-height: 9rem;
  line-height: 1.5;
}

:where(input, textarea, button, .btn):focus-visible {
  outline: none;

}

.actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
}

.hint {  font-size: var(--fs-0); }
.form-message {  font-size: var(--fs-0); min-height: 1.2em; }

/* ---------- Messages (succès / erreurs) ---------- */
.success, .errors {
  padding: var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--fs-0);
  margin-bottom: var(--space-3);
}
.success {

  border: 1px solid;

}
.errors {

  border: 1px solid;

}
.errors ul { margin: 0; padding-left: var(--space-4); }

/* =====================================================================
   Page d'accueil (index.php)
   ===================================================================== */

/* ---------- Logo + badge utilisateur dans l'en-tête ---------- */
.site-header h2 {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: 0;
}
/* Logo : c'est le <picture> qui porte la largeur, l'<img> la remplit.
   L'ancien attribut width="200px" (invalide, donc ignore) laissait l'image a
   ses 1536 px intrinseques ; flex item avec min-width:auto, elle refusait de
   retrecir et l'en-tete debordait sous ~400 px. */
.site-logo {
  display: block;
  width: min(200px, 42vw);
  flex: none;
}
.site-logo img { width: 100%; height: auto; display: block; }

/* Banniere du hero : les attributs width/height de l'<img> donnent son ratio
   au navigateur, qui reserve la place avant le chargement (pas de saut de
   mise en page). */
.hero-banner { width: 100%; max-width: 900px; height: auto; display: block; margin: 0 auto;}
.user-tag {
  font-size: var(--fs-0);
  opacity: .9;

}

/* ---------- Menu burger (mobile) ---------- */
.burger {
  display: none;

  border: 0;
  cursor: pointer;
  padding: var(--space-1);
  margin-left: auto;
  border-radius: var(--radius-sm);
}
.burger:focus-visible {
  outline: 2px solid;
  outline-offset: 2px;
}
.burger-line {
  display: block;
  width: 26px;
  height: 2px;

  margin: 5px 0;
  transition: transform .25s ease, opacity .25s ease;
}
.burger[aria-expanded="true"] .burger-line:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] .burger-line:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] .burger-line:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.site-header nav a {

  text-decoration: none;
  margin-left: var(--space-3);
  font-weight: 600;
  transition: opacity .2s;
}
.site-header nav a:hover { opacity: .75; }

@media (max-width: 768px) {
  .burger { display: inline-block; }
  #primaryNav {
    position: absolute;
    top: 100%;
    right: 0;
    left: 0;

    display: grid;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    transform-origin: top center;
    transform: scaleY(0);
    opacity: 0;
    pointer-events: none;
    transition: transform .25s ease, opacity .25s ease;
    z-index: 1000;
    border-bottom-left-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
  }
  #primaryNav a { margin-left: 0; padding: var(--space-2); border-radius: var(--radius-sm); }
  #primaryNav.is-open { transform: scaleY(1); opacity: 1; pointer-events: auto; }
}
@media (min-width: 769px) {
  /* Menu centre sous le logo, comme le bandeau « site en construction ».
     .container fait 560 px : les dix liens ne tiennent pas sur une ligne.
     flex-basis:100% donne au menu toute la largeur du conteneur (il passe
     donc sous le logo, qui se centre a son tour), et flex-wrap les repartit
     en lignes centrees au lieu de les comprimer — sans quoi « A propos » se
     coupait en deux. Le gap remplace le margin-left des liens : avec un
     margin-left, le premier lien de chaque ligne decale le centrage.
     Rien ne change sous 769 px : le couple logo / burger garde son
     space-between. */
  .site-header .row-between { justify-content: center; }
  #primaryNav {
    display: flex;
    flex-basis: 100%;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-3);
  }
  #primaryNav a { margin-left: 0; }
}

/* ---------- Héro ---------- */
.hero {
  text-align: center;
  padding-bottom: var(--space-5);
}
.hero h1 { font-size: var(--fs-3); }
.hero p { max-width: 600px; margin: var(--space-2) auto var(--space-3); }

/* ---------- Services / cartes ---------- */
.services { padding: var(--space-5) var(--space-3); }
.services h2 { text-align: center; margin-bottom: var(--space-5); }
.cards {
  max-width: 900px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--space-4);
  margin: 0 auto; 
}
.card h3 { margin: 0 0 var(--space-2); }

/* Titre de carte avec icône de rubrique (SVG inline posé par bt_icone(),
   cf. 01-inc/icones.php). L'icône est tracée en stroke="currentColor" : elle
   prend donc la couleur du <h3>, c'est-à-dire --encre, et suit les thèmes
   clair et sombre sans règle supplémentaire ici.

   flex: none sur le SVG est indispensable — sans lui, un titre long comprime
   l'icône (un élément flex peut rétrécir sous sa taille intrinsèque) et le
   picto devient un trait écrasé.

   Le badge PRO reste collé au libellé, comme avant : c'est le gap du flex qui
   remplace l'espace insécable du balisage précédent. Pas de margin-right:auto
   sur le libellé — il enverrait le badge contre le bord droit de la carte,
   ce qui n'est pas le rendu d'origine. */
.card-titre { display: flex; align-items: center; gap: var(--space-1); }
.card-titre svg { flex: none; width: 22px; height: 22px; }

/* Libellés d'entrée / sortie sur les cartes d'outils */
.inData  {  }   /* §155 — repli retiré : il recopiait la valeur du jeton */

/* ---------- Outils réservés aux comptes PRO ----------
   Une carte .card-pro se distingue de deux façons : un fond en dégradé (au
   lieu du --carte plat des autres cartes) et un badge PRO dans son titre.
   Pour un visiteur qui ne peut pas encore ouvrir l'outil (non connecté, ou
   compte free sur un outil PRO), le lien porte .btn.btn-locked au lieu de
   mener à l'outil — le vrai contrôle d'accès reste serveur, dans
   01-inc/auth_check_pro.php et 01-inc/auth_check.php. */
.card-pro {

  border: 1px solid;
}

.badge-pro {
  display: inline-block;
  vertical-align: middle;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.68em;
  font-weight: 700;
  letter-spacing: .08em;
  /* Doré fixe dans les deux thèmes : c'est une pastille "premium", pas un
     élément de charte, elle doit rester identique en clair comme en sombre. */

  border: 1px solid;
}

/* .btn-locked mène désormais vers connexion.php ou tarifs.php (cf.
   carteOutil() dans index.php et bt_plan_outils_accordeon() dans
   01-inc/plan_outils.php) : c'est une redirection vers l'étape suivante, pas
   un mur. Le curseur et le survol restent donc ceux d'un bouton normal — seul
   le contour en pointillés distingue visuellement « pas encore ouvert » de
   « ouvre l'outil ». */
.btn-locked {

  border: 1px dashed;
  box-shadow: none; /* pas d'anneau : « pas encore ouvert » reste discret (§106) */

  opacity: .85;
}

.card-pro .pro-note { margin: var(--space-2) 0 0; }

/* ---------- Pied de page riche (colonnes) ---------- */
.footer-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-4);
  text-align: left;
}
.footer-container h4 { margin: 0 0 var(--space-2); }
.footer-container ul { list-style: none; margin: 0; padding: 0; }
.footer-container ul li { margin-bottom: var(--space-1); }
.footer-container ul li a {  text-decoration: none; font-size: var(--fs-0); }
.footer-container ul li a:hover { text-decoration: underline; }
.footer-bottom {
  text-align: center;
  margin-top: var(--space-5);
  font-size: var(--fs-0);

  border-top: 1px solid;
  padding-top: var(--space-3);
}

/* =====================================================================
   Page d'administration (admin.php)
   Chrome (en-tête, chips, badges, pagination) aux couleurs de la charte ;
   le tableau lui-même reste sur un fond clair (--champ-fond) pour la
   lisibilité d'une liste dense de données.
   ===================================================================== */
.bar { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.links a {  text-decoration: none; }
.links a:hover { text-decoration: underline; }

.flash {

  border: 1px solid;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-3);

}

/* ---------- Chips (filtres) ---------- */
.chip a {
  display: inline-block;
  padding: var(--space-1) var(--space-2);
  border-radius: 999px;
  border: 1px solid;
  text-decoration: none;

}

/* ---------- Tableau ---------- */
.table-wrap { overflow: auto; border-radius: var(--radius-lg); }

/* Boutons DANS une cellule de tableau.
   Piege de contraste, le meme que celui deja traite pour .muted plus haut :
   partout ailleurs un bouton se pose sur --fond ou --carte, mais une cellule
   de tableau a pour fond --champ-fond, qui est CLAIR dans les deux themes.
   .btn-outline y arrive avec `color: var(--encre)` et `border: var(--filet)`
   — en theme clair ces trois jetons valent tous #f5f7f7. Le bouton est donc
   blanc sur blanc : rendu, cliquable, et rigoureusement invisible.
   .btn plein n'a pas le probleme (fond --action, texte #fff). */
/* Meme cause pour l'action destructrice : --etat-erreur-sur-carte (#ffb4a8, un saumon pale
   choisi pour rester lisible sur le rouge sombre de --carte) tombe a un
   contraste de 1,6:1 sur le fond clair d'une cellule. On reprend ici le
   rouge des badges, semantique et independant de la charte. */

table {
  width: 100%;
  border-collapse: collapse;

  border-radius: var(--radius-lg);
  overflow: hidden;
}
th, td {
  padding: var(--space-2);
  border-bottom: 1px solid;
  text-align: left;
  font-size: var(--fs-0);
  vertical-align: middle;
}
th {

  position: sticky;
  top: 0;
  z-index: 2;
}
th.sticky-col, td.sticky-col { position: sticky; left: 0; z-index: 3; }
th.sticky-col {  z-index: 4; }
td, th { min-width: 120px; }
td.sticky-col, th.sticky-col { min-width: 60px; }
.nowrap { white-space: nowrap; }

/* ---------- Badges de statut (couleurs sémantiques, indépendantes de la charte) ---------- */
.badge { display: inline-block; padding: 4px 8px; border-radius: 999px; font-size: 12px; }
.badge.ok   {   border: 1px solid; }
.badge.wait {   border: 1px solid; }
/* Etat pose volontairement, ni bon ni mauvais (ex. un plafond de sessions
   simultanees regle par l'admin). Suit la charte et non une couleur
   semantique : c'est justement l'absence de signal qui est recherchee. */
.badge.neutral {

  border: 1px solid;
  font-variant-numeric: tabular-nums;
}

/* ---------- Reglage du nombre de sessions simultanees (/admin) ---------- */
/* Trois elements colles en une seule commande : [-] [valeur] [+]. Les deux
   formulaires sont mis en ligne ici plutot qu'en style="display:inline" pour
   que le groupe reste solidaire aussi en mode cartes (mobile), ou les <form>
   du tableau retombent sinon les uns sous les autres.
   La largeur mini de la valeur evite que la ligne saute d'un cran quand le
   libelle passe de « illimité » a « 3 postes ». */
.conn-max { display: inline-flex; align-items: center; gap: var(--space-1); }
.conn-max form { display: inline; margin: 0; }
.conn-max .btn { padding: 2px 10px; min-width: 2.1rem; line-height: 1.4; }
.conn-max .conn-max-val { min-width: 4.6rem; text-align: center; }
/* Butees (0 et 255) : le bouton reste en place, grise, plutot que de
   disparaitre — un bouton qui s'efface deplace les deux autres. */
.conn-max .btn[disabled] { opacity: .4; cursor: not-allowed; filter: none; transform: none; }

/* Etat reel (« 2 ouvertes ») sous le reglage, et non a cote : sur la meme
   ligne, il se lirait comme une troisieme valeur reglable alors qu'il ne se
   clique pas. Dessous et plus petit, c'est une legende. */
.conn-max-etat { margin-top: 4px; font-size: 12px; }
.conn-max-etat .badge { padding: 2px 8px; }

/* =====================================================================
   Panneau d'administration (body.page-admin)
   Seule page du site qui affiche un tableau large (9 colonnes dont une
   pleine de boutons). Les regles ci-dessous ne valent QUE la : les
   elargir a tout le site casserait la lecture des pages de contenu, ou
   une ligne de texte au-dela de ~75 caracteres devient penible.
   ===================================================================== */

/* Le 1100px de .container-wide est calibre pour un en-tete et du texte ;
   le tableau, lui, demande tout ce que l'ecran veut bien donner. Sur un
   ecran plus etroit que cette valeur, rien ne depasse : max-width ne force
   pas une largeur, il plafonne seulement celle du bloc, qui reste fluide. */
.page-admin main.container-wide { max-width: 1600px; }

/* LA cause du defilement horizontal : `td, th { min-width: 120px }` pose
   plus haut. A 9 colonnes cela reserve 1080px AVANT le moindre contenu, et
   le tableau deborde de son conteneur quoi qu'on fasse par ailleurs. Ici on
   rend la main au navigateur : chaque colonne prend la largeur de son
   contenu, et la colonne Actions — la seule dont le contenu sait se replier
   (.actions est en flex-wrap) — absorbe ce qui reste. */
.page-admin td, .page-admin th { min-width: 0; }
.page-admin td.sticky-col, .page-admin th.sticky-col { min-width: 0; }

/* Boutons compacts : a 6 actions par ligne, le rembourrage de 0.8rem prevu
   pour un bouton de formulaire (cible tactile) fait a lui seul deborder la
   colonne. Le tableau n'existe qu'en bureau — en dessous de 640px la page
   passe en cartes, ou le .btn reprend sa taille normale. */
@media (min-width: 641px) {
  .page-admin td .btn { padding: 0.35rem 0.6rem; font-size: 0.875rem; }
}

/* ---------- Pagination ---------- */
.pagination { display: flex; gap: var(--space-1); margin-top: var(--space-3); flex-wrap: wrap; }
.pagination a {
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  border: 1px solid;
  text-decoration: none;

}

/* =====================================================================
   Pages outils CVC / PB (calculateurs mono-page)
   Structure reprise de base-v0.css : en-tête simple (.title-row +
   .home-link), grilles de champs (.grid-3 / .row), panneau d'état/résultat
   (#calc / #result) et libellés de statut (.err / .ok) en span nu.
   ===================================================================== */
main {
  max-width: 920px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-3) calc(2.5rem + env(safe-area-inset-bottom));
}

.title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-block: 0 var(--space-3);
}
.title-row h1 { margin: 0; }
.home-link {
  white-space: nowrap;
  text-decoration: none;

  font-weight: 600;
}
.home-link:hover, .home-link:focus-visible { text-decoration: underline; }

.grid-3 {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(3, 1fr);
}
.row {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr 1fr;
}
.grid-3 label,
.row label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: var(--fs-0);
}

#calc, #result {
  margin-top: var(--space-2);
  padding: var(--space-3);

  border: 1px solid;
  border-radius: var(--radius-lg);
  font-size: var(--fs-0);
  word-break: break-word;

}

@media (max-width: 900px) {
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .grid-3, .row { grid-template-columns: 1fr; }
}

/* ---------- Points de rupture (table -> cartes en mobile) ---------- */
@media (max-width: 840px) {
  th, td { padding: var(--space-1); font-size: 13px; }
}
@media (max-width: 640px) {
  .table-wrap { overflow: visible; }
  table, thead, tbody, th, td, tr { display: block; }
  thead { position: absolute; left: -9999px; top: -9999px; height: 0; width: 0; overflow: hidden; }
  table { border-radius: 0; }
  tbody tr {

    border: 1px solid;
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-2);
  }
  /* En mode cartes la cellule occupe toute la largeur : le min-width de
     120px prevu pour le mode tableau n'a plus de sens et peut deborder. */
  td, th { border: none; border-bottom: 1px solid; min-width: 0; }
  tbody tr td:last-child { border-bottom: none; }
  td {
    display: grid;
    grid-template-columns: 42% 58%;
    align-items: baseline;
    gap: var(--space-1);
    padding: var(--space-2) var(--space-2);
  }
  td::before { content: attr(data-label); font-weight: 600; }
  td.actions-cell { display: block; padding: var(--space-2); }
  td.actions-cell .actions { display: flex; gap: var(--space-1); flex-wrap: wrap; }
  th.sticky-col, td.sticky-col { position: static; }
  td.hide-xs { display: none; }
}
@media (max-width: 380px) {
  td { grid-template-columns: 48% 52%; }
}

/* Note "compte FREE" affichée sous le titre Nos Services. */
.services-note { text-align: center; margin: calc(-1 * var(--space-3)) 0 var(--space-5); }

/* =====================================================================
   Bandeau « site en construction »
   Affiche sous l'en-tete de l'accueil : un plot de chantier, le message,
   un second plot.

   Fond --carte + texte --encre, comme .site-header : c'est le seul couple
   de jetons garanti contrastant dans les DEUX themes. Un fond derive de
   --action ne marcherait pas en theme clair, ou --action et --carte valent
   la meme couleur (#79031d) alors que --encre est presque blanc.

   Le bandeau prolonge donc visuellement l'en-tete ; le lisere orange qui le
   borde (couleur du plot) suffit a l'en detacher.

   role="status" cote HTML : c'est une information d'etat, pas une alerte
   bloquante — d'ou aussi le ton ambre/orange plutot que rouge.
   ===================================================================== */
.bandeau-construction {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(var(--space-3), 4vw, var(--space-6));
  padding: var(--space-3) var(--space-3);

  border-block: 3px solid; /* §155 — le plot a un jeton depuis le 19/09/2026 */
}
.bandeau-construction p {
  margin: 0;
  font-size: var(--fs-2);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-align: center;
  text-transform: uppercase;

}
/* La hauteur est fixee ici, pas par l'attribut height du balisage : ce
   dernier ne sert qu'a reserver le ratio avant le chargement du SVG. */
.bandeau-construction .plot {
  height: clamp(44px, 9vw, 72px);
  width: auto;
  max-width: 900px;
  flex: none;
  margin: 0 auto;
}
/* Sous 480 px, deux plots plus le texte sur une ligne obligeraient a reduire
   le message jusqu'a l'illisible : on ne garde que le plot de gauche. */
@media (max-width: 480px) {
  .bandeau-construction { gap: var(--space-3); }
  .bandeau-construction .plot:last-child { display: none; }
}

/* =====================================================================
   Grille tarifaire (tarifs.php, inscription.php)
   Rendue par bt_tarifs_tableau() — 01-inc/tarifs.php.

   TROIS BLOCS, ET NON PLUS UN SEUL TABLEAU
   La grille tenait auparavant dans un unique tableau de trois colonnes, dont
   les trois premieres lignes (intitules, prix, formulaire de souscription)
   etaient figees. Probleme : la largeur de la colonne « Pro » etait dictee
   par son contenu le plus large — le formulaire — et non par ce que la
   colonne porte reellement dans le corps du tableau, une simple pastille.
   Sur un telephone, cette colonne large ne laissait presque rien au nom des
   outils, qui partait sur trois lignes. D'ou la separation :

     .gt-offres         les deux offres, hors tableau, en cartes ;
     .gt-action-bandeau ce que le visiteur peut faire, sur toute la largeur ;
     .gt-tableau        Outils | Free | Pro, colonnes enfin etroites.

   POURQUOI PAS UN <table> POUR LE TROISIEME BLOC
   Le besoin est « en-tete fige, le reste defile en Y » a hauteur bornee. Un
   <thead> sticky ne tient pas cette promesse dans un conteneur a defilement
   interne sur tous les navigateurs vises : d'ou une grille CSS, avec les
   roles ARIA (table, row, columnheader, rowheader, cell) qui rendent la
   semantique tabulaire aux lecteurs d'ecran.

   ALIGNEMENT DES COLONNES ET BARRE DE DEFILEMENT
   La ligne d'en-tete et le corps defilant sont deux grilles independantes :
   elles ne s'alignent que parce qu'elles partagent --gt-cols. La barre de
   defilement du corps romprait cet alignement en lui volant sa largeur.
   D'ou --gt-gutter, reserve a droite de l'en-tete, et une barre forcee a la
   meme largeur (::-webkit-scrollbar). Sur les plateformes a barre flottante
   (tactile), la barre ne prend aucune place : le gutter y est remis a zero.
   ===================================================================== */
.grille-tarifs {
  /* Free et Pro ne portent plus qu'une pastille de 1,5 rem : leurs colonnes
     n'ont aucune raison d'etre larges. Tout le reste va au nom de l'outil. */
  --gt-cols: minmax(0, 1fr) 5.5rem 5.5rem;
  --gt-gutter: 10px;
  margin: var(--space-4) 0;
  display: grid;
  gap: var(--space-3);
}

/* Fond et bordure communs aux trois blocs. */
.gt-offre,
.gt-action-bandeau,
.gt-tableau {
  border: 1px solid;
  border-radius: var(--radius-lg);

}

/* ---------- Bloc 1 : les deux offres ---------- */
/* Pro occupe plus de place que Free : trois formules a deux prix chacune
   contre une seule ligne. */
.gt-offres {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr);
  gap: var(--space-3);
  align-items: start;
}
.gt-offre { padding: var(--space-3); }

/* Meme gradient que les cartes PRO de l'accueil, en beaucoup plus discret. */
.gt-offre-ligne { margin: 0; }
.gt-annuel { display: block; font-size: var(--fs-0); }

/* ---------- Les paliers Pro : prix | licences ---------- */
/* Deux colonnes, parce que ce sont deux informations independantes : ce que
   l'on paie, et ce que l'on ouvre. La colonne des prix porte deux lignes
   (mensuel puis annuel), celle des postes une seule — d'ou l'alignement en
   haut plutot qu'au centre. */
.gt-tarifs { display: grid; gap: 0; }
.gt-tarifs-ligne {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: var(--space-2);
  align-items: start;
  padding: var(--space-2) 0;
  border-top: 1px solid;
}
.gt-tarifs-entete {
  padding-top: 0;
  border-top: 0;
  font-size: var(--fs-0);
  font-weight: 600;
  opacity: .85;
}
/* Le titre du forfait est une LIGNE du tableau, posee entre les intitules de
   colonne et les prix, et qui court sur les deux colonnes. Enfant direct de
   .gt-tarifs (grille a une colonne), il occupe donc toute la largeur sans
   avoir a le declarer. Fond legerement appuye : c'est un bandeau, pas une
   ligne de donnees. */
.gt-tarifs-titre {
  margin: 0;
  padding: var(--space-2);
  border-radius: var(--radius-sm);

  font-size: var(--fs-1);
  font-weight: 700;

}
/* Le filet vertical rend visible la separation des deux colonnes, y compris
   sur les lignes ou la colonne de droite tient sur un seul mot. */
.gt-tarifs-ligne > * + * {
  padding-left: var(--space-2);
  border-left: 1px solid;
}
/* min-width: 0 sur les deux cellules : sans lui, un contenu insecable
   (« 2850 €/an ») refuserait de se comprimer et deborderait la colonne. */
.gt-tarifs-prix, .gt-tarifs-postes { min-width: 0; }
.gt-tarifs-postes { font-size: var(--fs-0); }
/* L'economie est l'argument de l'offre annuelle : elle se lit, elle ne se
   devine pas. Pastille plutot que couleur seule (--etat-conforme-sur-carte vaut un gris ici). */
.gt-eco {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  border: 1px solid;
  border-radius: 999px;
  font-size: 0.8rem;
  white-space: nowrap;
}

.gt-montant { display: block; font-size: var(--fs-1); line-height: 1.3; }
.gt-detail  { display: block; font-size: var(--fs-0); opacity: .8; }

/* Nom commercial du palier, au-dessus du montant : c'est par lui qu'un
   client designe sa formule au telephone, pas par « 95 euros ». */
.gt-nom {
  display: block;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: .75;
}
/* Le prix par licence : le seul chiffre qui se compare d'un palier a
   l'autre. Volontairement discret — il explique le montant, il ne le
   remplace pas. */
.gt-poste { opacity: .8; }
/* La note qui suit les quatre paliers : partage des licences et TVA. Elle
   appartient au bloc des prix, pas au tableau des outils. */
.gt-tarifs-note {
  margin: var(--space-2) 0 0;
  font-size: var(--fs-0);
  opacity: .85;
  max-width: 62ch;
}

/* ---------- Bloc 2 : le bandeau d'action ---------- */
.gt-action-bandeau {
  padding: var(--space-3);
  display: grid;
  gap: var(--space-2);
  justify-items: start;
}
.gt-etat { margin: 0; font-size: var(--fs-0); }

.gt-souscrire { display: grid; gap: var(--space-2); justify-items: start; }
.gt-choix { border: 0; margin: 0; padding: 0; display: grid; gap: 0.35rem; text-align: left; }
.gt-choix legend { padding: 0; font-size: var(--fs-0); font-weight: 600; opacity: .85; }
.gt-radio {
  display: flex;
  align-items: flex-start;
  gap: 0.45rem;
  font-size: var(--fs-0);
  line-height: 1.35;
  cursor: pointer;
}
/* Les radios heritent sinon du remplissage genereux des .field input du
   formulaire hote : sur trois lignes, la colonne doublerait de hauteur. */
/* accent-color: --encre et non --action. En theme clair --action vaut le meme
   rouge sombre que le fond du bandeau : le bouton COCHE y disparaissait,
   pendant que les non-coches restaient blancs — l'inverse exact de ce qu'il
   faut lire. Avec --encre, le coche est un disque clair a point sombre, net
   sur les deux fonds et dans les deux themes. */
.gt-radio input[type="radio"] {
  flex: none;
  width: 1rem;
  height: 1rem;
  min-height: 0;
  margin: 0.2rem 0 0;
  padding: 0;

}
/* Le bandeau occupe toute la largeur : un bouton etire dessus ferait dix
   centimetres de long. Il reprend sa largeur naturelle, et ne s'etire qu'en
   colonne unique (telephone), ou il redevient une cible de plein pouce. */
.gt-souscrire .btn { text-align: center; }

/* ---------- Bloc 3 : le tableau des outils ---------- */
.gt-tableau { overflow: hidden; }   /* les coins arrondis rognent les lignes */

.gt-ligne {
  display: grid;
  grid-template-columns: var(--gt-cols);
  align-items: center;
  gap: var(--space-2);
}
/* L'en-tete reserve la place de la barre de defilement du corps ; les lignes
   du corps, elles, ne la reservent pas — elle est deja prise par la barre. */
.gt-entete { padding-right: var(--gt-gutter); }
.gt-cell { padding: var(--space-2) var(--space-3); min-width: 0; }
.gt-col-free, .gt-col-pro { text-align: center; }

/* La colonne Pro se distingue sur toute la hauteur du tableau : c'est
   l'offre payante, elle doit se lire d'un bloc. */

/* Fond dérivé de --encre et non --carte : dans une .card, --carte est déjà
   le fond ambiant, l'en-tête ne s'en détacherait pas. */
.gt-entete {

  font-weight: 700;
  font-size: var(--fs-1);
  border-bottom: 2px solid;
}

/* ---------- Corps defilant ---------- */
/* La hauteur est bornee par le plus petit de 26rem et de la moitie de la
   fenetre : sur un ecran bas, un corps de 26rem repousserait les lignes
   figees hors du champ, et le tableau perdrait justement ce qui fait son
   interet. */
.gt-corps {
  max-height: min(26rem, 50vh);
  overflow-y: scroll; /* toujours reservee : la largeur ne saute
                                     pas selon le nombre d'outils */
  scrollbar-gutter: stable;
  scrollbar-width: thin; /* Firefox */
  overscroll-behavior: contain; /* en butee, la page ne part pas d'un coup */
}
/* Largeur imposee pour qu'elle corresponde exactement a --gt-gutter. */
.gt-corps::-webkit-scrollbar { width: 10px; }
.gt-corps::-webkit-scrollbar-thumb {

  border-radius: 999px;
}
.gt-corps:focus-visible { outline: 2px solid; outline-offset: -2px; }

/* Barres flottantes (tactile, macOS par defaut) : elles ne prennent aucune
   largeur, le gutter reserve creerait donc un decalage de 10 px entre les
   lignes figees et le corps. */
@media (hover: none), (pointer: coarse) {
  .grille-tarifs { --gt-gutter: 0px; }
  .gt-corps { overflow-y: auto; }
}

.gt-outil {
  border-bottom: 1px solid;
  font-size: var(--fs-0);
}
.gt-outil:last-child { border-bottom: 0; }
.gt-outil .gt-col-outil { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.gt-outil .badge-pro { flex: none; }

/* ---------- Pastilles d'acces ---------- */
/* Le vert et le rouge sont ecrits en dur, et c'est voulu : ce sont des
   couleurs de SENS (oui / non), pas des couleurs de theme. --etat-conforme-sur-carte vaut
   #cccccc dans les deux themes, il ne peut pas porter cette information.
   Ils restent lisibles sur les deux fonds, qui sont sombres l'un comme
   l'autre. Le sens n'est jamais porte par la seule couleur : la forme
   (coche / croix) et le aria-label le portent aussi. */
/* Pastille sur disque sombre : le vert et le rouge gardent le même contraste
   quel que soit le fond de la colonne (la colonne Pro est dégradée), et le
   même dans les deux thèmes. Sans ce disque, le rouge de la croix passerait
   sur le rouge sombre de --carte en thème clair. */
.acces {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0.2rem;
  border-radius: 50%;

}
.acces svg { width: 100%; height: 100%; }

/* ---------- Mobile ---------- */
/* C'est ici que se joue la lisibilite sur telephone. Les deux offres
   s'empilent, et les colonnes Free / Pro tombent a la largeur strictement
   necessaire a la pastille et a leur intitule : tout le reste va au nom de
   l'outil, qui tient alors sur une ou deux lignes au lieu de trois. */
@media (max-width: 640px) {
  .grille-tarifs { --gt-cols: minmax(0, 1fr) 3.2rem 3.2rem; }

  /* La .card qui accueille la grille reserve var(--space-5) de chaque cote :
     sur un ecran de 360 px, c'est 64 px pris au nom des outils, la ou il en
     manque justement. La grille reprend cette gouttiere en debordant de son
     conteneur, en laissant juste de quoi voir ses coins arrondis. */
  .card > .grille-tarifs {
    margin-inline: calc(var(--space-1) - var(--space-5));
  }
  /* Le gap entre colonnes fait le reste : trois colonnes, deux gouttieres. */
  .gt-ligne { gap: var(--space-1); }

  .gt-offres { grid-template-columns: 1fr; }
  .gt-offre { padding: var(--space-2); }

  /* Les deux colonnes de prix se replient : « nombre de licences
     partagées » sur 110 px de large partirait sur plusieurs lignes, et le
     filet vertical n'aurait plus rien a separer. La ligne d'intitules
     disparait avec elles — « Solo, 39 €/mois » suivi de « 1 licence » se lit
     sans etiquette (elle est deja aria-hidden, rien n'est perdu au clavier
     ni au lecteur d'ecran). */
  .gt-tarifs-entete { display: none; }
  .gt-tarifs-ligne { grid-template-columns: 1fr; gap: 0; }
  .gt-tarifs-ligne > * + * { padding-left: 0; border-left: 0; }
  .gt-tarifs-postes { opacity: .85; }
  .gt-cell { padding: var(--space-1) var(--space-2); }
  .gt-col-free, .gt-col-pro { padding-inline: var(--space-1); }
  .gt-entete { font-size: var(--fs-0); }
  .gt-montant { font-size: var(--fs-0); }
  .gt-detail { font-size: 0.8rem; }
  .gt-annuel { font-size: 0.8rem; }
  .gt-radio { font-size: 0.8rem; }
  .acces { width: 1.15rem; height: 1.15rem; }
  .gt-corps { max-height: min(20rem, 45vh); }

  /* Sur une colonne, le bouton redevient une cible de plein pouce. */
  .gt-action-bandeau, .gt-souscrire { justify-items: stretch; }
  .gt-souscrire .btn { width: 100%; }
}

/* Séparateur à l'intérieur d'une .card (profil.php, connexion.php).
   Le <hr> par défaut se dessine avec la couleur de bordure du navigateur :
   invisible sur --carte dans un thème, trop dur dans l'autre. */
.card hr {
  border: 0;
  border-top: 1px solid;
  margin: var(--space-4) 0;
}

/* ---------- Page Profil ---------- */
/* Liste de definitions plutot que des paragraphes : chaque ligne est bien
   une paire etiquette/valeur, et c'est <dl> qui le dit. */
.profil-liste {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--space-1) var(--space-4);
  margin: 0;
}
.profil-liste dt { font-weight: 600; opacity: .85; }
.profil-liste dd { margin: 0; }
@media (max-width: 480px) {
  .profil-liste { grid-template-columns: 1fr; gap: 0 0; }
  .profil-liste dd { margin-bottom: var(--space-2); }
}

/* ---------- Case à cocher étiquetée ---------- */
/* Le <label> ENVELOPPE la case : le texte devient cliquable sans qu'il
   faille apparier un for= et un id=, et la cible de clic passe de 13 px de
   côté à toute la ligne — ce qui compte sur mobile plus que partout
   ailleurs.
   align-items: start plutôt que center : sur deux lignes de texte, une case
   centrée verticalement flotte au milieu du paragraphe au lieu de désigner
   sa première ligne.
   font-weight normal en surcharge de « .field label », qui met tout en
   gras : une phrase entière en gras se lit comme un avertissement, alors
   qu'il s'agit d'une proposition facultative. */
.choix {
  display: flex;
  align-items: start;
  gap: var(--space-2);
  font-weight: 400;
  line-height: 1.5;
  cursor: pointer;
}
.choix input[type="checkbox"] {
  flex: 0 0 auto;
  width: 1.1em;
  height: 1.1em;
  margin-top: .15em;
  cursor: pointer;
}

/* ---------- Saisie d'expressions dans les champs de nombre ----------
   Habillage de 05-js/saisie-num.js. Deux etats, et rien de plus : un champ
   qui PORTE un calcul, un champ dont la saisie est FAUTIVE.

   Le marquage passe par une ombre interne plutot que par une bordure : une
   bordure de 3 px decalerait le texte au moment ou le resultat s'affiche, et
   un champ qui bouge quand on le quitte se remarque plus que le trait qu'on
   voulait montrer. L'ombre, elle, se pose sans rien pousser.

   Sur focus, la charte remplace le box-shadow par son halo : le marquage
   disparait le temps de l'edition, ce qui tombe bien -- a cet instant le
   champ affiche l'expression elle-meme, il n'a plus besoin d'etre annonce.

   L'infobulle (title) porte « 3*25+12 = 87 », ou le motif du refus. Elle est
   posee par le module, pas par la feuille de style. */

/* ---------- Menu « Admin » de l'en-tête (01-inc/menu_admin.php, §143) ----------
   Aucune couleur nouvelle : tout vient des variables de la charte. */
.menu-admin { position: relative; display: inline-block; text-align: left; }
.menu-admin > summary {
  cursor: pointer; list-style: none; font-weight: 600; 
  padding: 0 var(--space-1); border-radius: var(--radius-sm);
}
.menu-admin > summary::-webkit-details-marker { display: none; }
.menu-admin > summary::after { content: " ▾"; }
.menu-admin[open] > summary::after { content: " ▴"; }
.menu-admin > summary:focus-visible { outline: 2px solid; outline-offset: 2px; }
.menu-admin-liste {
  /* Centré sous « Admin » dans le menu de l'accueil (lui-même centré) ;
     aligné à droite dans les barres d'en-tête où il est en bout de ligne. */
  position: absolute; left: 50%; transform: translateX(-50%);
  top: calc(100% + var(--space-2)); z-index: 1100;
  /* Deux colonnes de groupes : la liste tient sans défilement à l'écran. */
  display: grid; grid-template-columns: repeat(2, minmax(15rem, 1fr));
  column-gap: var(--space-4); row-gap: var(--space-2);
  width: max-content; max-width: 92vw; max-height: 80vh; overflow-y: auto;

  border: 1px solid; border-radius: var(--radius-md);
   padding: var(--space-2) var(--space-3);
}
.menu-admin-groupe {
  padding-top: var(--space-1);
  border-top: 1px solid;
}
.menu-admin-titre {
  display: block; font-size: var(--fs-0); opacity: .75;
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 2px;
}
.site-header nav .menu-admin-liste a, .menu-admin-liste a {
  display: block; margin-left: 0; padding: 3px 0; font-weight: 500;
   text-decoration: none;
}
.menu-admin-liste a:hover, .menu-admin-liste a:focus-visible { text-decoration: underline; }
@media (max-width: 768px) {
  #primaryNav .menu-admin { display: block; text-align: center; }
  #primaryNav .menu-admin-liste {
    position: static; transform: none; grid-template-columns: 1fr; width: auto;
    max-height: none; box-shadow: none; text-align: left; margin-top: var(--space-2);
  }
}
@media (min-width: 769px) {
  /* Accueil : le menu est centré dans un conteneur étroit ; la liste se
     centre donc sur L'EN-TÊTE (position:relative), pas sur le mot « Admin ». */
  #primaryNav .menu-admin { position: static; }
  #primaryNav .menu-admin-liste { top: calc(100% - var(--space-2)); }
}
.links .menu-admin { margin-right: var(--space-2); }
.links .menu-admin-liste, .site-nav .menu-admin-liste { left: auto; right: 0; transform: none; }

/* =====================================================================
   §162 — CE QUI NE REJOINT JAMAIS LA CHARTE. À LIRE AVANT DE « NETTOYER ».
   ---------------------------------------------------------------------
   POURQUOI CE BLOC EXISTE. L'audit des couleurs (19/09/2026, dossier
   laragon/Interne/_audit-css/, hors du dossier servi)
   a ramené le site de 413 à 379 valeurs hexadécimales distinctes, en six
   étapes. Ce qui reste en littéral après ces six étapes ne l'est pas par
   oubli : chaque cas ci-dessous a une raison, et trois d'entre eux CASSENT
   si on les remplace par un var(--…). Sans cette liste, quelqu'un les
   remplacera un jour de bonne foi — et le premier ne préviendra pas.

   1. #808080 — L'ENCRE DE PLAN DU PONT DXF (05-js/synoptique.js, constante
      ENCRE_PLAN). VOLONTAIREMENT SANS JETON. svg2dxf.js abandonne EN SILENCE
      tout élément dont la couleur ne se résout pas en RGB : un var(--…) y
      produit un texte ABSENT du fichier livré, sans le moindre avertissement
      ni à l'écran ni dans la console. Créer un jeton inviterait quelqu'un à
      l'employer. La constante JS est la seule forme admise ; le §152 (texte
      blanc sur carte sombre) et le §153 (ACI 7 à l'export) reposent dessus.

   2. LA PALETTE DES COURRIELS (01-inc/auth_email.php, communications.php).
      Un client de messagerie n'exécute pas les variables CSS ni les feuilles
      liées : ces couleurs doivent rester littérales, en styles en ligne. À
      factoriser ENTRE ELLES, en constantes PHP, jamais en jetons CSS.

   3. LES BLOCS @media print (auditEnergetiqueApp/audit.css, outil23Juin1978,
      outilRT, chordsLyrics). Sur papier il n'y a pas de thème : le noir sur
      blanc y est un choix, pas un oubli, et il ne doit pas suivre --encre.

   4. LES PALETTES DE CANVAS (musique/index.php, diagrammeAirHumide,
      condensation, dimECS). Un canvas ne lit pas une variable CSS. La bonne
      forme n'est pas le littéral mais getComputedStyle sur le jeton — ce que
      diagrammeAirHumide et condensation font déjà (fonction palette()), et
      que dimECS ne fait pas encore. Point ouvert, pas exemption définitive.

   5. LES PLANCHES SVG GÉNÉRÉES (vitrine-synoptiques.php, aperçus des pages
      -doc). Produites par un script : toute correction y serait écrasée à la
      génération suivante. Agir dans les sources du générateur.

   6. LES ÉCHELLES ET COULEURS MÉTIER — elles ont des jetons, mais PAS ICI :
      02-css/echelles.css (§160). Classes BAC, familles de l'arrêté de 1986,
      régimes RT/RE, réseaux EF/ECS : la couleur y EST la donnée, elle ne suit
      pas le thème et ne passe pas par admin-palette.php. Idem pour la peau
      de l'atelier de dessin, 02-css/atelier.css (§159), second système
      assumé, dont le fond gris-bleu ne se fondra jamais dans l'ambre.

   7. LES APPLICATIONS INDÉPENDANTES, qui ne chargent pas la charte et ne le
      feront pas : musique/index.php (portage d'un programme C++, dont les
      couleurs doivent rester celles de main.cpp), musique/accordVisuel-
      Correspondance.php et chordsLyrics/index.php (outils personnels de
      l'admin, hors métier du site), divers/compteurDistanceParEquipe.php et
      divers/historiqueAdmin.php (le compteur de pas par équipe : une
      application à part, servie à des personnes qui ne sont pas membres du
      site). Classées le 19/09/2026 ; à reclasser si l'une d'elles entre un
      jour dans le catalogue des outils.

   Ce qui n'est PAS dans cette liste reste à faire, et se relit à tout
   moment : cd ../Interne/_audit-css && python3 audit.py plan && python3 audit.py docx
   ===================================================================== */
