/* ─── FONTS ───────────────────────────────────────────────────────────────
   Trois graisses d'Univers Com condensé (47 Light / 57 / 67 Bold) + Walbaum
   Book, telles que les styles de texte Figma les appellent. */
@font-face {
  font-family: 'WalbaumBook';
  src: url('../assets/fonts/WalbaumBook-Regular.woff') format('woff');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'UniversCom';
  src: url('../assets/fonts/UniversCom-47LightCond.woff') format('woff');
  font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'UniversCom';
  src: url('../assets/fonts/UniversCom-57Condensed.woff') format('woff');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'UniversCom';
  src: url('../assets/fonts/UniversCom-67BoldCond.woff') format('woff');
  font-weight: 700; font-style: normal; font-display: swap;
}

/* ─── RESET ──────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }
html, body { height: 100%; overflow: hidden; }
body {
  font: var(--text-body-small);
  background: var(--background-page);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
}
button { font-family: inherit; }
#icon-sprite { display: none; }
.icon { width: 20px; height: 20px; fill: currentColor; flex-shrink: 0; display: block; }

/* ─── LAYOUT ─────────────────────────────────────────────────────────────── */
/* Plus de header : le fond occupe tout l'écran, l'interface flotte au-dessus. */
#app   { position: relative; height: 100%; overflow: hidden; }
#stage { position: absolute; inset: 0; z-index: 1; }
#map   { position: absolute; inset: 0; }

/* ─── CONTRÔLE DE ZOOM (carte) ───────────────────────────────────────────── */
/* Étui pilule blanc (padding 4, gouttière 4) avec deux pastilles rondes de
   40 px et un séparateur, calqué sur #view-toggle. Remplace l'habillage par
   défaut de Leaflet (carré, bordures grises) — sélecteurs renforcés en
   spécificité pour battre .leaflet-bar a du CSS Leaflet chargé avant. */
.leaflet-bar.leaflet-control-zoom {
  display: flex; flex-direction: column;
  padding: var(--component-4);
  background: var(--surface-level-02);
  border: none;
  border-radius: var(--radius-full);
  box-shadow: var(--elevation-floating);
}
/* Calage à 16 px (screen-inset), comme les autres éléments flottants —
   remplace la marge par défaut de Leaflet (10 px), d'où le renfort de
   spécificité (4 classes) pour battre `.leaflet-right .leaflet-control` et
   `.leaflet-bottom .leaflet-control` du CSS Leaflet. La marge droite est
   aussi celle que initZoomControlAvoidance() (map.js) ajuste en JS pour
   décaler le bouton à gauche du panneau de filtres quand il déborde dessus. */
.leaflet-bottom.leaflet-right .leaflet-control.leaflet-control-zoom {
  margin: 0 var(--screen-inset) var(--screen-inset) 0;
  transition: margin-right 0.2s ease;
}
.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-in,
.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-out {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  background: var(--control-background-default);
  color: var(--control-content-default);
  font: var(--text-title-h5);
  line-height: 1;
  transition: background 0.15s;
}

.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-in { 
  border-radius: var(--radius-full) var(--radius-full) 0 0;
  border: var(--border-subtle);
  box-sizing: border-box;
  border-bottom-style: solid;
  border-width: 1px;
}
.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-out { border-radius: 0 0 var(--radius-full) var(--radius-full); }

.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-in:hover,
.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-out:hover {
  background: var(--control-background-hover);
}
.leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-out {
  position: relative;
}

/* Reste en permanence dans le DOM (jamais `hidden`) : un texte annoncé via
   aria-live doit déjà faire partie de l'arbre d'accessibilité pour que son
   changement soit fiablement lu par les lecteurs d'écran — masquer/démasquer
   l'élément lui-même est moins robuste selon les technologies d'assistance
   que faire varier son seul contenu, cf. updateStageEmpty(). Vide, il ne
   rend rien (pas de fond) ; pointer-events:none pour ne jamais bloquer
   panoramique/zoom sur la carte en dessous, même une fois le message affiché.
   z-index requis en vue carte : #map ne pose pas de contexte d'empilement
   à lui seul, les panes internes de Leaflet (jusqu'à ~700) s'intercalent
   donc directement dans celui de #stage et passeraient sinon par-dessus. */
#stage-empty {
  position: absolute; inset: 0; z-index: 800;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  color: var(--text-secondary);
  pointer-events: none;
}
/* Fond posé seulement quand le message a du contenu (donc jamais en vue
   carte hors ce cas) : même couleur que #mosaic, pour un raccord invisible
   dans cette vue — et pour rester lisible par-dessus les tuiles en vue carte. */
#stage-empty:not(:empty) { background: var(--background-page); }

/* Couches flottantes */
#filters-panel,
#brand-bar, #search-bar, #view-toggle, #footer-links { position: absolute; z-index: 500; }

/* ─── MARQUE + À PROPOS ──────────────────────────────────────────────────── */
/* Ligne de marque : title/h4 (Univers Com 47 Light Condensed 20 px), capitales,
   séparateur vertical de 22 px — relevé du cadre 36 × 26 des deux vues. */
#brand-bar {
  height: var(--topbar-h);
  top: var(--screen-inset); left: var(--screen-inset);
  display: flex; align-items: center; gap: var(--component-gap-16);

  background: var(--surface-level-01);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-container);
  box-shadow: var(--elevation-overlay);
  padding: var(--component-8) var(--component-24);
}
/* H1 de la page (RGAA 9.1) : le logotype, sans incidence visuelle — la boîte
   du h1 s'efface pour laisser l'ancre occuper la place exacte d'avant. */
#brand-bar h1 { display: contents; }
#brand-bar a {
  font: var(--text-title-h4);
  text-transform: uppercase;
  color: var(--text-primary);
  text-decoration: none;
  padding: 2px 0;
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s, color 0.15s;
  text-shadow: 0 0 12px var(--background-page), 0 0 4px var(--background-page);
}
#brand-bar a:hover { border-bottom-color: var(--text-primary); }
#brand-bar .brand-sep {
  width: 1px; height: 22px;
  background: var(--border-strong);
}

/* ─── RECHERCHE ──────────────────────────────────────────────────────────── */
#search-bar {
  top: var(--screen-inset); left: 50%; transform: translateX(-50%);
  width: min(var(--search-w), 40vw);
  height: var(--topbar-h);
  display: flex; align-items: center; gap: var(--component-gap-8);
  padding: 0 var(--component-16);
  background: var(--input-background-default);
  border: 1px solid var(--input-border-default);
  border-radius: var(--radius-full);
  box-shadow: var(--elevation-floating);
}
#search-bar .icon { color: var(--icon-secondary); }
#search-input {
  flex: 1; min-width: 0;
  border: none; outline: none; background: none;
  font: var(--text-body-base);
  color: var(--input-content-default);
}
/* `outline: none` ci-dessus vaut aussi pour :focus-visible (sélecteur d'ID,
   l'emporte sur la règle globale) : sans ce rappel, le focus clavier sur la
   recherche ne se voit pas — un « trou » silencieux dans l'ordre de
   tabulation plutôt qu'un vrai manque d'arrêt. */
#search-input:focus-visible {
  outline: 2px solid var(--focus-on-background-default);
  outline-offset: 2px;
}
#search-input::placeholder { color: var(--input-placeholder-default); }
#search-input::-webkit-search-cancel-button { display: none; }
#search-clear {
  background: none; border: none; cursor: pointer;
  color: var(--icon-secondary);
  display: flex; padding: 0;
}
#search-clear .icon { width: 16px; height: 16px; }
#search-clear:hover { color: var(--icon-primary); }

/* ─── BASCULE CARTE / MOSAÏQUE ───────────────────────────────────────────── */
/* Deux pastilles de 48 px dans un étui de 108 × 56 (padding 4, gouttière 4) :
   plus de libellé sous l'icône, l'état actif est porté par le disque doré. */
#view-toggle {
  top: var(--screen-inset); right: var(--screen-inset);
  display: flex; gap: var(--component-gap-4);
  padding: var(--component-4);
  background: var(--surface-level-02);
  border: none;   /* border/surface est transparent : l'étui fait 108 × 56 net */
  border-radius: var(--radius-full);
  box-shadow: var(--elevation-floating);
}
/* #filters-fab (bouton flottant filtres, mobile/tablette) partage ce style à
   l'identique — même composant visuel que .view-btn (3 états Figma
   Default/Hover/Activated = control-background-default/hover/selected) —
   sans en partager la classe, pour ne pas hériter du handler de bascule de
   vue de bindViewToggle() (`document.querySelectorAll('.view-btn')`). */
.view-btn, #filters-fab {
  width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--radius-full);
  background: var(--control-background-default);
  color: var(--control-content-default);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.view-btn:hover, #filters-fab:hover { background: var(--control-background-hover); }
.view-btn.is-active, #filters-fab.is-active {
  background: var(--control-background-selected);
  color: var(--control-content-selected);
}

/* Pastille de comptage sur #filters-fab (mobile/tablette) : seul indice,
   filtres repliés dans une modale, qu'un ou plusieurs filtres sont actifs.
   Même traitement que les grappes de la carte (rond sombre, chiffre clair)
   plutôt que le doré de l'état .is-active — qui, lui, ne dit rien sur les
   filtres eux-mêmes (juste que la modale est ouverte), et se confondrait
   avec un badge dans les mêmes tons chauds. */
.fab-badge {
  position: absolute; top: -2px; right: -2px;
  min-width: 20px; height: 20px;
  padding: 0 5px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-full);
  border: 2px solid var(--background-page);
  background: var(--icon-primary);
  color: var(--text-on-inverse);
  font: var(--text-interface-caption);
  font-variant-numeric: tabular-nums;
}

/* ─── VUE MOSAÏQUE ───────────────────────────────────────────────────────── */
#mosaic {
  position: absolute; inset: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--component-gap-12);
  /* Marge haute : dégager la barre de recherche (16 + 56 + 16). */
  padding: var(--content-top) var(--screen-inset) var(--screen-inset);
  align-content: start;
  background: var(--background-page);
}
/* Card (« snippet ») de bâtiment — MÊME composant sur la carte (popup) et en
   mosaïque (tuile). Pas d'`overflow: hidden` sur la card : en grille mosaïque
   cela écraserait la hauteur des rangées `auto`. Le rognage vit sur la vignette. */
.bldg-card {
  position: relative;
  display: flex; flex-direction: column;
  width: 100%;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-element);
  background: var(--surface-level-01);
  cursor: pointer;
  text-align: left;
  padding: 0;
  font-family: var(--font-sans);
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.bldg-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--elevation-floating);
}
.bldg-card.is-active {
  border-color: var(--background-brand-primary);
  box-shadow: var(--elevation-floating);
}
/* Léger soulèvement réservé à la mosaïque (déplacé dans un popup, il gênerait). */
#mosaic .bldg-card:hover { transform: translateY(-2px); }

.bldg-card-thumb {
  position: relative;
  aspect-ratio: 3 / 4;
  background: var(--background-subtle);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  border-radius: calc(var(--radius-element) - 1px) calc(var(--radius-element) - 1px) 0 0;
}
.bldg-card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb-skeleton { width: 100%; height: 100%; position: absolute; }
.no-img { font-size: var(--fs-150); color: var(--border-strong); }
/* Badge arrondissement : pastille pleine (background/inverse), plus le voile
   semi-transparent d'avant — lisible quelle que soit la photo dessous. */
.bldg-card-arr {
  position: absolute; top: var(--component-8); right: var(--component-8);
  font: var(--text-body-small);
  color: var(--text-on-inverse);
  background: var(--background-inverse);
  padding: var(--component-2) var(--component-8);
  border-radius: var(--radius-badge);
}
/* Corps 240 × 78 : 8 / 12 / 12 de padding, 2 px entre les lignes, sans filet
   de séparation avec la vignette. */
.bldg-card-body {
  padding: var(--component-8) var(--component-12) var(--component-12);
  display: flex; flex-direction: column; gap: var(--component-gap-2);
}
.bldg-card-name {
  font: var(--text-title-h5);
  color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bldg-card-meta {
  font: var(--text-interface-caption);
  color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bldg-card-people {
  font: var(--text-body-small);
  color: var(--text-secondary);
}
/* Termes du thésaurus (Index Jantzen), après les personnes. */
.bldg-card-terms {
  font: var(--text-body-small);
  color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mosaic-more {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--text-secondary);
  padding: var(--component-24) 0;
}

/* ─── VUE MOSAÏQUE : CARTES LATÉRALES DANS LE FLUX ───────────────────────── */
/*
 * Même esthétique que la vue carte (cartes flottantes arrondies, marges), mais
 * la grille centrale leur réserve la place plutôt que d'être recouverte :
 * aucun chevauchement avec la barre de recherche ni la bascule d'affichage. La
 * vue carte n'est pas concernée.
 *
 * ⚙️ Largeur du volet détail pilotée en JS (mosaic-detail.js) via --md-w. */
:root { --md-w: var(--detail-w); }

/* Poignée de redimensionnement (tirette) : gélule pleine de 32 × 56 à cheval sur
   le bord droit du volet, posée en surimpression (elevation/overlay) et portant
   l'icône `drag_indicator` de 24 px. Trois états sur les tokens `control/*`. */
.panel-resize {
  position: absolute; top: 50%; right: -16px;
  transform: translateY(-50%);
  width: 32px; height: 56px; z-index: 20;
  display: flex; align-items: center; justify-content: center;
  padding: var(--component-16) var(--component-8);
  cursor: ew-resize; touch-action: none;
  background: var(--control-background-default);
  border: none;
  border-radius: var(--radius-full);
  box-shadow: var(--elevation-overlay);
  color: var(--control-content-default);
  transition: background 0.15s, color 0.15s;
}
.panel-resize-grip { width: 24px; height: 24px; }
.panel-resize:hover,
.panel-resize:focus-visible {
  background: var(--control-background-hover);
  color: var(--control-content-hover);
}
.panel-resize:active,
.panel-resize.is-dragging {
  background: var(--control-background-selected);
  color: var(--control-content-selected);
}
.panel-resize:focus { outline: none; }

/* Grille centrale : marges réservées aux cartes latérales via le padding
   (les cartes flottent dans ces gouttières, sans recouvrir les tuiles). */
.is-mosaic #mosaic {
  padding: var(--content-top) var(--screen-inset) var(--screen-inset);
  padding-right: calc(var(--filters-w) + 2 * var(--screen-inset));
}
.is-mosaic.filters-collapsed #mosaic { padding-right: 150px; }
.is-mosaic.has-detail #mosaic { padding-left: calc(var(--md-w) + 2 * var(--screen-inset)); }

/* Volet détail (gauche) — carte flottante, comme la fiche de la vue carte. */
#mosaic-detail {
  position: absolute; z-index: 500;
  top: var(--content-top); left: var(--screen-inset); bottom: var(--screen-inset);
  width: var(--md-w);
  display: flex;
  background: var(--surface-level-01);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-container);
  box-shadow: var(--elevation-overlay);
}
/* Le corps ne porte plus de padding : chaque bloc gère ses 20 px latéraux, afin
   que les filets sous les titres de section aillent d'un bord à l'autre. */
#mosaic-detail-body {
  flex: 1; overflow-y: auto;
  padding: 0;
}
/* Bouton « fermer » tertiaire circulaire de 32 px, partagé par toutes les
   modales de l'app (fiche bâtiment, pages statiques, filtres en mobile). */
.modal-close-btn {
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  background: var(--button-tertiary-background-default);
  border: 1px solid var(--button-tertiary-border-default);
  border-radius: var(--radius-full);
  color: var(--button-tertiary-content-default); cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.modal-close-btn:hover {
  background: var(--button-tertiary-background-hover);
  border-color: var(--button-tertiary-border-hover);
  color: var(--button-tertiary-content-hover);
}
#mosaic-detail-close {
  position: absolute; top: var(--component-12); right: var(--component-12); z-index: 21;
}

/* Titre de section (« Architectes & Artistes », « Photographie(s) de… ») :
   title/h3 en condensé 24 px, souligné d'un filet pleine largeur. */
.md-section-title {
  display: block;
  padding: var(--component-8) var(--component-20) var(--component-8);
  font: var(--text-title-h3);
  color: var(--text-primary);
}
.md-section-label {
  display: block;
  margin-bottom: var(--component-gap-8);
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
}
/* Titre du volet : title/h2 (Walbaum 32 px) — c'est l'accroche éditoriale de
   la fiche, nettement au-dessus des titres de sections. */
.md-title {
  display: block;
  padding: var(--component-16) var(--component-20) var(--component-8);
  font: var(--text-title-h2);
  color: var(--text-primary);
}
.md-address {
  padding: 0 var(--component-20);
  font: var(--text-interface-caption);
  color: var(--text-secondary);
}
.md-loading { padding: 0 var(--component-20); color: var(--text-secondary); font: var(--text-body-small); }

/* En-tête de la galerie (titre + dropdown « Éléments architecturaux ») :
   ancré en haut du volet pendant le scroll des photos, fond opaque pour ne
   pas laisser transparaître la grille qui défile dessous. */
#md-photos-header {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface-level-01);
}
.md-sticky-sentinel { height: 1px; margin-bottom: -1px; }
/* Rappel du nom du bâtiment : masqué tant que le titre de la fiche (plus
   haut, .md-title) reste visible ; affiché seulement une fois l'en-tête
   réellement figé en haut du volet, pour ne pas perdre le contexte pendant
   le défilement d'une longue galerie (cf. .md-sticky-sentinel, observée en
   JS — même motif que .filter-section-sentinel/.is-stuck). */
#md-photos-context {
  display: none;
  padding: var(--component-8) var(--component-20) 0;
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
}
#md-photos-header.is-stuck #md-photos-context { display: block; }

/* Galerie : mosaïque justifiée — des rangées de hauteur égale qui remplissent
   toute la largeur, sans blancs, en préservant le ratio de chaque photo. Les
   dimensions de chaque tuile sont posées par layoutJustified() (mosaic-detail.js) ;
   le conteneur ne fait qu'aligner les rangées les unes sous les autres. */
#md-photos {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: var(--component-gap-8);
  padding: var(--component-20);
}
.md-photo {
  padding: 0;
  flex: 0 0 auto;                 /* largeur/hauteur imposées par le layout JS */
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-media);
  overflow: hidden; background: var(--background-subtle);
  cursor: pointer;
  transition: border-color 0.15s;
}
.md-photo:hover { border-color: var(--border-strong); }
.md-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }


/* ─── LEAFLET ────────────────────────────────────────────────────────────── */
.leaflet-container { background: var(--background-subtle); }
.leaflet-tile-pane { filter: saturate(8) hue-rotate(15deg); }

.marker-poi {
  width: 22px; height: 30px;
  background: url('../assets/icons/poi-building.svg') no-repeat center / contain;
  cursor: pointer;
  transform-origin: 50% 100%; /* pivot sur la base posée au sol */
  transition: transform 0.12s ease;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.35));
}
.marker-poi:hover  { transform: scale(1.25); }
/* État « activé » : POI sélectionné (page ouverte) ou card épinglée — nettement
   distingué par un halo doré de la marque, en plus de l'agrandissement. */
.marker-poi.active {
  transform: scale(1.4);
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.35))
          drop-shadow(0 0 5px var(--background-brand-primary));
}

/* Grappes : disque noir plein, diamètre posé en ligne par map.js selon le
   nombre d'objets contenus (voir CLUSTER_SIZE_MIN / CLUSTER_SIZE_MAX).
   Le corps de texte, lui, reste fixe : proportionnel au disque, il devenait
   illisible sur les petites grappes. */
.cluster-marker { background: none; border: none; }
.cluster-dot {
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--icon-primary);
  color: var(--text-on-inverse);
  font-family: var(--font-sans);
  font-size: var(--text-body-small-size);
  font-weight: var(--fw-700);
  line-height: var(--lh-1);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: transform 0.12s ease;
}
.cluster-dot:hover { transform: scale(1.1); }

/* Anneau de focus clavier des grappes d'arrondissement (vue ville) :
   iconSize: [0,0] côté JS (le rond est positionné par transform CSS, pas par
   les anchor/size Leaflet — cf. showArrondissementView()), donc l'élément qui
   reçoit réellement le focus (et l'outline :focus-visible générique) est une
   boîte de taille nulle posée sur le point géographique de l'arrondissement,
   pas sur le rond affiché à côté. On retire cet anneau côté élément focalisé
   et on le rejoue autour du rond (son seul enfant), qui a lui une vraie
   taille. */
.arr-cluster-marker:focus-visible { outline: none; }
.arr-cluster-marker:focus-visible .arr-cluster-dot {
  outline: 2px solid var(--focus-on-background-default);
  outline-offset: 2px;
}

/* Emprise de la grappe au survol — doré Orsay (brand/600). */
.cluster-coverage {
  fill: var(--background-brand-primary);
  fill-opacity: 0.15;
  stroke: var(--background-brand-primary);
  stroke-width: 1.5;
  stroke-opacity: 0.9;
}

/* Emprise d'arrondissement : même aspect que le survol d'une grappe ronde
   (.cluster-coverage), avec un léger renfort au survol puisqu'elle est cliquable. */
.arr-polygon {
  fill: var(--background-brand-primary);
  fill-opacity: 0.15;
  stroke: var(--background-brand-primary);
  stroke-width: 1.5;
  stroke-opacity: 0.9;
  cursor: pointer;
  transition: fill-opacity 0.15s;
}
.arr-polygon:hover { fill-opacity: 0.28; }

/* Étiquette d'arrondissement (vue ville) : numéro + rond de comptage — deux
   marqueurs distincts (cf. showArrondissementView()) positionnés côte à côte
   sur le même point via transform. Le numéro reste décoratif (le clic dessus
   ne fait rien) ; le rond, lui, est cliquable au même titre que le polygone
   — cf. le commentaire sur son binding JS. .arr-cluster-dot reprend
   intégralement le style .cluster-dot des grappes bâtiments. */
.arr-label-num {
  pointer-events: none;
  display: block;
  font: var(--text-title-h5);
  color: var(--background-brand-primary);
  text-align: right;
  white-space: nowrap;
  /* Halo clair : lisibilité garantie par-dessus n'importe quelle tuile. */
  text-shadow: 0 0 6px var(--background-page), 0 0 3px var(--background-page),
               0 0 2px var(--background-page);
}

.leaflet-popup-content-wrapper {
  border-radius: var(--radius-element);
  box-shadow: var(--elevation-overlay);
  background: var(--surface-level-01);
  border: 1px solid var(--border-subtle);
}
.leaflet-popup-content { margin: 0 !important; font-family: var(--font-sans) !important; }
.leaflet-popup-tip-container { display: none; }
/* Popup carte = card partagée : le conteneur Leaflet s'efface, la card fournit
   son propre cadre (bordure, arrondi, ombre). */
.bldg-card-popup .leaflet-popup-content-wrapper {
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
}
.bldg-card-popup .leaflet-popup-content { width: 210px !important; }
.bldg-card-popup .bldg-card { box-shadow: var(--elevation-overlay); }

/* ─── PANNEAU DE FILTRES ─────────────────────────────────────────────────── */
/* Panneau de filtres : 300 px, calé à 16 px du bord droit, sous le bandeau de
   recherche (88 px) — identique dans les deux vues.
   La hauteur suit le contenu et ne se déploie que si les facettes dépliées le
   demandent : tout replié, la boîte se réduit à son en-tête et dégage la carte.
   Le plafond reste la pleine hauteur disponible, au-delà duquel le corps défile. */
#filters-panel {
  top: var(--content-top); right: var(--screen-inset);
  max-height: calc(100vh - var(--content-top) - var(--screen-inset));
  width: var(--filters-w);
  display: flex; flex-direction: column;
  background: var(--surface-level-01);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-container);
  box-shadow: var(--elevation-overlay);
  overflow: hidden;
}
#filters-header {
  padding: var(--component-12) var(--component-16);
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}
/* En-tête 56 px : titre en title/h4 (condensé 20 px, pas le serif), compte en
   overline et bouton de repli tertiaire de 32 px. */
#filters-header-top {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 32px;
}
#filters-title {
  font: var(--text-title-h4);
  color: var(--text-primary);
}
#filters-header-right { display: flex; align-items: center; gap: var(--component-gap-16); }
#search-results-count {
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
  padding-top: var(--component-8);
}
/* Bouton tertiaire circulaire de 32 px — même composant que la fermeture du
   volet détail. */
#filters-toggle {
  width: 32px; height: 32px; flex-shrink: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: var(--button-tertiary-background-default);
  border: 1px solid var(--button-tertiary-border-default);
  border-radius: var(--radius-full);
  color: var(--button-tertiary-content-default);
  line-height: var(--lh-1);
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
#filters-toggle:hover {
  background: var(--button-tertiary-background-hover);
  border-color: var(--button-tertiary-border-hover);
  color: var(--button-tertiary-content-hover);
}

#filters-active-bar { display: none; flex-wrap: wrap; gap: var(--component-gap-8); margin-top: var(--component-gap-8); }
#filters-active-bar.has-active { display: flex; }
/* Un filtre actif rappelé sous le titre, c'est la même puce que dans la facette,
   dans son état sélectionné — d'où la mise en commun du gabarit avec `.chip`. */
.filter-active-tag {
  display: inline-flex; align-items: center; gap: var(--component-6);
  min-height: 32px;
  padding: 0 var(--component-6) 0 var(--component-12);
  border: 1px solid var(--tag-border-selected);
  border-radius: var(--radius-badge);
  font: var(--text-body-base);
  background: var(--tag-background-selected);
  color: var(--tag-content-selected);
}
.filter-active-tag-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 20px; padding: 0;
  background: none; border: none; cursor: pointer;
  color: inherit; opacity: 0.6; line-height: var(--lh-1);
  transition: opacity 0.10s;
}
.filter-active-tag-remove:hover { opacity: 1; }
#filter-reset-btn {
  background: none; border: none; cursor: pointer;
  font: var(--text-interface-button-medium);
  color: var(--text-secondary);
  text-decoration: underline; text-underline-offset: 2px;
  padding: var(--component-8) 0;
}
#filter-reset-btn:hover { color: var(--text-primary); }

/* `min-height: 0` : sans lui, un enfant flexible refuse de rétrécir sous la
   taille de son contenu et le défilement ne s'amorce jamais au plafond. */
#filters-body { overflow-y: auto; flex: 0 1 auto; min-height: 0; }

/* ─── REPLI DES FILTRES (largeur + hauteur) ──────────────────────────────── */
/* Le bouton −/+ rétracte la boîte : on ne garde que le titre et l'icône,
   rapprochés. Vaut pour les deux vues (carte et mosaïque). */
#filters-panel.is-collapsed { width: auto; overflow: hidden; }
#filters-panel.is-collapsed #filters-body,
#filters-panel.is-collapsed #filters-active-bar,
#filters-panel.is-collapsed #search-results-count { display: none; }
#filters-panel.is-collapsed #filters-header { border-bottom: none; }
#filters-panel.is-collapsed #filters-header-top { justify-content: flex-start; gap: var(--component-gap-8); }

.filter-section { border-bottom: 1px solid var(--border-subtle); }
.filter-section:last-child { border-bottom: none; }
/* Sentinelle de détection du « collage » : repère à l'IntersectionObserver
   (voir initStickyFilterHeaders dans filters.js) pour savoir quand l'en-tête
   ci-dessous est réellement figé en haut de #filters-body, par opposition à
   son flux normal. 1 px annulé par une marge négative — l'observer a besoin
   d'une aire mesurable pour calculer un intersectionRatio ; à hauteur nulle,
   ce ratio resterait bloqué à 0 et ne franchirait jamais le seuil. */
.filter-section-sentinel { height: 1px; margin-bottom: -1px; }
/* Hiérarchie de titres (RGAA 9.1) : le <h3> qui porte le bouton d'accordéon
   ne doit rien changer à la mise en page — sa boîte s'efface. */
.filter-section-heading { display: contents; }
/* Ligne « Dropdown » : 48 px de haut, libellé à 20 px du bord, chevron de
   24 px collé à 12 px du bord droit. */
.filter-section-header {
  width: 100%; min-height: 48px;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--component-gap-8);
  padding: 0 var(--component-12) 0 var(--component-20);
  background: var(--menu-item-background-default); border: none; cursor: pointer;
  color: var(--menu-item-text-default);
  transition: color 0.15s, background 0.15s, box-shadow 0.15s;
  /* Sticky dans #filters-body : l'en-tête de la section en cours de lecture
     reste visible pendant le défilement de son contenu long (fond opaque
     requis, le token par défaut étant transparent). */
  position: sticky; top: 0; z-index: 2;
  background-color: var(--surface-level-01);
}
/* L'en-tête touche les 3 bords de #filters-body, qui défile (overflow: auto)
   — l'anneau :focus-visible générique déborde de 2px (outline-offset positif)
   et se fait donc rogner sur ces 3 côtés par le conteneur, ne laissant voir
   que le bas : un simple filet plutôt qu'un cadre. Décalage négatif = anneau
   rentré, jamais rogné, quel que soit le conteneur. */
.filter-section-header:focus-visible { outline-offset: -2px; }
/* Élévation la plus discrète (« anchored ») uniquement pendant que l'en-tête
   est effectivement collé — pas en position normale dans le flux. */
.filter-section-header.is-stuck { box-shadow: var(--elevation-anchored); }
/* Intitulé de section : interface/Button/Medium en casse normale — les
   capitales espacées d'avant sont réservées aux sur-titres (overline). */
.filter-section-label { font: var(--text-interface-button-medium); }
.filter-section-header:hover { color: var(--menu-item-text-hover); background: var(--menu-item-background-hover); }
.filter-section-header[aria-expanded="true"] { color: var(--menu-item-text-hover); }
/* Les deux éléments de droite (compte optionnel + chevron) forment le « Ctrl »
   de la maquette : 24 px de large, le badge s'insérant avant le chevron. */
.filter-section-ctrl { display: flex; align-items: center; gap: var(--component-gap-4); flex-shrink: 0; }
.filter-section-arrow {
  width: 24px; height: 24px;
  transition: transform 0.15s; color: var(--menu-item-icon-default);
}
.filter-section-header[aria-expanded="false"] .filter-section-arrow { transform: rotate(-90deg); }
.filter-section-body { display: none; padding: var(--component-8) var(--component-20) var(--component-20); }
.filter-section-body.open { display: block; }

.filter-group { margin-bottom: var(--component-8); }
.filter-chips { display: flex; flex-wrap: wrap; gap: var(--component-gap-4); }

/* Puce : hauteur fixe de 32 px, libellé en body/base, pastille de compte
   optionnelle qui resserre le padding droit de 12 à 6. */
.chip {
  display: inline-flex; align-items: center; gap: var(--component-6);
  min-height: 32px;
  padding: 0 var(--component-12);
  border: 1px solid var(--tag-border-default);
  border-radius: var(--radius-badge);
  font: var(--text-body-base);
  cursor: pointer;
  color: var(--tag-content-default);
  background: var(--tag-background-default);
  transition: background 0.10s, border-color 0.10s, color 0.10s;
}
.chip:has(.chip-count) { padding-right: var(--component-6); }
.chip-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 20px;
  padding: 0 var(--component-8);
  border: 1px solid; border-color: inherit;   /* suit l'état de la puce */
  border-radius: var(--radius-badge);
  font: var(--text-interface-caption);
  font-variant-numeric: tabular-nums;
}
.chip:hover { background: var(--tag-background-hover); border-color: var(--tag-border-hover); color: var(--tag-content-hover); }
.chip.active { background: var(--tag-background-selected); color: var(--tag-content-selected); border-color: var(--tag-border-selected); }

.filter-linkbtn {
  background: none; border: none; cursor: pointer;
  padding: 0;
  font-size: var(--text-interface-caption-size);
  color: var(--text-secondary);
  text-decoration: underline; text-underline-offset: 2px;
}
.filter-linkbtn:hover { color: var(--text-primary); }

/* Affichage vertical des puces de période */
#date-chips-container {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--component-gap-4); /* Espace vertical entre les puces */
}

/* S'assurer que le wrapper prend toute la largeur */
#date-chips-container .thes-term {
  display: block;
  width: 100%;
}

/* ─── THÉSAURUS : RECHERCHE, GROUPES, DÉFINITIONS ───────────────────────── */
/* Champ de recherche du thésaurus (composant Figma « Filter Search Bar ») :
   40 px de haut, icône 18 px, texte body/base (pas body/small — la puce en
   dessous s'articule à 16 px), 16 px avant la première puce (8 sous le champ
   + 8 en tête du groupe). Icône et texte suivent le contenu de l'input
   (input/content), pas icon/secondary — le champ « s'assombrit » identiquement
   au survol/focus, comme dans les états Hover/Filled du composant Figma. */
.thes-search {
  display: flex; align-items: center; gap: var(--component-gap-8);
  height: 40px;
  padding: 0 var(--component-8);
  margin-bottom: var(--component-16);
  background: var(--input-background-default);
  border: 1px solid var(--input-border-default);
  border-radius: var(--radius-element);
}
.thes-search:hover { background: var(--input-background-hover); border-color: var(--input-border-hover); }
.thes-search:focus-within { border-color: var(--input-border-active); }
.thes-search .icon { width: 18px; height: 18px; color: var(--input-content-default); flex-shrink: 0; }
.thes-search:hover .icon, .thes-search:focus-within .icon { color: var(--input-content-hover); }
.thes-search input {
  flex: 1; min-width: 0;
  border: none; outline: none; background: none;
  font: var(--text-body-base);
  color: var(--input-content-default);
}
/* Même rappel que #search-input : `outline: none` ci-dessus s'applique aussi
   à :focus-visible et rendrait sinon le focus clavier invisible. */
.thes-search input:focus-visible {
  outline: 2px solid var(--focus-on-background-default);
  outline-offset: 2px;
}
.thes-search input::placeholder { color: var(--input-placeholder-default); }
.thes-search input::-webkit-search-cancel-button { display: none; }
/* Croix d'effacement — n'apparaît que lorsqu'un terme a été saisi (attribut
   `hidden` posé/retiré en JS), même composant que #search-clear. */
.thes-search-clear {
  background: none; border: none; cursor: pointer; padding: 0;
  display: flex; flex-shrink: 0;
  color: var(--input-content-default);
}
.thes-search-clear .icon { width: 16px; height: 16px; }
.thes-search-clear:hover { color: var(--input-content-hover); }

.thes-group + .thes-group { margin-top: var(--component-16); }
/* Sur-titre de catégorie : le décompte reste porté par les puces elles-mêmes,
   pas par l'intitulé du groupe. */
.thes-group-label {
  display: block;
  margin-bottom: var(--component-gap-8);
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
}
.thes-group-label::after { content: '\00a0:'; }

/* Composant « Chip + Infos » : le terme (82 px de gabarit) et le segment « i »
   (34 px) partagent une même gélule de 32 px, séparés par un filet commun. */
.thes-terms { display: flex; flex-wrap: wrap; gap: var(--component-gap-8); }
.thes-term { display: inline-flex; align-items: stretch; }
.thes-term .chip { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.thes-term .chip:has(.chip-count) { gap: var(--component-8); padding-right: var(--component-8); }
.thes-term:not(:has(.thes-info)) .chip { border-radius: var(--radius-badge); }

.thes-info {
  width: 34px;
  margin-left: -1px;
  display: flex; align-items: center; justify-content: center;
  background: var(--tag-background-default);
  border: 1px solid var(--tag-border-default);
  border-radius: 0 var(--radius-badge) var(--radius-badge) 0;
  color: var(--tag-content-default);
  font: var(--text-title-h5-weight) var(--fs-100)/var(--lh-150) var(--font-serif);
  cursor: pointer;
  transition: background 0.10s, color 0.10s, border-color 0.10s;
}
.thes-info:hover,
.thes-info[aria-expanded="true"] {
  background: var(--tag-background-hover);
  border-color: var(--tag-border-hover);
  color: var(--text-primary);
}

/* La carte prend toute la largeur : elle force un retour à la ligne dans la
   grappe de puces, et reste dans le flux (aucun rognage par le panneau). */
.thes-def {
  flex-basis: 100%;
  margin: var(--component-gap-4) 0;
  padding: var(--component-12);
  background: var(--background-brand-secondary);
  border: 1px solid var(--feedback-info-border);
  border-radius: var(--radius-element);
  font: var(--text-body-base);
  color: var(--text-secondary);
}
.thes-def-text { line-height: var(--lh-150); color: var(--feedback-info-text); }
.thes-def-text + .thes-def-text { margin-top: var(--component-gap-8); }

.thes-def-links {
  list-style: none;
  margin-top: var(--component-gap-8);
  display: flex; flex-direction: column; gap: 2px;
}
.thes-def-links a {
  color: var(--link-default);
  text-underline-offset: 2px;
}
.thes-def-links a:hover { color: var(--link-hover); text-decoration: none; }
.thes-def-source {
  margin-top: var(--component-16);
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.thes-empty { font: var(--text-body-base); color: var(--text-secondary); }

/* Style pour les puces de filtre désactivées */
.chip:disabled,
.chip.disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none; /* Empêche les clics et le hover */
  background-color: var(--tag-background-disabled);
  color: var(--tag-content-disabled);
  border-color: transparent;
}

/* ─── FOCUS VISIBLE (RGAA 10.7) ──────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid var(--focus-on-background-default);
  outline-offset: 2px;
}

/* ─── INFOS BÂTIMENT (composants partagés par le volet détail) ──────────── */
/* Grille méta : deux colonnes par ligne — sur-titre à gauche sur une colonne
   fixe de 148 px, valeur en gras à droite, rangées de 32 px sans gouttière. */
.info-meta-grid {
  display: flex; flex-direction: column;
  padding: var(--component-8) var(--component-20) var(--component-16);
}
.info-meta-cell {
  display: grid;
  grid-template-columns: minmax(0, 148px) 1fr;
  gap: var(--component-gap-8);
  padding: var(--component-2) 0 var(--component-2) 0;
}
.info-meta-label {
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
  position: relative;
  padding-top: var(--component-6);
}
.info-meta-label::after { 
  content: '\00a0:';
  display: none;
}
.info-meta-value { font: var(--text-body-base); color: var(--text-primary); }

/* ─── INFOBULLES ACCESSIBLES ─────────────────────────────────────────────
 * Déclencheur : soulignement pointillé discret (pas de couleur de lien, pour
 * ne pas laisser croire à un lien). Bulle sous le déclencheur — jamais
 * au-dessus, pour ne pas se faire rogner par l'`overflow-y: auto` du volet. */
.has-tooltip {
  position: relative;
  cursor: help;
  text-decoration: underline dotted;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 3px;
}
.tooltip {
  position: absolute;
  top: calc(100% + 6px); left: 0;
  width: max-content; max-width: 260px;
  padding: var(--component-8) var(--component-12);
  background: var(--background-inverse);
  color: var(--text-on-inverse);
  font: var(--text-body-small);
  text-decoration: none;
  text-transform: none;
  letter-spacing: normal;
  border-radius: var(--radius-element);
  box-shadow: var(--elevation-floating);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s;
  pointer-events: none;
  z-index: 20;
}
.has-tooltip.tooltip-visible .tooltip { opacity: 1; visibility: visible; }

.info-elements-label {
  display: block;
  margin-top: var(--component-20);
  margin-bottom: var(--component-gap-8);
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
}
/* ─── PERSONNES LIÉES (architectes) ─────────────────────────────────────── */
/* Carte personne : vignette carrée de 56 px (silhouette de repli si aucune
   photo), 16 px de gouttière, nom + rôle réunis sur une seule ligne en
   body/base-bold. */
.info-personnes {
  display: flex; flex-direction: column; gap: var(--component-gap-8);
  padding: var(--component-8) var(--component-20) var(--component-16);
}
.person-card {
  display: flex;
  gap: var(--component-gap-16);
  align-items: flex-start;
  padding: var(--component-8) 0;
}
.person-thumb {
  flex: none;
  width: 56px; height: 56px;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-media);
  overflow: hidden;
  background: var(--surface-level-02);
  cursor: pointer;
}
.person-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Repli silhouette : garantit une vignette même sans photo (média absent ou
   en échec de chargement) — statique, à la différence de la vraie photo. */
.person-thumb-placeholder {
  cursor: default;
  background: var(--background-subtle);
  color: var(--border-strong);
}
.person-thumb-placeholder .icon { width: 56px; height: 56px; }
.person-info { display: flex; flex-direction: column; gap: var(--component-gap-2); min-width: 0; }
/* Nom de la personne : un bouton (active le filtre « Architectes & Artistes »
   sur cette personne), mais qui garde l'apparence d'un simple titre — reset
   du chrome natif de <button>, style couleur/police inchangé. Le soulignement
   au survol/focus (plutôt qu'une couleur de lien) signale l'interactivité
   sans reposer sur la seule couleur (RGAA 3.2 / WCAG 1.4.1). */
.person-name {
  display: block;
  width: 100%;
  border: none;
  background: none;
  padding: 0;
  margin: 0;
  text-align: left;
  font: var(--text-body-base);
  color: var(--text-primary);
  cursor: pointer;
}
.person-name.has-tooltip {
  cursor: pointer;                 /* remplace le curseur "aide" par défaut */
  text-decoration: none;           /* remplace le pointillé permanent par défaut */
}
.person-name:hover,
.person-name:focus-visible {
  text-decoration: underline;
  color: var(--text-primary);      /* explicite : pas de couleur de lien au survol */
}
.person-links {
  font: var(--text-body-small);
  color: var(--text-secondary);
  display: flex;
  column-gap: var(--component-4);
  flex-wrap: wrap;
}
.person-links a { color: var(--link-default); text-underline-offset: 2px; }
.person-links a:hover { color: var(--link-hover); text-decoration: none;}

.credit-link {  color: var(--text-on-inverse); }
.credit-link:hover { opacity: 0.8; text-decoration: none; }
.credit-link a { color: var(--link-default); text-underline-offset: 2px; }
.credit-link a:hover { color: var(--link-hover); }

/* Puce « lien externe » (open_in_new) accolée au libellé, dans les deux
   contextes ci-dessus : liens des personnes (fiche bâtiment) et crédit
   Wikidata (lightbox du portrait). */
.person-links a, .credit-link a, a.credit-link, .thes-def-links a {
  display: inline-flex; align-items: center; gap: var(--component-gap-4);
}
.icon-external { width: 16px; height: 16px; margin-top: 4px; }

/* ─── ÉLÉMENTS ARCHITECTURAUX (volet détail) ──────────────────────────────
   Les termes des photos, regroupés par catégorie du thésaurus sous une ligne
   « Dropdown » repliable. Puces identiques aux filtres, mais à 8 px de
   gouttière (contre 4 dans le panneau de droite). */
.archi-groups {
  padding: 0 var(--component-20) var(--component-8);
  container-type: inline-size;   /* le volet est redimensionnable : cf. plus bas */
}
.archi-groups[hidden] { display: none; }
.archi-group { padding: var(--component-4) 0; }
.archi-group-label {
  display: block;
  padding: var(--component-8) 0;
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
  width: 120px;
}
.archi-group-label::after { content: '\00a0:'; }
.archi-chips { display: flex; flex-wrap: wrap; gap: var(--component-gap-8); }

/* Dès que les puces peuvent tenir sur une largeur utile (~240 px), la catégorie
   passe à gauche des puces plutôt qu'au-dessus : le volet respire en largeur.
   Réservé au volet bâtiment — le panneau de filtres, lui, reste toujours empilé. */
@container (min-width: 340px) {
  .archi-group {
    display: flex; align-items: flex-start;
    gap: var(--component-gap-8);
  }
  .archi-group-label {
    flex: none;
    padding: 10px 0 0;   /* aligne le sur-titre sur la 1re rangée de puces (32 px) */
  }
  .archi-chips { flex: 1; min-width: 0; }
}
.archi-empty { padding: var(--component-8) 0; font: var(--text-body-small); color: var(--text-secondary); }

.info-meta-value a {
  color: inherit;
  text-decoration: none;
  word-break: break-all; /* Évite que l'URL ne dépasse de la grille */
}

/* Léger soulignement discret au survol pour indiquer qu'il est cliquable */
.info-meta-value a:hover {
  text-decoration: underline;
}

/* Permalien : style « lien » standard (cf. .person-links a, #page-overlay-body
   a) plutôt que le style discret ci-dessus, car la valeur EST le lien. Un
   clic copie l'URL au lieu de naviguer (rouvrir la même page n'a pas de sens
   ici) — `.has-tooltip`/`.tooltip` (définis plus haut) affichent la
   confirmation « Lien copié » ; la couleur/le soulignement propres à
   `.has-tooltip` sont ici redéfinis pour prendre le style lien. */
.info-permalink.has-tooltip {
  display: inline-flex;
  align-items: center;
  gap: var(--component-gap-4);
  color: var(--link-default);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: currentColor;
  text-underline-offset: 2px;
  word-break: break-all;
}
.info-permalink.has-tooltip:hover { color: var(--link-hover); text-decoration: none; }
.info-permalink .icon-copy { flex: none; }
.info-permalink.copied { color: var(--icon-secondary); }


/* ─── VISIONNEUSE PLEIN ÉCRAN ────────────────────────────────────────────── */
#lightbox {
  position: fixed; inset: 0; z-index: 1000;
  background: var(--bg-inverse-heavy);
  display: flex; align-items: center; justify-content: center;
  padding: var(--component-48);
}
/* Hauteur figée sur le conteneur (et non déduite du contenu) : la légende et
   la rangée d'actions restent ainsi à une position fixe d'une photo à
   l'autre, quel que soit son ratio — seule la zone image (flexible) absorbe
   la variation de hauteur, au lieu de faire varier la hauteur du groupe
   entier (qui déplaçait tout le bloc, centré verticalement dans #lightbox). */
#lightbox-figure {
  display: flex; flex-direction: column; align-items: center; gap: var(--component-gap-12);
  width: 100%; height: 100%; max-width: 100%; max-height: 100%; min-width: 0;
}
#lightbox-img-wrap {
  flex: 1 1 auto; min-height: 0; width: 100%;
  display: flex; align-items: center; justify-content: center;
}
#lightbox-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--radius-media);
  background: var(--background-subtle);
}
#lightbox-caption {
  flex-shrink: 0;
  font: var(--text-body-base);
  color: var(--text-on-inverse);
  text-align: center;
}
/* Terme de la légende : un bouton (active le filtre thésaurus sur ce terme) —
   reset du chrome natif de <button>, mais souligné par défaut comme les
   autres liens de l'appli (cf. .credit-link, même principe sur ce fond sombre
   de la visionneuse) ; couleur inchangée (blanc, comme le reste de la
   légende) plutôt que la couleur de lien habituelle, qui jurerait sur cet
   overlay. */
.lightbox-term-link {
  display: inline;
  border: none;
  background: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: var(--text-on-inverse);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.lightbox-term-link:hover,
.lightbox-term-link:focus-visible {
  text-decoration: none;
  opacity: 0.8;
}

/* Empêche la sélection et le drag-and-drop des images */
#md-photos img,
.lightbox img {
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none; /* Attention : si tu mets pointer-events: none sur l'img, c'est le bouton parent qui capte les clics */
}
/* Rangée fixe sous la légende : indépendante de la largeur de l'image, qui
   varie avec son ratio (object-fit: contain) — les flèches ne se déplacent
   donc plus d'une photo à l'autre. */
#lightbox-nav-row {
  display: flex; flex-shrink: 0; gap: var(--component-gap-12);
}
#lightbox-close {
  position: absolute; top: var(--component-24); right: var(--component-24);
}
#lightbox-close, .lightbox-nav {
  width: 44px; height: 44px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-level-01);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-badge);
  color: var(--icon-primary);
  cursor: pointer;
  transition: opacity 0.15s, background 0.15s;
}
#lightbox-close:hover, .lightbox-nav:hover:not(:disabled) { background: var(--surface-interactive-background-hover); }
.lightbox-nav:disabled { opacity: 0.25; cursor: default; }

/* ─── LIENS DISCRETS ─────────────────────────────────────────────────────── */
#footer-links {
  left: 50%;
  transform: translate(-50%);
  bottom: 16px;
  display: flex; gap: var(--component-gap-8);
  font-size: var(--text-body-small);
  color: var(--text-secondary);
}
#footer-links a {
  color: var(--text-secondary);
  text-decoration: none;
  background: var(--bg-page-ghost);
  padding: 3px var(--component-4);
  border-radius: var(--radius-element);
}
#footer-links a:hover { color: var(--text-primary); }


/* ─── PAGES STATIQUES ────────────────────────────────────────────────────── */
#page-overlay {
  position: fixed; inset: 0;
  background: var(--background-page);
  z-index: 900;
  display: flex; flex-direction: column;
  overflow: hidden;
}
#page-overlay-header {
  height: 64px; flex-shrink: 0;
  border-bottom: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--component-40);
}
/* Pages statiques : hors des deux vues de référence Figma. On garde le serif
   éditorial, avec la graisse explicite (Walbaum n'existe qu'en Regular). */
#page-overlay-title {
  font-family: var(--font-serif);
  font-size: var(--text-title-h4-size);
  font-weight: var(--fw-400);
  line-height: var(--lh-120);
  color: var(--text-primary);
}

#page-overlay-tabs {
  display: flex; gap: var(--component-gap-24);
  padding: 0 var(--component-40);
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}
.page-tab {
  background: none; border: none; cursor: pointer;
  padding: var(--component-16) 0;
  font: var(--text-interface-overline);
  letter-spacing: var(--text-interface-overline-ls);
  text-transform: uppercase;
  color: var(--text-secondary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 0.15s, border-color 0.15s;
}
.page-tab:hover { color: var(--text-primary); }
.page-tab.is-active { color: var(--text-primary); border-bottom-color: var(--background-brand-primary); }

#page-overlay-body {
  flex: 1; overflow-y: auto;
  padding: var(--component-48) var(--component-40);
  max-width: 720px; margin: 0 auto; width: 100%;
}
#page-overlay-body h1 {
  font-family: var(--font-serif);
  font-size: var(--text-title-h1-size);
  font-weight: var(--text-title-h1-weight);
  line-height: var(--text-title-h1-lh);
  margin-bottom: 28px;
  color: var(--text-primary);
}
#page-overlay-body h2 {
  font-family: var(--font-serif);
  font-size: var(--text-title-h3-size);
  font-weight: var(--text-title-h3-weight);
  line-height: var(--text-title-h3-lh);
  margin: 28px 0 var(--component-12);
  padding-bottom: var(--component-8);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-primary);
}
#page-overlay-body p {
  font-size: var(--text-body-large-size);
  line-height: var(--text-body-large-lh);
  color: var(--text-secondary);
  margin-bottom: 14px;
}
#page-overlay-body p strong { color: var(--text-primary); font-weight: var(--fw-700); }
#page-overlay-body a { color: var(--link-default); text-underline-offset: 3px; }
#page-overlay-body a:hover { color: var(--link-hover); }
#page-overlay-body ul { padding-left: var(--component-20); margin-bottom: 14px; }
#page-overlay-body li {
  font-size: var(--text-body-large-size);
  line-height: var(--text-body-large-lh);
  color: var(--text-secondary);
  margin-bottom: var(--component-4);
}

/* ─── ADAPTATIONS ────────────────────────────────────────────────────────── */
/* Chrome mobile/tablette (≤900px) : masqués par défaut plutôt que via
   l'attribut `hidden` (son reset `[hidden]{display:none!important}`
   empêcherait de les réafficher en media query sans dupliquer le
   !important) ; placés ici, après leurs règles de composant respectives
   (`.view-btn, #filters-fab` et `.modal-close-btn`), pour l'emporter dans
   la cascade à spécificité égale. */
#filters-fab, #filters-close, #filters-footer { display: none; }

@media (max-width: 1279px) {
  #filters-panel { width: 240px; }
}

@media (max-width: 900px) {
  /* ── EN-TÊTE SUR DEUX RANGÉES ────────────────────────────────────────────
     Rangée 1 : marque + à propos (inchangée, juste resserrée).
     Rangée 2 : recherche + bascule carte/mosaïque, côte à côte — calcul CSS
     pur (pas de wrapper ni de JS) : 108px est la largeur connue de
     #view-toggle (2 × 48px de bouton + gouttières, cf. règle desktop), donc
     la recherche peut occuper exactement l'espace restant via `right`. */
  /* En-tête conventionnel : plein largeur, collé au bord, hauteur réduite
     (48 au lieu de 56) — remplace la carte flottante desktop. */
  #brand-bar {
    top: 0; left: 0; right: 0;
    height: 48px;
    border-radius: 0; border-left: none; border-right: none; border-top: none;
    box-shadow: none;
    gap: var(--component-gap-12);
  }
  #brand-bar a { font-size: var(--text-body-base-size); }

  /* Rangée 2 : recherche + bascule carte/mosaïque, côte à côte, même hauteur
     (48px de part et d'autre — .view-btn passe de 48 à 40px ci-dessous, d'où
     92px = 2×40 + gouttières/paddings de #view-toggle inchangés). Calcul CSS
     pur (pas de wrapper ni de JS) : la recherche occupe l'espace restant via
     `right`, connaissant la largeur fixe de #view-toggle. */
  #search-bar {
    top: 60px; left: var(--screen-inset);
    right: calc(92px + var(--screen-inset) + var(--component-gap-8));
    width: auto; height: 48px;
    transform: none;
  }
  #view-toggle { top: 60px; }
  .view-btn { width: 40px; height: 40px; }

  /* ── CONTRÔLE DE ZOOM LEAFLET ──────────────────────────────────────────────
     Déjà à screen-inset du bord (règle desktop, cf. plus haut) — même
     distance que #filters-fab ci-dessous. Seule la taille des pastilles
     change, pour rester proportionné au reste du chrome mobile. */
  .leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-in,
  .leaflet-bar.leaflet-control-zoom a.leaflet-control-zoom-out {
    width: 32px; height: 32px;
  }

  /* ── BOUTON FLOTTANT « FILTRES » ────────────────────────────────────────── */
  #filters-fab {
    display: flex;
    position: fixed; bottom: var(--screen-inset); left: var(--screen-inset);
    z-index: 500;
    box-shadow: var(--elevation-floating);
  }

  /* ── FILTRES EN MODALE PLEIN ÉCRAN ────────────────────────────────────────
     #filters-toggle (repli en place) n'a de sens qu'en desktop ; sur cette
     largeur la fermeture est une vraie fermeture de modale, portée par le
     nouveau #filters-close. */
  #filters-toggle { display: none; }
  #filters-close { display: flex; }
  #filters-panel {
    display: none;
    position: fixed; inset: 0;
    width: auto; max-height: none;
    border-radius: 0; border: none; box-shadow: none;
  }
  #filters-panel.filters-mobile-open,
  #filters-panel.filters-mobile-closing { display: flex; z-index: 900; }
  #filters-body { flex: 1 1 auto; }

  /* Barre basse sticky : nombre de résultats à gauche, retour à droite —
     toujours visible, quel que soit le défilement dans #filters-body. */
  #filters-footer {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--component-gap-16);
    flex-shrink: 0;
    padding: var(--component-12) var(--component-16);
    padding-bottom: calc(var(--component-12) + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--border-subtle);
    background: var(--surface-level-01);
  }
  #filters-footer-count {
    font: var(--text-interface-overline);
    letter-spacing: var(--text-interface-overline-ls);
    text-transform: uppercase;
    color: var(--text-secondary);
  }
  #filters-footer-back {
    flex-shrink: 0;
    height: 40px;
    padding: 0 var(--component-16);
    display: flex; align-items: center; justify-content: center;
    font: var(--text-interface-button-medium);
    color: var(--button-primary-content-default);
    background: var(--button-primary-background-default);
    border: 1px solid var(--button-primary-border-default);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
  }
  #filters-footer-back:hover {
    background: var(--button-primary-background-hover);
    border-color: var(--button-primary-border-hover);
  }

  /* ── FICHE BÂTIMENT EN MODALE PLEIN ÉCRAN ─────────────────────────────────
     Le redimensionnement n'a pas de sens en plein écran : la tirette est
     masquée (son JS pointer n'a rien à intercepter sur un élément caché). */
  #mosaic-detail {
    position: fixed; inset: 0;
    width: auto;
    border-radius: 0; border: none; box-shadow: none;
    z-index: 900;
  }
  #mosaic-detail-handle { display: none; }

  /* ── GRILLE MOSAÏQUE ───────────────────────────────────────────────────────
     Les réservations de marge pour panneau de filtres/fiche bâtiment ancrés
     n'ont plus lieu d'être : ces deux panneaux sont maintenant des overlays
     plein écran, masqués par défaut plutôt que dockés en permanence.
     Règle posée sur `.is-mosaic #mosaic` (et non sur `#mosaic` seul) : c'est
     le sélecteur qui porte déjà le raccourci `padding` en desktop
     (main.css ~l.337) et il est plus spécifique — une règle sur `#mosaic`
     seul ne l'aurait jamais emporté, quel que soit l'ordre des règles dans
     le fichier (bug constaté : le bouton flottant mordait sur la dernière
     rangée de cartes, faute de marge basse réellement appliquée). Bas :
     assez pour dégager le bouton flottant filtres (48px + marge). */
  .is-mosaic #mosaic { padding: 124px var(--screen-inset) 88px; }

  /* ── ANIMATIONS D'APPARITION/DISPARITION (filtres, fiche bâtiment) ────────
     Réservées à cette largeur : en desktop, ces panneaux restent des cartes
     non modales dont l'ouverture/fermeture ne doit pas être ralentie.
     Panneau censé « monter » depuis le bas de l'écran : on part donc de
     translateY(100%) (hors écran) plutôt que d'un léger décalage, et
     l'opacité ne bouge qu'au tout début (apparition) ou tout à la fin
     (disparition) de l'animation, pour ne pas donner un effet de fondu sur
     le déplacement lui-même. La fermeture est pilotée par JS (classes
     `filters-mobile-closing` / `is-closing`, retirées à l'issue de
     `animationend`) puisqu'elle doit désormais durer le temps de
     l'animation avant de démasquer réellement le panneau. */
  @media (prefers-reduced-motion: no-preference) {
    @keyframes modal-slide-up {
      from { transform: translateY(100%); opacity: 0; }
      8%   { opacity: 1; }
      to   { transform: translateY(0);    opacity: 1; }
    }
    @keyframes modal-slide-down {
      from { transform: translateY(0);    opacity: 1; }
      92%  { opacity: 1; }
      to   { transform: translateY(100%); opacity: 0; }
    }
    #filters-panel.filters-mobile-open,
    #mosaic-detail.is-opening {
      animation: modal-slide-up 0.28s cubic-bezier(0.16, 1, 0.3, 1);
    }
    #filters-panel.filters-mobile-closing,
    #mosaic-detail.is-closing {
      animation: modal-slide-down 0.22s cubic-bezier(0.4, 0, 1, 1);
    }
  }

  /* ── TITRES RÉDUITS ────────────────────────────────────────────────────── */
  #filters-title { font: var(--text-body-base-bold); }
  .md-title      { font: var(--text-title-h3); }
  .md-section-title { font: var(--text-title-h4); }
}
