/* =========================================================================
   Votre enseigne (nom de travail) - palier median, direction « De A a B »
   SOCLE COMMUN aux quatre pages : index, calculateur, merci, 404.

   Sources : directions/mediane.md §2 (jetons), mediane-affinage.md §3
   (grammaire de composants) et §4 (ce qu'il ne faut pas toucher),
   mediane-phase2.md §A.2 (liste exacte du contenu de ce fichier).

   Aucune requete externe. Polices systeme macOS/iOS uniquement.
   Toutes les couleurs vivent dans le bloc :root ci-dessous. Ailleurs : var(--*).

   Ordre des feuilles, sur chaque page :
     index.html       base.css puis accueil.css
     calculateur.html base.css puis calculateur.css
     merci.html       base.css puis pages.css
     404.html         base.css puis pages.css

   Le contrat de balisage de chaque composant est dans _COMPOSANTS.md.
   ========================================================================= */

/* --------------------------------------------------------------- 1. Jetons */

:root {
  color-scheme: dark;

  /* Palette d'origine, huit jetons, roles verrouilles par la direction §2 */
  --fond: #0D1E18;
  --panneau: #14312A;
  --craie: #F2EFE6;
  --craie-douce: #AFC0B6;
  --signal: #F6B01E;
  --contour: #63836F;
  --filet: #2E4A3E;
  --filet-fort: #63836F;
  --voile: rgba(13, 30, 24, .78);

  /* Cinq jetons ajoutes par mediane-affinage.md §3.0. Ratios mesures le
     19.09.2026 sur la formule de luminance relative WCAG 2.1. */
  --alerte: #E8836E;              /* bordure et texte d'erreur. Rien d'autre. 6,50:1 sur --fond */
  --contour-fort: #8AA795;        /* champ rempli, carres vides, cadre de vignette. 6,61:1 sur --fond */
  --signal-appui: #DE9C10;        /* fond du bouton principal au survol et a l'appui. Rien d'autre. */
  --voile-photo: rgba(13, 30, 24, .55); /* lisere sombre sous le trace quand il croise une photo (R6) */

  /* Trois jetons ajoutes par mediane-phase2.md §A.2.1 */
  --e20: 20px;                    /* bande graphique du rail : 56 = 10 + 20 + 6 + 16 + 4 */
  --gouttiere-calc-g: 40px;       /* couloir gauche du calculateur */
  --gouttiere-calc-d: 24px;       /* gouttiere droite montee de 16 a 24, seule derogation */

  /* Polices systeme (a remplacer par des polices embarquees avant mise en ligne) */
  --police-titre: "Futura", "Avenir Next", "Century Gothic", system-ui, sans-serif;
  --police-texte: "Avenir Next", "Avenir", "Helvetica Neue", system-ui, sans-serif;
  --police-chiffre: "DIN Alternate", "DIN Condensed", "Avenir Next Condensed", sans-serif;

  /* Echelle typographique.
     R3 option B : le plafond de --t-h1 passe de 5rem a 4.5rem pour remonter le
     bouton du heros vers la ligne de pli. Voir mediane-affinage.md §2 R3. */
  --t-h1: clamp(2.4rem, 1.4rem + 4.2vw, 4.5rem);
  --t-h2: clamp(1.9rem, 1.3rem + 2.4vw, 3rem);
  --t-h3: 1.5rem;
  --t-texte: clamp(1rem, .96rem + .2vw, 1.125rem);
  --t-micro: .875rem;
  --t-chiffre: clamp(2.6rem, 2rem + 2.6vw, 4rem);

  /* Echelle de 4 */
  --e4: 4px;
  --e8: 8px;
  --e12: 12px;
  --e16: 16px;
  --e24: 24px;
  --e32: 32px;
  --e48: 48px;
  --e64: 64px;
  --e96: 96px;
  --e128: 128px;
  --e160: 160px;
  --e200: 200px;

  /* Grille de page - valeurs mobile, redefinies plus bas */
  --largeur-max: 1180px;
  --gouttiere-g: 40px;
  --gouttiere-d: 16px;
  --retrait-rail: 0px;
  --rail-in: -20px;
  --amplitude: 10px;

  /* Plans */
  --z-decor: 0;
  --z-contenu: 1;
  --z-trace: 3;
  --z-bandeau: 4;                 /* le bandeau collant passe devant le trace */

  /* Mouvement */
  --duree-courte: 180ms;
  --duree-moyenne: 260ms;
  --sortie: cubic-bezier(.16, 1, .3, 1);
}

@media (min-width: 768px) {
  :root {
    --gouttiere-g: 32px;
    --gouttiere-d: 32px;
    --gouttiere-calc-g: 32px;
    --gouttiere-calc-d: 32px;
    --retrait-rail: 56px;
    --rail-in: 16px;
    --amplitude: 28px;
  }
}

@media (min-width: 1080px) {
  :root {
    --gouttiere-g: min(6vw, 96px);
    --gouttiere-d: min(6vw, 96px);
    --gouttiere-calc-g: min(6vw, 96px);
    --gouttiere-calc-d: min(6vw, 96px);
    --retrait-rail: 64px;
    --amplitude: 36px;
  }
}

/* ---------------------------------------------------------------- 2. Socle */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--fond);
  color: var(--craie);
  font-family: var(--police-texte);
  font-size: var(--t-texte);
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }

h1, h2, h3 {
  margin: 0;
  font-family: var(--police-titre);
  font-weight: 500;
  text-wrap: balance;
}

h1 { font-size: var(--t-h1); line-height: 1.04; letter-spacing: -.025em; }
h2 { position: relative; font-size: var(--t-h2); line-height: 1.04; letter-spacing: -.015em; }
h3 { font-size: var(--t-h3); line-height: 1.2; letter-spacing: 0; }

p { margin: 0; max-width: 62ch; text-wrap: pretty; }

ul, ol { margin: 0; padding: 0; list-style: none; }

a { color: inherit; }

/* Regle commune aux quatre pages. calculateur.css et pages.css la portaient
   chacune de leur cote ; un attribut du HTML ne doit pas dependre de la
   feuille de page qui se charge ensuite. */
[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}

/* Un titre d'arret porte tabindex="-1" pour recevoir le focus quand le script
   change d'ecran : c'est un point d'atterrissage pour le lecteur d'ecran, pas
   une commande. Chrome lui applique pourtant :focus-visible, et un rectangle
   ambre de la largeur du titre s'affichait a chaque pas du calculateur.
   Declaree AVANT .onglet:focus-visible (§9), de meme specificite (0,2,0) :
   l'onglet, qui est un vrai controle, garde son contour par l'ordre. */
[tabindex="-1"]:focus { outline: none; }

.micro {
  font-size: var(--t-micro);
  line-height: 1.45;
  color: var(--craie-douce);
}

.visuellement-cache {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Lien d'evitement. Hors ecran au repos, pose en haut a gauche au focus.

   Il etait en position: absolute avec top: -100px. Un element absolu se cale
   sur son ancetre positionne le plus proche, pas sur la page : dans
   calculateur.html cet ancetre commence sous le bandeau-trajet, et -100 px ne
   suffisaient pas a le sortir de l'ecran. Le lien restait visible en
   permanence et recouvrait le debut du rail, sur ordinateur comme sur mobile.

   Desormais : position fixe, donc calee sur la fenetre quoi qu'il arrive, et
   un deplacement de 200 % de sa propre hauteur vers le haut au repos. Aucune
   transition : rien a replier sous prefers-reduced-motion. */
.saut {
  position: fixed;
  left: var(--e8);
  top: var(--e8);
  z-index: calc(var(--z-bandeau) + 1);
  padding: var(--e12) var(--e16);
  background: var(--panneau);
  border: 1px solid var(--signal);
  border-radius: 2px;
  color: var(--craie);
  font-size: var(--t-micro);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
}

.saut:focus-visible { transform: translateY(0); }

/* ------------------------------------------------------- 3. Grille de page */

.bande {
  display: grid;
  grid-template-columns:
    [pleine-d] minmax(var(--gouttiere-g), 1fr)
    [texte-d] minmax(0, var(--largeur-max))
    [texte-f] minmax(var(--gouttiere-d), 1fr)
    [pleine-f];
}

.bande > * {
  grid-column: texte-d / texte-f;
  padding-left: var(--retrait-rail);
}

.bande > .bord-droit { grid-column: texte-d / pleine-f; }

.bande > .pleine-largeur {
  grid-column: pleine-d / pleine-f;
  padding-left: 0;
}

/* ------------------------------------------------------------- 4. Surfaces */

/* La seule profondeur du site : le passage --fond vers --panneau.
   Aucune ombre, aucun flou, aucun degrade de couleur. */
.panneau {
  position: relative;
  max-width: 520px;
  padding: var(--e24);
  background: var(--panneau);
  border-radius: 4px;
}

@media (min-width: 768px) { .panneau { padding: var(--e32); } }

/* --------------------------------------------------------------- 5. Champs */

/* Grammaire mediane-affinage.md §3.1. Cinq etats, et aucun sixieme :
   repos, survol, focus, rempli, erreur. Plus l'etat desactive. */

/* Le conteneur de champ est un <p> : sans cette ligne il heritait du
   max-width: 62ch du §2, qui est une mesure de confort de LECTURE, et cette
   mesure gouvernait la largeur des controles de saisie. Tous les champs du
   calculateur faisaient 648 px, le telephone comme l'adresse, pendant que le
   titre et le bouton de la meme colonne allaient jusqu'a 920 px : un
   decrochement de 143 px que personne n'avait decide. §3.1 fixe la hauteur,
   le retrait, le rayon et les cinq etats, jamais une largeur. */
.champ { max-width: none; }

.champ + .champ,
.champ + .pastilles,
.pastilles + .champ,
.pastilles + .pastilles { margin-top: var(--e24); }

.champ > label,
.pastilles > legend {
  display: block;
  padding: 0;
  margin: 0 0 var(--e8);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--craie);
}

.champ-saisie { position: relative; display: block; }

.champ input,
.champ select,
.champ textarea {
  width: 100%;
  height: 48px;
  padding: 0 var(--e12);
  font-family: var(--police-texte);
  font-size: 1rem;              /* jamais moins de 16 px, sinon iOS zoome */
  line-height: 1.4;
  color: var(--craie);
  background: transparent;
  border: 1px solid var(--contour);
  border-radius: 2px;
}

.champ textarea {
  height: auto;
  min-height: 96px;
  padding: var(--e12);
  resize: vertical;
}

/* Le texte indicatif reste en --craie-douce (7,35:1 sur --panneau) et jamais
   en gris efface. Direction §2 et mediane-phase2.md §H.6. */
.champ input::placeholder,
.champ textarea::placeholder { color: var(--craie-douce); opacity: 1; }

.champ input[type="date"],
.champ input[type="number"],
.champ input[type="tel"] { font-family: var(--police-chiffre); letter-spacing: .04em; }

/* Largeurs decidees par nature de contenu, au-dela de 768 px seulement : sous
   cette largeur la colonne est plus etroite que le plus petit des plafonds et
   c'est width: 100% qui gouverne, sauf pour la date, qu'un plafond de 200 px
   retrecirait sans raison sur un telephone.
   560 px portent « 1206 Geneve, avenue de Champel 24 » (276 px a 16 px) avec
   de la marge ; 260 px portent « 022 000 00 00 » en DIN plus le retrait ;
   200 px portent la date plus l'icone native du navigateur. */
@media (min-width: 768px) {
  .champ input[type="text"],
  .champ input[type="email"] { max-width: 560px; }
  .champ input[type="tel"] { max-width: 260px; }
  .champ input[type="date"] { max-width: 200px; }
}

.champ input:hover,
.champ select:hover,
.champ textarea:hover { border-width: 2px; padding: 0 11px; }

.champ textarea:hover { padding: 11px; }

/* Rempli. Le selecteur ne vise que les champs qui portent vraiment un texte
   indicatif : un input[type=date] n'a pas de placeholder, il satisferait
   :not(:placeholder-shown) des le chargement et paraitrait rempli a vide.
   Pour ceux-la, le script pose la classe .est-rempli. */
.champ input[placeholder]:not(:placeholder-shown),
.champ textarea[placeholder]:not(:placeholder-shown),
.champ input.est-rempli,
.champ select.est-rempli,
.champ textarea.est-rempli { border-color: var(--contour-fort); }

/* Erreur. Declaree apres le survol et le rempli, meme specificite, donc elle
   gagne par l'ordre. Le champ porte aussi aria-describedby vers le message. */
.champ input[aria-invalid="true"],
.champ select[aria-invalid="true"],
.champ textarea[aria-invalid="true"] {
  border: 2px solid var(--alerte);
  padding: 0 11px;
}

.champ textarea[aria-invalid="true"] { padding: 11px; }

.champ input:disabled,
.champ select:disabled,
.champ textarea:disabled { opacity: .5; cursor: not-allowed; }

/* Micro-texte d'aide, sous le champ. */
.champ-aide { display: block; margin-top: var(--e8); }

/* Deux champs lies (etage et ascenseur d'une meme adresse) : un seul libelle
   de groupe en <legend>, deux colonnes egales des 768 px.

   Une seule colonne en dessous : les huit pastilles d'etage font quatre par
   rangee, soit 4 x 52 + 3 x 10 = 238 px, alors qu'une demi-colonne de 375 px
   n'en offre que 148. Elles debordaient de leur colonne et repassaient SOUS
   « Avec ascenseur / Sans ascenseur ». A 375 px : Etage, puis Ascenseur. */
.groupe-lie {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--e16);
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

@media (min-width: 768px) {
  .groupe-lie { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

.groupe-lie > legend {
  display: block;
  padding: 0;
  margin: 0 0 var(--e8);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--craie);
}

/* .pastilles + .pastilles (plus haut) est la regle d'empilement VERTICAL de
   deux groupes qui se suivent dans le flux. Ici les deux groupes sont deux
   cellules d'une meme rangee de grille : ils doivent partir de la meme ligne.
   Sans cette ligne, « Ascenseur » descendait de 24 px sous « Etage », seule
   rupture d'alignement horizontal de l'ecran d'entree du calculateur.
   Specificite 0,3,0 : elle bat le 0,2,0 de la regle generale. L'ecart entre
   les deux groupes est desormais porte par le seul gap de la grille. */
.groupe-lie > .pastilles + .pastilles { margin-top: 0; }

/* ------------------------------------------------- 6. Messages d'erreur */

/* Grammaire mediane-affinage.md §3.9. Sous le champ, jamais en surimpression,
   jamais dans une bulle. Le message dit ce qui manque et ce qu'il faut faire. */

.message-erreur {
  display: flex;
  align-items: flex-start;
  gap: var(--e8);
  margin-top: var(--e8);
  max-width: 62ch;
  font-size: var(--t-micro);
  line-height: 1.45;
  color: var(--alerte);
}

.message-erreur .picto {
  flex: none;
  width: 14px;
  height: 14px;
  margin-top: .2em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.resume-erreurs {
  margin-bottom: var(--e24);
  padding: var(--e16);
  border: 1px solid var(--alerte);
  border-radius: 2px;
}

.resume-erreurs p { font-size: var(--t-micro); color: var(--alerte); }

.resume-erreurs ul { margin-top: var(--e8); }

.resume-erreurs li + li { margin-top: var(--e4); }

.resume-erreurs a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  font-size: var(--t-micro);
  color: var(--alerte);
  text-underline-offset: .22em;
}

/* --------------------------------------------------- 7. Groupe de pastilles */

/* Grammaire mediane-affinage.md §3.2. Sert au nombre de pieces, a l'etage,
   a l'ascenseur. Ce qui est rond, on clique dessus : les onglets, eux, n'ont
   aucun rayon. */

.pastilles { min-width: 0; margin: 0; padding: 0; border: 0; }

/* --cols vaut 4 par defaut (l'etage : 4 x 52 + 3 x 10 = 238 px sur 311 utiles
   a 375 px). --cols-large reprend --cols au-dela de 768 px si rien n'est dit. */
.pastilles-liste {
  display: grid;
  grid-template-columns: repeat(var(--cols, 4), 52px);
  gap: 10px;
  justify-content: start;
}

/* Le nombre de pieces garde ses deux rangees de trois sous 768 px. */
.pastilles-pieces { --cols: 3; --cols-large: 6; }

/* Pastilles larges (« Avec ascenseur ») : jamais plus de quatre par rangee. */
.pastilles-liste-large {
  display: flex;
  flex-wrap: wrap;
  grid-template-columns: none;
}

@media (min-width: 768px) {
  .pastilles-liste { grid-template-columns: repeat(var(--cols-large, var(--cols, 4)), 52px); }
  .pastilles-liste-large { grid-template-columns: none; }
}

.pastille { position: relative; }

.pastille input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.pastille label {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 52px;
  height: 52px;
  border: 1px solid var(--contour);
  border-radius: 999px;
  color: var(--craie);
  cursor: pointer;
  transition: border-color 120ms ease-out, background-color 120ms ease-out;
}

.pastille-large label {
  width: auto;
  height: 52px;
  padding: 0 20px;
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
}

.pastille-chiffre {
  font-family: var(--police-chiffre);
  font-size: 17px;
  line-height: 1;
  letter-spacing: .02em;
}

/* R9 : grille 3 x 2 de carres de 5 unites, SVG de 14 px de haut, trait de
   1,25 px d'ecran (non-scaling-stroke, sinon l'echelle du viewBox l'epaissit),
   carres vides en --contour-fort (5,35:1 sur --panneau) et non en --contour
   (3,33:1), ou l'icone rendait la meme tache sombre a chaque pastille. */
.pastille-icone { display: block; height: 14px; width: auto; }
.pastille-icone .carre-plein { fill: currentColor; }

.pastille-icone .carre-vide {
  fill: none;
  stroke: var(--contour-fort);
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
}

.pastille-icone .plus {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.pastille label:hover { border-color: var(--signal); }

.pastille input:checked + label {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--fond);
}

.pastille input:checked + label .carre-vide { stroke: var(--fond); }

.pastille input:focus-visible + label {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}

.pastille input:disabled + label { opacity: .5; cursor: not-allowed; }

/* -------------------------------------------------------- 7 bis. Case a cocher */

/* Remontee ici depuis calculateur.css : deux pages au moins en portent une
   (« Je ne connais pas encore la date » et le consentement de l'arret 5), et
   toute page qui ajoutera une case doit en herite du meme dessin plutot que de
   la redessiner. Regles identiques a celles qui etaient dans calculateur.css :
   rien ne change a l'ecran. Numerotee « 7 bis » pour ne pas decaler les huit
   sections suivantes, auxquelles _COMPOSANTS.md renvoie par leur numero.

   Aucun dessin maison : la case native, agrandie a 24 px, teintee par
   accent-color. Zone tactile de 44 px portee par la rangee. */
.case-a-cocher {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: var(--e12);
  align-items: start;
  min-height: 44px;
  max-width: 62ch;
}

.case-a-cocher input {
  width: 24px;
  height: 24px;
  margin: 7px 0 0;
  accent-color: var(--signal);
  cursor: pointer;
}

.case-a-cocher label {
  padding: var(--e8) 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--craie);
  cursor: pointer;
}

/* -------------------------------------------------------------- 8. Boutons */

/* Grammaire mediane-affinage.md §3.3. Un seul bouton principal par ecran.
   Libelles : verbe plus objet, jamais « OK », jamais « Continuer » seul. */

.bouton {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e8);
  width: 100%;
  min-height: 52px;
  padding: 0 var(--e24);
  background: var(--signal);
  color: var(--fond);
  border: 2px solid transparent;
  border-radius: 999px;
  font-family: var(--police-texte);
  /* Une pastille large choisie et le bouton principal partageaient hauteur
     52 px, rayon 999 px, fond --signal, texte --fond et graisse 600 : un seul
     pixel de corps les separait. Sur l'arret 4 du calculateur, trois pilules
     ambres de 52 px cohabitaient au meme ecran, dont deux etaient des etats et
     une l'action. §3.3 verrouille « un seul bouton principal par ecran » : la
     lettre etait respectee, l'effet visuel non.
     Rendre l'aplat ambre exclusif a l'action toucherait le §3.2 scelle et
     demande l'accord de Jhonno ; tant qu'il n'est pas rendu, la separation se
     fait par la taille (17 px contre 15 px, largeur plancher de 260 px) et par
     le chevron que porte tout bouton qui fait avancer le trajet. */
  font-size: 17px;
  font-weight: 600;
  letter-spacing: .01em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: background-color 120ms ease-out, border-color 120ms ease-out;
}

/* R12 : le survol changeait la seule bordure, ce qui faisait apparaitre un
   anneau sombre a l'interieur et paraitre le bouton plus petit. Le fond change
   aussi, et l'etat enfonce existe. Trois etats lisibles, sans deplacement. */
.bouton:hover { background: var(--signal-appui); border-color: var(--fond); }
.bouton:active { background: var(--signal-appui); border-color: var(--fond); border-width: 3px; }

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

.bouton-secondaire {
  background: transparent;
  color: var(--craie);
  border: 1px solid var(--contour);
}

.bouton-secondaire:hover { background: transparent; border-color: var(--contour-fort); }
.bouton-secondaire:active { background: transparent; border-color: var(--contour-fort); border-width: 2px; }

/* Bouton de texte (« Modifier »), sans boite : un lien qui est un bouton. */
.bouton-texte {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0;
  background: none;
  border: 0;
  color: var(--craie);
  font-family: var(--police-texte);
  font-size: var(--t-micro);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: .22em;
  text-decoration-thickness: 1px;
  cursor: pointer;
}

.bouton-texte:hover { text-decoration-thickness: 2px; }

.bouton .picto,
.bouton-texte .picto {
  flex: none;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Le chevron ne decore pas : il distingue l'action qui fait avancer le trajet
   des pastilles, qui n'en portent jamais. Il reste en fin de bouton. */
.bouton .picto-suite { margin-right: -4px; }

@media (min-width: 768px) {
  /* Plancher de largeur : sous 768 px le bouton est deja pleine largeur, donc
     deja plus large que la plus large des pastilles. Au-dela il redevient
     inline-flex et c'est la seule largeur ou il pouvait se confondre. */
  .bouton { width: auto; display: inline-flex; min-width: 260px; }
}

/* ----------------------------------------------------- 9. Onglets de piece */

/* Grammaire mediane-affinage.md §3.5. Pas de rayon : le rond est reserve au
   bouton et aux pastilles. Le rail est un trait, l'onglet actif porte un
   trait interieur, et jamais une ombre portee. */

.onglets {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  border-bottom: 1px solid var(--filet-fort);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.onglets::-webkit-scrollbar { display: none; }

.onglet {
  flex: none;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: var(--e8);
  height: 44px;
  padding: 0 var(--e16);
  background: none;
  border: 0;
  border-radius: 0;
  color: var(--craie-douce);
  font-family: var(--police-texte);
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}

.onglet[aria-selected="true"] {
  color: var(--craie);
  box-shadow: inset 0 -2px 0 var(--signal);
}

/* Zero objet : pas de nombre du tout, plutot qu'un « 0 ». */
.onglet-compte {
  font-family: var(--police-chiffre);
  font-size: 13px;
  letter-spacing: .04em;
  color: var(--craie-douce);
}

/* Vers l'interieur, sinon le contour deborde du rail. */
.onglet:focus-visible { outline: 2px solid var(--signal); outline-offset: -2px; }

/* Les sept onglets mesurent ensemble environ 950 px et la colonne de
   formulaire 792 px : a 1440 px, le dernier s'affichait reduit a la lettre
   « C » suivie d'un chevron. Le defilement lateral se justifie sur les 311 px
   utiles d'un telephone ; sur un ecran ou la page laisse 400 px de vide a
   droite du panneau, un onglet coupe a une initiale se lit comme un defaut
   d'affichage, pas comme une invitation a faire defiler. Une deuxieme rangee
   de 44 px, prise sur le vide deja present sous le formulaire.
   Le rail border-bottom reste sous la derniere rangee, l'onglet actif garde
   son trait interieur, et le chevron de fin de rangee de calculateur.css
   s'eteint de lui-meme : il depend d'un debordement qui n'existe plus. */
@media (min-width: 1080px) {
  .onglets { flex-wrap: wrap; overflow-x: visible; }
}

/* --------------------------------------------- 10. Case d'objet et compteur */

/* mediane-phase2.md §B.4.4. Chaque case est un controle, il y en a dix a seize
   par onglet : c'est un selecteur, pas la grille de trois cartes clonees que
   la direction §7 ecarte. Hauteur fixe : 12+36+8+38+2+15+9+44+12 = 176 px. */

.planche {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e12);
}

@media (min-width: 768px) {
  .planche { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--e16); }
}

@media (min-width: 1080px) {
  .planche { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

.case-objet {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 176px;
  padding: var(--e12);
  background: transparent;
  border: 1px solid var(--filet-fort);
  border-radius: 2px;
  transition: border-color 120ms ease-out;
}

.case-objet .picto {
  flex: none;
  width: 36px;
  height: 36px;
  color: var(--craie-douce);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Deux lignes reservees pour que toutes les cases s'alignent quel que soit
   le nom, et coupe par des points de suspension au-dela. */
.case-nom {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  margin-top: var(--e8);
  min-height: 38px;
  max-width: none;
  font-size: 15px;
  line-height: 1.25;
  color: var(--craie-douce);
}

.case-volume {
  margin-top: 2px;
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: 12px;
  line-height: 15px;
  letter-spacing: .03em;
  color: var(--craie-douce);
}

.case-objet .compteur { margin-top: auto; }

.case-objet.est-comptee { border-color: var(--signal); }
.case-objet.est-comptee .case-nom { color: var(--craie); }

/* L'usage de l'ambre hors trace, bouton et focus que §3.4 autorise : il marque
   ce qui est charge dans le camion. L'information n'est jamais portee par la
   seule couleur, le compteur affiche aussi un nombre. */
.case-objet.est-comptee::after {
  content: "";
  position: absolute;
  top: var(--e8);
  right: var(--e8);
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: var(--signal);
}

.case-libre { border-style: dashed; }
.case-libre .picto { color: var(--contour-fort); }

.case-onglet {
  position: absolute;
  top: var(--e8);
  right: var(--e12);
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: 12px;
  letter-spacing: .03em;
  color: var(--craie-douce);
}

.compteur {
  display: grid;
  grid-template-columns: 40px 1fr 40px;
  align-items: center;
  height: 44px;
}

.compteur-moins,
.compteur-plus {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: none;
  border: 1px solid var(--contour);
  border-radius: 999px;
  color: var(--craie);
  cursor: pointer;
  transition: border-color 120ms ease-out;
}

/* Zone tactile portee a 44 x 44 px sans changer le rond visible. */
.compteur-moins::after,
.compteur-plus::after { content: ""; position: absolute; inset: -2px; }

.compteur-moins:hover,
.compteur-plus:hover { border-color: var(--contour-fort); }

.compteur-moins .picto,
.compteur-plus .picto {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

.compteur-moins[aria-disabled="true"],
.compteur-plus[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

.compteur-valeur {
  width: 100%;
  height: 40px;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--craie);
  font-family: var(--police-chiffre);
  font-size: 20px;
  letter-spacing: .02em;
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}

.compteur-valeur::-webkit-outer-spin-button,
.compteur-valeur::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ------------------------------------------------ 11. Zone de depot d'images */

/* Grammaire mediane-affinage.md §3.6. Maquette : URL.createObjectURL et
   affichage seulement. Aucun envoi, aucun fetch, aucun domaine externe. */

.depot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e12);
  min-height: 140px;
  padding: var(--e24);
  background: transparent;
  border: 1px dashed var(--contour);
  border-radius: 2px;
}

/* Aucun changement de taille au survol de depot. */
.depot.est-survole { border-style: solid; border-color: var(--signal); background: var(--panneau); }

.depot .picto {
  width: 40px;
  height: 40px;
  color: var(--contour-fort);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.depot-titre { font-size: 17px; color: var(--craie); }
.depot-ou { font-size: var(--t-micro); color: var(--craie-douce); }

.vignettes {
  display: grid;
  grid-template-columns: repeat(auto-fill, 72px);
  gap: var(--e12);
  margin-top: var(--e16);
}

.vignette { position: relative; width: 72px; height: 72px; }

.vignette img {
  width: 72px;
  height: 72px;
  object-fit: cover;
  border: 1px solid var(--filet-fort);
  border-radius: 2px;
}

/* Repli du HEIC : Safari l'affiche, Chrome et Firefox non. Meme encombrement,
   le nom du fichier a la place de l'image. La photo reste comptee. */
.vignette-repli {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e4);
  width: 72px;
  height: 72px;
  padding: var(--e4);
  border: 1px solid var(--filet-fort);
  border-radius: 2px;
}

.vignette-repli .picto { width: 20px; height: 20px; }

.vignette-nom {
  max-width: 100%;
  overflow: hidden;
  font-family: var(--police-chiffre);
  font-size: 11px;
  line-height: 1.2;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--craie-douce);
}

.vignette-retrait {
  position: absolute;
  top: -6px;
  right: -6px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  background: var(--fond);
  border: 1px solid var(--filet-fort);
  border-radius: 999px;
  color: var(--craie);
  cursor: pointer;
}

.vignette-retrait .picto {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

/* ------------------------------------------ 12. Bandeau de progression A a B */

/* Grammaire mediane-affinage.md §3.7, precisee par mediane-phase2.md §B.1.
   C'est le trace de l'accueil couche. Pas de pastilles numerotees.
   Hauteur 56 px partout : 10 + 20 + 6 + 16 + 4.
   merci.html et 404.html en affichent une version figee. */

.bandeau-trajet {
  position: sticky;
  top: 0;
  z-index: var(--z-bandeau);
  height: 56px;
  padding: 10px var(--gouttiere-calc-d) 4px var(--gouttiere-calc-g);
  background: var(--fond);
  border-bottom: 1px solid var(--filet-fort);
}

.rail { position: relative; height: var(--e20); }

/* 24 px de marge de chaque cote, comme §3.7 le demande. */
.rail-piste {
  position: absolute;
  left: 24px;
  right: 24px;
  top: 9px;
  height: 2px;
  background: var(--filet-fort);
}

.rail-parcouru {
  display: block;
  width: calc(var(--avancement, 0) * 100%);
  height: 2px;
  background: var(--signal);
  transition: width var(--duree-moyenne) var(--sortie);
}

.rail-depart {
  position: absolute;
  left: 24px;
  top: 10px;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 999px;
  background: var(--signal);
}

/* Chaque arret porte sa position sur le rail par --t, de 0 a 1. */
.rail-arret {
  position: absolute;
  top: 10px;
  left: calc(24px + var(--t, 0) * (100% - 48px));
  transform: translate(-50%, -50%);
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

.rail-arret::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  margin: -3.5px 0 0 -3.5px;
  background: var(--fond);
  border: 2px solid var(--signal);
  border-radius: 999px;
}

.rail-arret.est-franchi::before { background: var(--signal); }
.rail-arret:disabled { cursor: default; }
.rail-arret:focus-visible { outline: 2px solid var(--signal); outline-offset: -8px; }

/* L'anneau d'arrivee se ferme par stroke-dashoffset : il lui faut un SVG. */
.rail-arrivee {
  position: absolute;
  top: 10px;
  right: 24px;
  width: var(--e20);
  height: var(--e20);
  margin: -10px -10px 0 0;
  overflow: visible;
}

.rail-arrivee circle {
  fill: none;
  stroke: var(--signal);
  stroke-width: 1.5;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset 400ms var(--sortie);
}

.rail-arrivee.est-ferme circle { stroke-dashoffset: 0; }

/* Un decalage de tiret egal a la longueur du trace ne dessine rien : l'anneau
   d'arrivee restait invisible pendant TOUT le remplissage et n'apparaissait
   qu'a la validation du dernier arret. Le rail s'arretait net sur rien, alors
   que la page vend un trajet A vers B : B n'existait pas.
   D'ou un cercle de repos, pose sous celui qui se ferme, en --contour-fort
   (6,61:1 sur --fond) et non en --signal : il dit « l'arrivee est la »,
   l'ambre dit « vous y etes ». §3.7 demande un anneau qui se ferme ; un
   anneau qui se ferme est un anneau qu'on voit d'abord ouvert.
   Specificite 0,2,0, elle bat le 0,1,1 de .rail-arrivee circle. Le balisage
   qui va avec est dans calculateur.html et pages.html :
     <circle class="rail-arrivee-repos" cx="10" cy="10" r="8"/>
   pose AVANT le cercle anime, dans le meme <svg class="rail-arrivee">. */
.rail-arrivee .rail-arrivee-repos {
  fill: var(--fond);
  stroke: var(--contour-fort);
  stroke-width: 1.5;
  stroke-dasharray: none;
  stroke-dashoffset: 0;
  transition: none;
}

.rail-libelles {
  position: relative;
  height: var(--e16);
  margin-top: 6px;
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: 12px;
  line-height: var(--e16);
  letter-spacing: .03em;
  color: var(--craie-douce);
}

.rail-lieu { position: absolute; top: 0; white-space: nowrap; }
.rail-lieu-depart { left: 0; }
.rail-lieu-arrivee { right: 0; }

/* Sous 768 px, seules les deux communes restent : les noms d'arret seraient
   illisibles a 311 px et ils sont deja dans le <h2> juste en dessous. */
.rail-nom {
  position: absolute;
  top: 0;
  left: calc(24px + var(--t, 0) * (100% - 48px));
  transform: translateX(-50%);
  white-space: nowrap;
}

.rail-nom { display: none; }

@media (min-width: 768px) {
  .rail-nom { display: block; }
  .rail-nom.est-courant { color: var(--craie); }
}

/* --------------------------------------------------- 13. Recapitulatif */

/* Grammaire mediane-affinage.md §3.8, precisee par mediane-phase2.md §B.2.
   Aucune ombre. Le montant reste en --craie : la direction §2 reserve l'ambre
   au trajet, aux reperes, au bouton et au focus. */

.recap {
  background: var(--panneau);
  border-radius: 4px;
  padding: var(--e24);
}

@media (min-width: 768px) { .recap { padding: var(--e32); } }

.recap-titre { font-size: var(--t-h3); color: var(--craie); }

.recap-lignes { margin-top: var(--e16); }

.recap-ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e16);
  padding: var(--e12) 0;
  border-top: 1px solid var(--filet-fort);
}

.recap-libelle { max-width: none; font-size: 15px; color: var(--craie-douce); }

/* Huit des onze libelles du recapitulatif sont des boutons de texte qui
   ramenent a leur arret. Avec la mise en forme generale de .bouton-texte ils
   sortaient en 14 px, graisse 600, --craie et soulignes, pendant que les trois
   libelles calcules (« Camion », « Duree estimee », « Estimation ») restaient
   en 15 px, graisse 400, --craie-douce : dans une colonne de 340 px, les
   libelles modifiables criaient plus fort que les chiffres qu'ils decrivent,
   et le soulignement est deja le signe des liens du pied de page.
   Les onze partagent desormais une taille, une graisse et une couleur ; le
   trait s'efface en --contour (3,33:1 sur --panneau, au-dessus du seuil de 3:1
   de WCAG 1.4.11) et la capacite a modifier se revele au survol et au focus. */
.recap-libelle .bouton-texte {
  font-size: 15px;
  font-weight: 400;
  color: var(--craie-douce);
  text-decoration-color: var(--contour);
  text-underline-offset: .22em;
}

.recap-libelle .bouton-texte:hover,
.recap-libelle .bouton-texte:focus-visible {
  color: var(--craie);
  text-decoration-color: var(--signal);
}

.recap-valeur {
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: var(--e16);
  letter-spacing: .02em;
  text-align: right;
  color: var(--craie);
}

.recap-valeur-note {
  display: block;
  font-size: 13px;
  color: var(--craie-douce);
}

/* Le recapitulatif redit le trajet : un trait vertical de 1 px court entre le
   repere du depart et celui de l'arrivee. */
.recap-trajet { position: relative; }

.recap-trajet::before {
  content: "";
  position: absolute;
  left: 3px;
  top: calc(var(--e12) + .7em);
  bottom: calc(var(--e12) + .7em);
  width: 1px;
  background: var(--filet-fort);
}

.recap-trajet .recap-libelle {
  display: flex;
  align-items: baseline;
  gap: var(--e12);
}

.recap-point,
.recap-anneau {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  transform: translateY(-1px);
}

.recap-point { background: var(--signal); }
.recap-anneau { background: var(--fond); border: 1.5px solid var(--signal); }

.recap-total {
  margin-top: var(--e16);
  padding-top: var(--e16);
  border-top: 1px solid var(--filet-fort);
}

.recap-total-libelle { font-size: 15px; color: var(--craie-douce); }

/* Aucune transition sur le montant : pas de compteur qui defile, pas de fondu.
   Il change, c'est tout. */
.recap-montant {
  margin-top: var(--e4);
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: 32px;
  line-height: 1.1;
  letter-spacing: .01em;
  color: var(--craie);
}

.recap-notes { margin-top: var(--e12); }
.recap-notes li + li { margin-top: var(--e8); }

.recap-notes li {
  font-size: var(--t-micro);
  line-height: 1.45;
  color: var(--craie-douce);
}

/* ------------------------------------------------------------ 14. Etat vide */

/* Grammaire mediane-affinage.md §3.10. Aucune boite, aucun cadre plein.
   Aligne a gauche comme tout le reste. Une invitation a agir, pas une humeur. */

.etat-vide {
  padding: 40px 0;
  border-top: 1px dashed var(--filet-fort);
  border-bottom: 1px dashed var(--filet-fort);
}

.etat-vide .picto {
  width: 40px;
  height: 40px;
  color: var(--contour-fort);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.etat-vide-titre { margin-top: var(--e16); font-size: 18px; color: var(--craie); }
.etat-vide-texte { margin-top: var(--e8); font-size: 15px; color: var(--craie-douce); }
.etat-vide .bouton { margin-top: var(--e24); }

/* ------------------------------------------------------- 15. Pied de page */

/* Les quatre pages portent le meme pied. */

.pied {
  --retrait-rail: 0px;
  background: var(--panneau);
  padding: var(--e32) 0 var(--e48);
  border-top: 1px solid var(--filet-fort);
}

.pied-rangee {
  display: flex;
  flex-direction: column;
  gap: var(--e16);
}

/* Le nom en pied de page passe en Avenir Next : Futura ne descend jamais sous
   24 px (direction, §2), et un troisieme rappel du titre n'apporte rien ici. */
.pied-nom {
  font-family: var(--police-texte);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .01em;
}

/* R4 : le separateur etait un ::before porte par le <li>. Quand le <li> passait
   a la ligne, le point partait avec lui et ouvrait la ligne suivante, seul.
   Sous 768 px il n'y a plus de separateur du tout : les filets de « Ce que
   nous faisons » font le travail, et la colonne passe de 58 a 45 px par ligne.
   Au-dela, le point est pose sur le <a> et ne peut plus etre orphelin. */
.liens {
  display: grid;
  font-size: var(--t-micro);
}

.liens li + li { border-top: 1px solid var(--filet-fort); }

.liens a,
.liens .lien-inerte {
  display: flex;
  align-items: center;
  min-height: 44px;
  color: var(--craie-douce);
  text-decoration: underline;
  text-underline-offset: .22em;
  text-decoration-thickness: 1px;
}

/* « Mentions legales » et « Protection des donnees » : les deux pages n'ont
   pas ete commandees et n'existent pas. Le libelle reste au pied de page pour
   dire ce qui viendra, mais ce n'est plus un lien : un <span class="lien-inerte">
   avec aria-disabled="true". Pas de soulignement, pas de curseur de main :
   rien ne se clique, et il n'y a aucun lien mort. Les deux libelles sont
   listes dans _A-REMPLACER.md. */
.liens .lien-inerte { text-decoration: none; cursor: default; }

.liens a:hover { color: var(--craie); text-decoration-thickness: 2px; }

@media (min-width: 768px) {
  .liens {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--e32);
  }

  .liens li { position: relative; }
  .liens li + li { border-top: 0; }

  /* Le point etait un ::before pose sur le <a>. Un display: inline-block ne
     protege pas de la decoration du parent : le soulignement du lien etait
     bien trace en dessous, et les separateurs s'affichaient comme des points
     soulignes. Le point passe donc sur le <li>, EN DEHORS DU FLUX : une boite
     absolue ne recoit pas la decoration du texte et aucun trait ne la
     traverse. Il est centre dans la gouttiere de 32 px, a droite de l'element
     qu'il suit et non a gauche du suivant : quand la rangee passe a la ligne,
     le point termine la ligne au lieu d'ouvrir la suivante, seul.
     Ne pas le remettre dans le flux, ni sur le <a>, ni sur le <li>. */
  .liens li:not(:last-child)::after {
    content: "\00B7";
    position: absolute;
    top: 0;
    bottom: 0;
    right: calc(var(--e32) / -2);
    display: flex;
    align-items: center;
    transform: translateX(50%);
    color: var(--craie-douce);
    pointer-events: none;
  }
}

@media (min-width: 900px) {
  .pied-rangee {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--e24) var(--e48);
  }
}

/* --------------------------------------------------- 16. Mouvement reduit */

/* Repli commun. Chaque feuille de page ajoute le repli de ses propres
   mouvements ; mediane-affinage.md §4 regle 3 : toute retouche ajoute son
   repli ou n'est pas livree. */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  /* Le trace du rail change de largeur sans transition, l'anneau d'arrivee
     est dessine d'emblee. */
  .rail-parcouru { transition: none; }
  .rail-arrivee circle { stroke-dasharray: none; stroke-dashoffset: 0; transition: none; }
}
