/* ════════════════════════════════════════════════════════════
   InfoTri — styles au-delà des utilitaires Tailwind
   ════════════════════════════════════════════════════════════ */

/* ── Fond des pages ─────────────────────────────────────────
   Aplat `#F8FAFC` tant qu'aucun dégradé n'est réglé — soit exactement ce que
   faisait la classe `bg-paper`. `min-height` et `fixed` : sans eux, un
   dégradé vertical se répéterait sur une page courte et se recalculerait au
   défilement sur une page longue. */
body {
  background: var(--page-fond, #F8FAFC);
  background-attachment: fixed;
  min-height: 100vh;
}

/* ── En-tête ────────────────────────────────────────────────
   Aplat de la couleur principale de la commune — la même que la barre
   supérieure de l'application. Tout ce qui s'y pose prend `--commune-sur`,
   le jeton de texte calculé pour cet aplat : une commune à couleur claire
   obtient du texte sombre, une commune à couleur soutenue du texte clair.
   Le liseré du bas garde l'en-tête visible quand l'aplat est presque blanc. */
.py-5{
padding-top: 1.25rem;	
padding-bottom: 1.25rem;
padding-left: 1.25rem;	
padding-right: 1.25rem;	
	
}
#entete {
  /* `--entete-fond` vaut l'aplat communal tant qu'aucun dégradé n'est réglé,
     et un `linear-gradient(…)` sinon. Le repli garde la barre colorée même
     si le gabarit est servi sans ces jetons. */
  background: var(--entete-fond, var(--commune));
  color: var(--entete-sur, var(--commune-sur));
  /* Ce que la barre CONTIENT lit `--commune-sur`, `--sur-commune-voile` et
     `--sur-commune-trait`. Les redéfinir ici suffit : la cascade porte les
     nouvelles valeurs jusqu'aux boutons, aux pastilles de langue et au
     liseré, sans qu'aucun des quatre usages n'ait à être retouché. */
  --commune-sur:       var(--entete-sur);
  --sur-commune-voile: var(--entete-voile);
  --sur-commune-trait: var(--entete-trait);
  /*box-shadow: inset 0 -1px 0 var(--sur-commune-trait);*/
}
#entete.est-colle { /*box-shadow: inset 0 -1px 0 var(--sur-commune-trait),
                                0 6px 24px rgba(11, 18, 32, .10);*/ }
/* Limité à `> div`, la barre supérieure : le menu mobile est un panneau
   blanc opaque, ses liens hériteraient sinon d'un texte clair sur fond clair. */
#entete > div a, #entete > div button { color: inherit; }
/* Le panneau du menu mobile est blanc : il reprend l'encre du site, pas la
   couleur de texte calculée pour l'aplat communal. */
#menu-mobile { color: #0B1220; }

/* Liens de navigation : l'inactif s'estompe, l'actif reprend l'opacité
   pleine. Jouer sur l'opacité plutôt que sur une seconde couleur évite
   d'avoir à calculer un « gris » lisible sur chaque teinte communale. */
#entete > div .nav-lien          { opacity: .72; }
#entete > div .nav-lien:hover,
#entete > div .nav-lien.est-actif { opacity: 1; }
#entete > div .nav-lien::after   { background: currentColor; }

.btn-entete:hover                  { background: var(--sur-commune-voile); }
/* Pleine opacité, et non `.72`.
   L'opacité ne change pas la couleur déclarée : elle MÉLANGE le texte avec
   le fond, et le contraste réel n'est plus celui du jeton. Mesuré, le
   retrait coûtait environ un point et demi — sur le bleu de Vevey la
   pastille tombait à 3,44:1 quand le lien voisin tenait 4,98:1, pour du
   texte de 12 px qui demande 4,5:1.
   La pastille courante se distingue par son APLAT, pas par la pâleur des
   autres : l'indice est plus fort, et il ne coûte rien à la lisibilité. */
#entete .pastille-langue            { opacity: 1; }
#entete .pastille-langue:hover      { background: var(--sur-commune-voile); }
#entete .pastille-langue.est-active { opacity: 1; background: var(--commune-sur);
                                      color: var(--commune); }

/* Soulignement animé des liens de navigation : le trait naît du
   centre, ce qui se lit comme un accent et non comme une bordure. */
.nav-lien::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; border-radius: 2px;
  background: var(--commune-texte);
  transform-origin: center;
  transition: transform .25s cubic-bezier(.22,1,.36,1);
}

/* ── Apparition au défilement ───────────────────────────────
   Une seule propriété animée (transform + opacity) : le compositeur
   s'en charge, sans recalcul de mise en page. */
.reveal {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity .55s cubic-bezier(.22,1,.36,1),
              transform .55s cubic-bezier(.22,1,.36,1);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.reveal.vu { opacity: 1; transform: none; }

/* ── Cartes ─────────────────────────────────────────────────
   L'élévation change, jamais la taille : une carte qui grandit au
   survol décale ses voisines et fait sautiller la grille. */
.carte {
  transition: border-color .2s ease, box-shadow .25s ease, background-color .2s ease;
}
.carte:hover {
  border-color: var(--commune-texte);
  box-shadow: 0 12px 30px -18px rgba(11,18,32,.35);
}

/* Filet coloré qui se déploie sur le bord gauche au survol. */
.carte-accent { position: relative; overflow: hidden; }
.carte-accent::before {
  content: '';
  position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--commune-texte);
  transform: scaleY(0); transform-origin: top;
  transition: transform .3s cubic-bezier(.22,1,.36,1);
}
.carte-accent:hover::before { transform: scaleY(1); }

/* ── Blocs d'accès rapide de l'accueil ──────────────────────
   Carte blanche, en portrait : une bande photographique en haut — ou un aplat
   de la couleur de la commune quand aucune image n'est déposée — puis le
   pictogramme et le titre, lisibles en permanence.

   Les proportions viennent d'une maquette fournie, mesurée au pixel : rapport
   de la bande, écarts et rayon y sont relevés et notés à chaque déclaration.

   Elles sont écrites ici et non en utilitaires `group-hover:` éparpillés :
   une proportion qui se lit à six endroits différents se corrige à cinq.

   Chaque `:hover` est doublé d'un `:focus-visible` : le relief de la carte
   doit répondre au clavier comme à la souris.
   ────────────────────────────────────────────────────────── */
.carte-acces {
  /* Rayon, fond et ombre relevés sur la maquette : la carte est un objet
     blanc posé sur la page, et non une fenêtre ouverte dans une photo. */
  border-radius: 22px;
  background: #fff;
  box-shadow: 0 10px 30px -18px rgba(11, 18, 32, .35);
  transition: box-shadow .25s ease, transform .25s ease;
}
.carte-acces:hover,
.carte-acces:focus-visible {
  transform: translateY(-4px);
  box-shadow: 0 20px 46px -20px rgba(11, 18, 32, .45);
}

/* Rapport de la bande du haut, mesuré sur la maquette : 520 de large pour
   283 de haut. Il est tenu quelle que soit la longueur du titre — sans lui,
   les quatre cartes d'une rangée n'auraient pas la même photo. */
.carte-acces .acces-media { aspect-ratio: 520 / 283; }

/* La photo s'approche à peine. `scale` seul : aucune propriété de mise en
   page n'est touchée, le compositeur suffit et la grille ne bouge pas. */
.carte-acces .acces-photo { transform: scale(1); transition: transform .4s ease; }
.carte-acces:hover .acces-photo,
.carte-acces:focus-visible .acces-photo { transform: scale(1.06); }

/* Écarts en POURCENTAGE de la largeur, comme dans la maquette : un `padding`
   en pourcentage se résout sur la largeur du bloc, et la carte garde donc ses
   proportions d'une colonne à quatre.
   Mesures : 64/520 sur les côtés, 41/520 au-dessus du pictogramme,
   66/520 entre le pictogramme et le titre, 29/520 sous le titre. */
.carte-acces .acces-corps { padding: 8% 12% 7%; }
.carte-acces .acces-ico   { margin-bottom: 11%; }

/* ── Ce qui a disparu, et pourquoi ──
   Le voile sombre, l'état « révélé » et la pastille en feuille ne sont plus
   là : la maquette montre une carte dont le pictogramme et le titre sont
   lisibles en permanence, et un voile qui les recouvrirait au survol
   masquerait précisément ce qu'elle met en avant.

   Avec eux disparaît la règle `@media (hover: none)` : il n'y a plus d'état
   à rendre permanent au doigt, tout est déjà visible.

   ⚠ Toute modification ici doit être reportée dans `previewAcces()`
   (`cms_tri/index.php`), qui redessine la carte pour l'aperçu du back-office.
   ────────────────────────────────────────────────────────── */

/* ── Titres de section ──────────────────────────────────────
   Le trait précède le titre et se lit comme une marque de chapitre. */
.titre-section { display: flex; align-items: center; gap: .75rem; }
.titre-section::before {
  content: ''; width: 28px; height: 3px; border-radius: 2px;
  background: var(--commune-texte); flex: none;
}

/* ── Pied de page ───────────────────────────────────────────
   Blanc tant qu'aucun dégradé n'est réglé — `--pied-fond` vaut alors
   `#FFFFFF` et rien ne change. Avec un dégradé, la classe `a-degrade`
   reprend la main sur les couleurs de texte : le pied emploie `text-muted`
   et `text-commune`, deux encres calculées pour un fond CLAIR, qui
   disparaîtraient sur un dégradé soutenu. */
#pied { background: var(--pied-fond, #FFFFFF); color: var(--pied-sur, #0B1220); }

#pied.a-degrade              { border-top-color: transparent; }
#pied.a-degrade .text-muted,
#pied.a-degrade .text-commune,
#pied.a-degrade a            { color: var(--pied-sur); }
/* Les libellés secondaires gardent leur retrait, par l'opacité et non par
   une seconde couleur : une teinte intermédiaire devrait être recalculée
   pour chaque dégradé, l'opacité suit toute seule. */
#pied.a-degrade .text-muted  { opacity: .82; }
#pied.a-degrade a:hover      { opacity: 1; }
/* Les traits fins du pied sont des `border-hair`, un gris clair invisible
   sur un fond sombre : on les tire de l'encre, donc du dégradé. */
#pied.a-degrade .border-hair {
  border-color: color-mix(in srgb, var(--pied-sur) 30%, transparent);
}
@supports not (color: color-mix(in srgb, red 30%, transparent)) {
  #pied.a-degrade .border-hair { border-color: var(--pied-sur); }
}

/* ── Calendrier ─────────────────────────────────────────────*/
.jour-collecte { position: relative; }
.jour-collecte .pastilles {
  position: absolute; left: 50%; bottom: 6px;
  transform: translateX(-50%);
  display: flex; gap: 3px;
}
.jour-collecte .pastille { width: 5px; height: 5px; border-radius: 50%; }

/* ── Pastille active (index alphabétique, filtres) ──────────
   Un aplat prend la couleur d'identité de la commune, jamais sa variante
   assombrie : celle-ci est calculée pour porter du TEXTE sur fond clair, et
   l'employer comme fond donnait un pavé noir chez les communes à couleur
   claire — l'une des nôtres est blanche, sa variante lisible est l'encre.
   Le texte posé dessus prend le jeton prévu pour ça, et un liseré garde la
   pastille visible quand l'aplat est presque blanc. */
/* `!important` assumé : la pastille porte `bg-white` en utilitaire, de même
   spécificité que cette classe, et la feuille de Tailwind est injectée après
   la nôtre — elle gagnait donc sur le fond mais pas sur la couleur du texte,
   ce qui donnait du blanc sur blanc. Un état doit primer sur un utilitaire. */
.lettre-active { background: var(--commune) !important;
                 color: var(--commune-sur) !important;
                 border-color: var(--commune-texte) !important;
                 box-shadow: inset 0 0 0 1px var(--commune-texte); }

/* ── Focus visible ──────────────────────────────────────────
   Anneau épais et contrasté : c'est le seul repère d'un utilisateur
   au clavier. Posé sur :focus-visible pour ne pas gêner la souris. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--commune-texte);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ── Respect des préférences de mouvement ───────────────────
   Le contenu reste intégralement accessible : seules les
   transitions disparaissent, aucun élément ne reste masqué. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  /* Les transitions sont déjà ramenées à l'instantané ci-dessus, mais un bond
     d'échelle de 15 % reste du mouvement : sur une photo plein cadre, c'est le
     geste le plus brusque de la page. L'état révélé, lui, demeure accessible —
     il apparaît simplement d'un coup. */
  .carte-acces .acces-photo,
  .carte-acces:hover .acces-photo,
  .carte-acces:focus-visible .acces-photo { transform: none !important; }
}

/* ── Impression ─────────────────────────────────────────────
   Un calendrier de collecte finit souvent sur un frigo. */
@media print {
  #entete, footer, .sans-impression { display: none !important; }
  main { padding-top: 0 !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
}

/* ── Icônes de catégorie ────────────────────────────────────
   Même police et mêmes codes que le back-office et l'application
   (`cms_tri/admin.css`, `infotri_icons.dart`) : une catégorie doit porter
   le même pictogramme partout. Toute icône ajoutée là-bas doit l'être ici. */
@font-face {
  font-family: 'Infotri';
  src: url('fonts/Infotri.ttf') format('truetype');
  font-weight: normal; font-style: normal; font-display: swap;
}
.infotri-icon { font-family: 'Infotri'; font-style: normal; font-weight: normal;
                line-height: 1; speak: none; }
.infotri-icon[data-slug="sac"]::before { content: "\e800"; }
.infotri-icon[data-slug="papier"]::before { content: "\e801"; }
.infotri-icon[data-slug="vegetable"]::before { content: "\e802"; }
.infotri-icon[data-slug="gazon"]::before { content: "\e803"; }
.infotri-icon[data-slug="dechets_verts"]::before { content: "\e803"; }
.infotri-icon[data-slug="verres"]::before { content: "\e804"; }
.infotri-icon[data-slug="alu"]::before { content: "\e805"; }
.infotri-icon[data-slug="reste_repas"]::before { content: "\e806"; }
.infotri-icon[data-slug="encombrant"]::before { content: "\e807"; }
.infotri-icon[data-slug="bois"]::before { content: "\e808"; }
.infotri-icon[data-slug="ferraille"]::before { content: "\e809"; }
.infotri-icon[data-slug="pet"]::before { content: "\e80a"; }
.infotri-icon[data-slug="inertes"]::before { content: "\e80b"; }
.infotri-icon[data-slug="textile"]::before { content: "\e80c"; }
.infotri-icon[data-slug="vaisselle"]::before { content: "\e80d"; }
.infotri-icon[data-slug="flacons"]::before { content: "\e80e"; }
.infotri-icon[data-slug="berlingots"]::before { content: "\e80f"; }
.infotri-icon[data-slug="capssules"]::before { content: "\e810"; }
.infotri-icon[data-slug="electriques"]::before { content: "\e811"; }
.infotri-icon[data-slug="cd"]::before { content: "\e812"; }
.infotri-icon[data-slug="pilles"]::before { content: "\e813"; }
.infotri-icon[data-slug="cartouches"]::before { content: "\e814"; }
.infotri-icon[data-slug="huiles_vegetales"]::before { content: "\e815"; }
.infotri-icon[data-slug="dechets_speciaux"]::before { content: "\e816"; }
.infotri-icon[data-slug="aerosol"]::before { content: "\e817"; }
.infotri-icon[data-slug="medicaments"]::before { content: "\e818"; }
.infotri-icon[data-slug="peintures_eau"]::before { content: "\e819"; }
.infotri-icon[data-slug="peintures"]::before { content: "\e81a"; }
.infotri-icon[data-slug="huiles_minerals"]::before { content: "\e81b"; }
.infotri-icon[data-slug="pneus"]::before { content: "\e81c"; }
.infotri-icon[data-slug="batteries"]::before { content: "\e828"; }
.infotri-icon[data-slug="composte"]::before { content: "\e81e"; }
.infotri-icon[data-slug="sagexes"]::before { content: "\e81f"; }
.infotri-icon[data-slug="animals"]::before { content: "\e820"; }
.infotri-icon[data-slug="conserves"]::before { content: "\e821"; }
.infotri-icon[data-slug="alu_conserves"]::before { content: "\e822"; }
.infotri-icon[data-slug="huiles_minerals_vegetals"]::before { content: "\e823"; }
.infotri-icon[data-slug="neons"]::before { content: "\e824"; }
.infotri-icon[data-slug="dechetrie_mobile"]::before { content: "\e829"; }
.infotri-icon[data-slug="ecopoint"]::before { content: "\e826"; }
.infotri-icon[data-slug="dechetrie_fix"]::before { content: "\e827"; }

/* ── L'attribut `hidden` doit gagner ────────────────────────
   Une classe utilitaire de display (`inline-flex`, `grid`, `block`…) a plus
   de poids que la règle `[hidden]` du navigateur : sans ceci, tout élément
   masqué par le script mais porteur d'une telle classe reste affiché. */
[hidden] { display: none !important; }

/* ── Calendrier : jour sélectionné ──────────────────────────
   Anneau plein plutôt qu'un simple changement de bordure : à 45 px de côté,
   une bordure de 1 px ne se distingue pas assez de l'état « a des collectes ». */
.jour-actif { border-color: var(--commune-texte) !important;
              box-shadow: inset 0 0 0 1.5px var(--commune-texte); }

/* Le <dialog> natif garde ses marges auto : on le recentre sans écraser
   `display`, sinon la fermeture ne le masquerait plus. */
#detail-collecte { margin: auto; }
#detail-collecte::backdrop { background: rgba(11, 18, 32, .45); }

/* ── Abécédaire : titres de lettre collants ─────────────────
   Le décalage est mesuré par le script, pas figé : la barre de recherche
   change de hauteur selon que l'index alphabétique tient sur une ligne ou
   sur trois. Une valeur en dur y cachait les titres derrière la barre sur
   téléphone, et les laissait flotter à vide quand l'index était absent. */
.abc-titre { top: var(--abc-decalage, 13rem); }
/* Deux colonnes : le panneau de recherche passe à gauche, il n'est donc plus
   au-dessus de la liste. Les titres de lettre se collent alors sous l'en-tête
   du site, et non sous un bandeau qui n'existe plus à cet endroit. */
@media (min-width: 1024px) {
  .abc-titre { top: 6rem; }
}

/* ── Contenu riche du back-office ───────────────────────────
   Les champs de l'abécédaire sortent d'un éditeur TinyMCE. Tailwind remet
   les marges des balises à zéro : sans ces règles, listes et paragraphes
   arrivent collés et le texte de la commune paraît mal saisi. */
.prose-abc > * + *       { margin-top: 0.75em; }
.prose-abc p             { margin: 0; }
.prose-abc strong, .prose-abc b { font-weight: 600; }
.prose-abc em, .prose-abc i     { font-style: italic; }
.prose-abc u             { text-decoration: underline; text-underline-offset: 2px; }
.prose-abc ul            { list-style: disc;    padding-left: 1.25em; }
.prose-abc ol            { list-style: decimal; padding-left: 1.35em; }
.prose-abc li + li       { margin-top: 0.3em; }
.prose-abc h2, .prose-abc h3, .prose-abc h4 {
  font-weight: 600; font-size: 1em; margin-top: 1em;
}
.prose-abc blockquote    { border-left: 2px solid #E2E8F0; padding-left: 1em; color: #475569; }
.prose-abc a             { color: var(--commune-texte); text-decoration: underline;
                           text-underline-offset: 2px; }

/* ── Actualités : la liste et l'article ─────────────────────
   Tous les articles sont dans la page ; un seul s'affiche.

   DEUX mécanismes, rendus exclusifs par le SÉLECTEUR et non par un
   `!important` : chaque règle est gardée par `:not(.js-actus)` ou par
   `.js-actus`. Sans cette garde, la règle du repli — qui porte un
   `:not(:has(…))`, donc une spécificité élevée — l'emportait sur celle du
   script, et le premier article restait affiché quoi qu'on clique.

   Sans JavaScript, c'est `:target` qui décide : le lien pose l'ancre, le
   navigateur fait le reste, la page reste utilisable. Dès que le script
   s'installe, il pose `js-actus` et reprend la main. */
.actu-zone:not(.js-actus) .actu-detail { display: none; }
.actu-zone:not(.js-actus) .actu-detail:target { display: block; }

/* Le plus récent tant que rien n'est visé : `articles()` trie par date
   décroissante, le premier du bloc est donc la dernière publication.
   `:has()` est le seul moyen de dire « aucun frère n'est visé » ; là où il
   manque, la règle tombe et la page attend un clic — dégradation
   acceptable, et il n'existe pas d'autre chemin en CSS pur. */
.actu-zone:not(.js-actus):not(:has(.actu-detail:target)) .actu-detail:first-child {
  display: block;
}

.actu-zone.js-actus .actu-detail { display: none; }
.actu-zone.js-actus .actu-detail.est-visible { display: block; }

/* Entrée de liste. L'état courant se marque sur le fond ET sur le titre :
   la seule couleur ne suffirait pas à qui ne la distingue pas. */
.actu-lien:hover .actu-titre { color: var(--commune-texte); }
.actu-lien.est-actif { background: color-mix(in srgb, var(--commune) 8%, transparent); }
.actu-lien.est-actif .actu-titre { color: var(--commune-texte); }

/* Repli pour les navigateurs sans `color-mix` : un gris neutre vaut mieux
   qu'aucun fond du tout, l'entrée courante devant rester repérable. */
@supports not (background: color-mix(in srgb, red 8%, transparent)) {
  .actu-lien.est-actif { background: #F1F5F9; }
}

/* Le changement d'article ne doit pas donner l'impression d'un
   rechargement : une apparition courte, et rien du tout si le visiteur a
   demandé moins d'animation. */
.actu-zone.js-actus .actu-detail.est-visible { animation: actu-entre 0.22s ease-out both; }
@keyframes actu-entre {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .actu-zone.js-actus .actu-detail.est-visible { animation: none; }
}

/* ── Formulaire de contact ──────────────────────────────────
   Le piège. Masqué SANS `display:none` ni `hidden` : certains robots
   ignorent les champs ainsi cachés, justement parce que c'est le piège le
   plus connu. On le sort de l'écran à la place — il reste un champ ordinaire
   pour qui lit le HTML, et il est hors du parcours clavier et des lecteurs
   d'écran par `tabindex` et `aria-hidden` dans le gabarit. */
.piege-contact {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ── Points de collecte ─────────────────────────────────────
   La carte occupe tout l'écran ; les panneaux flottent dessus. Leaflet pose
   ses propres couches en z-index 400-700, d'où les valeurs élevées côté
   panneaux — sans quoi la carte passerait devant la recherche. */
.leaflet-container            { font-family: inherit; background: #F1F5F9; }
/* Désaturation réservée au fond OpenStreetMap, le seul assez coloré pour
   concurrencer les pastilles de collecte. Positron et DataViz sont déjà des
   palettes sourdes : mesuré côte à côte, le filtre n'y change rien de visible,
   et il imposerait une couche de composition à chaque déplacement de la carte.
   Le filtre ne porte que sur les tuiles : marqueurs et infobulles vivent dans
   d'autres couches et gardent leurs couleurs exactes. */
.fond-osm .leaflet-tile-pane { filter: saturate(.85); }
/* Leaflet pose ses contrôles en z-index 1000 : sans cela, le zoom et la
   mention de source passaient devant les panneaux — et sur téléphone, en
   plein milieu de la fiche de détail. */
.panneau-recherche, .panneau-detail { z-index: 1100; }
@media (max-width: 1023px) {
  .panneau-detail                   { z-index: 1200; }
}
/* Panneau de détail ouvert : le zoom se décale pour rester atteignable au
   lieu de disparaître dessous. */
@media (min-width: 1024px) {
  .detail-ouvert .leaflet-bottom.leaflet-right { right: 440px; transition: right .22s ease; }
}
.leaflet-control-attribution  { font-size: 10px; }
.leaflet-tooltip              { border: none; border-radius: 8px; font-weight: 600;
                                font-size: 12px; box-shadow: 0 4px 16px rgba(11,18,32,.16); }

/* Barre de défilement horizontale des puces : présente mais discrète. */
.defile-discret                        { scrollbar-width: thin; }
.defile-discret::-webkit-scrollbar     { height: 4px; }
.defile-discret::-webkit-scrollbar-thumb { background: #E2E8F0; border-radius: 4px; }

/* Puce de filtre — même objet que l'index alphabétique, d'où `.lettre-active`
   comme état commun. Le `select` est stylé pareil pour que la rangée se lise
   comme une seule famille de contrôles. */
.puce {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid #E2E8F0; border-radius: 9999px;
  background: #fff; padding: 7px 14px;
  font-size: 13px; font-weight: 500; color: #0B1220;
  white-space: nowrap; cursor: pointer;
  transition: border-color .2s, background-color .2s, color .2s;
}
.puce:hover   { border-color: #0B1220; }
select.puce   { padding-right: 30px; appearance: none;
                background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
                background-repeat: no-repeat; background-position: right 10px center;
                background-size: 14px; }

/* Fiche de résultat dans le panneau de gauche. */
.fiche-point {
  display: flex; align-items: flex-start; gap: 12px; width: 100%;
  border: 1px solid transparent; border-radius: 16px;
  padding: 12px; text-align: left; cursor: pointer;
  transition: background-color .18s, border-color .18s;
}
.fiche-point:hover        { background: #F8FAFC; border-color: #E2E8F0; }
.point-vise .fiche-point  { background: var(--commune-voile); border-color: var(--commune-texte); }

/* État d'ouverture : la couleur seule ne suffit pas — le libellé la double,
   pour qui ne distingue pas le rouge du vert. */
.etat               { display: inline-flex; align-items: center; gap: 6px; font-weight: 500; }
.etat::before       { content: ''; width: 8px; height: 8px; border-radius: 50%;
                      background: currentColor; flex: none; }
.etat-ouvert        { color: #15803D; }
.etat-ferme         { color: #B91C1C; }
.etat-inconnu       { color: #475569; }

/* Apparition du panneau de détail : glissé sur grand écran, fondu sur
   téléphone où il occupe tout l'écran et n'a nulle part d'où glisser. */
.panneau-detail          { opacity: 0; transform: translateX(16px);
                           transition: opacity .22s ease, transform .22s ease; }
.panneau-detail.est-ouvert { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .panneau-detail        { transition: none; transform: none; }
}
@media (max-width: 1023px) {
  .panneau-detail        { transform: none; }
}

/* ── Points de collecte : carte et infobulles ───────────────
   Leaflet impose son propre style d'infobulle ; on l'aligne sur le reste du
   site plutôt que de laisser deux typographies cohabiter sur la même page. */
.leaflet-popup-content-wrapper { border-radius: 14px; box-shadow: 0 8px 32px rgba(11,18,32,.16); }
.leaflet-popup-content         { margin: 14px 16px; font-family: inherit; }
.popup-point                   { display: grid; gap: 2px; font-size: 14px; color: #0B1220; }
.popup-point strong            { font-size: 15px; font-weight: 700; }
.popup-type                    { font-size: 11px; font-weight: 600; text-transform: uppercase;
                                 letter-spacing: .08em; }
.popup-adr                     { color: #475569; }
.popup-titre                   { margin-top: 10px; font-size: 11px; font-weight: 600;
                                 text-transform: uppercase; letter-spacing: .08em; color: #475569; }
.popup-hor                     { margin: 4px 0 0; display: grid; gap: 2px; }
.popup-hor div                 { display: flex; justify-content: space-between; gap: 14px; }
.popup-hor dt                  { color: #475569; }
.popup-hor dd                  { margin: 0; font-variant-numeric: tabular-nums; }
.popup-lien                    { margin-top: 12px; font-weight: 600; color: var(--commune-texte); }

/* Fiche désignée depuis la carte : liseré à la couleur communale, le temps
   de retrouver de quel point il s'agit dans une longue liste. */
.point-vise > article          { border-color: var(--commune-texte);
                                 box-shadow: 0 0 0 1px var(--commune-texte); }
/* Le titre d'une fiche sert de raccourci vers la carte : il doit s'annoncer
   comme cliquable, sans devenir un faux lien. */
.titre-situable                { cursor: pointer; }
.titre-situable:hover          { color: var(--commune-texte); }

/* ── Informations : liste à gauche ──────────────────────────*/
.fiche-info {
  display: flex; align-items: flex-start; gap: 12px;
  border: 1px solid transparent; border-radius: 16px;
  padding: 12px; cursor: pointer;
  transition: background-color .18s, border-color .18s;
}
.fiche-info:hover     { background: #F8FAFC; border-color: #E2E8F0; }
.fiche-info.est-active { background: var(--commune-voile); border-color: var(--commune-texte); }

/* Contenu rédigé dans le back-office : la typographie vient du greffon
   `typography` de Tailwind, déjà chargé par le gabarit et déjà employé par la
   page Actualités. On ne reprend ici que ce qu'il ne couvre pas — un tableau
   large doit défiler dans son coin plutôt que d'élargir toute la page. */
.prose table          { display: block; overflow-x: auto; max-width: 100%; }

/* ── Bannière pleine largeur ────────────────────────────────
   `main` réserve 6rem sous l'en-tête, hauteur confortable pour un titre de
   section. Une bannière photo, elle, doit toucher l'en-tête : on lui rend la
   différence entre cette réserve et la hauteur réellement mesurée. Le repli à
   6rem annule la remontée si le script ne tourne pas — mieux vaut une bande
   vide qu'une image passant sous une barre opaque. */
.banniere-pleine { margin-top: calc(var(--entete-h, 6rem) - 6rem); }

/* Bannière qui sert d'en-tête à une page de section.

   Le titre y est désormais posé sur la photo, et plus au-dessus du contenu
   avec sa propre marge : sans cette respiration, le calendrier, la liste des
   déchets ou celle des actualités démarrent collés au bas de l'image.

   Portée par la bande et non par ce qui la suit : six corps de page la
   suivent, et chacun finirait par la régler un peu différemment. L'accueil
   ne la reçoit pas — son premier bloc est la grille des accès rapides, qui a
   déjà son rythme. */
.banniere-entete { margin-bottom: 2.5rem; }

/* Ombre du texte de la bannière.

   Le texte y est blanc par construction — une couleur communale serait
   illisible sur une photo quelconque — et le voile réglé par la commune ne
   suffit pas toujours : mesuré, 25,8 % de la zone de texte de Montreux
   dépasse 0,75 de luminance, contre 1,0 % à Vevey. Sur ce quart de surface
   quasi blanche, du blanc sur du blanc ne se lit pas.

   On épaissit le contour des lettres plutôt que le voile : assombrir l'image
   assez pour garantir le contraste partout la rendrait grise là même où elle
   est belle. `ombreBanniere()` choisit le niveau, à partir de la mesure ou du
   réglage de la commune.

   « Légère » est la valeur que le titre portait déjà, inchangée : c'est le
   plancher de l'automatique, donc aucune bannière ne s'éclaircit. */
.banniere-ombre-legere { text-shadow: 0 2px 24px rgba(11, 18, 32, .35); }
.banniere-ombre-forte  { text-shadow: 0 0 2px rgba(11, 18, 32, .95),
                                      0 1px 4px rgba(11, 18, 32, .9),
                                      0 2px 24px rgba(11, 18, 32, .45); }
@media (min-width: 640px) { .banniere-entete { margin-bottom: 3.5rem; } }

/* Hauteur de l'image du bandeau, réglée en back-office (migration 046).
   `min-height` et non `height` : la valeur est un PLANCHER. Un titre coupé
   en deux lignes, une accroche longue ou la recherche de commune doivent
   pouvoir pousser la bande plus bas ; une hauteur fixe les rognerait.

   La borne en `vh` protège le téléphone. Une commune règle sa bannière
   devant un grand moniteur : 700 px y occupent le tiers de l'écran, et la
   totalité de celui d'un portable — le reste de la page passerait sous la
   ligne de flottaison sans que personne ne l'ait voulu.

   Le contenu est centré verticalement : avec le rembourrage seul, il
   resterait collé en haut d'une bande rehaussée, et le bas de l'image
   paraîtrait vide. La classe n'est posée que si une hauteur est réglée —
   sans elle, le bandeau garde exactement sa composition d'origine. */
.bandeau-cale {
  /* La hauteur réglée vaut pour un GRAND écran ; en dessous, la bande la suit
     dans la même proportion.

     Sans cela, les 600 px réglés devant un moniteur donnaient la même bande
     sur un téléphone de 375 px de large : l'image y était rognée à l'extrême
     et la bande occupait la page entière avant le moindre contenu. La borne
     en `vh` protégeait de l'écran court, pas de l'écran étroit.

     1440 est l'écran de référence, le même que celui de l'aperçu du
     back-office (`echelleApercu`) : un réglage pris là-bas se retrouve ici.

     `--bandeau-h` est un NOMBRE de pixels, sans unité : CSS ne sait pas
     diviser une longueur par une longueur, et c'est le seul moyen de la
     multiplier par une fraction de la largeur. Les deux gabarits qui la
     posent écrivent donc « 600 » et non « 600px ». */
  --bandeau-px:   calc(var(--bandeau-h, 0) * 1px);
  --bandeau-prop: calc(var(--bandeau-h, 0) * 100vw / 1440);
  /* Plancher, pour qu'un écran étroit garde une vraie bande — jamais au-delà
     du réglage lui-même, sinon une commune qui demande 160 px en obtiendrait
     180. */
  --bandeau-sol:  min(180px, var(--bandeau-px));
  min-height: min(max(var(--bandeau-sol), var(--bandeau-prop)),
                  var(--bandeau-px), 78vh);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Pages pleine hauteur — la carte des points de collecte.
   La barre supérieure est `fixed` : le contenu doit s'en écarter de sa
   hauteur exacte, et une page qui occupe l'écran doit retrancher la même
   valeur. `--entete-h` est posée par le gabarit puis remesurée par le script ;
   le repli de 68px ne sert que si le script n'a pas tourné. */
.sous-entete    { padding-top: var(--entete-h, 68px); }
.pleine-hauteur { height: calc(100vh - var(--entete-h, 68px)); }

/* ── Enseigne de l'en-tête ──────────────────────────────────
   Le logo du menu latéral tient lieu de nom dans la barre. Sa hauteur est
   réglée par commune (`--logo-h`) : un mot-symbole large doit monter plus
   haut qu'un écusson carré, et une valeur unique ne conviendrait à personne.

   La largeur suit le rapport naturel plutôt qu'une borne serrée : avec
   `object-fit: contain`, une largeur trop contrainte rétrécit l'image EN
   HAUTEUR au lieu de la rogner, et la hauteur demandée n'est jamais atteinte.
   La borne ne sert donc qu'aux cas extrêmes. */
.logo-entete {
  height: var(--logo-h, 56px);
  width: auto;
  max-width: 340px;
  object-fit: contain;
}
/* Téléphone : l'écran commande. On plafonne sans jamais dépasser le réglage
   de la commune — un logo voulu petit ne doit pas grandir ici. */
@media (max-width: 639px) {
  .logo-entete { height: min(var(--logo-h, 56px), 44px); max-width: 220px; }
}
