/* =========================================================================
   calculateur.css — ce que la page d'estimation ajoute a base.css.

   Charge APRES base.css et les trois feuilles de marque, jamais avant. Elle ne
   redeclare aucun jeton et aucune couleur en dur : partout var(--*), et toutes
   les valeurs viennent de marque/tokens.css.

   Ce qui vit ici, et nulle part ailleurs (_COMPOSANTS.md §10 et §4) :
     - la TUILE D'OBJET : taille d'image, hauteur de case, grille de la planche
     - le bloc de resultat du recapitulatif, qui ne porte plus de montant
     - les trois positions du recapitulatif (colonne collante, bloc, barre basse)
     - les onglets collants sous le bandeau (top: 56px)
     - la barre basse de 84 px et sa bascule de recapitulatif
     - le repere du couloir gauche de l'arret en cours
     - le champ de recherche de l'inventaire
     - .groupe-lie, la seule forme de champ que la marque ne connait pas

   Ni aplat rouge, ni pli, ni semis, ni coupe en rabat sur cette page :
   le plan d'emploi des six formes plafonnees (cahier §1.5) lui en donne zero.

   Sources : site-swiss-pro-moving.md §2.3, §5.3, §5.4, §5.5 ;
   mediane-phase2.md §B.0 a §B.9, §H.4, §H.5. Aucune valeur inventee.
   ========================================================================= */

/* ------------------------------------------------- 1. Reglages de la page */

/* [hidden] est passe dans base.css le 19.09 (_COMPOSANTS.md §9) : un attribut
   du HTML ne doit pas dependre de la feuille de page qui se charge ensuite.
   La regle qui vivait ici est donc partie. Les deux exceptions du bloc
   <noscript> ont une specificite plus haute et continuent de gagner. */

body { min-height: 100dvh; }

/* Le calculateur a ses propres gouttieres : 40 px a gauche, 24 px a droite
   sous 768 px (§B.0, correction 2 du jury). Le couloir gauche n'est pas une
   marge bizarre, il porte le repere de l'arret en cours. */
.calc {
  --gouttiere-g: var(--gouttiere-calc-g);
  --gouttiere-d: var(--gouttiere-calc-d);
  --retrait-rail: 0px;
  padding-top: var(--e32);
  padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px) + var(--e48));
}

@media (min-width: 768px) {
  .calc { padding-top: var(--e48); padding-bottom: var(--e96); }
}

/* LE DEFILEMENT AU CLAVIER S'ARRETE AU-DESSUS DE LA BARRE BASSE.

   Defaut mesure le 20.09 a 375 x 812, sur calculateur.html?demo=1&etape=2 :
   la 2e tabulation pose le focus sur `input#voie-objets`, la pastille
   « Lister objet par objet ». Cet input-la est une boite de 1 px posee a
   y=795,4 ; le navigateur la juge donc DEJA VISIBLE et ne defile pas du tout
   (scrollY=0 alors que 5 045 px de defilement restaient disponibles). Mais ce
   qui est PEINT est le label, 191,5 x 52, de y=795,4 a y=847,4 — sous une
   fenetre de 812, et entierement derriere la barre basse fixe, qui occupe
   y=728..812. L'anneau de focus descendait 35 px sous le bord bas : au
   clavier, on ne voit pas ou on est.

   scroll-padding dit au navigateur ou commence vraiment la zone lisible du
   document : il defile alors de lui-meme pour poser le controle AU-DESSUS de
   la barre. Meme hauteur que la barre (§14 de cette feuille : 8 + 20 + 4 + 52
   = 84 px, plus l'encoche), plus --e16 d'air pour l'anneau et son
   contre-anneau.

   Sur `html` et non sur `:root` : ce n'est pas un jeton, c'est un reglage du
   defilement du document, et cette feuille ne redeclare aucun jeton.
   Sous 767 px seulement, exactement comme la barre : au-dela, `.arret-actions`
   revient dans le flux et ne recouvre plus rien. */
@media (max-width: 767px) {
  html { scroll-padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px) + var(--e16)); }
}

/* AU-DELA DE 767 PX, IL FAUT QUAND MEME DE L'AIR POUR L'ANNEAU.

   Defaut mesure le 24.09 a 1440 x 900, sur calculateur.html?demo=1&etape=2,
   apres l'ajout du h1 (.calc-titre, plus bas) : le h1 a descendu la barre
   d'onglets, et la tabulation pose le focus sur `button#o-sejour` a y=856,
   haut de 44 px. Son bas tombe a 900 px pile, le bord de la fenetre : le
   navigateur le juge DEJA VISIBLE et ne defile pas (scrollY=1). L'anneau et
   son contre-anneau (+4 px) finissaient donc a 904 px, rognes par le bas.

   Au-dela de 767 px, la barre basse n'est plus collee au bas de l'ecran,
   donc pas ses 84 px : seulement
   --e16 d'air, la meme marge que sous 767 px, pour que le navigateur defile
   des qu'un controle vient toucher le bord bas. */
@media (min-width: 768px) {
  html { scroll-padding-bottom: var(--e16); }
}

/* ET IL S'ARRETE AUSSI SOUS LES DEUX MOBILIERS COLLANTS DU HAUT.

   Defaut mineur releve le 20.09 a 375 x 812 : le bandeau du site est colle a
   0..56 px et la barre d'onglets de l'inventaire a 56..101 px, mais aucun
   conteneur ne portait de scroll-padding-top ni de scroll-margin-top. Tout
   saut d'ancre vers un panneau de piece (#p-cuisine existe dans le balisage)
   deposait donc le panneau a y=0, c'est-a-dire la premiere rangee de tuiles
   SOUS la barre : image mesuree de 13 a 93, barre de 56 a 101. Le site ne
   fabrique pas ce saut aujourd'hui, le visiteur ne le voit pas ; l'ancre
   existe pourtant, et le jour ou quelqu'un la rebranche elle doit tomber
   juste. Une regle qui coute deux declarations vaut mieux qu'un piege.

   Deux valeurs, parce qu'il y a deux mobiliers et qu'ils ne servent pas les
   memes ancres :
     - `scroll-padding-top` sur `html` = le bandeau du site (56 px) + de l'air.
       Il vaut pour TOUTES les ancres de la page, y compris le lien d'evitement.
     - `scroll-margin-top` sur les cibles qui vivent SOUS la barre d'onglets =
       la hauteur de cette barre en plus. A partir de 1080 px les sept onglets
       passent sur deux rangees (base.css §9, flex-wrap), la barre fait 88 px.
   Les deux s'additionnent : 56 + 12 + 44 = 112 px sous 1080 px, ce qui pose
   la premiere rangee de tuiles 11 px sous le bas de la barre. */
html { scroll-padding-top: calc(56px + var(--e12)); }

/* Lot 1 (24.09) : la barre collante porte desormais la recherche (8 + 48 px)
   AU-DESSUS des onglets. Les cibles qui vivent sous elle, et les controles
   qu'on y atteint au clavier en remontant (Maj+Tab), s'arretent donc sous
   ses 101 px (145 px a partir de 1080 px, onglets sur deux rangees), et non
   sous les seuls 44 px des onglets. */
.panneau-piece, .resultats,
.panneau-piece :is(button, input), .resultats :is(button, input),
.objets-libres :is(button, input) { scroll-margin-top: 104px; }

@media (min-width: 1080px) {
  .panneau-piece, .resultats,
  .panneau-piece :is(button, input), .resultats :is(button, input),
  .objets-libres :is(button, input) { scroll-margin-top: 148px; }
}

.calc-corps { position: relative; }

/* A partir de 1080 px : 792 px de formulaire, 48 px d'ecart, 340 px de
   recapitulatif. 792 + 48 + 340 = 1180 = --largeur-max. */
@media (min-width: 1080px) {
  .calc-corps {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    column-gap: var(--e48);
    align-items: start;
  }

  .calc-form { grid-column: 1; min-width: 0; }
}

/* --------------------------------------------- 2. Bandeau de demonstration */

/* Visible seulement avec ?demo=1, pour que personne ne prenne une capture de
   demonstration pour une saisie reelle (§D). */
.bandeau-demo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e16);
  min-height: 40px;
  padding: var(--e8) var(--gouttiere-calc-d) var(--e8) var(--gouttiere-calc-g);
  background: var(--surface);
  border-bottom: var(--filet-epaisseur) solid var(--filet-fort);
}

.bandeau-demo-texte {
  max-width: none;
  font-size: var(--t-petit);
  line-height: 1.45;
  color: var(--texte-secondaire);
}

/* ----------------------------------------------------- 3. Le bandeau-trajet */

/* Le rail lui-meme est dans base.css §12. Ici, seulement ce qui est propre au
   calculateur : sept marques regulierement espacees (disque, cinq arrets,
   anneau), donc sept etiquettes qui ne se marchent pas dessus.

   LES LIBELLES PASSENT SOUS LE TRACE (constat 4 du chef, 19.09).
   Mesure avant correction, ordinateur 1440 : le trace a y=74, les cinq noms
   d'arret et les deux communes a y=65 sur 16 px de haut. La ligne traversait
   le texte en plein milieu : « Le chargement » se lisait barre.
   Cause : dans calculateur.html le <p class="rail-libelles"> est place DANS
   #rail. Toutes ses soeurs (piste, disque, cinq boutons, anneau) sont en
   position absolue, donc hors flux ; le <p> est le seul enfant en flux et se
   pose en haut de #rail. Son margin-top de 6 px, qui devait l'en ecarter, se
   fond dans celui de #rail : #rail est en position relative, ce qui ne cree
   pas de contexte de formatage, et la marge sort du bloc sans rien decaler.
   Reponse : le sortir du flux a son tour et le caler a 26 px du haut de #rail,
   soit les 20 px du rail plus les 6 px d'ecart que base.css §12 avait prevus.
   Le budget de hauteur du bandeau est respecte au pixel :
   10 (padding haut) + 20 (rail) + 6 (ecart) + 16 (libelles) + 4 = 56 px.
   base.css n'est pas a moi : merci.html porte le meme <p> au meme endroit et
   le meme defaut, c'est signale au chef de chantier. */
.bandeau-calc .rail-libelles {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--e20) + 6px);
  margin-top: 0;
}

/* Les deux communes ne sont plus tronquees tant que la place existe.
   Avant : max-width 11ch = 63 px, alors que « 1206 Genève » en demande 67 et
   « 1227 Carouge » 72. Les deux extremites du trajet s'affichaient « 1206 Gen »
   et « 1227 Car… » sur un ecran de 1440 px ou le rail fait 1219 px de large.
   La vraie contrainte n'est pas un nombre de caracteres, c'est le premier nom
   d'arret : il est centre sur 16,67 % du rail, et il mesure au plus 81 px
   (« Le chargement »). Reste donc 16,67 % moins la moitie du nom moins un
   ecart net, que --e24 arrondit : 91 px a 768, 179 px a 1440.
   Sous 768 px les noms d'arret ne s'affichent pas (base.css §12) : les deux
   communes se partagent la largeur, la moitie moins un ecart chacune. */
.bandeau-calc .rail-lieu { overflow: hidden; text-overflow: ellipsis; }

@media (max-width: 767px) {
  .bandeau-calc .rail-lieu { max-width: calc(50% - var(--e12)); }
}

@media (min-width: 768px) {
  .bandeau-calc .rail-lieu { max-width: calc(16.67% - var(--e24)); }
}

/* ---------------------------------------------------------- 4. Sans script */

/* Aucun filet gauche ici : le filet gauche de 3 px est LA FORME de l'erreur
   (cahier §2.6), et un avertissement technique qui l'emprunterait rendrait
   l'erreur moins reconnaissable. Un cadre entier sur --surface, donc. */
.sans-js {
  display: none;
  max-width: var(--mesure);
  margin-bottom: var(--e32);
  padding: var(--e16);
  background: var(--surface);
  border: var(--filet-epaisseur) solid var(--filet);
  color: var(--texte);
}

/* ------------------------------------------------------------- 5. L'arret */

.arret { position: relative; }

/* Les 64 px separent deux arrets EMPILES, c'est-a-dire le seul cas ou ils le
   sont : sans JavaScript, les cinq sections se suivent dans la page.
   Avec JavaScript un seul arret est visible et les autres portent [hidden].
   La marge haute de l'arret courant subsistait pourtant : elle n'avait plus
   rien contre quoi se fondre, et poussait tout l'ecran de 64 px vers le bas.
   Mesure du 19.09, mobile 375, arret 2 : bas du bandeau y=56, bouton de retour
   y=152, soit 96 px de vide pour 32 px de retrait voulu (constat 5 du chef).
   Des que le voisin de gauche est masque, la marge n'a plus d'objet.
   Meme specificite que la regle au-dessus (0,2,0), declaree apres : elle
   gagne par l'ordre, et le cas sans script n'est pas touche. */
.arret + .arret { margin-top: var(--e64); }
.arret[hidden] + .arret { margin-top: 0; }

/* Le repere du couloir gauche. Statique : il ne se remplit pas, ne s'anime pas
   et ne mesure rien. Il dit « le titre est ici », comme les huit marqueurs de
   l'accueil disent « la section est ici ». C'est ce qui l'empeche d'entrer en
   concurrence avec le rail horizontal, qui lui mesure l'avancement (§B.0).
   --repere-y est pose par le script : c'est la mediane du <h2> dans l'arret.
   Au-dela de 768 px la gouttiere n'est plus asymetrique, le repere disparait. */
@media (max-width: 767px) {
  .arret::before,
  .arret::after {
    content: "";
    position: absolute;
    left: calc(-1 * var(--gouttiere-calc-g) / 2);
    width: 0;
  }

  .arret::before {
    top: 0;
    height: var(--repere-y, 60px);
    border-left: var(--filet-epaisseur) solid var(--filet-fort);
  }

  .arret::after {
    top: var(--repere-y, 60px);
    bottom: 0;
    border-left: 1px dashed var(--filet-fort);
  }

  .arret-titre::before {
    content: "";
    position: absolute;
    left: calc(-1 * var(--gouttiere-calc-g) / 2);
    top: 50%;
    width: 7px;
    height: 7px;
    margin: -3.5px 0 0 -3.5px;
    background: var(--fond);
    border: 2px solid var(--marque);
    border-radius: var(--rayon-rond);
  }
}

/* Le h1 de la page, « Estimer mon demenagement » (24.09). Une surligne dans
   la famille de texte, 700, au corps d'un titre de bloc : le grand titre de
   l'ecran reste le <h2> de l'arret (« Le depart », « La date »…), en
   condensee. Meme corps et meme graisse que le titre du recapitulatif
   (.recap-titre, base.css), qui lui fait face au-dela de 1080 px. */
.calc-titre {
  max-width: none;
  font-family: var(--police-texte);
  font-weight: var(--graisse-gras);
  font-size: var(--t-h3);
  line-height: var(--interligne-h3);
  letter-spacing: -.005em;
  color: var(--texte);
  margin: 0 0 var(--e16);
}

/* « Arret 2 sur 5 ». Renomme depuis .compteur, deja pris par le groupe
   moins / valeur / plus d'une case d'objet (_COMPOSANTS.md §16). */
.arret-compte {
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: 12px;
  line-height: 1.4;
  letter-spacing: .04em;
  color: var(--texte-secondaire);
}

.arret-titre { margin-top: var(--e4); }

/* « · encore environ 2 minutes » : la meme ligne, la meme encre, et rien qui
   bouge. Ce n'est pas un compte a rebours. */
.arret-temps { white-space: nowrap; }

/* F4 (lot 1) : le resume d'erreurs porte enfin .spm-alerte--erreur (fond,
   encre, filet gauche de 3 px). .spm-alerte est une rangee flexible pensee
   pour une icone et un texte ; ici un titre et une liste s'empilent. */
.resume-erreurs.spm-alerte { display: block; }
.resume-erreurs.spm-alerte ul { margin-top: var(--e8); }

/* F2 (lot 1) : « Vous avez écrit « Lausanne ». Où se trouve ce départ ? » */
.zone-question {
  max-width: var(--mesure);
  margin-top: var(--e8);
  font-size: var(--t-petit);
  line-height: var(--interligne-petit);
  color: var(--texte);
}

.zone-question-mot { font-weight: var(--graisse-medium); }

/* La mesure de charge, sur l'arret 2 seulement : celui qui pese la charge est
   le seul a le faire (§B.1). */
.arret-mesure {
  font-family: var(--police-chiffre);
  font-size: 20px;
  letter-spacing: .02em;
  color: var(--texte-secondaire);
  white-space: nowrap;
}

/* Resume d'arret. Une seule ligne au-dela de 768 px, ou la place existe ;
   deux lignes en dessous, ou elle n'existe pas (voir plus bas). */
.arret-resume {
  display: flex;
  align-items: baseline;
  gap: var(--e12);
  margin-top: var(--e12);
  max-width: none;
}

.arret-resume-texte {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--police-chiffre);
  font-size: 13px;
  letter-spacing: .03em;
  color: var(--texte-secondaire);
}

.arret-resume .spm-btn--fantome { flex: none; }

/* Sous 768 px la ligne perdait sa fin, c'est-a-dire l'information la plus
   recente. Releve du 19.09 sur 375 px : arret 2, « 1206 Genève, 3e, sans
   ascenseur · 3 piè… » ; arret 5, « 1206 Genève → 1227 Carouge · 24,7 m³ ·… ».
   Le nombre de pieces, le volume et la date tombaient a chaque fois.
   Or sur mobile le recapitulatif est replie dans la barre basse : cette ligne
   est le seul endroit ou le visiteur relit ce qu'il vient de donner.
   Deux lignes, puis les points de suspension, comme .case-nom dans base.css.
   « Modifier » remonte en premier et se cale a droite : il garde sa rangee et
   la ligne prend la largeur entiere en dessous. Cout : jusqu'a 20 px sur
   quatre arrets, largement couverts par les 64 px rendus plus haut. */
@media (max-width: 767px) {
  .arret-resume {
    flex-wrap: wrap;
    row-gap: var(--e4);
  }

  .arret-resume-texte {
    flex: 1 1 100%;
    white-space: normal;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }

  .arret-resume .spm-btn--fantome { order: -1; margin-left: auto; }
}

.arret-aide {
  margin-top: var(--e12);
  font-size: 15px;
  line-height: 1.5;
  color: var(--texte-secondaire);
}

/* Le bouton de retour vit en haut a gauche de l'arret (§B.4.7) : la barre
   basse de 84 px n'a la place que de la bascule et du bouton principal.

   SA PLACE EST RESERVEE SUR LES CINQ ARRETS, y compris le premier, qui n'a
   nulle part ou revenir. Mesure du 19.09, ordinateur 1440, avant correction :
   haut du <h2> a y=170 sur l'arret 1, y=310 sur les arrets 2 a 5. Le titre,
   element le plus important de l'ecran, changeait de place entre le premier
   ecran et les quatre suivants, et l'oeil devait le rechercher a chaque
   passage d'un arret a l'autre. 76 px = 52 de bouton + 24 de marge basse.
   L'arret 1 porte une bande vide, pas un bouton masque : un controle qu'on
   cache reste un controle, et celui-la n'existe pas.
   Elle ne coute rien la ou le bouton est present, c'est-a-dire quatre fois
   sur cinq ; sur l'arret 1 elle coute 76 px, sur l'ecran le plus court des
   cinq, et c'est le prix d'un titre qui ne bouge plus. */
.arret-entete { min-height: 76px; }

/* Sur téléphone, l'arrêt 1 rend sa bande vide (audit mobile 21.09, P1-4) : à
   l'arrivée, la première question commençait à 480 px sur 664, sous 76 px de
   rien. Le titre de l'arrêt 1 monte donc de 76 px par rapport aux quatre
   autres ; sur un écran de téléphone, voir la question vaut mieux que
   l'alignement d'un écran à l'autre. */
@media (max-width: 767px) {
  .arret[data-arret="1"] .arret-entete { min-height: 0; }
}

/* Une erreur corrigée à la sortie du champ garde sa place, invisible, jusqu'au
   changement d'arrêt : la colonne ne saute plus sous le doigt (P1-6). */
.message-erreur.erreur-levee { visibility: hidden; }

.arret-retour {
  width: auto;
  margin-bottom: var(--e24);
}

/* Le chevron du bouton de retour est un pictogramme de marque : 24 px, la
   taille de reference. `flex: none` l'empeche de se laisser etirer par le
   bouton, qui est un inline-flex. Sans cette ligne un <svg> sans dimensions
   prend sa taille de remplacement, 300 x 150 px, et le bouton avec lui. */
.arret-retour .spm-icone { flex: none; }

/* Les champs de saisie du calculateur ne s'etalent pas sur toute la colonne :
   46ch, la mesure etroite que la marque donne elle-meme a .spm-formulaire.
   Un champ de 740 px pour une adresse fait chercher ou commence la reponse.
   Le NPA est un nombre de quatre chiffres : 12ch, et le champ dit sa longueur
   avant meme qu'on y touche. */
.arret .spm-champ { max-width: var(--mesure-etroite); }
.arret .spm-champ--nombre { max-width: 12ch; }

/* Zone tactile de 44 px sur les boutons fantomes, qui n'en font que 32. */
.calc .spm-btn--fantome { position: relative; }
.calc .spm-btn--fantome::after { content: ""; position: absolute; inset: -6px -4px; }

/* Le groupe lie — « Logement de depart » : deux groupes de pastilles sous une
   meme legende. La marque ne connait pas cette forme (elle a .spm-groupe, qui
   est une etiquette plus un champ) : elle vit donc ici, et nulle part ailleurs.
   Aucun cadre, aucun fond : une legende et un retrait, comme partout. */
.groupe-lie {
  margin: 0;
  padding: 0;
  border: 0;
}

.groupe-lie > legend {
  padding: 0;
  font-weight: var(--graisse-medium);
}

.groupe-lie > .pastilles { margin-top: var(--e24); }

.arret > .spm-groupe,
.arret > .pastilles,
.arret > .groupe-lie,
.arret > .spm-case,
.arret > [data-zone-bloc],
.arret > .voies { margin-top: var(--e32); }

.arret > .message-erreur + .spm-groupe,
.arret > .message-erreur + .pastilles,
.arret > .message-erreur + .groupe-lie { margin-top: var(--e24); }

/* Dans un bloc de zone, les champs se suivent au meme rythme que les autres.
   Le premier ne reprend pas la marge : le bloc l'a deja. */
[data-zone-bloc] > .spm-groupe + .spm-groupe,
[data-zone-bloc] > .message-erreur + .spm-groupe { margin-top: var(--e24); }
[data-zone-bloc] > .spm-aide { margin-top: var(--e8); }

/* ------------------------------------------- 6. Les deux voies de l'arret 2 */

.voie-logement { margin-top: var(--e24); }
.voie-objets { margin-top: var(--e32); }

.voie-logement .etat-vide-titre {
  font-family: var(--police-chiffre);
  font-size: 20px;
  letter-spacing: .02em;
}

/* ------------------------------------------------------- 7. La recherche */

/* L'etiquette et son aide, au-dessus de la barre : elles defilent, la barre
   reste. L'aide est AU-DESSUS du champ (et non dessous, comme ailleurs) : sous
   le champ, elle serait passee sous la barre collante. */
.recherche { margin-bottom: 0; }

/* LA BARRE COLLANTE (lot 1). Champ + « Effacer » + confirmation + onglets :
   un seul mobilier colle sous le bandeau de 56 px, a la place des seuls
   onglets. Budget de hauteur sous 1080 px : 8 + 48 + 45 = 101 px ; pendant
   une recherche, les onglets s'effacent et il reste 8 + 48 + 8 + 1 = 65 px.
   Le fond est celui de la page : ce qui defile dessous disparait net. */
.recherche-collante {
  position: sticky;
  top: 56px;
  z-index: 3;
  padding-top: var(--e8);
  background: var(--fond);
}

.recherche-collante.est-en-recherche {
  padding-bottom: var(--e8);
  border-bottom: var(--filet-epaisseur) solid var(--filet-fort);
}

/* Aucune piece ne reste soulignee pendant la recherche. */
.recherche-collante.est-en-recherche .onglets-cadre { display: none; }

.recherche-ancre { display: block; height: 0; }

.recherche-ligne {
  display: flex;
  align-items: stretch;
  gap: var(--e8);
  max-width: var(--mesure-etroite);
}

.recherche-ligne .saisie-icone { flex: 1 1 auto; min-width: 0; }
.recherche-ligne .spm-champ { max-width: none; }

.recherche-effacer { flex: none; min-height: 48px; padding-inline: var(--e16); }

/* « Ajouté : 3 × Chaise. » Une coche, parce que le controle est reel : le
   compteur de l'objet a bien change. Encre du texte, jamais rouge. */
.recherche-confirmation {
  display: flex;
  align-items: center;
  gap: var(--e8);
  max-width: none;
  margin-top: var(--e8);
  font-size: var(--t-petit);
  line-height: var(--interligne-petit);
  color: var(--texte);
}

.recherche-confirmation .spm-icone,
.telephone-confirme .spm-icone {
  flex: none;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

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

.saisie-icone .picto-champ {
  position: absolute;
  left: var(--e16);
  top: 50%;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--texte-secondaire);
  pointer-events: none;
}

.saisie-icone input { padding-left: calc(var(--e16) + 16px + var(--e12)); }

/* La croix native des champs de recherche est retiree : le bouton
   « Effacer » la remplace, visible et nomme. */
#recherche::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ------------------------------------------------- 8. Onglets et planches */

/* Deux mobiliers fixes sur l'arret 2 : 56 px de bandeau et 44 px d'onglets.
   C'est le prix a payer pour ne pas perdre les onglets au bout de huit
   rangees de cases, et c'est assume (§B.4.2). */
.onglets-cadre {
  display: flex;
  margin-top: var(--e8);
  align-items: stretch;
  background: var(--fond);
}

/* Le chevron de fin de rangee : une opacite, jamais un degrade de couleur.

   IL OCCUPE SA PROPRE GOUTTIERE, IL NE SE POSE PLUS SUR LA PISTE.
   Defaut mesure le 20.09 a 375 px : l'indicateur etait `position: absolute;
   right: 0`, soit une plaque BLANCHE OPAQUE de 28 px (x 323..351) posee
   par-dessus les onglets. L'onglet actif « Cuisine » occupait 267..367 : on
   lisait « Cuisir » suivi d'un chevron, et la pastille de compte disparaissait
   dessous. L'onglet que le visiteur venait de choisir etait le seul dont le
   nom etait ampute.
   `.onglets-cadre.a-droite .onglets { padding-right: --e32 }` ne pouvait pas
   sauver la mise : un retrait de fin de contenu ne protege que le DERNIER
   onglet, a fond de defilement. Un onglet du milieu s'arrete sous la plaque
   quel que soit le retrait. La seule geometrie qui tient est celle-ci : le
   cadre devient une rangee, la piste prend la place restante, et le chevron
   vit A COTE d'elle. Plus rien ne peut stationner dessous.
   Le filet du rail passe avec lui, sinon la ligne s'interrompait sur 28 px.
   A partir de 1080 px la piste ne defile plus (base.css §9 : flex-wrap, deux
   rangees), `a-droite` n'est jamais pose : le chevron n'a plus de sujet, et
   une gouttiere pour rien rognerait la derniere rangee d'onglets.

   IL S'ETIRE A LA HAUTEUR DE LA PISTE, IL NE LA FIXE PAS. Premiere mesure du
   20.09 apres la mise en gouttiere : `height: 44px` avec le `box-sizing:
   border-box` du socle rendait une boite de 44 px filet compris, contre 45 px
   pour la piste (44 px d'onglet + 1 px de filet). Le rail se cassait d'un
   pixel a la jonction, visible a l'oeil sur la capture a 375 px. `stretch` +
   `min-height` : une seule hauteur, celle des onglets, et le filet est
   continu. */
.onglets-suite {
  flex: none;
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-left: var(--e12);
  background: var(--fond);
  border-bottom: var(--filet-epaisseur) solid var(--filet-fort);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duree-courte) var(--entree);
}

@media (min-width: 1080px) {
  .onglets-suite { display: none; }
}

/* La piste prend tout ce que le chevron laisse. `min-width: 0` sans quoi un
   conteneur de defilement en flex refuse de descendre sous la largeur de son
   contenu et deborde la page.
   `scroll-padding-inline` : quand le navigateur amene un onglet en vue de
   lui-meme (focus au clavier, `scrollIntoView` de calculateur.js), il le cale
   a 12 px du bord et non contre l'arete. */
.onglets {
  flex: 1 1 auto;
  min-width: 0;
  scroll-padding-inline: var(--e12);
}

.onglets-suite .picto {
  width: var(--e16);
  height: var(--e16);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--texte-secondaire);
}

.onglets-cadre.a-droite .onglets-suite { opacity: 1; }

.panneau-piece { margin-top: var(--e24); }
.panneau-piece:focus-visible { outline-offset: 4px; }

/* Visible seulement sans script, quand les sept planches s'ouvrent a la
   suite : sans titre, on ne saurait plus quelle piece on lit. */
.planche-titre {
  display: none;
  margin-bottom: var(--e16);
  font-size: 18px;
  color: var(--texte);
}

/* ------------------------------------------- 8 bis. La tuile d'objet ------ */

/* L'image remplace le pictogramme, et elle EST le sujet de la case.
   La source tranche : marque/inventaire/serie/_CRITIQUE-SERIE.md §4 ecrit
   « taille de tuile recommandee pour le calculateur : 80 px (96 px si la
   maquette le permet). Pas 64 », parce qu'a 80 px les micro-organes du style
   (poignees, hublots, tiroirs) redeviennent nommables. Le calcul retombe sur
   les memes valeurs, en partant de la case actuelle de 176 px :
     < 768 px : 12 + 80 + 8 + 38 + 2 + 15 + 9 + 44 + 12 = 220 px
     >= 768   : 12 + 96 + 8 + 38 + 2 + 15 + 9 + 44 + 12 = 236 px
   Controle de largeur a 375 px : la colonne utile fait environ 311 px, deux
   colonnes avec une gouttiere de 16 px donnent 147 px par case, moins 24 px
   de marge interieure = 123 px utiles. Une image de 80 px y tient. */
.case-objet { height: 220px; }

@media (min-width: 768px) {
  .case-objet { height: 236px; }
}

/* TROIS LIGNES DE NOM SOUS 480 PX.

   L'etiquette fusionnee par l'arbitrage A2 — l'objet `congelateur_coffre` a
   rejoint `congelateur`, dont le libelle est devenu « Congelateur (coffre ou
   armoire) » — ne tenait pas dans la tuile sur telephone. Mesure du 20.09 a
   375 px : `.case-nom` coupe a 2 lignes (base.css §10), clientHeight 38 pour
   un scrollHeight de 56, rendu a l'ecran « Congelateur (coffre ou… ». Ce que
   la fusion devait apporter — coffre OU armoire — etait precisement le
   morceau coupe.
   Le nom garde son `min-height: 38px` : les noms courts ne grandissent pas,
   et la hauteur de tuile reste FIXE, donc les tuiles d'une meme rangee gardent
   leur hauteur commune et le compteur reste cale en bas (`margin-top: auto`).
   La tuile paie les 19 px de la troisieme ligne, en reprenant le calcul du
   bloc ci-dessus, ligne de nom portee de 38 a 57 px (15 px x 1,25 x 3 lignes,
   arrondi au pixel superieur) :
     12 + 80 + 8 + 57 + 2 + 15 + 9 + 44 + 12 = 239 px
   Sous 480 px seulement : au-dela, la colonne s'elargit et le nom tient en
   deux lignes — verifie a 600 px, scrollHeight 38 pour clientHeight 38.
   Les cases de resultat de recherche ne sont pas concernees : `.resultats
   .case-objet` est en `height: auto` (§9 de cette feuille). */
@media (max-width: 479px) {
  .case-objet { height: 239px; }

  .case-nom {
    -webkit-line-clamp: 3;
    line-clamp: 3;
  }
}

.case-image {
  flex: none;
  width: 80px;
  height: 80px;
  object-fit: contain;
  align-self: center;
  border-radius: var(--rayon);   /* aucune image n'est arrondie */
  box-shadow: var(--ombre);      /* --ombre vaut none */
}

@media (min-width: 768px) {
  .case-image { width: 96px; height: 96px; }
}

/* Le contre-anneau blanc du focus doit rester visible quand deux cases sont
   voisines : 16 px d'ecart a tous les paliers, pour 4 px d'anneau de chaque
   cote. base.css pose 12 px sous 768 px, ce qui tient de justesse ; ici on
   ne joue pas sur la marge. */
.planche { gap: var(--e16); }

/* L'etat choisi ne passe JAMAIS par la couleur seule : un filet de 2 px en
   --marque, un rabat rouge au coin haut-droit, et le nombre qu'affiche le
   compteur. Trois signaux.
   Le fond ne change pas : une case au fond teinte dissocierait le blanc de
   l'image du blanc de la case, et le decoupage se verrait. */
.case-objet.est-comptee {
  border-color: var(--marque);
  border-width: 2px;
  padding: calc(var(--e12) - 1px);   /* la case ne bouge pas d'un pixel */
}

/* Un rabat, pas un triangle : le triangle est reserve a l'erreur.
   La SEULE arete oblique va de (0,4px) a (8px,0) : pente 4/8 = 0,5, donc
   1 : 2, la pente d'ouverture du systeme. C'est la forme de .puce::before, a
   l'echelle. Ne pas ecrire polygon(0 0, 100% 0, 100% 100%, 8px 4px) : cette
   variante-la porte une arete de pente 1,5, qui n'appartient a aucune des deux
   pentes et qu'un banc de mise en page rougit, a juste titre. */
.case-objet.est-comptee::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 16px;
  height: 8px;
  border-radius: var(--rayon);
  background: var(--marque);
  clip-path: polygon(0 4px, 8px 0, 100% 0, 100% 100%, 0 100%);
}

/* La case « Ajouter un objet qui n'est pas ici » est un vrai bouton. */
button.case-objet {
  align-items: flex-start;
  justify-content: flex-start;
  gap: var(--e8);
  background: transparent;
  color: var(--texte-secondaire);
  font-family: var(--police-texte);
  text-align: left;
  cursor: pointer;
}

button.case-objet:hover { border-color: var(--marque); color: var(--texte); }
button.case-objet .case-nom { margin-top: 0; }
button.case-objet .spm-icone { flex: none; color: var(--texte-secondaire); }

/* ------------------------------------------ 9. Resultats de la recherche */

.resultats { margin-top: var(--e24); }

.resultats-titre {
  margin-bottom: var(--e16);
  max-width: none;
  font-size: 15px;
  color: var(--texte-secondaire);
}

/* UN RESULTAT, UNE LIGNE (lot 1). C'est la MEME case, deplacee par
   chercher() puis remise en place : ici elle se couche. L'image a gauche
   (40 px sous 480 px, 48 au-dela), le nom, le volume et la piece au milieu,
   le compteur a droite — le « + » et la quantite sont DANS le resultat, on
   ajoute sans quitter la recherche. Sous 480 px : 311 px de colonne a 375,
   moins 24 de marge, 40 d'image, 24 d'ecarts et 120 de compteur laissent
   103 px au nom (« Réfrigérateur » en demande 97). */
.resultats .planche { grid-template-columns: minmax(0, 1fr); gap: var(--e8); }

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

.resultats .case-objet {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto;
  grid-template-areas:
    "image nom    compteur"
    "image volume compteur"
    "image piece  compteur";
  align-content: center;
  column-gap: var(--e12);
  height: auto;
  min-height: 76px;
  padding: var(--e8) var(--e12);
}

.resultats .case-objet.est-comptee { padding: calc(var(--e8) - 1px) calc(var(--e12) - 1px); }

.resultats .case-image { grid-area: image; width: 48px; height: 48px; align-self: center; }

.resultats .case-nom {
  grid-area: nom;
  align-self: end;
  min-height: 0;
  margin: 0;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow-wrap: break-word;
  hyphens: auto;
}

.resultats .case-volume { grid-area: volume; margin: 0; }

.resultats .case-onglet {
  grid-area: piece;
  position: static;
  align-self: start;
  margin: 0;
}

.resultats .compteur { grid-area: compteur; width: 120px; margin: 0; align-self: center; }

@media (max-width: 479px) {
  .resultats .case-objet { grid-template-columns: 40px minmax(0, 1fr) auto; column-gap: var(--e8); }
  .resultats .case-image { width: 40px; height: 40px; }
}

/* La ligne « Ajouter « baby-foot » à ma liste », quand rien ne correspond. */
.resultats .case-objet.ligne-ajout-libre {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--e12);
  min-height: 56px;
  padding: var(--e12) var(--e16);
}

.resultats .ligne-ajout-libre .spm-icone { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
.resultats .ligne-ajout-libre .case-nom { align-self: center; color: var(--texte); }

@media (min-width: 768px) {
  .resultats .case-objet.ligne-ajout-libre { grid-column: 1 / -1; }
}

/* « Ajouter 3 × Chaise » : ce que fait la touche Entree, ecrit sur un bouton. */
.recherche-rapide { margin-bottom: var(--e16); }

/* ------------------------------------------------------ 10. Objets libres */

/* Le compteur emploie les pictogrammes de marque (.spm-icone), qui valent
   --icone-taille, soit 24 px. Dans un bouton de 40 px c'est trop : 16 px, la
   valeur que base.css donnait au pictogramme local. Avec l'interstice
   ci-dessous, ce sont les deux seules geometries du compteur qui ne soient pas
   deja dans la feuille de marque. */
.compteur-moins .spm-icone,
.compteur-plus .spm-icone {
  width: 16px;
  height: 16px;
  stroke-linecap: round;
}

/* L'INTERSTICE DU COMPTEUR — 8 px, ni plus ni moins.

   base.css §10 pose `grid-template-columns: 40px 1fr 40px` sans gouttiere :
   les trois pieces sont JOINTIVES, bord a bord. Mesure du 20.09 a 375 px,
   avant correction : button.compteur-moins [53, 165, 40, 40] finit a x=93 et
   input.compteur-valeur [93, 165, 41,5, 40] commence a x=93 — 0 px d'ecart.
   Le focus pose un anneau de 2 px double d'un contre-anneau blanc de 2 px,
   soit 4 px vers l'exterieur : l'anneau du champ repeignait donc 4 x 40 =
   160 px2 du bouton voisin, a chaque tabulation, sur chacune des lignes
   d'objet. Dix chevauchements par largeur au controle 7 du banc de mise en
   page, aux trois largeurs.

   8 px et pas moins : 4 px pour l'anneau du controle qui a le focus, 4 px
   pour celui du voisin quand c'est lui qui le prend. C'est le chiffre et la
   raison de `.planche { gap: var(--e16) }` quelques lignes plus haut, a
   l'echelle d'un controle et non d'une case.

   8 px et pas plus : le champ vit sur ce qui reste de la case. Mesure a
   375 px, la ou la case est la plus etroite (147,5 px de case, 121,5 px de
   compteur) : 8 px d'interstice laissent 25,5 px de champ, et « 99 » en
   mesure 19,2 en DIN Alternate 20 px, interlettrage compris. A 12 px il ne
   reste que 17,5 px et le nombre est ROGNE (scrollWidth 20 > 17,5). A 768 et
   1440 px le champ est plus large encore (38 et 35,6 px).

   minmax(0, 1fr) et non 1fr : la colonne du milieu doit pouvoir ceder les
   16 px sans que la taille minimale automatique de l'`<input>` s'y oppose.
   Mesure : Chrome rend la meme chose avec 1fr — le minimum explicite ne
   depend pas de cette bonne volonte-la, et aucun compteur ne deborde de sa
   case (debordement du document mesure a 0 px aux trois largeurs). */
.compteur {
  grid-template-columns: 40px minmax(0, 1fr) 40px;
  column-gap: var(--e8);
}

.objets-libres { margin-top: var(--e32); }

.objets-libres-titre { font-size: 18px; color: var(--texte); }

.objets-libres-liste { margin-top: var(--e16); padding-left: 0; list-style: none; }

.objet-libre {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: end;
  gap: var(--e12);
  padding: var(--e16) 0;
  border-top: var(--filet-epaisseur) solid var(--filet-fort);
}

.objet-libre .spm-groupe { margin: 0; min-width: 0; }
.objet-libre .compteur { width: 120px; margin-bottom: 2px; }

.objet-libre-note {
  grid-column: 1 / -1;
  max-width: none;
  font-family: var(--police-chiffre);
  font-size: 12px;
  letter-spacing: .03em;
  color: var(--texte-secondaire);
}

.objet-libre-retrait {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin-bottom: var(--e8);
  padding: 0;
  background: none;
  border: var(--filet-epaisseur) solid var(--filet);
  border-radius: var(--rayon);
  color: var(--texte-secondaire);
  cursor: pointer;
}

.objet-libre-retrait::after { content: ""; position: absolute; inset: -8px; }
.objet-libre-retrait:hover { border-color: var(--marque); color: var(--texte); }

.objet-libre-retrait .picto {
  width: var(--e16);
  height: var(--e16);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* F10 (lot 1) : le champ, le compteur et la croix restent sur UNE ligne,
   telephone compris. A 375 px : 311 - 120 - 28 - 2 x 8 = 147 px de champ.
   La croix (28 px visibles, 44 px au doigt par son ::after) se centre sur
   le champ de 48 px : 10 px de marge basse. */
.objet-libre .objet-libre-retrait { margin-bottom: 10px; }

@media (max-width: 480px) {
  .objet-libre { gap: var(--e8); }
}

/* ------------------------------------------------------------ 11. Photos */

.photos { margin-top: var(--e48); }
.photos-titre { color: var(--texte); }
.photos .depot { margin-top: var(--e16); }
.vignettes { margin-top: var(--e16); }
.photos-exemple { margin-top: var(--e12); }
.photos-vide { margin-top: var(--e24); }
.photos-mention { margin-top: var(--e12); }
.photos-mention + .photos-mention { margin-top: var(--e4); }

/* ---------------------------------------------------- 12. Case a cocher */

/* SECTION VIDEE au rhabillage. La case a cocher du site etait redessinee ici
   (appearance: none, contour vert, rayon de 2 px, coche tracee a la main).
   C'est desormais .spm-case de marque/components.css, qui pose la rangee, la
   taille du doigt et accent-color: var(--marque). Redessiner par-dessus
   creerait une seconde source pour une seule valeur, et --rayon vaut 0 : le
   rayon de 2 px etait de toute facon un defaut.
   Le numero de section est conserve pour que les renvois restent justes.
   Reste le seul reglage que la marque ne peut pas connaitre : l'espacement du
   consentement, qui suit un groupe de pastilles et non un champ. */
.case-consentement { margin-top: var(--e32); }

#nlpd { margin-top: var(--e8); }
/* 05.10 : l'envoi de la demande. L'etat « en cours » et l'alerte d'echec
   suivent le consentement ; l'alerte reprend .spm-alerte--erreur de la marque. */
.envoi-en-cours { margin-top: var(--e16); }
.envoi-echec { margin-top: var(--e24); }
.envoi-echec-actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--e8) var(--e16); margin-top: var(--e16);
}
.envoi-echec-appel .a-fournir { font-weight: 500; }

/* Le champ piege : hors ecran, jamais display:none (certains robots sautent
   les champs masques ainsi), hors tabulation par son tabindex. */
.champ-piege {
  position: absolute; left: -10000px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}

/* La surface, facultative : la mention suit l'etiquette, en plus discret. */
.etiquette-facultatif { font-weight: 400; color: var(--texte-secondaire); }
.champ-surface { max-width: 12rem; }

/* ------------------------------------------------- 13. Le recapitulatif */

/* Trois positions, une par largeur (§B.2). base.css ne fixe que la surface. */

/* Sous 768 px : replie dans la barre basse, ouvert au-dessus d'elle. */
@media (max-width: 767px) {
  .recap {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(84px + env(safe-area-inset-bottom, 0px));
    z-index: var(--z-bandeau);
    display: none;
    max-height: 60dvh;
    overflow-y: auto;
    padding: var(--e24) var(--gouttiere-calc-d) var(--e24) var(--gouttiere-calc-g);
    border-radius: 0;
    border-top: var(--filet-epaisseur) solid var(--filet-fort);
  }

  .recap[data-ouvert="1"] { display: block; }
}

/* De 768 a 1079 px : un bloc en fin de formulaire, pleine largeur. */
@media (min-width: 768px) {
  .recap { margin-top: var(--e64); }
}

/* A partir de 1080 px : colonne de droite, collante.

   UN ELEMENT COLLANT PLUS HAUT QUE LA FENETRE NE COLLE PAS. Mesure du 19.09,
   ordinateur 1440 x 900 : le panneau allait de y=152 a y=1214, soit 1 062 px
   dans une fenetre de 900. Une fois pince a top:72, ses 234 derniers pixels
   restaient sous le pli pour toujours : le montant se posait sur le bord bas
   de l'ecran et les quatre reserves du §B.2 n'etaient JAMAIS atteignables.
   D'ou un plafond de hauteur et un defilement propre au panneau. Le chiffre
   72 px est celui du collage ; --e24 laisse respirer le bas.
   overscroll-behavior: contain empeche le defilement du panneau, arrive en
   butee, d'emporter la page derriere lui.
   Le second geste est dans calculateur.html : les trois reserves qui ne
   changent pas d'un arret a l'autre passent sous un <details> ferme. */
@media (min-width: 1080px) {
  .recap {
    grid-column: 2;
    margin-top: 0;
    position: sticky;
    top: 72px;
    max-height: calc(100dvh - 72px - var(--e24));
    display: flex;
    flex-direction: column;
    overscroll-behavior: contain;
  }

  /* CE QUI DEFILE, C'EST LE CORPS, PAS LE PANNEAU ENTIER.
     Le titre reste en haut, le bloc de resultat reste en bas, et seules les
     lignes glissent entre les deux. `min-height: 0` est obligatoire : sans
     lui, un element de flex refuse de descendre sous la hauteur de son
     contenu et le plafond du panneau ne mord plus. */
  .recap-titre, .recap-total { flex: none; }

  .recap-corps {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* Le plafond de hauteur rend le panneau atteignable, il ne suffit pas a
     rendre le montant visible. Mesure du 19.09 apres les deux gestes de la
     critique, arrets 1 a 5 avec les donnees de demonstration : panneau 804 px
     de haut pour 990 px de contenu, montant a y=951, c'est-a-dire sous le bord
     bas du panneau. La critique le prevoyait sans le voir : elle annonce
     elle-meme « panneau a environ 942 px ferme », soit 138 px de plus que les
     804 px qu'elle vient de fixer. Deux gestes sur trois, donc.

     LE TROISIEME GESTE A D'ABORD ETE UN COLLAGE, ET LE COLLAGE MANGEAIT UNE
     LIGNE. Le bloc etait `position: sticky; bottom: -32px` dans un panneau qui
     defilait en entier, et la note annoncait que « les onze lignes defilent
     DESSOUS ». Au repos, elles y etaient DEJA. Mesure du 20.09, 1440 x 900,
     aux cinq arrets et sur les deux onglets d'inventaire, chiffres identiques
     partout : panneau 804 px pour 990 px de contenu, bloc epingle a y=848
     alors que sa place naturelle etait a y=987 — 138 px de lignes avalees,
     dont « Date » coupee en deux dans la hauteur et « Photos » entierement
     recouverte. Le visiteur n'avait aucune raison de deviner qu'un defilement
     les lui rendrait.
     Un `padding-bottom` sur `.recap-lignes` ne pouvait pas reparer ca : il
     repousse la place NATURELLE du bloc, jamais sa place EPINGLEE, qui reste
     au bas du cadre de defilement. Les memes lignes seraient restees dessous,
     avec en prime un trou blanc de la hauteur du bloc a fond de course.
     Ce qui repare, c'est de sortir le bloc de la zone qui defile : le panneau
     devient une colonne, `.recap-corps` prend le defilement, et le bloc de
     resultat est le pied de cette colonne. Il ne quitte pas la vue — c'etait
     l'intention, elle est tenue — et il ne recouvre plus rien, a aucun
     defilement. La barre de defilement du corps est, elle, l'affordance qui
     manquait : elle dit qu'il reste des lignes.
     Plus de fond ni de retrait a poser ici : le bloc n'est plus au-dessus de
     quoi que ce soit, et base.css §13 lui donne deja sa marge et son filet
     superieur. Le prix est ce qu'on vient chercher : il ne se merite pas au
     defilement. */
}

/* Ce que ce panneau rend n'est plus un montant : une phrase. Elle prend la
   place du chiffre de 32 px, et elle reste la reponse a la question que le
   visiteur se pose — meme quand la reponse est « pas ici ».
   28 px, et pas moins : la condensee noire ferme ses contre-poincons sous
   24 px et devient une tache (fondations.md §2.3). Au-dessus de ce plancher
   elle a le droit de parler, et c'est la voix de titrage de la marque.
   L'approche reste a zero : une condensee noire est deja serree. */
.recap-devis {
  margin-top: var(--e4);
  max-width: none;
  font-family: var(--police-titre);
  font-size: 28px;
  font-weight: var(--graisse-noire);
  line-height: 1.1;
  letter-spacing: var(--approche-h2);
  color: var(--texte);
}

/* Le tiret d'attente n'est pas un titre : il repasse en chiffre, a la taille
   du texte, dans l'encre secondaire. Rien n'y est affirme. */
.recap-devis[data-vide="1"] {
  font-family: var(--police-chiffre);
  font-size: var(--t-chiffre-petit);
  font-weight: var(--graisse-normale);
  color: var(--texte-secondaire);
}

/* L'emplacement du repere « a partir de ». Il est vide et masque tant que
   l'entreprise n'a pas donne de chiffre ; la regle existe pour que le jour ou
   quelqu'un retire le hidden, la ligne soit deja dessinee. */
.recap-repere {
  margin-top: var(--e4);
  max-width: none;
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
}

.recap-repere b {
  font-family: var(--police-chiffre);
  font-weight: var(--graisse-medium);
  color: var(--texte);
}

/* La phrase de portee : une seule des trois est visible. Elle explique ce que
   la zone change au devis, et elle ne crie pas — c'est une precision, pas une
   alerte, donc ni rouge ni filet. */
.recap-rappel {
  margin-top: var(--e8);
  max-width: none;
  font-size: var(--t-petit);
  line-height: var(--interligne-petit);
  color: var(--texte-secondaire);
}

/* Etat vide du panneau (§3.10, composant .etat-vide de base.css §14).
   Avant : le premier ecran du calculateur ouvrait sur « Estimation », un tiret
   isole, puis deux reserves sur un montant qui n'avait pas encore ete calcule.
   La page commencait par expliquer ce qu'un prix inexistant ne comprend pas.
   Les deux reserves reviennent avec le montant, la ou elles ont un sujet :
   c'est le script qui les redonne, aucune phrase nouvelle ailleurs. */
#recap-vide { margin-top: var(--e16); }

/* Le depli du perimetre. Un <summary>, rien d'autre : pas de fond, pas de
   cadre, pas de pictogramme, pas de fleche maison. Le triangle du navigateur
   est retire au profit du meme signe que le reste de la page, un chevron trace
   en deux traits, pour que l'objet ne detonne pas au milieu des notes.
   Le libelle est un peu plus clair que les notes : il les annonce, il n'en est
   pas une. Pas de transition : le contenu d'un <details> ne s'anime pas sans
   script, et personne n'attend qu'il le fasse. */
.recap-portee { margin-top: var(--e12); }

.recap-portee > summary {
  display: flex;
  align-items: center;
  gap: var(--e8);
  min-height: 32px;
  font-size: var(--t-petit);
  color: var(--texte-secondaire);
  cursor: pointer;
  list-style: none;
}

.recap-portee > summary::-webkit-details-marker { display: none; }

.recap-portee > summary::after {
  content: "";
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}

.recap-portee[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
.recap-portee > summary:hover { color: var(--texte); }

.recap-portee > summary:focus-visible { outline-offset: 2px; }

.recap-portee .recap-notes { margin-top: var(--e8); }

/* --------------------------------------------------- 14. La barre basse */

.arret-actions { margin-top: var(--e48); }

/* Sous 768 px : 8 de marge + 20 de bascule + 4 + 52 de bouton = 84 px. */
@media (max-width: 767px) {
  .arret-actions {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-bandeau);
    display: grid;
    grid-template-rows: 20px 52px;
    row-gap: var(--e4);
    margin-top: 0;
    height: calc(84px + env(safe-area-inset-bottom, 0px));
    padding: var(--e8) var(--gouttiere-calc-d) env(safe-area-inset-bottom, 0px) var(--gouttiere-calc-g);
    background: var(--fond);
    border-top: var(--filet-epaisseur) solid var(--filet-fort);
  }
}

/* Au-dela de 768 px la bascule n'a plus d'objet : le recapitulatif est dans la
   page, en bloc puis en colonne. Elle s'affichait pourtant.
   Le display: none ci-dessous etait ecrit `.recap-bascule`, soit 0,1,0, et la
   regle de base `.recap-bascule { display: flex }` qui la suit porte la meme
   specificite : declaree APRES, elle gagnait, et le none n'a jamais rien fait.
   Trois consequences mesurees le 19.09 sur 1440 :
     — le resultat du panneau ecrit deux fois au meme ecran, en bas a gauche
       et en gros dans le panneau de droite ;
     — un chevron orphelin sans libelle, a x=688 sur l'arret 1 ;
     — .recap-bascule porte width: 100% : devenue element flexible de la
       rangee, elle reclamait toute la largeur et comprimait le bouton
       principal a son minimum, 209 px a l'arret 1, 173 px a l'arret 5. Les
       cinq libelles passaient a deux lignes alors que la rangee avait 580 px
       de vide.
   Elle etait en outre inerte : elle bascule data-ouvert sur .recap, qui n'a
   display: none que sous 767 px. Un bouton visible, focalisable, qui annonce
   aria-expanded et ne fait rien.
   `.arret-actions .recap-bascule` vaut 0,2,0 et bat la regle de base.
   Le bouton principal reprend sa largeur naturelle et se cale a droite, sur
   la meme verticale que le titre et « Modifier ». */
@media (min-width: 768px) {
  .arret-actions { display: flex; align-items: center; gap: var(--e16); }
  .arret-actions .recap-bascule { display: none; }
  .arret-actions .spm-btn--primaire { flex: none; width: auto; margin-left: auto; }
}

.recap-bascule {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e8);
  width: 100%;
  /* 44 px de haut pour de vrai (audit mobile P1-9 : la boîte mesurait 20 px,
     et la zone de toucher n'existait que par un pseudo-élément). Les marges
     négatives rendent les 24 px ajoutés : la barre basse garde sa hauteur. */
  height: 44px;
  margin-block: -12px;
  padding: 0;
  background: none;
  border: 0;
  color: var(--texte-secondaire);
  font-family: var(--police-texte);
  font-size: var(--t-petit);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

/* La zone tactile est la boîte elle-même (44 px, ci-dessus) ; le
   pseudo-élément ne l'élargit plus que sur les côtés. */
.recap-bascule::after { content: ""; position: absolute; inset: 0 -8px; }

.recap-bascule .picto {
  flex: none;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform var(--duree-courte) var(--entree);
}

.recap-bascule[aria-expanded="true"] .picto { transform: rotate(180deg); }

/* ------------------------------------------------- 15. Mouvement reduit */

/* base.css §16 replie le rail. Ce qui suit replie ce que cette feuille
   ajoute : mediane-affinage.md §4 regle 3, toute retouche porte son repli. */
@media (prefers-reduced-motion: reduce) {
  .onglets-suite { transition: none; }
  .recap-bascule .picto { transition: none; }
}

/* En-tête d'une seule ligne sur téléphone (audit mobile 21.09, P1-8) : « Retour
   à l'accueil » ne tenait pas à côté du logo (200 px, minimum écran de la
   marque, et sa zone de protection) et passait à la ligne : 160 px d'en-tête,
   45 % de l'écran à l'arrivée avec le rail et la barre basse. Le libellé reste
   le même, en corps de texte petit, sur deux lignes à droite du logo. La zone
   de protection du logo est son propre padding : l'écart de la rangée passe à
   0 sans que rien n'y entre.
   À partir de 360 px seulement : en dessous (iPhone SE de 1re génération,
   320 px), logo 224 px + libellé 71 px dépassent la colonne de 264 px ; la
   rangée repasse à la ligne comme avant, sans débordement. */
@media (min-width: 360px) and (max-width: 599px) {
  .spm-entete .entete-corps { flex-wrap: nowrap; column-gap: 0; }
  /* Le logo ne rétrécit JAMAIS sous ses 200 px (minimum écran de la marque) :
     relevé à 375 px sans cette ligne, le flex le ramenait à 190 px. C'est le
     bouton qui cède, jusqu'à la largeur de « l'accueil ». */
  .spm-entete .spm-entete__logo { flex-shrink: 0; }
  .spm-entete .entete-corps > .spm-btn {
    min-height: 44px;
    max-width: 7.5em;
    padding: var(--e4) var(--e8);
    font-size: var(--t-petit);
    line-height: 1.15;
    white-space: normal;
  }
}

/* ------------------------------------ 15. Lot 1 : telephone, garantie, photos */

/* LE TELEPHONE ET SON INDICATIF. Un selecteur, puis le numero, sur une ligne.
   Le selecteur est un .spm-champ comme les autres (filet, hauteur 48 px,
   aucun rayon) ; le triangle natif est retire au profit du chevron de la
   marque, retourne. 9,5em tiennent « +423 Liechtenstein » ferme sur « +41
   Suisse » sans le couper ; a 375 px il reste 157 px au numero, qui en
   demande 115 pour « 079 123 45 67 ». */
.telephone-ligne {
  display: flex;
  align-items: stretch;
  gap: var(--e8);
  max-width: var(--mesure-etroite);
}

.indicatif-cadre { position: relative; flex: none; width: 9.5em; }

.arret select.indicatif {
  width: 100%;
  max-width: none;
  padding-right: calc(var(--e12) + 16px + var(--e8));
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.indicatif-chevron {
  position: absolute;
  right: var(--e12);
  top: 50%;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--texte-secondaire);
  pointer-events: none;
  transform: rotate(180deg);
}

.telephone-ligne input[type="tel"] { flex: 1 1 auto; min-width: 0; max-width: none; }

/* « Nous vous appellerons au +33 6 12 34 56 78. » : la coche n'apparait que
   la ou le controle est reel, apres la sortie du champ. */
.telephone-confirme {
  display: flex;
  align-items: flex-start;
  gap: var(--e8);
  max-width: var(--mesure);
  margin-top: var(--e8);
  font-size: var(--t-petit);
  line-height: var(--interligne-petit);
  color: var(--texte);
}

.telephone-confirme .spm-icone { margin-top: .15em; }

/* La garantie de remise : une phrase, et le texte d'origine replie. Le meme
   chevron trace en deux traits que le depli du recapitulatif. */
.garantie { margin-top: var(--e4); }

.garantie > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--e8);
  min-height: 44px;
  font-size: var(--t-petit);
  color: var(--texte);
  text-decoration: underline;
  text-underline-offset: .22em;
  cursor: pointer;
  list-style: none;
}

.garantie > summary::-webkit-details-marker { display: none; }

.garantie > summary::after {
  content: "";
  width: 7px;
  height: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}

.garantie[open] > summary::after { transform: translateY(1px) rotate(-135deg); }
.garantie > summary:focus-visible { outline-offset: 2px; }
.garantie > .spm-aide { margin-top: var(--e4); max-width: var(--mesure); }

/* « Déposez vos photos ici » ne parle qu'a une souris. Au doigt, il reste le
   seul bouton, « Ajouter des photos ». */
@media (hover: none) and (pointer: coarse) {
  .depot .depot-souris { display: none; }
}

/* ------------------------------------------------- 16. Le camion qui se remplit

   28.09.2026 : tetris-v3, concept 2 (le camion en volume) avec l'envol du
   concept 1. Repris de references/calculateur-idees/tetris-v3/commun/page.css
   et v3.css, bornes a .chargement : aucune de ces classes ne sort du dessin.
   Le camion au trait fin, blanc ; les objets en silhouettes pleines, noires
   au premier rang, grises au fond ; l'epaisseur de chaque silhouette suit la
   fuyante 1:2 de la marque par des ombres pleines, sans flou. Sous le
   camion, la ligne de la marque sert de jauge : rouge sur la part chargee.
   Aucune ombre portee de boite, rayon zero. */
/* Rangs : noir devant, gris au fond. Le rang du fond reste a 3,4:1 sur blanc
   (#8F8B86) : ses fentes blanches et ses traits se lisent encore (WCAG 1.4.11). */
.chargement { position: relative; --rang-1: #56524D; --rang-2: #8F8B86; color: var(--texte); }
.chargement .vt-scene { position: relative; height: var(--scene-h, 188px); }
.chargement .vt-flotte { position: absolute; inset: 4px 0 40px; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; gap: 18px; }
.chargement .vt-flotte--ligne { flex-direction: row; align-items: flex-end; justify-content: center; }
.chargement .vt-vehicule { position: relative; margin: 0; flex: none; }
.chargement .vt-dessin { position: absolute; inset: 0; width: 100%; height: 100%; display: block; overflow: visible; }
.chargement .vt-devant { pointer-events: none; }
.chargement .vt-legende { position: absolute; top: 100%; left: 0; right: 0; margin-top: 22px; color: var(--texte-secondaire);
  font-size: var(--t-micro); line-height: 1.3; text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Illustration « S4 » (29.09.2026) : le vehicule est une image (fond blanc,
   fondu dans la surface par multiply), recadree par .vt-cadre ; les objets
   poses sont les images en couleur de la liste, detourees, dans leur rang
   (le fond d'abord). */
.chargement .vt-cadre { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.chargement .vt-image { position: absolute; display: block; max-width: none; mix-blend-mode: multiply; user-select: none; }
.chargement .vt-interieur { position: absolute; inset: 0; pointer-events: none; }
/* Le plan de chargement (rendu-plan.js, 30.09) : un SVG cale exactement sur
   l'image du vehicule ; chaque objet est un <g class="rp-objet"> portant sa
   place du moteur en data-*. */
.chargement .vt-plan { position: absolute; display: block; max-width: none; overflow: hidden; pointer-events: none; }
.chargement .rp-objet { transform-box: view-box; }
/* Bandeau etroit (< 600 px) : cadre recadre sur la caisse ; l'image du
   vehicule deborde du cadre a gauche (coupee par .vt-cadre) : chargement.js
   pose une marge de la taille de ce debordement (padding-left). */
.chargement .vt-flotte.vt-flotte--recadre { box-sizing: border-box; }
/* Voie « d'apres le logement » : un volume sans objets connus. Hachures a la
   pente 1:2 de la marque, jamais des meubles inventes. */
.chargement .vt-bloc { position: absolute; inset: 0; width: 100%; height: 100%; display: block; overflow: visible; }
.chargement .vt-bloc-dessus { fill: var(--surface-enfoncee); fill-opacity: .9; stroke: var(--texte-faible); stroke-width: 1; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.chargement .vt-bloc-face { fill: var(--surface-enfoncee); fill-opacity: .96; stroke: var(--texte-faible); stroke-width: 1; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.chargement .vt-bloc-trait { fill: var(--neutre-300); }
/* Jhonno 05.10 : plus de jauge ni de pourcentage. .vt-jauge n'est plus
   qu'une ligne d'ancrage, sans trait, à la place de l'ancienne barre : elle
   porte « 17,7 m³ » (les m³ chargés dans CE véhicule), calé à droite, à la
   hauteur où se lisait le pourcentage. Écrit en --texte. */
.chargement .vt-jauge { position: absolute; height: 0; pointer-events: none; }
/* 05.10 soir (DA, m3-colle) : collé sous SES roues (la figure s'arrête sous
   elles, la ligne est 4 px plus bas) ; corps de texte (16-17 px) au lieu du
   micro (13 px) : il se lit à côté d'un dessin de 320 px. */
.chargement .vt-m3 { position: absolute; right: 0; top: 0; padding: 0;
  color: var(--texte); font: 700 var(--t-texte)/1.25 var(--police-chiffre); font-variant-numeric: tabular-nums; white-space: nowrap; }
.chargement .vt-jauge--vide .vt-m3 { display: none; }
/* Décision 1 (01.10) : « On a réorganisé le camion… », 3 s, une ligne */
.chargement .vt-reorg { position: absolute; left: 50%; top: 0; transform: translateX(-50%); z-index: 3; margin: 0;
  max-width: 100%; padding: 4px 10px; border-radius: 999px; background: var(--fond, #fff); color: var(--texte);
  box-shadow: 0 1px 4px rgba(0,0,0,.14); font-size: var(--t-micro); line-height: 1.35; white-space: nowrap; overflow: hidden; pointer-events: none; }
.bandeau-chargement .vt-reorg--bandeau { position: absolute; left: 8px; right: 8px; bottom: calc(100% + 6px); box-shadow: 0 1px 4px rgba(0,0,0,.14); z-index: 3; margin: 0; padding: 2px 8px; border-radius: 999px;
  background: var(--fond, #fff); color: var(--texte); font-size: var(--t-micro); line-height: 1.35; white-space: nowrap; overflow: hidden; text-align: center; pointer-events: none; }
/* L'envol : l'image de la case, au-dessus de tout, jamais sous le doigt.
   R1 (DA 30.09) : OPAQUE — l'image est détourée (fond transparent) ; le
   multiply la rendait brune et translucide sur la carrosserie sombre. */
.vt-envol { position: fixed; z-index: 20; pointer-events: none; transform-origin: 50% 50%; will-change: transform;
  opacity: 1; mix-blend-mode: normal; }
.vt-envol img { display: block; width: 100%; height: 100%; object-fit: contain; mix-blend-mode: normal; opacity: 1; }

/* Le recapitulatif, a partir de 1080 px : la scene va d'un bord a l'autre du
   panneau (340 px), hors du corps qui defile. */
.recap-chargement { margin: var(--e8) calc(-1 * var(--e24)) calc(-1 * var(--e8)); }
@media (min-width: 768px) { .recap-chargement { margin-inline: calc(-1 * var(--e32) + var(--e8)); } }
/* La legende du dessin se tait ici : la ligne « Vehicules », juste dessous,
   nomme deja le palier, et chaque pixel rendu au corps du panneau est une
   ligne de recapitulatif de plus a l'ecran. Les m³ restent sous le vehicule. */
/* N3 (DA 30.09, 5.9) : a 1440 les vehicules faisaient ~150 px de large (un
   metre de meuble = 16 px) : noms et vignettes illisibles. La figure prend
   la largeur du recapitulatif, les deux vehicules l'un sous l'autre. */
/* B5 (01.10) : la ligne « N,N m³ » est SOUS la figure : la scène lui garde
   36 px en pied (comme sous 600 px). */
.recap-chargement .chargement { --scene-h: 290px; }
.recap-chargement .chargement[data-vehicules="2"] { --scene-h: 620px; }
.recap-chargement .vt-flotte { inset: 0 0 36px; }
.recap-chargement .vt-legende { display: none; }
@media (min-width: 600px) and (max-width: 1079px) { .recap-chargement { display: none; } }
/* R6 (DA 30.09) : sous 600 px, le dessin est ICI, pleine largeur (~358 px),
   recadré sur la caisse ; le bandeau ne garde que le texte et le bouton. */
@media (max-width: 599px) {
  .recap-chargement { margin-inline: 0; }
  .recap-chargement .chargement { --scene-h: 316px; }
  .recap-chargement .chargement[data-vehicules="2"] { --scene-h: 640px; }
  .recap-chargement .vt-flotte { inset: 0 0 36px; }
}
/* R4 : ce que le moteur n'a pas pu poser, dit sous la figure */
.chargement .vt-restants { margin: var(--e8) 0 0; color: var(--texte); font-size: var(--t-micro); line-height: 1.35; text-align: center; }
/* R4 (DA 30.09) : sous la ligne « N,N m³ » du vehicule concerne, a 1440 comme a 390 */
.chargement .vt-debord { position: absolute; left: 0; right: 0; margin: 0; color: var(--marque-texte, #B51F14);
  font: 600 var(--t-micro)/1.3 var(--police-texte); text-align: right; white-space: normal;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.bandeau-chargement .vt-debord { display: none; }
/* la place des deux lignes, sous la scene */
.chargement[data-debord] { margin-bottom: 40px; }
.bandeau-chargement .chargement[data-debord] { margin-bottom: 0; }
/* D1 (DA 30.09, 5.9) : la place des deux lignes s'AJOUTE a la scene (les
   vehicules ne rapetissent pas) ; chargement.js pose la marge basse exacte
   du vehicule concerne : en colonne, le suivant descend d'autant */
.chargement[data-debord] .vt-scene { height: calc(var(--scene-h, 188px) + 44px); }
.bandeau-chargement .chargement[data-debord] .vt-scene { height: var(--scene-h, 88px); }

/* Le bandeau, sous 1080 px : colle au bas de la fenetre, au-dessus de la
   barre basse sur telephone. Il ne vit qu'a l'arret 2. */
.bandeau-chargement { display: none; }
.bandeau-chargement-voir { display: none; }
@media (max-width: 1079px) {
  .bandeau-chargement:not([hidden]) {
    position: sticky;
    bottom: 0;
    z-index: var(--z-bandeau);
    display: grid;
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
    align-items: center;
    column-gap: var(--e16);
    margin: var(--e32) calc(-1 * var(--gouttiere-calc-d)) 0 calc(-1 * var(--gouttiere-calc-g));
    padding: var(--e8) var(--gouttiere-calc-d) var(--e8) var(--gouttiere-calc-g);
    background: var(--surface);
    border-top: var(--filet-epaisseur) solid var(--filet);
  }
  .bandeau-chargement .chargement { --scene-h: 88px; }
  .bandeau-chargement .vt-flotte { inset: 2px 0 6px; align-items: flex-start; }
  .bandeau-chargement .vt-legende, .bandeau-chargement .vt-m3 { display: none; }
  .bandeau-chargement-texte { margin: 0; display: flex; flex-direction: column; gap: 2px; }
  .bandeau-chargement-taux { font: 700 var(--t-texte)/1.25 var(--police-texte); color: var(--texte); font-variant-numeric: tabular-nums; }
  .bandeau-chargement-vehicule { font-size: var(--t-micro); line-height: 1.35; color: var(--texte-secondaire); }
}
@media (max-width: 767px) {
  .bandeau-chargement:not([hidden]) {
    bottom: calc(84px + env(safe-area-inset-bottom, 0px));
    grid-template-columns: minmax(0, 1fr) minmax(0, 9.5rem);
    column-gap: var(--e12);
  }
  .bandeau-chargement .chargement { --scene-h: 72px; }
}
/* R6/R7 : sous 600 px, le texte sur une ligne, et le bouton qui ouvre le
   dessin pleine largeur dans le récapitulatif. */
@media (max-width: 599px) {
  .bandeau-chargement:not([hidden]) { grid-template-columns: minmax(0, 1fr) auto; row-gap: 6px; }
  .bandeau-chargement-scene { display: none; }
  .bandeau-chargement-texte { grid-column: 1; grid-row: 1; }
  .bandeau-chargement-vehicule { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .bandeau-chargement-voir { display: inline-flex; align-items: center; grid-column: 2; grid-row: 1 / span 2; min-height: 44px; padding: 0 var(--e12);
    border: var(--filet-epaisseur) solid var(--filet-fort); border-radius: 999px; background: var(--surface); color: var(--texte);
    font: 600 var(--t-micro)/1.2 var(--police-texte); cursor: pointer; }
}

/* Le clavier ne pose pas un controle SOUS le bandeau : la zone lisible du
   document s'arrete au-dessus de lui (meme doctrine que la barre basse, en
   haut de cette feuille). 90 px = 8 + 72 + 8 + 1 de filet, arrondi ;
   106 px = 8 + 88 + 8 + 1 entre 768 et 1079 px. */
@media (max-width: 767px) {
  html:has(#bandeau-chargement:not([hidden])) {
    scroll-padding-bottom: calc(84px + 90px + env(safe-area-inset-bottom, 0px) + var(--e16));
  }
}
@media (min-width: 768px) and (max-width: 1079px) {
  html:has(#bandeau-chargement:not([hidden])) { scroll-padding-bottom: calc(106px + var(--e16)); }
}


/* B4 (01.10) : au-delà de 42 m³, le dessin est un EXEMPLE. Titre et mention
   au-dessus ; vignettes de même largeur en rangées ; chaque véhicule posé sur
   une ligne de sol grise qui s'arrête à lui ; son nom dessous, aligné avec ses
   voisins de rangée ; aucun chiffre. */
.chargement .vt-exemple { margin: 0 0 var(--e12); display: flex; flex-direction: column; gap: 2px; text-align: center; }
.chargement .vt-exemple-titre { font: 700 var(--t-texte)/1.3 var(--police-texte); color: var(--texte); }
.chargement .vt-exemple-note { font-size: var(--t-micro); line-height: 1.35; color: var(--texte-secondaire); }
.bandeau-chargement .vt-exemple { display: none; }
.chargement .vt-flotte--exemple { flex-direction: row; flex-wrap: wrap; align-items: flex-end; align-content: flex-start; justify-content: center; }
.chargement .vt-flotte--exemple .vt-jauge { display: none; }
.chargement .vt-flotte--exemple .vt-vehicule::after { content: ""; position: absolute; left: 2%; right: 2%; top: 100%; height: 1px; background: var(--neutre-300); }
.recap-chargement .vt-flotte--exemple .vt-legende,
.chargement .vt-flotte--exemple .vt-legende { display: block; margin-top: 10px; color: var(--texte); font-weight: 600; }
.bandeau-chargement .vt-flotte--exemple .vt-legende { display: none; }
.bandeau-chargement .vt-flotte--exemple .vt-vehicule::after { display: none; }
/* B3 (01.10) : sous 600 px, le texte du bandeau a toute la largeur (rangée 1),
   le bouton dessous (rangée 2), aligné à gauche sous le texte (05.10 : plus
   de jauge à côté de lui, aucun trou) : « Camion : 17,7 m³ · Fourgon : 4,1 m³ »
   tient sur une ligne, « Plusieurs véhicules, confirmés après la visite » entier. */
@media (max-width: 599px) {
  .bandeau-chargement-texte { grid-column: 1 / -1; grid-row: 1; }
  .bandeau-chargement-taux { white-space: nowrap; }
  .bandeau-chargement-vehicule { text-overflow: clip; }
  .bandeau-chargement-voir { grid-column: 1 / -1; grid-row: 2; justify-self: start; min-height: 44px; }
}
/* B3 : au repos, tant que l'intitulé « Chercher un objet » est dans la zone du
   bandeau collant, le bandeau s'efface (calculateur.js) ; il revient dès que
   l'intitulé est passé au-dessus. Aucune place gagnée ni perdue : visibilité. */
.bandeau-chargement.bandeau-chargement--efface { visibility: hidden; opacity: 0; }
.bandeau-chargement { transition: opacity 160ms cubic-bezier(.2,0,0,1), visibility 0s linear 0s; }
.bandeau-chargement.bandeau-chargement--efface { transition: opacity 160ms cubic-bezier(.4,0,1,1), visibility 0s linear 160ms; }
@media (prefers-reduced-motion: reduce) { .bandeau-chargement, .bandeau-chargement.bandeau-chargement--efface { transition: none; } }

/* =====================================================================
   LOT 4 (06.10.2026) — LA BANDE 3D DU CHARGEMENT (version A, maquette
   v10-lot0/A/page.css). Au-dessus des cartes de l'arrêt 2, collée en haut
   pendant qu'on liste : ≈ 860 × 300 à 1440, 180 px pleine largeur sous
   600 px. Le récapitulatif et le bandeau ne portent plus de dessin.
   ===================================================================== */
.bande3d { position: sticky; top: 0; z-index: 6; height: 300px; margin: 14px 0 18px; background: var(--surface, #F7F6F4); overflow: hidden; }
.bande3d-scene { position: absolute; inset: 0; }
.bande3d-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.b3-etq { opacity: 0; position: absolute; white-space: nowrap; pointer-events: none; transition: opacity 160ms linear; font-family: var(--police-texte); font-size: 13px; color: var(--texte-doux, #5b5955); line-height: 1; }
.b3-etq .b3-m3 { font-family: var(--police-chiffre); font-variant-numeric: tabular-nums; font-size: 22px; color: var(--texte, #161514); margin-left: 4px; letter-spacing: 0; }
.b3-phrase { position: absolute; margin: 0; padding: 0 0 0 8px; border-left: 2px solid #DA291C; font-family: var(--police-texte); font-size: 12px; line-height: 16px; color: var(--texte, #161514); white-space: normal; transform: translateY(30px); opacity: 0; transition: opacity 120ms linear; pointer-events: none; }
.b3-phrase.vu { opacity: 1; }
.b3-phrase span { display: block; }
.case-objet { position: relative; transition: background-color 120ms linear, box-shadow 120ms linear; }
.case-objet.b3-carte-active { outline: 3px solid #DA291C; outline-offset: 2px; background-color: #FBE3E0; box-shadow: 0 10px 22px rgba(218, 41, 28, .28); }
/* la pastille : DANS la case (la maquette la posait à −11 px, coupée par le rabat .est-comptee::after, clip-path 16 × 8) */
.case-objet.b3-carte-active::after { content: attr(data-b3-dest); position: absolute; top: 6px; right: 6px; width: auto; height: auto; clip-path: none; padding: 3px 7px; background: #DA291C; color: #fff; font: 600 11px/1.1 var(--police-texte); border-radius: 2px; z-index: 1; white-space: nowrap; }
.b3-vignette { display: block; object-fit: contain; background: #fff; border: 2px solid #DA291C; border-radius: 4px; box-shadow: 0 6px 16px rgba(22, 21, 20, .25); }
/* repli sans WebGL : les mêmes chiffres, en texte */
.bande3d.sans-webgl { height: auto; min-height: 72px; display: flex; align-items: center; }
.bande3d.sans-webgl .bande3d-scene { position: static; width: 100%; }
.b3-repli { padding: 14px 16px; }
.b3-repli p { margin: 0; }
.b3-repli-flotte { font-family: var(--police-chiffre); font-variant-numeric: tabular-nums; font-size: 20px; color: var(--texte, #161514); }
.b3-repli-phrase { margin-top: 4px !important; font-size: 13px; color: var(--texte-doux, #5b5955); }
.b3-repli-phrase:empty { display: none; }
/* l'ancien dessin (récapitulatif, bandeau) n'existe plus */
#recap-chargement, #bandeau-chargement { display: none !important; }
@media (max-width: 599px) {
  .bande3d { height: 196px; margin: 8px 0 4px; border-bottom: 1px solid var(--trait, #E4E1DC); }   /* pleine largeur : chargement.js (caler) ; correction critique : 196 px (≤ 200) et un filet (charte : aucune ombre portée), le champ de recherche ne « dépasse » plus sous la bande */
  .bande3d.sans-webgl { height: auto; }
  .b3-etq { font-size: 11px; } .b3-etq .b3-m3 { font-size: 16px; margin-left: 3px; }
  .b3-phrase { font-size: 13px; line-height: 16px; padding-left: 6px; white-space: normal; max-width: none; transform: none; left: 16px !important; right: 16px; top: 6px !important; }
  .b3-phrase .b3-detail { display: block; color: var(--texte-doux, #5b5955); }   /* la 2e ligne (ce qui part au fourgon) reste à 390 */
  #bande3d + .arret-resume { flex-wrap: nowrap; align-items: center; margin-top: 6px; }   /* « Modifier » sur la ligne de l'adresse */
  #bande3d + .arret-resume .arret-resume-texte { flex: 1 1 auto; }
  #bande3d + .arret-resume .spm-btn { order: 2; margin-left: 0; flex: none; }
}
@media (prefers-reduced-motion: reduce) { .b3-etq, .b3-phrase, .case-objet { transition: none; } }
