/* ma-boite-a-livres — feuille unique, mobile d'abord, budget 3G.
   Direction : fiche de bibliothèque. Papier froid, encre violette d'école
   (le violet des tampons et des porte-plumes), dates en "tampon dateur"
   monospace. Aucune police web : pile système. */

:root {
  --papier:   #FCFBF8;
  --encre:    #221E33;
  --encre-2:  #6B6577;
  --tampon:   #5A3FA0;   /* encre violette d'école */
  --tampon-f: #47327F;
  --regle:    #E4E1D8;   /* hairlines, comme les lignes d'une fiche */
  --estompe:  #8B8677;
  --alerte:   #8A5A1F;
  --valide:   #2E7D46;   /* checks verts de l'encadré « gains » (23/08/2026) */
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--papier);
  color: var(--encre);
  font: 17px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

main { max-width: 640px; margin: 0 auto; padding: 0 20px 40px; }

/* ---- entête / pied ---- */
.entete {
  max-width: 640px; margin: 0 auto; padding: 14px 20px;
  border-bottom: 1px solid var(--regle);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
/* Une seule ligne : les noms de boîte longs s'élident (22/08/2026). */
.entete-texte { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.entete-icones { flex-shrink: 0; display: flex; gap: 10px; }
.entete-icone img { width: 28px; height: auto; display: block; }
.entete-icone-login img { width: 23px; }   /* login seul en 23 px (Leo 23/08) */
/* Pastille rouge : nouveaux messages dans la discussion (23/08/2026). */
.entete-icone-nonlu { position: relative; }
.entete-icone-nonlu::after {
  content: ''; position: absolute; top: -2px; right: -3px;
  width: 9px; height: 9px; border-radius: 50%;
  background: #C63A2F; border: 1.5px solid var(--papier);
}
/* Guide « ajouter à l'écran d'accueil » (Leo 11/09/2026) : <details> dans
   l'en-tête, summary = pictogramme (SVG en currentColor), panneau en popup
   CSS pure — même mécanique que les popups « gains ». Toujours cibler
   `> summary` : un summary descendant du panneau n'est pas concerné. */
.installer > summary.installer-apercu {
  list-style: none; cursor: pointer; display: block; color: var(--encre);
}
.installer > summary.installer-apercu::-webkit-details-marker { display: none; }
.ico-installer { width: 28px; height: 28px; display: block; }
.installer[open]::before {
  content: ''; position: fixed; inset: 0;
  background: rgba(20, 17, 30, 0.55); z-index: 40;
}
.installer[open] > summary.installer-apercu { position: relative; z-index: 41; }
.installer-popup {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 41; width: min(92vw, 420px); max-height: 86vh; overflow-y: auto;
  background: var(--papier); border: 1px solid var(--regle); border-radius: 6px;
  padding: 18px; box-shadow: 0 8px 40px rgba(20, 17, 30, 0.35);
  white-space: normal; text-align: left; font-weight: 400;
}
.installer-popup h3 { margin: 0 0 8px; padding-right: 36px; font-size: 18px; }
.installer-popup p { margin: 0 0 14px; font-size: 15px; }
.installer-plateforme + .installer-plateforme { border-top: 1px solid var(--regle); margin-top: 12px; padding-top: 12px; }
.installer-plateforme h4 { margin: 0 0 6px; font-size: 16px; }
.installer-appareil { color: var(--tampon); font-weight: 400; font-size: 14px; }
.installer-etapes { margin: 0; padding-left: 22px; font-size: 15px; }
.installer-etapes li + li { margin-top: 4px; }
/* Bandeau « installer » (Leo 12/09/2026) : sous l'en-tête, rendu hidden
   par le serveur et révélé par boite.js selon l'appareil. Boutons compacts
   (le .bouton par défaut est pleine largeur). */
.installer-bandeau {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 12px 0 0; padding: 10px 12px;
  border: 1px solid var(--tampon); border-radius: 6px; background: #fff;
}
.installer-bandeau-ico { flex-shrink: 0; display: block; }
.installer-bandeau-ico .ico-installer { width: 34px; height: 34px; }
.installer-bandeau-texte { flex: 1 1 180px; min-width: 0; font-size: 15px; line-height: 1.35; }
.installer-bandeau-boutons { display: flex; gap: 8px; margin-left: auto; }
.installer-bandeau .bouton { width: auto; padding: 8px 14px; font-size: 15px; white-space: nowrap; }
.installer-guide-bouton { margin-top: 12px; }
/* `.bouton` pose display:block, qui l'emporte sur l'attribut hidden du
   navigateur : le bouton « Installer » ne doit exister que quand boite.js
   le révèle (événement Chrome), jamais sur iPhone. */
.installer-action[hidden], .installer-bandeau[hidden] { display: none; }
.marque {
  color: var(--encre); text-decoration: none;
  font-weight: 800; letter-spacing: -0.02em; font-size: 17px;
}
.pied {
  max-width: 640px; margin: 24px auto 0; padding: 16px 20px 32px;
  border-top: 1px solid var(--regle);
  display: flex; gap: 18px; flex-wrap: wrap;
}
.pied a { color: var(--encre-2); font-size: 14px; text-decoration: none; }
.pied a:hover { color: var(--tampon); }

/* ---- page boîte ---- */
h1 {
  font-size: 30px; line-height: 1.15; font-weight: 800;
  letter-spacing: -0.02em; margin: 26px 0 2px;
}
.commune { margin: 0 0 14px; color: var(--encre-2); font-size: 16px; }

h2 {
  font-size: 13px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--encre-2); margin: 30px 0 10px;
}

/* Le tampon dateur : la signature de la page. Jamais « présent »,
   toujours une date d'observation, encrée comme au guichet. */
.tampon {
  display: inline-block;
  font-family: var(--mono); font-size: 14px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--tampon); border: 2px solid var(--tampon);
  border-radius: 3px; padding: 4px 10px; margin: 2px 0 6px;
}
.tampon-perimee, .tampon-jamais { color: var(--estompe); border-color: var(--estompe); }

.flash {
  border-left: 3px solid var(--tampon);
  padding: 8px 12px; margin: 14px 0; font-size: 15px;
  background: #F3F0FA;
}

.photo-etagere { margin: 18px 0 0; }
.photo-etagere img {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--regle); border-radius: 4px;
}

/* ---- inventaire : les lignes de la fiche ---- */
.items { list-style: none; margin: 0; padding: 0; }
.item {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; padding: 12px 0;
  border-bottom: 1px solid var(--regle);
}
.item-texte { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.item-titre { font-weight: 600; }
.item-auteur { color: var(--encre-2); font-size: 15px; }
.item-type {
  font-size: 12px; color: var(--encre-2); text-transform: uppercase;
  letter-spacing: 0.06em;
}
.item-vu { font-family: var(--mono); font-size: 12.5px; color: var(--tampon); margin-top: 3px; }

.item-grise .item-titre, .item-grise .item-auteur { color: var(--estompe); }
.item-grise .item-vu { color: var(--estompe); }

.item-apercu { color: var(--encre); text-decoration: underline dotted; text-underline-offset: 3px; }
.item-apercu:hover { color: var(--tampon); }
.carrousel-photo figcaption a { text-decoration: underline dotted; text-underline-offset: 2px; }
.deja-inscrit { text-align: left; }
.deja-inscrit a { color: var(--tampon); }
.connexion { margin-top: 20px; }
.connexion summary { display: inline; }
.connexion .form-email { margin-top: 10px; max-width: 420px; }
.item-couverture {
  flex-shrink: 0; height: 64px; width: auto; align-self: center;
  border: 1px solid var(--regle); border-radius: 3px;
}
.item-actions { flex-shrink: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.item-prise summary { list-style: none; }
.item-prise summary::-webkit-details-marker { display: none; }
.prise-choix { display: flex; flex-direction: column; align-items: flex-end; }
.lien-discret {
  background: none; border: none; padding: 6px 0; cursor: pointer;
  color: var(--encre-2); font-size: 13px; text-decoration: underline;
  text-underline-offset: 2px; font-family: inherit;
}
.lien-discret:hover { color: var(--tampon); }

/* Chevron uniforme des dépliants texte (22/08/2026) : marqueur natif masqué,
   ▸ dessiné qui pivote à l'ouverture. Les summaries-boutons restent nus. */
summary.lien-discret { list-style: none; }
summary.lien-discret::-webkit-details-marker { display: none; }
summary.lien-discret::before, .pourquoi > summary::before { content: '▸ '; }
details[open] > summary.lien-discret::before,
.pourquoi[open] > summary::before { content: '▾ '; }

.vide { color: var(--encre-2); }

/* ---- actions ---- */
.actions { margin-top: 26px; }

.bouton {
  display: block; width: 100%; text-align: center;
  padding: 15px 16px; border-radius: 4px; border: 1.5px solid var(--encre);
  background: transparent; color: var(--encre);
  font: 600 17px/1.2 system-ui, sans-serif;
  text-decoration: none; cursor: pointer;
}
.bouton-primaire { background: var(--tampon); border-color: var(--tampon); color: #fff; }
.bouton-primaire:hover, .bouton-primaire:focus { background: var(--tampon-f); border-color: var(--tampon-f); }
.sous-action { margin: 8px 0 0; font-size: 14px; color: var(--encre-2); text-align: center; }

.form-email label {
  display: block; font-size: 13px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--encre-2); margin-bottom: 6px;
}
.form-email input {
  display: block; width: 100%; padding: 13px 12px; margin-bottom: 10px;
  font: 17px/1.2 system-ui, sans-serif;
  border: 1.5px solid var(--regle); border-radius: 4px;
  background: #fff; color: var(--encre);
}
.form-email input:focus { outline: 2px solid var(--tampon); outline-offset: 1px; border-color: var(--tampon); }
/* Radios et checkbox : exemptées du bloc pleine largeur ci-dessus (Leo
   31/08/2026) — étirées à 100 %, la coche se dessinait seule, CENTRÉE sur sa
   ligne, séparée de son libellé. Ici elles restent en ligne avec le texte. */
.form-email input[type="radio"], .form-email input[type="checkbox"] {
  display: inline-block; width: auto; margin: 0 6px 0 0; vertical-align: -1px;
}

.repli { margin-top: 18px; }
.repli summary { cursor: pointer; color: var(--tampon); font-weight: 600; }
.repli[open] summary { margin-bottom: 12px; }

/* ---- page boîte simplifiée (19-20/08/2026) ---- */
.marque-detail { color: var(--encre-2); font-size: 15px; }
.logo-boite {
  display: block; width: min(100%, 340px); height: auto; margin: 18px auto 4px;
}
/* Image posée par une mairie (027) : ce qu'elle montre et ses proportions sont
   inconnus du code — on borne les DEUX côtés, sans quoi une image carrée
   occuperait 340 px de haut. */
.logo-mairie { width: auto; max-width: min(100%, 340px); max-height: 150px; }
.service { margin: 0 0 14px; color: var(--encre-2); font-size: 16px; text-align: center; }

/* Boutons sur deux lignes centrées (20/08/2026). */
.bouton-2l { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; padding: 11px 10px; }
.bouton-2l small { font-size: 13px; font-weight: 400; opacity: 0.85; }

/* Rangée duo : Annoncer un livre | Ranger ou photographier (30/08/2026).
   Chaque cellule empile la phrase de gains puis son bouton ; les boutons
   s'étirent à la même hauteur, quelle que soit la longueur des libellés. */
.rangee-duo { display: flex; gap: 10px; margin-top: 14px; align-items: stretch; }
.rangee-duo .duo-cell { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.rangee-duo .bouton { flex: 1; margin: 0; }
.photo-etagere figcaption.tampon { margin-top: 8px; }

/* Vitrine (Leo 30/08/2026) : la photo d'ensemble + le rayon animé — il
   remplace le carrousel horizontal des couvertures. */
.vitrine { display: flex; gap: 10px; align-items: stretch; justify-content: center; margin: 0 0 6px; }
.vitrine-photo { margin: 0; min-width: 0; position: relative; }
.vitrine-photo img {
  height: 240px; width: auto; max-width: 100%; display: block;
  border: 1px solid var(--regle); border-radius: 4px;
}
/* Légende en bandeau SUR la photo (décision Leo 20/08/2026) : blanc quasi
   opaque, texte noir — plus rien n'est écrit sous les photos. */
.vitrine-photo figcaption.bandeau {
  position: absolute; left: 1px; right: 1px; bottom: 1px;
  background: rgba(255, 255, 255, 0.88); color: #000;
  font-size: 12.5px; padding: 4px 8px; border-radius: 0 0 4px 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vitrine-photo figcaption.bandeau a {
  color: #000; text-decoration: underline dotted; text-underline-offset: 2px;
}

/* Le rayon : des étagères de couvertures qui défilent de bas en haut, en CSS
   pur — deux copies de la bande pour une boucle sans couture. L'invitation
   reprend le bandeau blanc des photos. */
/* Largeur adaptative (Leo 31/08/2026) : le rayon occupe l'espace restant à
   côté de la photo — borné pour rester une colonne, jamais un mur. */
.rayon { margin: 0; flex: 1 1 112px; min-width: 100px; max-width: 240px; }
.rayon-apercu {
  position: relative; display: block; height: 240px; overflow: hidden;
  border: 1px solid var(--regle); border-radius: 4px; background: var(--papier);
  cursor: pointer; list-style: none;
}
.rayon-apercu::-webkit-details-marker { display: none; }
.rayon-defile { height: 100%; overflow: hidden; }
.rayon-bande { animation: rayon-monte 16s linear infinite; }
.rayon-apercu:hover .rayon-bande { animation-play-state: paused; }
.rayon-fixe .rayon-bande { animation: none; }
@keyframes rayon-monte {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
.rayon-etagere {
  display: flex; align-items: flex-end; justify-content: center; gap: 7px;
  padding: 8px 6px 0; border-bottom: 3px solid var(--regle);
}
/* Les couvertures suivent la largeur de la bande (moitié moins l'espacement),
   plafonnées — la hauteur découle du ratio de chaque couverture. */
.rayon-etagere img {
  width: calc(50% - 10px); max-width: 88px; height: auto; display: block;
  border: 1px solid var(--regle); border-radius: 2px;
}
.rayon-invite {
  position: absolute; left: 1px; right: 1px; bottom: 1px;
  background: rgba(255, 255, 255, 0.88); color: #000; text-align: center;
  font-size: 12px; font-weight: 600; padding: 4px 4px; border-radius: 0 0 4px 4px;
}
/* Popover pleine page : même mécanique <details> en surimpression CSS que
   les popups « gains » (boite.js ajoute clic-fond et Échap). */
.rayon[open]::before {
  content: ''; position: fixed; inset: 0;
  background: rgba(20, 17, 30, 0.55); z-index: 40;
}
.rayon[open] > summary.rayon-apercu { position: relative; z-index: 41; }
.rayon-popover {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 41; width: min(94vw, 560px); max-height: 86vh;
  display: flex; flex-direction: column;
  background: var(--papier); border: 1px solid var(--regle); border-radius: 6px;
  padding: 18px; box-shadow: 0 8px 40px rgba(20, 17, 30, 0.35);
}
.rayon-popover h3 { margin: 0 0 12px; padding-right: 36px; font-size: 18px; }
/* Croix de fermeture du popover : confort JS (hidden levé par boite.js). */
.rayon-popover .popover-fermer,
.installer-popup .popover-fermer {
  position: absolute; top: 8px; right: 8px;
  background: transparent; border: none; color: var(--encre);
  font: 700 26px/1 system-ui, sans-serif; cursor: pointer;
  width: 36px; height: 36px; border-radius: 50%;
}
.rayon-popover .popover-fermer:hover,
.installer-popup .popover-fermer:hover { background: var(--regle); }
/* C'est la GRILLE qui défile, pas le popover : le titre et la croix restent
   épinglés en haut (une croix en absolute dans un conteneur scrollable
   partirait avec le contenu). */
.rayon-grille {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
  overflow-y: auto; min-height: 0;
}
.rayon-grille img {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--regle); border-radius: 3px;
}
/* Page « toutes les vues » : défilement vertical, une vue par figure. */
.photos-page > * + * { margin-top: 18px; }
.photo-vue { margin: 0; position: relative; }
.photo-vue img {
  width: 100%; height: auto; display: block;
  border: 1px solid var(--regle); border-radius: 4px;
}
.photo-vue .bandeau {
  position: absolute; left: 1px; right: 1px; bottom: 1px;
  background: rgba(255, 255, 255, 0.88); color: #000;
  font-size: 12.5px; padding: 4px 8px; border-radius: 0 0 4px 4px;
}

/* Légende en texte normal, pas de tampon ici (décision Leo 19/08/2026). */
.photo-legende { margin: 4px 0 0; font-size: 15px; color: var(--encre-2); }
.photo-legende a { color: var(--tampon); }
.maj-photo { margin-top: 22px; }
.pourquoi { display: inline-block; }
.pourquoi summary {
  list-style: none; cursor: pointer; color: var(--tampon);
  font-size: 13.5px; text-decoration: underline dotted; text-underline-offset: 2px;
}
.pourquoi summary::-webkit-details-marker { display: none; }
.pourquoi[open] { display: block; }
.pourquoi p {
  margin: 6px 0 0; font-size: 14px; color: var(--encre-2);
  border-left: 3px solid var(--regle); padding: 4px 10px;
}
.service a { color: var(--tampon); }
.classement-anonyme { color: var(--estompe); font-style: italic; }
/* Tout en bas, sous le pied : « Service approuvé et soutenu par » + logo,
   sur une seule ligne (21/08/2026). */
.pied-mairie {
  max-width: 640px; margin: 0 auto; padding: 0 20px 28px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 13.5px; color: var(--encre-2);
}
.pied-mairie img { max-height: 40px; width: auto; vertical-align: middle; }
.pied-mairie a { color: var(--encre-2); }

/* ---- récompenses clarifiée (19/08/2026) ---- */
.recompenses-solde {
  font-size: 19px; font-weight: 700; color: var(--tampon); margin: 14px 0 4px;
}
/* Étapes en pastilles numérotées, ligne courte + sous-ligne (23/08/2026). */
.recompenses-etapes { list-style: none; counter-reset: etape; margin: 10px 0 20px; padding: 0; }
.recompenses-etapes li {
  counter-increment: etape; display: flex; gap: 10px; align-items: flex-start;
  padding: 5px 0; color: var(--encre);
}
.recompenses-etapes li::before {
  content: counter(etape); flex: 0 0 22px; height: 22px; border-radius: 50%;
  background: var(--tampon); color: #fff;
  font: 700 12.5px/22px var(--mono); text-align: center;
}
.etape-sous { display: block; font-size: 13px; color: var(--encre-2); margin-top: 1px; }
/* Icône récompense en ligne — remplace le mot « point » (23/08/2026). */
.ico-reward { width: 17px; height: 17px; vertical-align: -3px; }
/* Image cadeau de la 4e étape (Leo 02/09/2026) : 50 % plus grande que
   l'icône récompense, marges verticales négatives = elle DÉBORDE de sa
   ligne au lieu de repousser celle du dessus (les marges d'une image
   inline comptent dans la hauteur de ligne, en négatif aussi). */
.ico-cadeau { width: 36px; height: 36px; margin: -10px 0; }
/* Libellés de récompenses sans gras sur la page publique (Leo 02/09/2026) —
   .item-titre reste à 600 partout ailleurs (inventaire, /c, admin). */
.recompense-commercant .item-titre { font-weight: normal; }

/* Coup de cœur (Leo 26/08/2026) : l'icône remplace le mot « cœur » dans les
   libellés, exactement comme reward.png remplace « point ». */
/* SVG inline : `fill="currentColor"` suit la couleur du texte. Violet sur le
   papier, blanc sur le bouton primaire — une image au violet figé y était
   invisible (fond identique). Les lignes grisées l'estompent avec le reste. */
.ico-coeur { width: 16px; height: 15px; vertical-align: -2px; color: var(--tampon); }
.bouton-primaire .ico-coeur { color: #fff; }
.ico-argent { width: 16px; height: 16px; vertical-align: -3px; color: var(--tampon); }
/* Icône livre incorporée aux libellés de boutons : elle suit la couleur du
   texte, donc blanche sur le bouton primaire et encre ailleurs. */
.ico-livre { width: 17px; height: 17px; vertical-align: -3px; }

/* Bandeau de soutien : mairie et commerçants réunis sous une phrase. Les
   logos gardent leurs proportions et se replient sur les petits écrans. */
.soutiens { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--regle); }
.soutiens-phrase { margin: 0 0 10px; text-align: center; font-size: 15px; color: var(--encre-2); }
.soutiens-logos {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 14px;
}
.soutiens-logos img { height: 38px; width: auto; max-width: 130px; object-fit: contain; }
/* Taille adaptée au nombre de logos (Leo 31/08/2026) : jusqu'à 3, grands ;
   jusqu'à 6, moyens ; au-delà, la taille d'origine. Classe posée par la vue. */
.soutiens-peu img { height: 72px; max-width: 220px; }
.soutiens-quelques img { height: 52px; max-width: 170px; }
.soutiens-logos a { color: var(--encre-2); text-decoration: none; }

/* Classement : la ligne du visiteur, repérable sans rien révéler des autres. */
.classement-moi { background: #F2EEFA; }
.classement-moi td { font-weight: 600; }
.classement-vous { color: var(--tampon); font-weight: 400; font-size: 13px; }

/* Points : l'icône est RÉPÉTÉE, jamais « 2x » (Leo 27/08/2026). Les icônes
   se serrent légèrement pour qu'une valeur à 5 reste lisible sur mobile. */
.pts { display: inline-flex; align-items: center; gap: 1px; white-space: nowrap; }
.pts .ico-reward { width: 15px; height: 15px; vertical-align: -2px; }

/* Phrase de gains « {ico} à gagner ! » AU-DESSUS des boutons d'action
   (Leo 30/08/2026) — elle remplace la pastille absolue du 27/08, pour la
   même raison d'origine : posée SUR le bouton primaire, l'icône récompense
   se noyait dans le violet du fond (image à couleur figée, la page ne peut
   pas la reteindre). Calée à droite, comme l'était la pastille. */
.pts-gagner {
  display: flex; justify-content: flex-end; align-items: center; gap: 1px;
  font-size: 13px; color: var(--encre-2); white-space: nowrap;
  margin: 0 2px 3px 0;
}
.pts-gagner .ico-reward { width: 15px; height: 15px; }
.gains-liste .pts { gap: 0; }

/* Pages de choix (30/08/2026) : « Attention coup de cœur ! » et « De l'ordre
   et une liste à jour ! » — une pile d'options, phrase de gains puis bouton. */
.choix-intro { margin: 18px 0 0; text-align: left; font-size: 16px; }
.choix-actions { display: flex; flex-direction: column; gap: 20px; margin-top: 16px; }
.choix-option .bouton { margin: 0; }
.titre-coeur .ico-coeur { width: 26px; height: 24px; vertical-align: -3px; }

/* Parrainage : le QR doit rester scannable — fond blanc franc, marge propre,
   et une taille bornée pour ne pas déborder sur un petit écran. */
.parrainage-promesse { text-align: center; font-size: 17px; margin: 16px 0; }
.parrainage-qr {
  max-width: 260px; margin: 0 auto; padding: 12px;
  background: #fff; border: 1px solid var(--regle); border-radius: 4px;
}
.parrainage-qr svg { display: block; width: 100%; height: auto; }
.parrainage-lien {
  text-align: center; font-size: 13px; word-break: break-all;
  color: var(--encre-2); margin: 4px 0 0;
}
.parrainage-note { margin-top: 18px; }

/* Mot de la mairie, sous la phrase d'accueil de la boîte. */
.message-mairie {
  margin: 6px 0 0; text-align: center; font-size: 15px;
  color: var(--encre-2); font-style: italic;
}
/* Espace mairie : le mot de passe généré doit être lisible à voix haute. */
.mairie-identifiants { text-align: center; line-height: 1.7; }
.mairie-mdp { font-size: 20px; letter-spacing: 0.08em; }
.mairie-bareme td { vertical-align: middle; }
.mairie-points { width: 70px; font: inherit; padding: 4px 6px;
  border: 1px solid var(--regle); border-radius: 4px; background: var(--papier); color: var(--encre); }
.item-marque-coeur .ico-coeur, .item-grise .item-marque-coeur .ico-coeur { color: inherit; }
.item-marque-coeur {
  display: inline-flex; align-items: center; gap: 4px; align-self: flex-start;
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--tampon); margin-bottom: 2px;
}
.item-coeur { border-left: 3px solid var(--tampon); padding-left: 10px; }
.item-mot {
  margin-top: 4px; font-style: italic; color: var(--encre-2);
  font-size: 14px; quotes: '\00AB\00A0' '\00A0\00BB';
}
.item-grise .item-marque-coeur, .item-grise .item-mot { color: var(--estompe); }
/* Présentation vocale d'un coup de cœur (30/08/2026) : lecteur natif, compact. */
.item-audio { display: block; margin-top: 6px; width: 100%; max-width: 320px; height: 36px; }
/* Le mot du déposant : champ ordinaire, révélé avec le bouton de clôture. */
.coeur-mot { border: 0; padding: 0; margin: 18px 0 0; }
.coeur-mot legend { font-weight: 600; padding: 0; }
.coeur-mot textarea {
  width: 100%; box-sizing: border-box; font: inherit; padding: 8px;
  border: 1px solid var(--regle); border-radius: 4px; background: var(--papier);
  color: var(--encre); resize: vertical;
}
.moderation-mot { display: inline-block; margin-top: 4px; font-style: italic; }
.recompense-commercant h2 { margin-bottom: 2px; }
.recompense-enseigne { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 12px; margin: 22px 0 4px; }
/* L'enseigne est l'identité du bloc : pas le style « libellé de section »
   du h2 global (13 px capitales grises — 22/08/2026). */
.recompense-enseigne h2 {
  margin: 0; font-size: 19px; font-weight: 700; color: var(--encre);
  text-transform: none; letter-spacing: normal;
}
.recompense-logo { display: block; max-height: 64px; width: auto; }
.recompense-adresse { margin: 0; }
.recompense-adresse a { color: var(--encre-2); text-decoration: none; }
.recompense-adresse a:hover { color: var(--tampon); text-decoration: underline; }
.pin { width: 14px; height: auto; vertical-align: -2px; margin-right: 4px; }
.admin-logo-apercu { display: block; max-height: 48px; width: auto; margin-bottom: 6px; }
.admin-supprimer { color: var(--alerte) !important; }
.admin-carte { height: 340px; border: 1.5px solid var(--regle); border-radius: 4px; }
.contact-corps { font: 16px/1.5 system-ui, sans-serif; }
.recompense-indispo { color: var(--estompe); font-size: 13.5px; text-align: right; }
.recompense-bouton { width: auto; padding: 9px 14px; font-size: 15px; }
.actions-trio { display: flex; flex-direction: column; gap: 4px; }
.actions-trio .bouton { margin-top: 14px; }
/* Les phrases de gains espacent elles-mêmes les boutons de l'actions-trio ;
   dans la rangée duo, la cellule reprend la main (sinon le 14 px du trio se
   cumulerait avec le margin-top de la rangée). */
.actions-trio .pts-gagner { margin-top: 14px; }
.duo-cell .pts-gagner { margin-top: 0; }
.duo-cell .bouton { margin-top: 0; }
.actions-trio .sous-action { margin: 6px 0 0; text-align: center; }
.abonner { margin: 0; }
/* .repli summary teint le texte en violet : sur le bouton primaire (fond
   violet), le libellé doit rester blanc. */
/* > : seul le bouton violet DIRECT est blanc — les dépliants imbriqués
   (« Je m'inscris » / « J'ai déjà un compte », boutons neutres) restent
   en encre (blanc sur blanc sinon — bug signalé par Leo le 21/08). */
.abonner > summary { list-style: none; text-align: center; color: #fff; }
.abonner > summary:hover, .abonner > summary:focus { color: #fff; }
.abonner summary::-webkit-details-marker { display: none; }
.abo-option > summary { color: var(--encre); }
.abo-option > summary:hover { color: var(--tampon); }
.abonner[open] summary { margin-bottom: 0; }
.abonner .form-email { margin-top: 12px; }
/* Pot de miel du formulaire d'abonnement (13/10/2026) : sorti de l'écran, PAS
   en display:none ni en attribut hidden — les robots sautent ces champs-là. */
.pot-miel { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
/* Étape intermédiaire : deux options empilées, boutons neutres. */
.abo-option { margin-top: 10px; }
.abo-option > summary { list-style: none; text-align: center; }
.abo-option > summary::-webkit-details-marker { display: none; }
.abo-option[open] > summary { border-color: var(--tampon); color: var(--tampon); }
.isbn-bloc { margin-top: 22px; }

.lien-secondaire {
  display: inline-block; margin-top: 14px;
  color: var(--tampon); font-weight: 600; text-decoration: none;
}
.lien-secondaire:hover { text-decoration: underline; }

.actions-secondaires {
  display: flex; gap: 20px; flex-wrap: wrap;
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--regle);
}
.actions-secondaires a { color: var(--encre-2); font-size: 15px; text-decoration: underline; text-underline-offset: 2px; }
.actions-secondaires a:hover { color: var(--tampon); }

/* ---- voisines / listes de boîtes ---- */
.voisines ul { list-style: none; margin: 0; padding: 0; }
.voisines li { padding: 11px 0; border-bottom: 1px solid var(--regle); }
.voisines a { color: var(--encre); font-weight: 600; text-decoration: none; }
.voisines a:hover { color: var(--tampon); }
.voisine-meta { display: block; font-size: 14px; color: var(--encre-2); margin-top: 2px; }
.mono { font-family: var(--mono); font-size: 13px; }

/* ---- accueil (refonte 21/08/2026) ---- */
.accueil > * + * { margin-top: 26px; }
.accueil-date { font-size: 13px; color: var(--encre-2); margin: 0 0 10px; text-align: center; }
.stats-grille { display: flex; gap: 12px; }
.stat {
  flex: 1; text-align: center; padding: 14px 8px;
  border: 1px solid var(--regle); border-radius: 4px; background: #fff;
}
.stat-n { display: block; font: 700 28px/1.1 var(--mono); color: var(--tampon); }
.stat-l { display: block; font-size: 13px; color: var(--encre-2); margin-top: 3px; }
/* Liens des sources : discrets, la citation prime sur le lien. */
.stats-source a { color: inherit; text-decoration: underline; }
.stat-c { display: block; font-size: 12px; color: var(--estompe); margin-top: 4px; font-family: var(--mono); }

.accueil-profils { display: flex; flex-direction: column; gap: 14px; }
.profil { border-left: 3px solid var(--tampon); padding: 2px 0 2px 14px; }
.profil h2 { margin: 0 0 4px; }
.profil p { margin: 0; font-size: 15px; color: var(--encre); }

.accueil-exemple h2 { margin-bottom: 10px; }
/* Photo à 30 %, texte à droite (Leo 21/08/2026) ; fond papier, sans carte ni
   bordure, bouton « Découvrir » sous le texte (Leo 22/08/2026). */
.exemple-carte { display: flex; align-items: flex-start; gap: 14px; color: var(--encre); }
.exemple-carte img {
  width: 30%; flex: 0 0 30%; height: auto; display: block;
  border: 1px solid var(--regle); border-radius: 4px;
}
.exemple-texte p { margin: 0 0 12px; font-size: 15px; }
.exemple-bouton { max-width: 300px; }
.accueil-appel {
  max-width: 420px; margin: 22px auto 10px; text-align: center;
  font-size: 15px; color: var(--encre-2);
}
.accueil-contact { max-width: 340px; margin-left: auto; margin-right: auto; }

/* ---- accueil : vitrine pour les communes (19/09/2026) ----
   La page s'adresse d'abord à un élu, sans cesser d'accueillir l'habitant.
   Rien n'y est masqué : aucun élément à `hidden`, aucun <details> — les deux
   pièges CSS du projet (une règle `display` qui l'emporte sur l'attribut
   `hidden`, une règle `.x summary` qui frappe les summaries descendants) sont
   sans objet ici, et aucune parade n'est donc posée. L'espacement entre
   sections vient de `.accueil > * + *`, déjà défini plus haut. */
/* Ni filet ni retrait au-dessus des sections (Leo 21/09/2026) : les blocs
   s'enchaînent, seule la marge les sépare. */
.accueil-section { }
.accueil-section h2 { margin: 0 0 8px; font-size: 20px; line-height: 1.25; }
.accueil-section h3 {
  margin: 18px 0 4px; font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--encre-2, #6B6577);
}
.accueil-section > p { margin: 0 0 10px; font-size: 15px; }
.accueil-section > p:last-child { margin-bottom: 0; }

/* Cadran décoratif du principe : centrage DÉTERMINISTE par marge auto sur un
   bloc, jamais par un text-align hérité (même règle que la vraie jauge). */
.accueil-jauge {
  display: block; margin: 2px auto 12px;
  width: min(100%, 200px); height: auto;
}

/* Listes de la vitrine : des filets de fiche, pas des puces rondes. */
.accueil-liste { list-style: none; margin: 0; padding: 0; }
.accueil-liste li {
  position: relative; padding: 9px 0 9px 17px; font-size: 15px;
  border-bottom: 1px solid var(--regle, #E4E1D8);
}
.accueil-liste li::before {
  content: '\203A'; position: absolute; left: 0; top: 9px;
  color: var(--tampon, #5A3FA0); font-weight: 700;
}
.accueil-liste li:last-child { border-bottom: 0; padding-bottom: 0; }
.accueil-liste b { font-weight: 700; }

/* « Ce que ce service ne promet pas » : encadré, jamais replié. */
.accueil-honnete {
  border: 1px solid var(--regle, #E4E1D8); border-left: 3px solid var(--tampon, #5A3FA0);
  border-radius: 4px; padding: 16px 18px; background: #fff;
}
.accueil-honnete h2 { margin: 0 0 8px; font-size: 20px; line-height: 1.25; }
.accueil-honnete > p { margin: 0 0 6px; font-size: 15px; color: var(--encre-2, #6B6577); }

/* Appel à l'élu : le seul bloc qui conduise au formulaire de contact. */
.accueil-elu {
  border: 1px solid var(--regle, #E4E1D8); border-radius: 4px;
  padding: 18px 18px 14px; background: #fff; text-align: center;
}
.accueil-elu h2 { margin: 0 0 8px; font-size: 20px; line-height: 1.25; }
.accueil-elu > p { margin: 0 0 14px; font-size: 15px; }
.accueil-elu .accueil-appel { margin: 12px auto 0; }

/* ---- vitrine : PARTI PRIS VISUEL (Leo 19/09/2026) ----
   Trois passes n'avaient corrigé que la structure : la page restait un
   document, faute de moment d'entrée. Leo a arbitré pour un hero photo et une
   alternance de fonds, ce qui sort de la charte « papier » du reste du site.
   Ces règles ne valent QUE sur `.accueil` : aucune autre page ne bouge. */

/* Filet : les bandes sortent de la colonne par des marges négatives calculées
   en vw. Sans cela, une barre de défilement horizontale apparaît. */
html { overflow-x: hidden; }

/* Un SERIF pour les titres. Pas de webfont (règle du projet, et c'est une
   décision de Leo, pas une conséquence du poids) : Georgia est présente
   partout et donne à la page son air de page imprimée, ce qui est exactement
   la direction « fiche de bibliothèque » et non une landing générique. */
.accueil h1,
.accueil h2 {
  font-family: ui-serif, Georgia, "Iowan Old Style", "Times New Roman", serif;
  letter-spacing: -0.02em; text-wrap: balance;
}
.accueil h1 {
  margin: 0 0 14px; font-size: 30px; line-height: 1.08;
  font-weight: 700; color: #fff;
}

/* ---- bandes pleine largeur ----
   `margin-inline` négatif pour sortir de la colonne, `padding-inline` de même
   valeur pour y ramener le contenu, puis `.bande-int` reborne à 1040 px. */
.bande {
  margin-inline: calc(50% - 50vw);
  padding: 30px calc(50vw - 50%);
}
.bande-int { max-width: 1040px; margin: 0 auto; }
/* La bande blanche se distingue par son fond seul, sans liseré. */
.bande-blanche { background: #fff; }
/* Alternance des fonds (Leo 21/09/2026) : une rangée en duo sur deux passe
   en blanc, pour que la suite des blocs ne se lise plus comme un seul aplat
   crème. Le fond saigne jusqu'aux bords de la fenêtre, comme `.bande`. La
   classe est posée dans la VUE et non calculée en CSS : un `nth-child`
   compterait aussi le hero et les bandes, et se décalerait au moindre
   réordonnancement. */
.accueil-section.fond-blanc {
  background: #fff;
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);
}
/* Le rembourrage vertical vaut pour TOUTES les rangées en duo, colorées ou
   non. Mesuré le 21/09/2026 : posé sur la seule bande, il décalait son
   illustration de 34 px vers le bas et mangeait l'imbrication — le
   chevauchement tombait de 70 à 36 px. Une géométrie uniforme le rend
   constant. Le sélecteur de classe est EXACT : `.accueil-duo` n'attrape pas
   `.accueil-duo-photo`, contrairement à une recherche de sous-chaîne. */
.accueil-section:has(> .accueil-duo) { padding-block: 34px; }
.bande-sombre { background: var(--encre, #221E33); }
/* Bande « librairie » (Leo 21/09/2026) : photo en fond, texte en ENCRE et non
   en blanc. L'image est presque blanche — luminosité moyenne 0,90 — et AUCUN
   voile n'est appliqué : mesuré, son 1er centile vaut 0,51, l'encre y garde un
   contraste de 8,6 pour un seuil de 4,5. Voiler n'aurait fait que la pâlir.
   Préfixe `vitrine-` : c'est lui que rendu.php réécrit vers /apercu/. */
/* Auteurs du territoire (Leo 25/09/2026). HAUTEUR commune, largeurs libres :
   les quatre couvertures ont des rapports de 0,711 à 0,991, et un cadre fixe
   avec `object-fit: cover` aurait rogné des titres et des noms d'auteurs sur
   des ouvrages réels. C'est aussi ainsi que des livres se posent côte à côte.
   Aucune variable non vérifiée ici : seule `--regle` est employée, avec son
   repli — une variable non résolue rendrait le filet invisible. */
.accueil-auteurs .auteurs-rangee {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 22px; margin-top: 24px;
}
.accueil-auteurs figure { margin: 0; text-align: center; }
.accueil-auteurs .auteurs-rangee img {
  height: 210px; width: auto; display: block;
  border: 1px solid var(--regle, #E4E1D8); border-radius: 3px; background: #fff;
}
.accueil-auteurs figcaption { margin-top: 9px; font-size: 14px; line-height: 1.35; }
.accueil-auteurs .auteur-titre { display: block; font-weight: 600; }
.accueil-auteurs .auteur-noms { display: block; color: #6A6478; font-size: 13px; }
@media (max-width: 620px) {
  /* GRILLE de deux colonnes, et non plus une rangée qui s'enroule (Leo
     25/09/2026, corrigé le jour même). En flex, la largeur d'une figure est
     fixée par sa LÉGENDE et non par sa couverture : « Sophie Moronval et
     Nargis Karimova » rendait la première figure trop large pour partager sa
     rangée, et les quatre couvertures se répartissaient 1 / 2 / 1. La cellule
     de grille borne la légende ; la hauteur commune des images demeure. */
  .accueil-auteurs .auteurs-rangee {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 18px 14px; justify-items: center;
  }
  .accueil-auteurs figure {
    display: flex; flex-direction: column; align-items: center; max-width: 100%;
  }
  .accueil-auteurs .auteurs-rangee img { height: 150px; max-width: 100%; }
  .accueil-auteurs figcaption { max-width: 100%; }
}

.bande-librairie {
  /* Voile blanc à 55 % (Leo 21/09/2026) : demandé pour que la photo RECULE
     derrière le texte, non pour la lisibilité — celle-ci était déjà acquise,
     mesurée à 8,9 sur la page rendue. Posé en dégradé plat par-dessus
     l'image, la propriété `background` n'acceptant qu'une seule couche
     colorée de fond. */
  background: linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55)),
              var(--papier, #FCFBF8) url('/assets/vitrine-librairie.jpg?v=1')
              center / cover no-repeat;
}
/* `.accueil` en tête du sélecteur : sans lui, `.accueil h2` (bloc bureau plus
   bas) l'emporte à spécificité égale et le titre s'affiche en encre sombre
   sur fond sombre, donc invisible. Constaté le 19/09/2026. */
.accueil .bande-sombre h2,
.accueil .bande-sombre b { color: #fff; }
.bande-sombre p, .bande-sombre li { color: rgba(255, 255, 255, 0.82); }
/* (filet retiré le 21/09/2026 : plus de ::before à recolorer ici) */
.bande-sombre .accueil-liste li { border-bottom-color: rgba(255, 255, 255, 0.16); }
.bande-violet { background: var(--tampon, #5A3FA0); }

/* ---- hero ---- */
.accueil-hero {
  position: relative; overflow: hidden; display: flex; align-items: flex-end;
  margin-inline: calc(50% - 50vw);
  padding: 48px calc(50vw - 50%) 40px;
  min-height: 380px;
}
.hero-photo {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  /* La boîte est à DROITE de la photo, qui est panoramique. En colonne
     étroite, le hero devient presque carré et ne laisse voir qu'environ 40 %
     de la largeur : on se cale donc sur le bord droit pour que la boîte y
     soit entière. Le bureau reprend un cadrage moins extrême plus bas. */
  object-position: 100% center;
}
/* Voile sombre : sans lui, le texte blanc devient illisible dès que la photo
   est claire. Dégradé plutôt qu'aplat, pour garder la photo lisible en haut. */
.hero-voile {
  position: absolute; inset: 0; z-index: 1; display: block;
  background: linear-gradient(to right, rgba(34, 30, 51, 0.9), rgba(34, 30, 51, 0.0));
}
/* Pastille du titre (Leo 21/09/2026) : blanc sur violet, calquée sur
   .bouton-primaire — même --tampon, même rayon 4 px. Le fond opaque
   supprime la dépendance au contraste de la photo, qui faisait tomber
   le mot coloré à 1,4 en colonne étroite. Rembourrage en em : le titre
   passe de 30 px à 72 px, des pixels fixes seraient faux à une taille
   ou à l'autre. box-decoration-break : le titre se coupe en deux lignes
   en colonne étroite, et sans lui le second fragment perdrait fond et
   arrondi. */
.titre-accent {
  background: var(--tampon); color: #fff;
  border-radius: 4px; padding: 0.04em 0.16em;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
/* Mot en violet dans un titre de section (Leo 21/09/2026) : texte seul,
   sans pastille — ces titres vivent sur fond papier, pas sur la photo.
   Contraste mesuré 7,65 sur #FCFBF8, au-dessus des deux seuils. */
.mot-accent { color: var(--tampon); }
.hero-contenu { position: relative; top: 0; z-index: 2; width: 100%; max-width: 1040px; margin: 0 auto; }
/* Le logo est EXIGÉ sur cette page par le smoke (cas l.1097). À 58 px il ne
   se lisait pas et passait pour un artefact : il tient ici le rôle de
   signature, au-dessus du titre. */
.accueil-hero .logo-boite { width: 96px; height: auto; margin: 0 0 18px; display: block; }
.accueil-hero .service {
  margin: 0 0 22px; text-align: left;
  font-size: 16px; color: rgba(255, 255, 255, 0.9);
}
.accueil-hero .accueil-date { text-align: left; color: rgba(255, 255, 255, 0.66); }
.accueil-hero .stats-grille { max-width: 620px; }
/* Tuiles « de verre » : le fond translucide laisse voir la photo dessous. */
.accueil-hero .stat {
  background: rgba(255, 255, 255, 0.13);
  border-color: rgba(255, 255, 255, 0.32);
}
.accueil-hero .stat-n { color: #fff; }
.accueil-hero .stat-l { color: rgba(255, 255, 255, 0.86); }
.accueil-hero .stat-c { color: rgba(255, 255, 255, 0.66); }

/* ---- écran de téléphone (Leo 19/09/2026) ----
   Une capture réelle de la page d'une boîte, montrée dans un cadre dessiné en
   CSS plutôt qu'incrusté dans l'image : le trait reste net à toute taille, et
   la capture peut être remplacée sans refaire le cadre. Elle a pris la place
   du cadran décoratif, qui ne montrait qu'un arc sans rien prouver. */
.tel-cadre {
  max-width: 247px; margin: 0 auto; padding: 10px 9px 12px;
  background: var(--encre, #221E33); border-radius: 28px;
  box-shadow: 0 10px 26px rgba(34, 30, 51, 0.26);
}
/* Le haut-parleur, seul détail qui fait lire l'objet comme un téléphone. */
.tel-cadre::before {
  content: ''; display: block; width: 54px; height: 5px;
  margin: 1px auto 9px; border-radius: 3px; background: rgba(255, 255, 255, 0.34);
}
/* La vitre porte le rognage : le rayon animé est positionné par rapport à
   elle, et rien ne dépasse des angles arrondis. */
.tel-vitre { position: relative; border-radius: 19px; overflow: hidden; }
.tel-ecran { width: 100%; height: auto; display: block; }

/* Le rayon : fenêtre posée sur la grille de couvertures de la capture, en
   POURCENTAGES (x 218..378, y 330..535 sur une capture de 400 × 780), pour
   qu'elle suive l'image à toute taille d'affichage. La bande contient deux
   fois la même série, et le défilement s'arrête à -50 % : la boucle est donc
   sans raccord visible. */
.tel-rayon {
  position: absolute; left: 54.5%; top: 42.3%;
  width: 40%; height: 26.3%; overflow: hidden;
}
.tel-rayon img {
  width: 100%; height: auto; display: block;
  animation: telDefile 26s linear infinite;
}
@keyframes telDefile {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
/* Second écran : l'inventaire DÉFILE. La vitre est bornée au format du
   téléphone et le ruban (400 × 2400, une vingtaine de livres) glisse derrière.
   Aller-retour plutôt que boucle : un retour brutal en haut de liste se
   verrait, `alternate` remonte doucement et ne demande aucune duplication. */
.tel-vitre-defile { aspect-ratio: 400 / 760; }
.tel-ruban {
  width: 100%; height: auto; display: block;
  /* `linear` et non `ease-in-out` : une liste qui défile doit avancer à
     vitesse régulière, et la courbe démarrait si lentement que le mouvement
     était imperceptible pendant les premières secondes. */
  animation: telScroll 34s linear infinite alternate;
}
@keyframes telScroll {
  from { transform: translateY(0); }
  to   { transform: translateY(-68.5%); }   /* (2411 - 760) / 2411 */
}

/* Règle du projet : toute animation s'arrête si le visiteur l'a demandé. */
@media (prefers-reduced-motion: reduce) {
  .tel-rayon img,
  .tel-ruban { animation: none; }
}

/* En colonne étroite, `.accueil-duo` n'est pas en flex (son `display: flex` et
   son `gap` vivent au-dessus de 760 px) : sans cette marge, le titre du bloc
   collait au bas du cadre du téléphone. Remise à zéro en bureau, où le gap
   reprend la main. */
.accueil-duo-image + .accueil-duo-texte { margin-top: 20px; }

/* L'illustration se peint AU-DESSUS du fond du bloc suivant. Sans cela, la
   bande blanche d'un bloc remonté (marge négative de l'imbrication) viendrait
   ROGNER le bas du téléphone précédent : un fond de frère se peint après.
   Un élément positionné doté d'un z-index passe devant le fond d'un frère
   NON positionné, quel que soit l'ordre du document — d'où ces deux lignes,
   et non un z-index posé sur les sections, qui aurait demandé de les
   numéroter toutes. Le cadre de référence du rayon animé reste `.tel-vitre`,
   déjà positionnée : rien ne bouge de ce côté. */
.accueil-duo { position: relative; z-index: 1; }
/* Illustration NUE dans une colonne de duo (Leo 21/09/2026) : cette photo
   n'est pas une capture d'écran, elle ne va pas dans un cadre de téléphone.
   Pas d'ombre ni de liseré : les angles de l'image sont aplatis sur le blanc
   de sa section, un contour les dessinerait. */
.duo-illustration { width: 100%; height: auto; display: block; }

/* Badge de source, DANS l'étiquette (Leo 21/09/2026 : d'abord à cheval sur
   la bordure haute, puis descendu à l'intérieur). Fond blanc et filet : les
   deux logos fournis sont opaques à fond blanc, le badge les absorbe au lieu
   de laisser un rectangle. On ne retouche jamais les pixels d'une marque
   tierce, on les pose. */
.stat { position: relative; }
.stat-source {
  position: absolute; top: 10px; right: 12px;
  /* 26 px et non 18 : mesuré à l'écran, un badge de 18 px de haut rendait
     le mot « Ipsos » illisible et la bannière de l'OFGL méconnaissable —
     une attribution qu'on ne reconnaît pas n'attribue rien. Porté à 39 px
     le 21/09/2026 (+50 %, Leo) : à 26 px le carré Ipsos se lisait, mais la
     bannière de l'OFGL, de rapport 2,8, restait un frottis. */
  /* 24 px par defaut (Leo 21/09/2026 : « trop gros sur mobile ») : les 39 px
     avaient ete choisis pour un ecran large et s'appliquaient sans distinction
     au telephone, ou l'etiquette ne fait que ~165 px de large — le badge y
     mangeait le chiffre. Les 39 px sont rendus plus bas, a partir de 760 px. */
  height: 24px; width: auto; display: block;
  background: #fff; padding: 2px 5px;
  border: 1px solid var(--regle, #E4E1D8); border-radius: 3px;
}

/* ---- photos en duo avec le texte ---- */
.accueil-duo-photo { display: grid; gap: 22px; }
.accueil-duo-photo figure { margin: 0; }
.duo-photo {
  width: 100%; height: auto; display: block;
  aspect-ratio: 3 / 4; object-fit: cover; border-radius: 8px;
}
/* ---- chiffres du sondage (Leo 20/09/2026) ----
   Les tuiles sont celles du hero, libérées quand les chiffres du service en
   ont été retirés. À quatre, elles doivent pouvoir passer à la ligne : en
   colonne étroite, quatre tuiles côte à côte seraient illisibles. */
.accueil-chiffres .stats-grille { flex-wrap: wrap; gap: 10px; margin-top: 18px; }
.accueil-chiffres .stat { flex: 1 1 150px; padding: 16px 10px; }
.accueil-chiffres .stat-n { font-size: 26px; line-height: 1.15; }
.accueil-chiffres .stat-l { margin-top: 6px; }
.chiffres-chute {
  margin: 20px 0 0; font-size: 17px; font-weight: 700;
  color: var(--encre, #221E33); max-width: 46ch;
}
/* La source : discrète, mais présente. Sans elle ces nombres ne valent rien. */
.stats-source { margin: 10px 0 0; font-size: 12.5px; color: var(--estompe, #8B8677); }

/* Capture du courriel : ni cadre de téléphone ni bordure, une ombre douce
   suffit — c'est un document qu'on lit, pas un appareil qu'on tient. */
.mail-capture {
  /* 85 % le 21/09/2026, puis 68 % le même jour : 20 % de moins encore. */
  max-width: 68%; margin-inline: auto;
  width: 100%; height: auto; display: block; border-radius: 10px;
  box-shadow: 0 6px 22px rgba(34, 30, 51, 0.16);
}
.accueil-duo-photo figcaption {
  margin-top: 8px; font-size: 13px; text-align: center; color: var(--encre-2, #6B6577);
}

/* Les cartes dépliantes se détachent du papier : une ombre très légère
   suffit à les faire lire comme cliquables. */
.accueil-groupe { box-shadow: 0 1px 3px rgba(34, 30, 51, 0.08); }

@media (min-width: 760px) {
  .accueil h1 { font-size: 72px; }
  /* Le relèvement du contenu du hero est réservé aux grandes largeurs (Leo
     21/09/2026). Sur iPhone, ces 50 px collaient le titre à 23 px du bord
     tandis que 112 px de vide traînaient sous le texte — déséquilibre mesuré
     à 375 et 390 px, apparu quand la promesse a gagné une ligne. */
  .hero-contenu { top: -50px; }
  .accueil h2 { font-size: 32px; }
  .accueil-hero { min-height: 500px; padding-top: 72px; padding-bottom: 56px; }
  /* En bureau le hero est large : le recadrage est faible et un cadrage
     collé au bord droit couperait la scène. On revient à 72 %. */
  .hero-photo { object-position: 72% center; }
  .accueil-hero .logo-boite { width: 72px; }
  /* `max-width: none` (Leo 21/09/2026) : retirer le 58ch ne suffisait pas,
     la règle `.service` des 70ch bridait encore le paragraphe à 841 px.
     Poids (0,2,0) contre (0,1,0) — calculé, pas supposé. */
  .accueil-hero .service { font-size: 21px; max-width: none; }
  .bande { padding-top: 44px; padding-bottom: 44px; }
  /* Image à gauche, texte à droite ; `inverse` échange les deux, pour que la
     page ne répète pas deux fois la même composition. */
  .accueil-duo-photo { grid-template-columns: 420px 1fr; gap: 36px; align-items: center; }
  .accueil-duo-photo.inverse { grid-template-columns: 1fr 420px; }
  .accueil-duo-photo.inverse figure { order: 2; }
}

/* ---- vitrine : illustrations et blocs dépliants (Leo 19/09/2026) ----
   « Pas trop de textes en première lecture » : les blocs longs sont des
   <details>, donc repliables SANS JavaScript, et leur contenu reste dans le
   HTML (indexable, imprimable). La classe est posée sur le <details> et le
   CSS cible `> summary` : une règle descendante frapperait les summaries
   imbriqués, piège déjà rencontré deux fois sur ce projet. */
/* TROIS colonnes à toutes les largeurs, jamais `auto-fit` : sur téléphone il
   retombait à une seule colonne, et la bande devenait 750 px de photos avant
   le premier argument ; sur grand écran il aurait laissé trois vignettes
   étriquées alignées à gauche. Trois boîtes, trois communes, une bande. */
.accueil-photos {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 10px; margin: 0;
}
.accueil-photo { margin: 0; }
/* Cadre CARRÉ, pas le portrait natif des photos : sur téléphone, trois
   602 × 800 en pleine largeur faisaient 1 600 px de photos avant le premier
   argument, soit l'inverse de ce qu'on cherche. `object-fit: cover` recadre
   sans déformer ; `height` est posé pour que la place soit réservée avant
   que l'image n'arrive. */
.accueil-photo img {
  width: 100%; height: auto; display: block; aspect-ratio: 1 / 1;
  object-fit: cover; border-radius: 4px; border: 1px solid var(--regle, #E4E1D8);
}
.accueil-photo figcaption {
  margin-top: 6px; font-size: 13px; color: var(--encre-2, #6B6577);
  text-align: center;
}

.accueil-repli > summary {
  cursor: pointer; list-style: none;
}
.accueil-repli > summary::-webkit-details-marker { display: none; }
.accueil-repli > summary:focus-visible { outline: 2px solid var(--tampon, #5A3FA0); outline-offset: 3px; }
.accueil-repli > summary h2,
.accueil-repli > summary h3 { display: inline; margin: 0; }
/* Chevron ▸/▾, convention des dépliants texte du projet. Il REMPLACE le filet
   violet de `.accueil h2::before`, qui est un bloc : les deux se disputeraient
   le même pseudo-élément. */
.accueil-repli > summary h2::before,
.accueil-repli > summary h3::before {
  content: '▸ '; display: inline; width: auto; height: auto;
  margin: 0; background: none; border-radius: 0; color: var(--tampon, #5A3FA0);
}
.accueil-repli[open] > summary h2::before,
.accueil-repli[open] > summary h3::before { content: '▾ '; }
.accueil-repli[open] > summary { margin-bottom: 10px; }
/* Un groupe replié garde la carte : fermés, les quatre pavés sont de hauteur
   égale, ce qui était impossible avec des listes de longueurs différentes. */
.accueil-groupe > summary h3 { font-size: 14px; }

/* ---- vitrine : mise en page BUREAU (19/09/2026) ----
   Le rendu mobile de la refonte était juste ; c'est l'écran large qui était
   sinistré : 640 px de contenu au centre de 1200, deux marges vides, et les
   24 prestations en une seule file de puces identiques. L'essentiel de ce
   bloc est donc sous `min-width: 760px` et ne touche à rien en dessous.

   L'élargissement passe par une classe posée sur <body> par la vue. Ni
   `:has()` (inutile ici), ni une retouche de `main` seul : `.entete` (l.34),
   `.pied` (l.101) et `.pied-mairie` (l.379) sont bornés à 640 px eux aussi,
   et n'élargir que le contenu ferait flotter un en-tête étroit au-dessus. */
/* Le lien « Toutes les boîtes » quitte le pied de la VITRINE seulement (Leo
   21/09/2026). Le pied est commun à tout le site : le retirer de layout.php
   le ferait disparaître de chaque page, production comprise. La classe
   `large`, posée sur le <body> par la seule vitrine, borne l'effet à elle.
   Sélecteur de SUFFIXE : relevé sur la page servie, `/carte` est le seul
   href qui se termine ainsi — les trois autres liens du pied sont intacts. */
body.large .pied a[href$="/carte"] { display: none; }

body.large main,
body.large .pied,
body.large .pied-mairie { max-width: 1040px; }
/* L'en-tête du site est MASQUÉ sur la seule vitrine (Leo 21/09/2026) : la
   page s'ouvre directement sur l'image, sans bandeau au-dessus. Les autres
   pages le gardent — `body.large` n'est posée que par l'accueil. */
body.large .entete { display: none; }

/* Les h2 du site sont de petites capitales grises (règle globale, l.115) :
   sur la vitrine ils doivent porter la page. Neutralisation LOCALE — les
   autres pages gardent leur traitement intact. */
.accueil h2 {
  font-size: 26px; font-weight: 700; text-transform: none;
  letter-spacing: -0.01em; line-height: 1.2; color: var(--encre, #221E33);
}
/* Le filet violet sous les titres a été RETIRÉ (Leo 21/09/2026). Le chevron
   des dépliants, qui vit sur le même pseudo-élément, est conservé : il est
   redéfini plus bas par `.accueil-repli > summary h2::before`. */
/* Les deux profils restent des sous-titres : ils ne concurrencent pas les
   sections, et leur filet ferait doublon avec la barre violette du bloc. */
.profil h2 { font-size: 17px; }
/* (filet retiré le 21/09/2026 : plus de ::before à masquer sur les profils) */
.accueil-groupe h3 { margin-top: 0; }
.stat-n { font-variant-numeric: tabular-nums; }

@media (min-width: 760px) {
  .accueil > * + * { margin-top: 40px; }

  /* Confort de lecture : sur 1040 px, un paragraphe pleine largeur dépasse
     130 caractères par ligne, l'œil perd le début de la suivante. Le texte
     courant reste sous ~70 caractères ; les listes et les cartes, déjà
     étroites par leur grille, n'en ont pas besoin. */
  .service, .accueil-section > p, .accueil-honnete > p { max-width: 70ch; }
  /* Les DEUX paragraphes du bloc des chiffres échappent à la limite de 70ch
     (Leo 21/09/2026) : l'introduction et la ligne de source doivent tenir sur
     une ligne sous des tuiles qui occupent toute la largeur.
     Poids (0,2,1) contre (0,1,1) pour la règle ci-dessus — calculé, pas
     supposé : une surcharge trop légère avait déjà été ignorée en silence,
     et s'en remettre à l'ordre du fichier à poids égal serait fragile. */
  .accueil-chiffres.accueil-section > p { max-width: none; }
  /* Même exemption pour les auteurs du territoire (Leo 25/09/2026) : son
     paragraphe d'introduction restait bridé à la largeur de lecture alors que
     la rangée de couvertures occupe toute la bande. Sélecteur de MÊME
     spécificité que la règle générale qu'il neutralise — un sélecteur plus
     léger serait resté sans effet (piège CSS documenté du projet). */
  .accueil-auteurs.accueil-section > p { max-width: none; }
  .service { margin-left: auto; margin-right: auto; }
  .accueil-elu > p { max-width: 58ch; margin-left: auto; margin-right: auto; }

  /* Le principe : le cadran cesse d'être une vignette perdue au centre. */
  .accueil-duo { display: flex; align-items: center; gap: 30px; }
  /* Le gap reprend la main : la marge posée pour la colonne étroite
     décalerait le texte et casserait son centrage face au téléphone. */
  .accueil-duo-image + .accueil-duo-texte { margin-top: 0; }
  .accueil-duo-image { flex: 0 0 300px; }
  .accueil-jauge { width: min(100%, 300px); margin: 0; }
  .accueil-duo-texte > p { margin: 0 0 10px; font-size: 15px; }
  .accueil-duo-texte > p:last-child { margin-bottom: 0; }

  /* Le second téléphone passe à droite : deux duos identiques se liraient
     comme une répétition. `order` suffit, l'ordre du HTML reste logique. */
  .accueil-duo.inverse .accueil-duo-image { order: 2; }

  /* Rangée à ILLUSTRATION agrandie (Leo 21/09/2026) : 525 px au lieu de 300,
     soit 75 % de plus. La photo de l'encart montre du texte imprimé, que
     300 px réduisaient à l'état de trace.
     Le paragraphe se resserre de lui-même : la rangée fait 1000 px et l'écart
     30, il passe donc de 670 à 445 px sans qu'aucune largeur ne soit posée.
     DANS la requête média large seulement : en colonne étroite la rangée est
     empilée et l'image occupe déjà toute la largeur. */
  /* `min(525px, 100% - 330px)` et non 525 fixes (Leo 21/09/2026, corrigé le
     même jour) : l'imbrication superpose cette rangée à la précédente, dont
     l'illustration occupe 300 px à GAUCHE. Une colonne fixe de 525 px mordait
     donc dessus dès que la fenêtre se resserrait — collisions mesurées entre
     760 et 820 px, c'est-à-dire juste après le seuil où la page passe en deux
     colonnes. 330 = les 300 px de la voisine plus les 30 px d'écart. Au-delà
     de 900 px la colonne vaut bien ses 525 px. */
  .accueil-duo.duo-illustre .accueil-duo-image { flex: 0 0 min(525px, 100% - 330px); }

  /* Cinq tuiles sur TROIS colonnes, donc 3 puis 2 (Leo 21/09/2026 : la
     sixième, tarifaire, a été retirée). `flex: 1 1 150px` en donnait quatre
     par ligne dans la colonne de droite, plus étroite que la pleine page. */
  .accueil-chiffres .stat { flex: 1 1 calc(33.333% - 7px); }
  /* Les 39 px valides par Leo : l'etiquette fait ici un tiers de la rangee. */
  .stat-source { height: 39px; }

  /* Imbrication verticale des rangées (Leo 21/09/2026) : une rangée en duo
     qui SUIT une autre rangée en duo remonte, pour que son illustration
     occupe le vide laissé par le texte de la précédente — mesuré : ce texte
     s'arrête 188 px avant le bas du téléphone voisin. Les deux illustrations
     sont sur des côtés opposés (`order: 2` ci-dessus), elles ne peuvent donc
     pas se heurter : seules leurs hauteurs se recouvrent.
     On décrit la CONDITION, pas la liste des blocs. C'est essentiel ici : la
     TROISIÈME rangée en duo de la page suit une bande PLEINE LARGEUR, et une
     règle du genre « tous les duos sauf le premier » la ferait entrer en
     collision avec elle.
     `> .accueil-duo` et non `.accueil-duo` : une règle descendante
     attraperait un duo imbriqué — piège déjà rencontré deux fois ici.
     Un navigateur sans `:has()` retombe sur la mise en page actuelle.
     JAMAIS hors de cette requête média : en colonne étroite les blocs
     s'empilent (mesuré : illustrations pleine largeur, marges de 26 px), et
     une remontée y ferait chevaucher un téléphone et un texte. */
  /* 900 px et non 760 (Leo 21/09/2026, second correctif) : entre ces deux
     largeurs la remontee faisait retomber l'illustration d'une rangee sur le
     TEXTE de la suivante — pas sur son image, contrairement a ce que j'avais
     d'abord diagnostique. La cause n'est pas la largeur des colonnes mais la
     HAUTEUR des rangees : resserrees, leurs paragraphes gagnent des lignes,
     et 70 px de remontee ne suffisent plus a passer en dessous. Balayage
     760/768/820/900/1024/1180/1280 : zero collision a partir de 900. */
  @media (min-width: 900px) {
  .accueil-section:has(> .accueil-duo) + .accueil-section:has(> .accueil-duo) {
    /* -138 et non -70 : le rembourrage vertical des rangées (34 px de chaque
       côté) s'intercale entre deux illustrations et annulait presque tout le
       décalage — mesuré, le chevauchement tombait à 2 px. -138 + 68 = -70,
       la valeur voulue. Changer `padding-block` impose de revoir ce nombre. */
    margin-top: -138px;
    }
  }


  .accueil-profils { flex-direction: row; gap: 28px; }
  .profil { flex: 1; }

  /* Les quatre groupes de prestations : deux cartes par rangée. */
  .accueil-groupes {
    display: grid; grid-template-columns: repeat(2, 1fr);
    gap: 18px; margin-top: 18px; align-items: start;
  }
  .accueil-groupe {
    border: 1px solid var(--regle, #E4E1D8); border-radius: 4px;
    background: #fff; padding: 16px 18px;
  }

  /* Éthique et honnêteté : six fiches sur deux colonnes. Le filet bas des
     listes de fiche ferait un damier une fois en grille. */
  .accueil-fiches {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 30px;
  }
  .accueil-fiches li { border-bottom: 0; }
  .accueil-fiches b { display: block; margin-bottom: 2px; }

  /* Le seul geste appuyé de la page : l'appel à l'élu, en violet plein.
     Tout le reste tient sur le papier, pour que ce bloc-ci se voie. */
  .accueil-elu {
    background: var(--tampon, #5A3FA0);
    border-color: var(--tampon, #5A3FA0);
    padding: 30px 24px 24px;
  }
  .accueil-elu h2, .accueil-elu > p { color: #fff; }
  /* (filet retiré le 21/09/2026 : plus de ::before à centrer ici) */
  .accueil-elu .accueil-appel { color: rgba(255, 255, 255, 0.86); }
  .accueil-elu .bouton {
    background: #fff; color: var(--tampon, #5A3FA0); border-color: #fff;
  }
}

/* ---- statiques / messages ---- */
.baseline { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin: 30px 0 8px; line-height: 1.3; }
.comment p { color: var(--encre); }
.zone { color: var(--encre-2); font-size: 15px; text-align: center; }
.statique p { color: var(--encre); }
/* Carte des alentours (Leo 31/08/2026) : la HAUTEUR est posée par
   alentours-carte.js — sans JS, aucun cadre vide n'apparaît. */
#carte-alentours { border: 1px solid var(--regle); border-radius: 4px; margin: 0 0 14px; }
/* Avis « en cours de rédaction » des pages statiques (Leo 31/08/2026). */
.statique-avis {
  border: 1px solid var(--regle); border-left: 3px solid var(--tampon);
  border-radius: 4px; padding: 10px 12px; font-size: 14.5px; color: var(--encre-2);
}
.message h1 { font-size: 24px; }

/* ---- pipeline photo (tranche 2) ---- */
/* Pages dépôt / prendre / discussion : respiration verticale (20/08). */
#photo-app { margin-top: 22px; }
#photo-app > * + * { margin-top: 22px; }
.discussion > * + * { margin-top: 16px; }
.discussion h1 { margin-bottom: 2px; }
.prises { display: flex; flex-direction: column; gap: 4px; }
.prises .sous-action { margin: 8px 0 2px; }
.prises .bouton { margin: 0; }
.bouton-fichier { position: relative; overflow: hidden; }
.bouton-fichier input[type="file"] {
  position: absolute; inset: 0; opacity: 0; cursor: pointer; font-size: 0;
}
/* État d'envoi : texte normal, court — pas de tampon majuscules (20/08). */
.envoi-etat { margin: 0 0 6px; font-size: 15px; color: var(--encre); }
.progression {
  height: 14px; margin: 14px 0 8px;
  border: 1.5px solid var(--tampon); border-radius: 4px;
  background: #fff; overflow: hidden;
}
.progression-barre {
  height: 100%; width: 0; background: var(--tampon);
  transition: width 0.4s ease;
}

/* ---- administration / modération (tranche 3) ---- */
.admin-table { width: 100%; border-collapse: collapse; font-size: 15px; }
.admin-table td { padding: 8px 6px; border-bottom: 1px solid var(--regle); vertical-align: top; }
.admin-table a { color: var(--tampon); margin-right: 8px; }
.admin-inactive td { color: var(--estompe); }
.admin-textarea {
  display: block; width: 100%; padding: 10px; margin-bottom: 10px;
  font: 13px/1.5 var(--mono); border: 1.5px solid var(--regle); border-radius: 4px;
  background: #fff; color: var(--encre);
}
.admin-select {
  display: block; width: 100%; padding: 12px; margin-bottom: 10px;
  font: 17px/1.2 system-ui, sans-serif;
  border: 1.5px solid var(--regle); border-radius: 4px; background: #fff;
}
.admin-nav a { margin-right: 4px; }
.admin-actions-cellule form { display: inline-block; margin-right: 6px; }

.signaler-types { border: 1px solid var(--regle); border-radius: 4px; padding: 12px 14px; margin: 0 0 14px; }
.signaler-types legend { font-weight: 600; padding: 0 4px; }
.signaler-choix { display: block; padding: 7px 0; cursor: pointer; }

.moderation-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.moderation-photo { margin: 0; }
.moderation-photo img { width: 100%; height: auto; border: 1px solid var(--regle); border-radius: 4px; }
.moderation-photo figcaption { font-size: 13px; color: var(--encre-2); margin: 4px 0; }
.moderation-clore { margin-top: 24px; }

.voucher-encours { border: 2px solid var(--tampon); border-radius: 4px; padding: 14px 16px; margin: 18px 0; }
.voucher-code { font-size: 34px; font-weight: 700; letter-spacing: 0.25em; color: var(--tampon); margin: 6px 0; }
.commercant-code { text-transform: uppercase; letter-spacing: 0.2em; font-size: 22px; }
.commercant-recredit input[type="file"] { display: block; font-size: 13px; margin: 4px 0; }
/* « Max. [N] gagnant(s) par [période] » sur une seule ligne. */
.offre-quota { display: flex; align-items: center; gap: 8px; }
.offre-quota label { margin: 0; }
.offre-quota input { width: 72px; margin: 0; }
.offre-quota-periode { width: auto; margin: 0; }
.admin-inline { display: inline-block; }

.planche-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 20px; }
.planche-carte { margin: 0; text-align: center; border: 1px solid var(--regle); border-radius: 4px; padding: 14px; }
.planche-qr svg { width: 180px; height: 180px; }
.planche-url { font-size: 12px; margin: 6px 0 0; }
@media print {
  .entete, .pied, .planche-cacher-impression { display: none !important; }
  .planche-carte { break-inside: avoid; border: 1px solid #000; }
  main { max-width: none; }
}

/* ---- discussion par boîte (20/08/2026) ---- */
.discussion-fil {
  max-height: 55vh; overflow-y: auto; padding: 6px 2px;
  display: flex; flex-direction: column; gap: 8px;
  border: 1px solid var(--regle); border-radius: 4px; padding: 12px;
  background: #fff;
}
.bulle {
  max-width: 82%; align-self: flex-start;
  background: #F3F0FA; border-radius: 10px 10px 10px 3px;
  padding: 7px 11px; font-size: 15px;
}
.bulle-moi {
  align-self: flex-end; background: var(--tampon); color: #fff;
  border-radius: 10px 10px 3px 10px;
}
.bulle-pseudo { display: block; font-size: 12px; font-weight: 700; opacity: 0.75; }
.bulle-moi .bulle-pseudo { color: #fff; }
.bulle-texte { display: block; word-wrap: break-word; }
.bulle-heure { display: block; font-size: 10.5px; opacity: 0.6; text-align: right; margin-top: 2px; }
.discussion-form { display: flex; gap: 8px; margin-top: 12px; }
.discussion-form input {
  flex: 1; padding: 12px; font: 16px/1.2 system-ui, sans-serif;
  border: 1.5px solid var(--regle); border-radius: 4px; background: #fff; color: var(--encre);
}
.discussion-form input:focus { outline: 2px solid var(--tampon); outline-offset: 1px; }
.discussion-envoyer { width: auto; padding: 12px 18px; }

/* ---- visionneuse plein écran (21/08/2026) ---- */
.visionneuse {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(20, 17, 30, 0.94);
  display: flex; align-items: center; justify-content: center;
}
.visionneuse[hidden] { display: none; }
.visionneuse img {
  max-width: 97vw; max-height: 92vh; width: auto; height: auto;
  border-radius: 4px; box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5);
}
.visionneuse-fermer, .visionneuse-nav {
  position: absolute; z-index: 51;
  background: rgba(252, 251, 248, 0.14); border: none; color: #fff;
  font: 700 30px/1 system-ui, sans-serif; cursor: pointer;
  width: 48px; height: 48px; border-radius: 50%;
}
.visionneuse-fermer:hover, .visionneuse-nav:hover { background: rgba(252, 251, 248, 0.3); }
.visionneuse-fermer { top: 10px; right: 10px; }
/* Flèches SUR l'image (semi-transparentes), plus d'espace perdu autour. */
.visionneuse-prec { left: 4px; top: 50%; transform: translateY(-50%); background: rgba(20, 17, 30, 0.45); }
.visionneuse-suiv { right: 4px; top: 50%; transform: translateY(-50%); background: rgba(20, 17, 30, 0.45); }
.visionneuse-legende {
  position: absolute; left: 0; right: 0; bottom: 16px;
  text-align: center; color: #fff; font-size: 15px; margin: 0; padding: 0 60px;
}

/* ---- encadré « comment gagner » (23/08/2026) ---- */
/* ---- jauge de la boîte et défi (029) ----
   Arc SVG inline : le cadran commence AU PLANCHER, il n'a donc pas de zone
   rouge et l'aiguille n'a pas à être bridée. Couleurs explicites sur l'arc —
   une teinte figée héritée serait invisible selon le fond. */
/* En-tête avec jauge (029) : elle REMPLACE le logo du service — la main, le
   téléphone et la flèche ont été retirés le 15/09/2026 (Leo). Il ne reste que
   le cadran entre un petit et un gros cadeau, qui dispose donc de toute la
   largeur : tailles revues à la hausse. */
.entete-jauge {
  display: flex; align-items: center; justify-content: center;
  gap: 6px; margin: 16px auto 2px;
}
.jauge-cadeaux { display: flex; align-items: center; gap: 4px; }
.jauge-cadeau { width: auto; }
/* Le petit cadeau est retourné en miroir (Leo 15/09/2026) : les deux
   cadeaux regardent ainsi vers le cadran. */
.jauge-cadeau-petit { height: 28px; transform: scaleX(-1); }
.jauge-cadeau-grand { height: 58px; }
/* Centrage (Leo 15/09/2026) : les deux cadeaux n'ont pas la même largeur,
   le cadran était donc tiré vers la gauche. Même emplacement de 58 px des
   deux côtés, image calée CONTRE le cadran — le petit est retourné en miroir,
   son « left » tombe donc à droite à l'écran. */
.jauge-cadeau-petit, .jauge-cadeau-grand {
  width: 58px; object-fit: contain; object-position: left center;
}
/* « continuons ! » : lien stylé en bouton violet, dans le fil de la phrase. */
.jauge-suite {
  display: inline-block; padding: 2px 10px; border-radius: 4px;
  background: var(--tampon, #5A3FA0); color: #fff; font-weight: 600;
  text-decoration: none;
}
.jauge-suite:hover, .jauge-suite:focus-visible { background: #4A3386; color: #fff; }
/* Cible du bouton : un peu d'air au-dessus, et un défilement doux sauf si
   le visiteur a demandé moins d'animations. */
#participer { scroll-margin-top: 16px; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
.entete-jauge .jauge-cadran { width: 160px; height: auto; margin: 0; }
/* Dans l'en-tête, le cadran est déjà dessiné : il ne reste que la phrase et
   le défi, sans encadré. */
.jauge-nue { border: 0; background: none; padding: 0; margin: 2px 0 10px; }

/* Marge du bas portée de 4 à 20 px (Leo 15/09/2026) : l'encart touchait le
   bloc suivant. NB : cette règle, placée APRÈS .jauge-nue et de même
   spécificité, l'emporte sur elle — l'encart de l'en-tête garde donc son
   cadre blanc, ce qui est l'aspect validé. */
.jauge {
  margin: 12px 0 20px; border: 1px solid var(--regle); border-radius: 4px;
  padding: 14px 16px 12px; background: #fff; text-align: center;
}
/* Centrage DÉTERMINISTE : marge auto sur un bloc, sans dépendre d'un
   text-align hérité. */
.jauge-cadran { display: block; margin: 0 auto; }
/* Miniature dans le fil d'un titre : même arc, même aiguille, sans les
   chiffres — illisibles à cette taille. Règle APRÈS .jauge-cadran, dont elle
   doit renverser le display. */
.jauge-cadran-mini {
  display: inline-block; width: auto; height: 2em;
  vertical-align: -0.55em; margin: 0 .12em;
}
.jauge-nombre {
  font: 700 24px/1 ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  fill: var(--encre, #221E33);
}
/* Bornes : des <text> DANS le SVG, calés sur les extrémités de l'arc. */
.jauge-borne { font: 500 12px/1 var(--mono); fill: var(--encre-2, #6B6577); }
.ico-jauge { height: .78em; width: auto; vertical-align: -.06em; }
.jauge-phrase { margin: 4px 0 0; font-size: 15px; }
/* Le cœur de fin de phrase est ROUGE : la teinte vit ici, le SVG reste en
   currentColor. */
.jauge-coeur .ico-coeur { color: #C0392B; }
/* « une boîte à livres vivante et appréciée » : la chute de la phrase, à la
   taille du reste (Leo 15/09/2026 — le 1.2em a été retiré), en demi-gras. */
.jauge-grand { font-weight: 600; }
.jauge-defi { margin: 8px 0 0; font-size: 15px; color: var(--tampon); font-weight: 600; }
.jauge-plein { color: var(--valide); }

/* ---- sondage de commune (028) ----
   Même boîte blanche que l'encadré « gains » : c'est un encadré de la page,
   jamais un passage obligé. Les deux échappatoires sont côte à côte et
   visuellement secondaires — mais ce sont de vrais boutons, pas des liens
   décoratifs : tout le parcours marche sans JS. */
.sondage {
  margin-top: 22px; border: 1px solid var(--regle); border-radius: 4px;
  padding: 12px 16px 16px; background: #fff;
}
.sondage-titre { margin: 0 0 4px; }
.sondage-intro { margin: 0 0 6px; font-style: italic; color: var(--encre-2); }
.sondage-aide { margin: 0 0 12px; font-size: 14px; color: var(--encre-2); }
.sondage-question {
  border: 0; border-top: 1px solid var(--regle); margin: 0; padding: 10px 0 4px;
}
.sondage-question legend { font-size: 14px; font-weight: 600; padding: 0; }
.sondage-question .signaler-choix { display: block; padding: 3px 0; }
.sondage-libre {
  width: 100%; font: inherit; padding: 6px 8px; border: 1px solid var(--regle);
  border-radius: 4px; background: var(--papier); color: var(--encre);
}
.sondage-echappatoires { display: flex; gap: 10px; margin-top: 8px; }
.sondage-echappatoires .bouton { flex: 1; font-size: 14px; }
/* Réponses libres côté mairie : du texte écrit par des visiteurs. */
.sondage-libres { margin: 6px 0 0; padding-left: 18px; font-size: 14px; }
/* Avertissement sous la question libre, dans /mairie. */
.avertissement { color: #8A3324; }

.gains {
  margin-top: 22px; border: 1px solid var(--regle); border-radius: 4px;
  padding: 12px 16px 4px; background: #fff;
}
.gains-titre { margin: 0 0 4px; }
.gains-liste { list-style: none; margin: 0; padding: 0; }
.gain-ligne {
  display: flex; align-items: center; gap: 8px; padding: 9px 0;
  font-size: 15px; border-bottom: 1px solid var(--regle);
}
.gains-liste > li:last-child .gain-ligne { border-bottom: none; }
summary.gain-ligne { cursor: pointer; list-style: none; }
summary.gain-ligne::-webkit-details-marker { display: none; }
.gain-check { color: var(--valide); font-weight: 700; }
.gain-libelle { min-width: 0; }
.gain-pts {
  margin-left: auto; white-space: nowrap;
  color: var(--tampon); font-weight: 600; font-size: 14px;
}
/* Popup en CSS pur : le <details> ouvert pose un fond assombri (::before)
   et son panneau en surimpression ; le summary reste au-dessus (re-clic =
   fermeture sans JS ; boite.js ajoute clic-fond et Échap). */
.gain[open]::before {
  content: ''; position: fixed; inset: 0;
  background: rgba(20, 17, 30, 0.55); z-index: 40;
}
.gain[open] > summary.gain-ligne {
  position: relative; z-index: 41; background: var(--papier);
  border-radius: 4px; padding-left: 6px; padding-right: 6px;
}
.gain-popup {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 41; width: min(92vw, 400px); max-height: 80vh; overflow-y: auto;
  background: var(--papier); border: 1px solid var(--regle); border-radius: 6px;
  padding: 18px; box-shadow: 0 8px 40px rgba(20, 17, 30, 0.35);
}
.gain-popup h3 { margin: 0 0 8px; font-size: 18px; }
.gain-popup p { margin: 0 0 14px; font-size: 15px; }

/* ---- paramètres du compte (23/08/2026) ---- */
.parametres-note { text-align: left; margin: 0 0 8px; }
.parametres-alerte .bouton { margin-top: 8px; }
a.parametres-supprimer { color: var(--alerte); }
.bouton.parametres-supprimer {
  color: var(--alerte); border-color: var(--alerte); background: transparent;
}

/* ---- petits écrans (22/08/2026) ---- */
@media (max-width: 480px) {
  /* Encart exemple empilé : la photo à 30 % devenait un timbre-poste. */
  .exemple-carte { flex-direction: column; }
  .exemple-carte img { width: 100%; flex: none; }
  .exemple-bouton { max-width: none; }
  /* Stats : les trois tuiles restent en rangée, chiffres resserrés. */
  .stat { padding: 10px 4px; }
  .stat-n { font-size: 22px; }
  /* Vitrine (19/09/2026) : titres de section un cran plus bas, encadrés un
     peu moins épais sur les côtés. */
  .accueil-section h2, .accueil-honnete h2, .accueil-elu h2 { font-size: 18px; }
  .accueil-honnete, .accueil-elu { padding-left: 14px; padding-right: 14px; }
}

/* ---- sélection des BD par la mairie (032) ----
   Quatre candidats par emplacement : l'album proposé et ses trois remplaçants.
   Tout tient en HTML : des boutons radio dans un formulaire, aucun JS requis.
   Couleurs avec REPLI — une variable non résolue rendrait l'écran illisible. */
.selection { max-width: 960px; margin: 0 auto; }
.selection-intro { color: var(--encre-2, #6B6577); }
.selection-date {
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 12px; letter-spacing: 0.04em; color: var(--encre-2, #6B6577);
}
.selection-alerte, .selection-valide, .selection-ok {
  border-radius: 4px; padding: 12px 14px; margin: 14px 0;
}
.selection-alerte { border: 1px solid #C0392B; background: #FDF3F2; color: #7B241C; }
.selection-alerte ul { margin: 8px 0 0; padding-left: 20px; }
.selection-valide, .selection-ok { border: 1px solid var(--vert, #2E7D46); background: #F1F8F3; }

.sel-emplacement { border: 0; border-top: 1px solid var(--filet, #E4E1D8); margin: 0; padding: 18px 0 8px; }
.sel-emplacement legend {
  font-weight: 700; font-size: 15.5px;
  color: var(--tampon, #5A3FA0); padding: 0;
}
.sel-aide { margin: 5px 0 0; font-size: 13px; color: var(--encre-2, #6B6577); }
.sel-candidats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 12px; }
.sel-candidat {
  display: flex; flex-direction: column; gap: 4px; cursor: pointer;
  border: 1px solid var(--filet, #E4E1D8); border-radius: 4px; padding: 8px;
  background: var(--papier, #FCFBF8);
}
.sel-candidat:has(input:checked) { border-color: var(--tampon, #5A3FA0); border-width: 2px; padding: 7px; }
.sel-candidat input { margin: 0 0 4px; accent-color: var(--tampon, #5A3FA0); }
.sel-vignette { position: relative; display: block; }
.sel-vignette img {
  display: block; width: 100%; aspect-ratio: 3 / 4; object-fit: contain;
  background: #EFEDE7; border-radius: 2px;
}
.sel-sans-image { display: block; width: 100%; aspect-ratio: 3 / 4; background: #EFEDE7; border-radius: 2px; }
.sel-badge {
  position: absolute; top: 4px; left: 4px; background: var(--tampon, #5A3FA0); color: #fff;
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 2px;
}
.sel-titre { font-weight: 600; font-size: 13.5px; line-height: 1.25; }
.sel-meta, .sel-etat { font-size: 12px; color: var(--encre-2, #6B6577); }
.sel-absent { opacity: 0.5; cursor: not-allowed; }

/* Barre d'action collée en bas : le lot est long, les boutons doivent rester
   sous la main. L'encoche du téléphone s'ajoute au rembourrage, jamais à 0. */
.selection-barre {
  position: sticky; bottom: 0; display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; background: var(--papier, #FCFBF8);
  border-top: 1px solid var(--filet, #E4E1D8);
  padding: 12px 0 calc(12px + env(safe-area-inset-bottom, 0px));
}
.selection-compte { flex: 1; font-size: 13px; color: var(--encre-2, #6B6577); }
/* `.bouton` est pleine largeur dans tout le site : dans la barre, les deux
   actions doivent tenir côte à côte, sans quoi elles s'empilent. */
.selection-barre .bouton { width: auto; display: inline-flex; align-items: center; justify-content: center; }
/* Sans cette ligne, le `display: inline-flex` ci-dessus l'emporterait sur le
   display:none du navigateur et le bouton masqué resterait visible. Piège
   rencontré deux fois en production. */
.selection-barre .bouton[hidden] { display: none; }
.selection-note { font-size: 13px; color: var(--encre-2, #6B6577); margin-top: 18px; }

/* Loupe et visionneuse : révélées par selection.js. `[hidden]` est répété
   explicitement — une règle d'auteur qui pose `display` l'emporte sinon sur le
   display:none du navigateur, et l'élément masqué s'affiche quand même. */
.sel-loupe {
  position: absolute; right: 4px; bottom: 4px;
  background: rgba(252, 251, 248, 0.92); border: 1px solid var(--filet, #E4E1D8);
  border-radius: 3px; font-size: 11px; padding: 2px 7px; cursor: pointer;
  color: var(--encre, #221E33);
}
.sel-loupe[hidden] { display: none; }
.sel-fige { overflow: hidden; }

.sel-visionneuse {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(20, 18, 28, 0.94);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: calc(16px + env(safe-area-inset-top, 0px)) 16px
                     calc(16px + env(safe-area-inset-bottom, 0px));
}
.sel-visionneuse[hidden] { display: none; }
.sel-visionneuse-titre { color: #fff; font-weight: 600; margin: 0; text-align: center; }
.sel-visionneuse-image { flex: 1; display: flex; align-items: center; justify-content: center; min-height: 0; }
.sel-visionneuse-image img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 3px; }
.sel-fermer {
  position: absolute; top: calc(10px + env(safe-area-inset-top, 0px)); right: 12px;
  width: 38px; height: 38px; border-radius: 50%; border: 0;
  background: rgba(255, 255, 255, 0.9); font-size: 22px; line-height: 1; cursor: pointer;
}
.sel-onglets { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.sel-onglet {
  border: 1px solid rgba(255, 255, 255, 0.5); background: transparent; color: #fff;
  border-radius: 999px; padding: 6px 14px; font-size: 13px; cursor: pointer;
}
.sel-onglet.actif { background: #fff; color: var(--encre, #221E33); border-color: #fff; }

.sel-auto {
  position: sticky; bottom: 0; margin: 0; text-align: right;
  font-size: 13px; color: var(--vert, #2E7D46);
}
.sel-auto[hidden] { display: none; }

.sel-auto-info { margin: 18px 0 0; font-size: 13.5px; color: var(--vert, #2E7D46); }
.sel-auto-info[hidden] { display: none; }
/* L'avertissement de validation : appuyé sans être alarmant — la validation
   est irréversible et lance une livraison, mais ce n'est pas une erreur. */
.sel-avert {
  margin: 6px 0 0; padding: 10px 12px; font-size: 13.5px;
  border-left: 3px solid var(--tampon, #5A3FA0);
  background: var(--papier-2, #F6F4EF); border-radius: 0 3px 3px 0;
}

@media (max-width: 640px) {
  .sel-candidats { grid-template-columns: repeat(2, 1fr); }
  .selection-barre .bouton { flex: 1; }
}

/* ---- LE MUR DU LOT (032, 18/09/2026) ----
   Remplace la grille « un emplacement = quatre radios » : à quatorze
   récompenses, celle-ci empilait 56 vignettes. Les règles .sel-emplacement et
   .sel-candidats ci-dessus ne sont plus employées — laissées en place plutôt
   que retirées à l'aveugle, comme le veut le projet. */
.sel-etat { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 18px 0 12px; }
.sel-etat b { font-size: 13.5px; }
.sel-jauge { flex: 1; min-width: 150px; height: 7px; border-radius: 99px; background: var(--filet, #E4E1D8); overflow: hidden; }
.sel-jauge i { display: block; height: 100%; background: var(--tampon, #5A3FA0); }
.sel-etat-detail { font-size: 13px; color: var(--encre-2, #6B6577); }

/* auto-fill et non six colonnes fixes : à trois récompenses, une grille figée
   tassait les cartes en timbres-poste dans un coin. Le padding du haut laisse
   la place à la pastille numérotée, qui déborde de 7 px. */
.sel-mur {
  display: grid; gap: 12px; padding-top: 10px;
  grid-template-columns: repeat(auto-fill, minmax(155px, 1fr));
}
.sel-carte {
  position: relative; display: flex; flex-direction: column; gap: 5px;
  border: 1px solid var(--filet, #E4E1D8); border-radius: 4px; padding: 7px;
  background: #fff; text-decoration: none; color: inherit; cursor: pointer;
}
.sel-carte:hover, .sel-carte:focus-visible { border-color: var(--tampon, #5A3FA0); }
.sel-carte-modifiee { border-color: var(--tampon, #5A3FA0); border-width: 2px; padding: 6px; }
.sel-carte img { width: 100%; aspect-ratio: 3 / 4; object-fit: contain; background: #EFEDE7; border-radius: 2px; }
.sel-num {
  position: absolute; top: -7px; left: -7px; width: 22px; height: 22px; border-radius: 50%;
  background: var(--encre, #221E33); color: #fff; text-align: center;
  font: 600 11px/22px ui-monospace, Menlo, monospace;
}
.sel-carte-titre { font-size: 12.5px; font-weight: 600; line-height: 1.25; }
.sel-carte-chg {
  font: 10px/1 ui-monospace, Menlo, monospace; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--tampon, #5A3FA0);
}
.sel-carte-chg[hidden] { display: none; }

/* Barre fixe : l'avertissement y est AVEC le bouton, pour qu'on ne puisse plus
   valider sans l'avoir sous les yeux — il défilait hors champ auparavant. */
.sel-barre {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  background: var(--papier, #FCFBF8); border-top: 1px solid var(--filet, #E4E1D8);
  padding: 12px 18px calc(12px + env(safe-area-inset-bottom, 0px));
}
.sel-barre-in { max-width: 1000px; margin: 0 auto; display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
.sel-barre .sel-avert {
  flex: 1; min-width: 260px; margin: 0; font-size: 12.5px; color: var(--encre-2, #6B6577);
  border-left: 3px solid var(--tampon, #5A3FA0); padding: 0 0 0 10px; background: none; border-radius: 0;
}
.sel-barre .sel-auto-info { margin: 0; font-size: 12.5px; color: var(--vert, #2E7D46); }
.sel-barre form { margin: 0; }
.sel-barre .bouton { width: auto; }

.sel-fenetre {
  position: fixed; inset: 0; z-index: 50; background: rgba(20, 18, 28, 0.55);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.sel-fenetre[hidden] { display: none; }
.sel-fen {
  position: relative; background: var(--papier, #FCFBF8); border-radius: 6px;
  max-width: 940px; width: 100%; max-height: 92vh; overflow: auto; padding: 22px;
}
.sel-fen-titre { margin: 0 0 3px; font-size: 19px; }
.sel-fen-intro { margin: 0 0 16px; font-size: 13.5px; color: var(--encre-2, #6B6577); }
.sel-fen-cands { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.sel-cand {
  display: flex; flex-direction: column; gap: 7px; background: #fff;
  border: 1px solid var(--filet, #E4E1D8); border-radius: 4px; padding: 9px;
}
.sel-cand-retenu { border: 2px solid var(--tampon, #5A3FA0); padding: 8px; }
.sel-cand img { width: 100%; aspect-ratio: 3 / 4; object-fit: contain; background: #EFEDE7; border-radius: 2px; }
.sel-cand-badge {
  margin: 0; align-self: flex-start; background: var(--tampon, #5A3FA0); color: #fff;
  font: 10px/1 ui-monospace, Menlo, monospace; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 3px 7px; border-radius: 2px;
}
.sel-cand-titre { margin: 0; font-size: 12.5px; font-weight: 600; line-height: 1.25; }
.sel-cand-meta { margin: 0; font-size: 11.5px; color: var(--encre-2, #6B6577); }
.sel-cand .bouton { margin-top: auto; width: 100%; }
.sel-vues-liens { display: flex; gap: 5px; flex-wrap: wrap; margin: 0; }
.sel-vues-liens a, .sel-vues-liens button {
  /* `font: 10.5px inherit` était INVALIDE — le raccourci exige une famille
     réelle, et le navigateur jetait la déclaration entière : les pilules
     s'affichaient en taille normale et débordaient. */
  font-size: 10.5px; font-family: inherit; line-height: 1.4;
  border: 1px solid var(--filet, #E4E1D8); background: #fff;
  color: var(--encre-2, #6B6577); border-radius: 99px; padding: 2px 8px; cursor: pointer; text-decoration: none;
}
.sel-retour { margin: 0 0 10px; font-size: 13.5px; }

/* Visionneuse plein écran (032) : la grande image pèse ~200 Ko, d'où le témoin
   d'attente — sans lui, on clique et rien ne bouge pendant deux secondes. Il
   est dessiné en CSS : un pictogramme à télécharger aurait le défaut qu'il est
   censé masquer. */
.sel-plein {
  position: fixed; inset: 0; z-index: 60; background: rgba(18, 16, 24, 0.95);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: calc(18px + env(safe-area-inset-top, 0px)) 18px calc(18px + env(safe-area-inset-bottom, 0px));
}
.sel-plein[hidden] { display: none; }
.sel-plein-titre { margin: 0; color: #fff; font-weight: 600; text-align: center; }
.sel-plein-image {
  position: relative; flex: 1; min-height: 0; width: 100%;
  display: flex; align-items: center; justify-content: center;
}
.sel-plein-image img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 3px; }
.sel-plein-image.sel-chargement::after {
  content: ""; position: absolute; width: 38px; height: 38px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.25); border-top-color: #fff;
  animation: sel-tourne 0.8s linear infinite;
}
@keyframes sel-tourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .sel-plein-image.sel-chargement::after { animation: none; }
}
.sel-plein-fermer {
  position: absolute; top: calc(12px + env(safe-area-inset-top, 0px)); right: 14px;
  width: 40px; height: 40px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(255, 255, 255, 0.92); font-size: 24px; line-height: 1;
}
.sel-plein-onglets { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.sel-plein-onglet {
  border: 1px solid rgba(255, 255, 255, 0.45); background: transparent; color: #fff;
  border-radius: 999px; padding: 6px 14px; font-size: 13px; font-family: inherit; cursor: pointer;
}
.sel-plein-onglet.actif { background: #fff; color: var(--encre, #221E33); border-color: #fff; }
.sel-cand img { cursor: zoom-in; }

/* Le mur n'a plus de palier : auto-fill s'adapte seul. Seule la fenêtre, à
   quatre colonnes fixes, doit se replier sur les petits écrans. */
@media (max-width: 620px) {
  .sel-fen-cands { grid-template-columns: repeat(2, 1fr); }
}

/* accessibilité */
:focus-visible { outline: 2px solid var(--tampon); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .rayon-bande { animation: none; }
}
