/* Mise en page de l'application. Les couleurs et les fontes n'y figurent pas :
   elles sont portées par les feuilles de thème (theme-libre.css, servi par
   défaut, et theme-dsfr.css), sous forme de variables. Une couleur écrite en
   dur ici serait insensible à la bascule de thème. */

/* L'échelle de l'interface (font-size de la racine) est posée par
   site-entete.css : le bandeau est dimensionné en rem, et il est servi à des
   pages qui ne chargent pas cette feuille-ci. */

body, html {
    margin: 0;
    padding: 0;
    height: 100%;
    /* width: 100%; retiré car implicite */
    overflow: hidden;
    font-family: var(--police);
}

body {
    display: flex;
    flex-direction: column;
}

/* Ascenseurs visibles en permanence. Par défaut, les systèmes récents les
   superposent au contenu et n'en montrent le curseur qu'au moment du
   défilement : ne restait à l'œil que la gouttière, qui laissait croire
   qu'il n'y avait rien à faire défiler. Colorer l'ascenseur le fait dessiner
   en permanence ; la propriété étant héritée, la poser sur la racine vaut
   pour tous les cadres défilants — page, panneau de coordonnées, tiroir du
   menu, listes de suggestions, tableaux. Le curseur est pris dans le gris de
   texte plutôt que dans le gris désactivé, pour tenir le rapport de
   contraste de 3:1 des éléments d'interface (crit. 3.2). */
html {
    scrollbar-color: var(--texte-mention) var(--fond-alt);
}

/* Même rendu pour les navigateurs WebKit qui ignorent encore les deux
   propriétés ci-dessus. */
::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background-color: var(--fond-alt);
}

::-webkit-scrollbar-thumb {
    border-radius: 5px;
    background-color: var(--texte-mention);
}

::-webkit-scrollbar-thumb:hover {
    background-color: var(--texte);
}

/* Contenu réservé aux technologies d'assistance (titre de page, libellés). */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Lien d'évitement (crit. 12.7) : hors écran, visible à la prise de focus. */
.lien-evitement {
    position: absolute;
    top: -100px;
    left: 0.5rem;
    z-index: 1000;
    padding: 0.5rem 0.75rem;
    background-color: var(--accent);
    color: #fff;
    text-decoration: none;
    border-radius: 0 0 0.25rem 0.25rem;
}

.lien-evitement:focus {
    top: 0;
}

/* Prise de focus visible et homogène sur tous les éléments interactifs
   (crit. 10.7), sans imposer l'outline aux clics souris. */
:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}

/* --- Bandeau de titre et menu du site : décrits dans site-entete.css, que
   toutes les pages chargent — l'administration comprise, qui ne charge pas
   cette feuille-ci. --- */

/* --- Intitulés en tête des barres (« Localisation : », « Service
   DGFiP : ») : en-têtes de repli de leur barre, sur tout écran — le clic
   replie ou déplie (CollapsibleBars.js). L'état replié est porté par
   data-repli-adresse / data-repli-service sur <html>, posés avant la
   première peinture par theme-init.js quand il est mémorisé (règles du
   repli plus bas). --- */

.bar-entete {
    display: flex;
    align-items: baseline;
    align-self: flex-end;
    gap: 0.375rem;
    margin: 0;
    padding: 0 0 0.375rem;
    border: none;
    background: none;
    font-family: inherit;
    /* 1rem : cran « md » de l'échelle DSFR, corps de l'application. */
    font-size: 1rem;
    font-weight: 700;
    color: var(--texte);
    text-align: left;
    cursor: pointer;
    /* Intitulé copiable : sans cette levée, Firefox exclut le texte des
       boutons de la sélection et du copié-collé (le clic issu d'un glisser
       de sélection ne bascule pas le repli, cf. CollapsibleBars.js). */
    -webkit-user-select: text;
    user-select: text;
}

/* Chevron d'état au bout de la zone de titre : ▾ barre dépliée, ▸ barre
   repliée (règle du repli plus bas) — l'affordance du repli, offert sur
   tout écran. Porté par la zone de titre plutôt que par le bouton : il
   occupe ainsi la même place déplié (avant les champs) et replié (avant le
   résumé). L'intitulé ne porte pas de deux-points : accolés au chevron
   (« : ▾ »), deux signes se lisaient mal. Taille propre (au lieu
   d'hériter du 1rem du bouton) : le glyphe seul est trop fin pour rester
   lisible à ce corps. */
.bar-titre::after {
    content: '▾';
    font-size: 1.5rem;
    line-height: 1;
    color: var(--texte-mention);
}

/* Titres centrés sur la hauteur de leur barre, à largeur commune — celle
   de la zone de titre (--largeur-titres, ci-dessous) —, pour que les
   champs des deux barres commencent au même aplomb. */
#adresse-entete,
#service-entete {
    align-self: center;
    min-width: var(--largeur-titres);
}

/* Largeur commune des zones de titre, calée au plus juste sur « Service
   DGFiP ▾ » (texte, écart et chevron de repli, mesurés au corps md) : 7 rem
   en Source Sans 3, 8 rem en Marianne, plus large — sans quoi
   « Localisation » s'écarterait du bord gauche de l'espace inutile. */
:root {
    --largeur-titres: 7rem;
}

html[data-theme="dsfr"] {
    --largeur-titres: 8rem;
}

/* Le titre de section (h2) enveloppe le bouton de repli sans influer sur la
   mise en page : le bouton reste l'élément flex de la barre. */
.bar-h2 {
    display: contents;
    margin: 0;
    font: inherit;
}

/* Zone de titre : le texte puis le chevron, justifiés à droite de la
   largeur commune --largeur-titres — sur tout écran, barre pliée ou dépliée :
   « Localisation ▾ » et « Service DGFiP ▾ » finissent au même aplomb,
   juste avant leurs champs (ou leur résumé), et rien ne bouge au repli.
   En en-tête pleine largeur (champs empilés), la zone garde cette largeur
   à gauche de l'en-tête, au lieu de s'étirer et de repousser le chevron au
   bord droit de l'écran. */
.bar-titre {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 0.375rem;
    flex: 0 0 auto;
    min-width: var(--largeur-titres);
    white-space: nowrap;
}

/* Résumé du contenu de la barre : n'apparaît que barre repliée. */
.bar-resume {
    display: none;
    font-weight: 400;
    color: var(--texte-mention);
}

/* Barre repliée (attribut posé par CollapsibleBars.js, ou par theme-init.js
   avant la première peinture quand le repli est mémorisé) : champs masqués,
   l'en-tête s'étend sur la barre — titre, résumé, chevron refermé — et rend
   sa hauteur à la carte. */
html[data-repli-adresse] #address-fields,
html[data-repli-service] #structure-form {
    display: none;
}

html[data-repli-adresse] #adresse-entete,
html[data-repli-service] #service-entete {
    flex: 1;
}

html[data-repli-adresse] #address-bar .bar-resume,
html[data-repli-service] #form-panel .bar-resume {
    display: block;
    /* flex-grow à 0 : le résumé se cale sur son propre texte plutôt que
       d'étirer sa boîte jusqu'au bout de la barre. flex-shrink reste à 1
       pour l'ellipse si le résumé est plus long que l'espace restant. */
    flex: 0 1 auto;
    min-width: 0;
    position: relative;
    /* Avec le gap du bouton (0.375rem), reproduit l'écart titre / champs
       de 0.875rem, puis le retrait des champs (0.625rem) : le résumé
       commence à l'aplomb des champs qu'il remplace, derrière le même
       liseré (::before ci-dessous). */
    margin-left: 0.5rem;
    padding-left: 0.625rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Le liseré couleur du thème, conservé barre repliée : il passe des champs
   masqués au résumé, au même aplomb. */
html[data-repli-adresse] #address-bar .bar-resume::before,
html[data-repli-service] #form-panel .bar-resume::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 0.25rem;
    border-radius: 2px;
    background-color: var(--accent);
}

html[data-repli-adresse] #adresse-entete .bar-titre::after,
html[data-repli-service] #service-entete .bar-titre::after {
    content: '▸';
}

/* Bandeau vertical couleur du thème entre chaque titre et ses champs :
   délimite les champs qui relèvent de « Localisation » et ceux de
   « Service DGFiP ». Retiré sur smartphone (cf. media query), où les
   en-têtes de repli pleine largeur séparent déjà les deux groupes. */
#address-fields::before,
#structure-form::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.25rem;
    bottom: 0.25rem;
    width: 0.25rem;
    border-radius: 2px;
    background-color: var(--accent);
}

/* --- Barre de recherche d'adresse --- */

#address-bar {
    position: relative;
    z-index: 11;
    display: flex;
    gap: 0.5rem 0.875rem;
    padding: 0.5rem 0.625rem 0;
    background-color: var(--fond);
}

/* Groupe des trois champs, à côté du titre : le retour à la ligne (fenêtre
   étroite ou texte agrandi) se fait dans le groupe, si bien que le champ
   adresse reste aligné sur le champ département au lieu de repartir sous
   « Localisation : » — même schéma que #structure-form. */
#address-fields {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 0.875rem;
    flex: 1;
    min-width: 0;
    /* Place du bandeau ::before (0.25rem) et son écart aux champs. */
    padding-left: 0.625rem;
}

.address-field {
    display: flex;
    flex-direction: column;
    gap: 0.1875rem;
    /* Cran « sm » : les libellés, un cran sous le corps des champs. */
    font-size: 0.875rem;
    color: var(--texte-mention);
    min-width: 0;
}

.address-box {
    position: relative;
}

/* Double toucher des menus (ClavierSurDemande.js) : ni zoom ni délai de
   300 ms sur le second toucher. */
.address-box input,
.predictive-select-input {
    touch-action: manipulation;
}

/* Département et commune : largeurs calées sur les libellés les plus longs
   de la base, avec un peu de marge pour la croix et le chevron (calage
   d'origine : Marianne 13px ; les deux polices de thème sont exprimées dans
   la même racine en rem, Source Sans 3 étant la plus étroite des deux).
   Adresse : le champ finit à l'aplomb de la colonne mission du formulaire
   structures (32 + 24 + 24 + 2 × 0.875 d'écarts = 81.75rem), soit
   81.75 − 17.25 − 25.75 − 2 × 0.875 = 37rem.
   Ces largeurs calibrées sont des maxima (étape 1 de l'enchaînement,
   Disposition.js) : quand la ligne se resserre, les champs se compriment
   d'abord jusqu'à leur plancher — la flex-basis, qui commande aussi le
   retour à la ligne, à ajuster à l'usage — avant de passer à la ligne. */
#departement-field {
    flex: 1 1 13rem;
    max-width: 17.25rem;
}

#commune-field {
    flex: 1 1 17rem;
    max-width: 25.75rem;
}

#address-field {
    flex: 1 1 20rem;
    max-width: 37rem;
}

/* Chevron des champs à menu déroulant (département, commune), repris des
   menus du formulaire structures. Le champ adresse n'en a pas : il n'a
   rien à dérouler tant que rien n'est saisi. */
#departement-field .address-box::after,
#commune-field .address-box::after {
    content: '▾';
    position: absolute;
    top: 50%;
    right: 0.4375rem;
    color: var(--texte);
    pointer-events: none;
    transform: translateY(-50%);
}

.address-field input {
    box-sizing: border-box;
    width: 100%;
    font-size: 1rem;
    font-family: inherit;
    /* Place pour la croix (à 1.375rem) et, sur département/commune, le
       chevron (0.4375rem) */
    padding: 0.3125rem 2.5rem 0.3125rem 0.375rem;
    border: none;
    border-bottom: 2px solid var(--contour-champ);
    border-radius: 0.25rem 0.25rem 0 0;
    background-color: var(--fond-champ);
    color: var(--texte);
}

.address-field input:focus {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}

/* Croix de remise à zéro, calquée sur les menus « Service DGFiP » : on retire
   la croix native du navigateur au profit du même bouton × (visible dès que
   le champ porte une valeur, via :placeholder-shown). */
.address-field input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.address-clear {
    position: absolute;
    top: 50%;
    right: 1.375rem;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.125rem;
    height: 1.125rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--texte-mention);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.address-clear:hover {
    color: var(--texte);
    background: var(--fond-champ);
}

.address-field input:placeholder-shown ~ .address-clear {
    display: none;
}

.address-suggestions {
    position: absolute;
    z-index: 20;
    top: calc(100% + 2px);
    left: 0;
    box-sizing: border-box;
    width: max-content;
    min-width: 100%;
    max-width: min(40rem, 90vw);
    max-height: 16.5rem;
    overflow-y: auto;
    border: 1px solid var(--bordure);
    border-radius: 0 0 0.25rem 0.25rem;
    background-color: var(--fond);
    box-shadow: 0 6px 18px rgba(0, 0, 18, 0.16);
}

.address-suggestions[hidden] {
    display: none;
}

.address-suggestion {
    padding: 0.3125rem 0.4375rem;
    font-size: 1rem;
    color: var(--texte);
    cursor: pointer;
    white-space: normal;
}

.address-suggestion-contexte {
    color: var(--texte-mention);
}

.address-suggestion:hover,
.address-suggestion.active {
    background-color: var(--accent-selection);
    color: var(--accent);
}

/* --- Formulaire de sélection des structures --- */

#form-panel {
    display: flex;
    align-items: flex-end;
    /* Écart titre / champs de 0.875rem, comme sur la barre de localisation. */
    gap: 0.5rem 0.875rem;
    padding: 0.5rem 0.625rem;
    background-color: var(--fond);
    color: var(--texte);
    border-bottom: 1px solid var(--bordure);
    box-shadow: 0 1px 3px rgba(0, 0, 18, 0.16);
    z-index: 10;
}

#structure-form {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.5rem 0.875rem;
    flex: 1;
    /* Place du bandeau ::before (0.25rem) et son écart aux champs. */
    padding-left: 0.625rem;
}

/* Ordinateur : trois colonnes de deux lignes (périmètre / structures /
   mission), la ligne haute de la 1re colonne se partageant entre niveau et
   direction. Les colonnes se replient l'une sous l'autre quand la fenêtre
   manque de largeur, et se déplient en champs empilés sur smartphone. */
.form-colonne {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 100%;
    min-width: 0;
}

.form-ligne {
    display: flex;
    gap: 0.875rem;
    min-width: 0;
}

#structure-form label {
    display: flex;
    flex-direction: column;
    gap: 0.1875rem;
    /* Cran « sm » : les libellés, un cran sous le corps des champs. */
    font-size: 0.875rem;
    color: var(--texte-mention);
    min-width: 0;
}

/* Ligne du libellé des champs à cadenas : le texte et le bouton côte à
   côte, le cadenas collé au libellé. */
.champ-libelle {
    display: flex;
    align-items: center;
    gap: 0.3125rem;
}

/* Cadenas d'épinglage d'un choix (type, mission), juste à droite du
   libellé. Ouvert (discret) : valeur dérivée, re-déduite aux changements
   de contexte ; fermé (accent) : choix fixé, conservé de direction en
   direction — état vide assumé s'il n'y existe pas. Il s'allume de
   lui-même à tout choix au menu ; un clic le bascule. */
.cadenas {
    display: inline-flex;
    padding: 0 1px;
    border: none;
    background: none;
    color: var(--texte-mention);
    cursor: pointer;
    line-height: 1;
}

/* Picto dimensionné en rem : il suit le réglage de taille du texte — les
   attributs width/height du SVG, en px, ne servent que de repli. */
.cadenas svg {
    width: 0.75rem;
    height: 0.75rem;
}

/* Le cadenas ouvert porte la même anse, glissée à droite du boîtier :
   son viewBox est plus large (18 × 16), d'où une largeur augmentée dans
   le même rapport — l'échelle reste 3/4, donc boîtier et hauteur
   identiques au cadenas fermé. */
.cadenas svg.cadenas-ouvert {
    width: 0.84375rem;
}

/* display ci-dessus neutraliserait l'attribut hidden. */
.cadenas[hidden] {
    display: none;
}

.cadenas:hover {
    color: var(--texte);
}

.cadenas[aria-pressed="true"] {
    color: var(--accent);
}

.cadenas[aria-pressed="false"] .cadenas-ferme,
.cadenas[aria-pressed="true"] .cadenas-ouvert {
    display: none;
}

/* Champ dont le choix est fixé (classe posée par majCadenas) : le fond
   prend la teinte claire de l'accent — la même qui marque la sélection
   dans les listes — pour que l'épinglage se voie au premier regard. */
#structure-form .champ-fixe .predictive-select-input {
    background-color: var(--accent-selection);
}

/* Champ service fonctionnel retiré quand le service choisi n'en compte aucun
   (display: flex ci-dessus neutraliserait l'attribut hidden). */
#structure-form label[hidden] {
    display: none;
}

/* Chaque champ occupe toute la largeur de sa colonne : c'est la colonne qui
   porte désormais la largeur, pour que les deux lignes s'alignent. */
#structure-form .predictive-select {
    position: relative;
    width: 100%;
}

/* Largeurs calées sur les libellés les plus longs de la base, mesurés au
   corps md (1rem) dans la plus large des deux polices de thème, Marianne :
   « départemental » fait 7.25rem, « D69 - DiSI RHONE-ALPES AUVERGNE
   BOURGOGNE » 24.8125rem — plus le rembourrage des champs (0.375rem à
   gauche ; 1.375rem ou 2.5rem à droite selon qu'ils portent une croix) et
   une légère marge. La 1re colonne additionne niveau (8rem) et
   direction ; la circonscription, pleine colonne, suit d'elle-même. La
   colonne structures loge le développé des sigles de la cellule de base
   et du service fonctionnel.
   Comme pour les champs de localisation, ces largeurs sont des maxima :
   les colonnes se compriment jusqu'à leur plancher (flex-basis) avant de
   se replier l'une sous l'autre, les libellés comprimés gardant leurs
   points de suspension. */
#form-colonne-direction {
    flex: 1 1 22rem;
    max-width: 32rem;
}

/* Colonnes structures et mission (celle-ci logeant le champ noms) : plutôt
   que les valeurs les plus longues — des cas
   isolés qui doubleraient la colonne —, le calage retient le 90e centile
   des largeurs : 90 % des valeurs s'affichent entières, le reste garde les
   points de suspension. Pour le champ noms, centile pris sur les services
   proposés d'emblée (les services fonctionnels, accessibles à la recherche, sont
   presque tous plus larges que la colonne) : « ATELIER DE
   PHOTOGRAMMETRIE SAINT-GERMAIN-EN-LAYE », 29.02rem.

   Les plus longues valeurs du champ noms, tronquées à l'affichage, et où
   les retrouver (direction, code du type) :
   - « division d'un établissement de services informatiques POLE
     EXPLOITATION ET SUPPORT » 42.44rem — DiSI Centre-Ouest (D44), DVESI ;
   - « division d'une direction territoriale DIVISION PILOTAGE
     COMMUNICATION RISQUES » 40.96rem — DiSI Centre-Ouest (D44), DVDIR ;
   - « division d'un établissement de services informatiques POLE
     EXADATA/EXALOGIC » 39.20rem — DiSI Centre-Ouest (D44), DVESI ;
   - « CENTRE DES FINANCES PUBLIQUES NANTERRE 235 AVE G. CLEMENCEAU
     (CFP) » 38.57rem — DDFiP Hauts-de-Seine (921), GIMM3 ;
   - « CENTRE DES FINANCES PUBLIQUES ST-AMAND-MONTROND RUE MARENGO »
     37.44rem — DDFiP Cher (180), GIMM3.
   Record toutes valeurs confondues, un service fonctionnel : « division d'un
   établissement de services informatiques POLE EXPLOITATION ET SUPPORT —
   équipe ou service d'un établissement de services informatiques EQUIPE
   ADMINISTRATION FONCTIONNELLE » 96.60rem — DiSI Centre-Ouest (D44),
   DVESI. */
#form-colonne-structures {
    flex: 1 1 17rem;
    max-width: 24rem;
}

#form-colonne-mission {
    flex: 1 1 17rem;
    max-width: 24rem;
}

/* Le champ type (cellule de base), dans la colonne structures, s'arrête
   au 90e centile de ses propres valeurs, mesuré sur « PCRP — Pôle de
   contrôle des revenus et patrimoine » (24.89rem) ; le développé a gagné
   un « du » depuis et rejoint les valeurs tronquées ci-dessous. Avant la
   media query smartphone, dont le pleine largeur doit garder la main.

   Les plus longues valeurs du champ type, tronquées à l'affichage, et une
   direction où les retrouver :
   - « services de direction ou spécialisés d'une direction spécialisée »
     29.91rem — DSFiP-APHP (TAP) ;
   - « PCRP — Pôle de contrôle des revenus et du patrimoine » 26.37rem —
     DDFiP Pas-de-Calais (620) ;
   - « division ou support d'un bureau des services centraux » 25.90rem —
     services centraux (B32) ;
   - « division d'un établissement de services informatiques » 25.76rem —
     DDFiP Pas-de-Calais (620) ;
   - « CSRH — Centre de services des ressources humaines » 25.44rem —
     DRFiP Nouvelle-Aquitaine et Gironde (330). */
#structure-form .predictive-select-form-cellule {
    width: 24rem;
    max-width: 100%;
}

/* Ligne haute de la 1re colonne : niveau à sa largeur propre, direction
   occupe le reste. */
#structure-form .form-ligne > label:first-child {
    flex: 0 0 8rem;
}

#structure-form .form-ligne > label:last-child {
    flex: 1 1 auto;
}

#structure-form .predictive-select::after {
    content: '▾';
    position: absolute;
    top: 50%;
    right: 0.4375rem;
    color: var(--texte);
    pointer-events: none;
    transform: translateY(-50%);
}

#structure-form .predictive-select-input {
    box-sizing: border-box;
    width: 100%;
    font-size: 1rem;
    font-family: inherit;   /* la police du thème, comme le reste de l'interface */
    padding: 0.3125rem 1.375rem 0.3125rem 0.375rem;
    border: none;
    border-bottom: 2px solid var(--contour-champ);
    border-radius: 0.25rem 0.25rem 0 0;
    background-color: var(--fond-champ);
    color: var(--texte);
    /* Les développés de sigles les plus longs débordent encore : les couper
       par des points de suspension plutôt qu'au ras du champ. */
    text-overflow: ellipsis;
}

#structure-form .predictive-select-input:focus {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}

#structure-form .predictive-select-input:disabled {
    color: var(--desactive);
    border-bottom-color: var(--desactive);
    opacity: 0.6;
}

/* Croix de remise à zéro, entre le texte et le chevron (tous sauf niveau) */
#structure-form .predictive-select-form-direction .predictive-select-input,
#structure-form .predictive-select-form-circonscription .predictive-select-input,
#structure-form .predictive-select-form-cellule .predictive-select-input,
#structure-form .predictive-select-form-fonctionnel .predictive-select-input,
#structure-form .predictive-select-form-structure .predictive-select-input,
#structure-form .predictive-select-form-mission .predictive-select-input {
    padding-right: 2.5rem;
}

#structure-form .predictive-select-clear {
    position: absolute;
    top: 50%;
    right: 1.375rem;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.125rem;
    height: 1.125rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--texte-mention);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

#structure-form .predictive-select-clear[hidden] {
    display: none;
}

#structure-form .predictive-select-clear:hover {
    color: var(--texte);
    background: var(--fond-champ);
}

#structure-form .predictive-select-native {
    display: none;
}

#structure-form .predictive-select-options {
    position: absolute;
    z-index: 20;
    top: calc(100% + 2px);
    left: 0;
    box-sizing: border-box;
    /* Corps md, comme le champ : la liste héritait sinon du corps sm des
       libellés (les options sont des descendantes du label). */
    font-size: 1rem;
    width: max-content;
    min-width: 100%;
    max-width: min(30rem, 90vw);
    max-height: 16.5rem;
    overflow-y: auto;
    border: 1px solid var(--bordure);
    border-radius: 0 0 0.25rem 0.25rem;
    background-color: var(--fond);
    box-shadow: 0 6px 18px rgba(0, 0, 18, 0.16);
}

#structure-form .predictive-select-options[hidden] {
    display: none;
}

#structure-form .predictive-select-option {
    display: flex;
    align-items: flex-start;
    gap: 0.375rem;
    padding: 0.3125rem 0.4375rem;
    color: var(--texte);
    cursor: pointer;
    white-space: normal;
}

#structure-form .predictive-select-option input[type='checkbox'] {
    flex: 0 0 auto;
    margin: 1px 0 0;
    accent-color: var(--accent);
    pointer-events: none;
}

#structure-form .predictive-select-option:hover,
#structure-form .predictive-select-option.active {
    background-color: var(--accent-selection);
    color: var(--accent);
}

/* Disposition adaptative : des critères mesurés par Disposition.js — qui
   porte l'enchaînement complet des adaptations — à chaque
   redimensionnement, quelle qu'en soit la cause : fenêtre, zoom du
   navigateur, réglage de taille du texte, barre repliée.

   data-titres-dessus : une des deux barres ne peut plus loger son intitulé
   et ses champs côte à côte sur une seule ligne. « Localisation : » et
   « Service DGFiP : » passent tous deux au-dessus de leurs champs —
   première mesure d'adaptation, qui rend toute la largeur aux champs avant
   leurs retours à la ligne (règles plus bas).

   data-champs-empiles : la fenêtre est plus étroite que SEUIL_CHAMPS rems
   — le successeur, mesuré, de l'ancienne media query de 640 px, qui ne
   voyait ni le zoom ni l'échelle de texte. Champs empilés pleine largeur,
   en-têtes de repli pleine largeur, barres en accordéon
   (CollapsibleBars.js). Le formulaire n'est pas plafonné : déployé, il
   s'affiche entier, et c'est la page qui défile (data-menus-defilables,
   ci-dessous) — un ascenseur interne écrêtait les listes de suggestions et
   masquait les derniers champs.

   data-menus-defilables : les trois bandeaux (en-tête, Localisation,
   Service DGFiP) dépassent leur part de la hauteur de fenêtre. La page
   redevient défilante et l'en-tête cesse d'être collante : les bandeaux
   s'échappent vers le haut et rendent toute la fenêtre à la carte, qui
   prend 100 svh de hauteur — en largeur, elle garde le reste de la ligne,
   quitte à être rectangulaire. Le panneau, à la même hauteur, fait défiler
   ses coordonnées dans #info-contenu. Le défilement de la page,
   contrairement à un plafonnement des barres (max-height + overflow-y),
   n'écrête pas les listes de suggestions, positionnées en absolu.

   data-panneau-dessous : le panneau dépasse sa part de la largeur de
   fenêtre, ou la carte à son côté serait trop verticale (plus haute que
   RATIO_CARTE fois sa largeur). Il passe sous la carte, qui occupe alors
   toute la largeur et se fait carrée (hauteur = largeur). C'est l'ancien
   régime smartphone, désormais déclenché à la mesure : il vaut aussi pour
   un texte très agrandi sur une fenêtre étroite.

   data-repli-adresse et data-repli-service ne sont pas des mesures mais
   des choix : le repli d'une barre au clic sur son en-tête
   (CollapsibleBars.js), mémorisé hors champs empilés — leurs règles sont
   plus haut, avec les barres.

   data-menu-permanent ne porte pas de règle ici : le
   tiroir du menu amarré en colonne et la place que le contenu lui cède
   sont décrits dans site-entete.css, le menu étant commun à toutes les
   pages. Les barres et #content, enfants de body, suivent d'eux-mêmes son
   rembourrage gauche.

   Sans ces attributs, rien ne défile : body tient dans la fenêtre et la
   carte absorbe la hauteur restante (flex: 1) — le seuil des menus lui
   garantit sa part de fenêtre. */
html[data-menus-defilables],
html[data-panneau-dessous],
html[data-menus-defilables] body,
html[data-panneau-dessous] body {
    height: auto;
    overflow: visible;
}

/* Écran plus haut que la page : le contenu ne s'étire pas, c'est le pied de
   page qui descend au bas de la fenêtre, comme sur les pages annexes. */
html[data-menus-defilables] body,
html[data-panneau-dessous] body {
    min-height: 100vh;
    min-height: 100svh;
}

html[data-menus-defilables] #site-footer,
html[data-panneau-dessous] #site-footer {
    margin-top: auto;
}

html[data-menus-defilables] .site-entete {
    position: static;
}

html[data-menus-defilables] #content {
    flex: none;
    height: 100vh;
    height: 100svh;
}

/* Panneau sous la carte : l'empilement l'emporte sur la hauteur pleine
   fenêtre ci-dessus (même spécificité, règle plus basse). */
html[data-panneau-dessous] #content {
    flex: none;
    flex-direction: column;
    height: auto;
}

html[data-panneau-dessous] #info-panel {
    flex: none;
    border-left: none;
    border-top: 1px solid var(--bordure);
}

html[data-panneau-dessous] #map-cadre {
    flex: none;
    aspect-ratio: 1;
}

/* Intitulés au-dessus des champs (data-titres-dessus, cf. commentaire de la
   disposition adaptative plus haut) : les deux barres passent en colonne. */
html[data-titres-dessus] #address-bar,
html[data-titres-dessus] #form-panel {
    flex-direction: column;
    align-items: stretch;
}

/* Un intitulé posé au-dessus de ses champs doit se rattacher à eux, non au
   bandeau qui le précède : le seul rembourrage bas de .bar-entete (0.375rem)
   l'en sépare, contre 0.75rem au-dessus. En champs empilés, où l'intitulé
   est un en-tête pleine largeur, les écarts des règles empilées gardent la
   main. Écart de colonne inchangé : Disposition.js le mesure. */
html[data-titres-dessus]:not([data-champs-empiles]) #address-bar,
html[data-titres-dessus]:not([data-champs-empiles]) #form-panel {
    row-gap: 0;
    padding-top: 0.75rem;
}

/* En champs empilés, le width: 100% des règles empilées (plus bas, donc
   gagnantes à spécificité égale) garde la main : ce flex-start y est sans
   effet. La min-width --largeur-titres des intitulés est conservée exprès : leur
   largeur mesurée par Disposition.js reste la même des deux côtés de la
   bascule. */
html[data-titres-dessus] #adresse-entete,
html[data-titres-dessus] #service-entete {
    align-self: flex-start;
}

/* Champs empilés (data-champs-empiles, critère mesuré — voir l'enchaînement
   dans Disposition.js) : champs pleine largeur empilés, en-têtes de repli
   pleine largeur, formulaire entier (sans ascenseur). Les flex: none et
   max-width: none défont le couple plancher / maximum du régime large. */
html[data-champs-empiles] #address-bar,
html[data-champs-empiles] #address-fields {
    gap: 0.375rem;
}

html[data-champs-empiles] #departement-field,
html[data-champs-empiles] #commune-field,
html[data-champs-empiles] #address-field {
    flex: none;
    width: 100%;
    max-width: none;
}

/* En-tête pleine largeur, au-dessus des champs empilés. */
html[data-champs-empiles] #address-bar,
html[data-champs-empiles] #form-panel {
    flex-direction: column;
    align-items: stretch;
}

/* Les en-têtes pleine largeur délimitent déjà les deux groupes. */
html[data-champs-empiles] #address-fields,
html[data-champs-empiles] #structure-form {
    padding-left: 0;
}

html[data-champs-empiles] #address-fields::before,
html[data-champs-empiles] #structure-form::before {
    content: none;
}

/* Même logique pour le résumé des barres repliées : ni retrait à l'aplomb
   des champs (ils sont pleine largeur), ni liseré. La zone de titre garde
   sa largeur commune et sa justification, comme sur grand écran. */
html[data-champs-empiles] #address-bar .bar-resume,
html[data-champs-empiles] #form-panel .bar-resume {
    margin-left: 0;
    padding-left: 0;
}

html[data-champs-empiles] #address-bar .bar-resume::before,
html[data-champs-empiles] #form-panel .bar-resume::before {
    content: none;
}

html[data-champs-empiles] .bar-entete,
html[data-champs-empiles] #adresse-entete,
html[data-champs-empiles] #service-entete {
    align-self: stretch;
    width: 100%;
    padding: 0.125rem 0;
}

html[data-champs-empiles] #structure-form {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 0.375rem;
}

/* Les colonnes se défont : leurs deux lignes, et la ligne partagée
   niveau / direction, repassent en champs empilés pleine largeur. */
html[data-champs-empiles] #form-colonne-direction,
html[data-champs-empiles] #form-colonne-structures,
html[data-champs-empiles] #form-colonne-mission,
html[data-champs-empiles] #structure-form .form-ligne {
    flex: none;
    width: 100%;
    max-width: none;
    flex-direction: column;
    gap: 0.375rem;
}

html[data-champs-empiles] #structure-form .form-ligne > label:first-child {
    flex: 0 0 auto;
}

html[data-champs-empiles] #structure-form label {
    width: 100%;
}

html[data-champs-empiles] #structure-form .predictive-select {
    max-width: none;
    width: 100%;
}

/* --- Partie sous les menus : carte + panneau d'information --- */

#content {
    display: flex;
    flex: 1;
    min-height: 0;
    /* Largeur de référence du panneau ; Disposition.js la mesure (sur une
       sonde) pour décider de son passage sous la carte. */
    --largeur-info: clamp(20rem, 28vw, 30rem);
}

#info-panel {
    flex: 0 0 var(--largeur-info);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    min-height: 0;
    background-color: var(--fond);
    border-left: 1px solid var(--bordure);
    /* Corps md et interligne 1.5 : le couple 16px / 24px du DSFR. */
    font-size: 1rem;
    line-height: 1.5;
    color: var(--texte);
}

/* Navigation dans l'historique des recherches : « précédent » à gauche,
   « suivant » à droite, fixés en tête pendant que les coordonnées défilent
   au-dessous. Un lien grisé (disabled) signale une extrémité atteinte. */
#info-historique {
    flex: 0 0 auto;
    display: flex;
    justify-content: space-between;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--bordure);
}

#info-historique button {
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: var(--accent);
    /* Souligné au repos : les liens DSFR le sont toujours, le survol ne
       portant que le changement de couleur. */
    text-decoration: underline;
    cursor: pointer;
}

#info-historique button:hover:not(:disabled) {
    color: var(--accent-hover);
}

#info-historique button:active:not(:disabled) {
    color: var(--accent-active);
}

#info-historique button:disabled {
    text-decoration: none;
}

#info-historique button:disabled {
    color: var(--texte-mention);
    cursor: default;
}

/* Export CSV des services affichés : lien entre « précédent » et
   « suivant », masqué tant que rien n'est listé. L'icône (flèche de
   téléchargement, à droite du libellé) suit la taille et la couleur
   du texte. */
#info-export-csv svg {
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    margin-left: 0.25rem;
}

/* Encart des anomalies connues (Anomalies.js) : entre l'historique et les
   coordonnées, une ligne par anomalie touchée par la sélection ou la
   localisation, liée à son article de anomalies.html. */
#anomalies-encart {
    flex: 0 0 auto;
    padding: 0.625rem 0.75rem;
    border-bottom: 1px solid var(--bordure);
    background-color: var(--avertissement-fond);
    font-size: 0.875rem;
    line-height: 1.5;
}

.anomalie-encart {
    margin: 0.25rem 0;
    padding-left: 0.75rem;
    /* Filet d'avertissement : épaisseur fixe, comme les autres filets. */
    border-left: 3px solid var(--avertissement);
}

#info-contenu {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /* Gouttière d'ascenseur réservée d'office, comme au tiroir du menu
       (site-entete.css) : sans elle, l'ascenseur des longues listes mord
       sur le texte, dont les lignes se recomposent à chaque passage d'une
       sélection courte à une longue (ascenseurs classiques seulement). */
    scrollbar-gutter: stable;
    padding: 0.625rem 0.75rem;
}

.info-panel-vide {
    margin: 0.25rem 0;
    font-style: italic;
    color: var(--texte-mention);
}

/* Conseil de geste du panneau vide, sur sa propre ligne sous la phrase :
   clic principal et secondaire à la souris, appui long au doigt — le
   pointeur principal décide, comme ecranTactile() (helpers.js). */
.info-conseil-souris,
.info-conseil-tactile {
    display: block;
    margin-top: 0.5rem;
}
.info-conseil-tactile {
    display: none;
}
@media (pointer: coarse) {
    .info-conseil-souris {
        display: none;
    }
    .info-conseil-tactile {
        display: block;
    }
}

/* Rappel du sigle des types affichés, en tête des coordonnées
   (« SIP : Service des Impôts des Particuliers », InfoPanel._sigles) :
   centré et mis en valeur sur le fond d'accent, comme la ligne visée du
   glossaire. */
.info-sigle {
    margin: 0.25rem 0 0.5rem;
    padding: 0.25rem 0.5rem;
    text-align: center;
    background-color: var(--accent-fond);
    color: var(--accent);
    border-radius: 2px;
}

.info-structure {
    display: flex;
    gap: 0.5625rem;
    padding: 0.5625rem 0;
    border-bottom: 1px solid var(--bordure);
}

/* Bandeau vertical pleine hauteur rappelant l'emprise de la structure :
   contour foncé (couleur pleine) et fond clair (couleur à l'opacité des
   aplats), tous deux posés en style inline. */
.info-bandeau {
    flex: 0 0 0.625rem;
    align-self: stretch;
    /* Descend le bandeau de la demi-différence entre la ligne du nom
       (1rem × 1.5 = 1.5rem) et le carré (0.875rem) : le carré se retrouve
       centré sur la première ligne du nom de la structure. */
    margin-top: 0.3125rem;
    border: 2px solid;
    /* Bord haut épaissi : avec le biseau des bordures adjacentes, il forme un
       carré plein de la couleur d'emprise en tête du bandeau. */
    border-top-width: 0.875rem;
    border-radius: 2px;
}

.info-corps {
    min-width: 0;
    flex: 1;
}

.info-structure h3 {
    margin: 0 0 0.3125rem;
    font-size: 1rem;
    color: var(--accent);
}

.info-structure p {
    margin: 0.125rem 0;
}

.info-libelle {
    color: var(--texte-mention);
}

/* Horaires d'accueil : liste de description (catégorie → créneaux).
   Le libellé de catégorie est en contraste plein (repère de lecture, y
   compris pour un malvoyant), les jours atténués. */
.info-horaires {
    margin: 0.125rem 0 0;
    display: flex;
    flex-direction: column;
    gap: 0.1875rem;
}

.info-horaires dt {
    font-weight: 700;
    color: var(--texte);
}

.info-horaires dd {
    margin: 1px 0 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

/* Numéro(s) de téléphone, en tête de « Accueil téléphonique ». */
.info-tel {
    margin-bottom: 0.125rem;
}

/* Jours et heures alignés en deux colonnes ; les heures d'une même ligne
   restent groupées (« 8h30–12h · 13h30–16h »). */
.info-creneau {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.625rem;
    align-items: baseline;
}

.info-jours {
    color: var(--texte-mention);
}

.info-heures {
    color: var(--texte);
    font-variant-numeric: tabular-nums;
}

.info-heures-sep {
    color: var(--texte-mention);
    padding: 0 0.1875rem;
}

#info-panel a {
    color: var(--accent);
}

#map-cadre {
    position: relative;
    flex: 1;
    min-height: 0;
    min-width: 0;
    background-color: #000;
    overflow: hidden;
}

#map {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    /* Contexte d'empilement : tout ce que MapLibre pose dans le conteneur
       (voile des gestes coopératifs à z-index 99999, contrôles, infobulles)
       reste sous le bandeau collant (z-index 40) quand la page défile en
       affichage téléphone — comme déjà, par le transform, en texte agrandi. */
    z-index: 0;
    /* Appui long tactile = clic secondaire (UIManager.initAppuiLong) :
       Safari iOS ne doit pas y superposer sa bulle de rappel. */
    -webkit-touch-callout: none;
}

/* Texte agrandi : la carte est grossie du même facteur — conteneur MapLibre
   réduit d'autant puis agrandi par transform, comme un zoom d'affichage.
   Étiquettes, traits, repères et contrôles, dessinés en px, grossissent
   ensemble ; MapLibre ramène de lui-même les positions du pointeur dans le
   repère du canevas (getBoundingClientRect / offsetWidth). La netteté est
   préservée en relevant le pixelRatio du rendu d'autant (main.js). */
html[data-echelle] #map {
    width: calc(100% / var(--echelle));
    height: calc(100% / var(--echelle));
    transform: scale(var(--echelle));
    transform-origin: 0 0;
}

/* Les infobulles, seules parties de la carte réglées en rem pour suivre le
   grossissement du texte, seraient grossies deux fois maintenant que le
   conteneur l'est : on divise leurs valeurs rem par le facteur, le transform
   les remet à l'échelle choisie. */
html[data-echelle] .maplibregl-popup-content {
    font-size: calc(1rem / var(--echelle));
}

html[data-echelle] .maplibregl-popup-close-button {
    font-size: calc(1.5rem / var(--echelle));
    width: calc(2rem / var(--echelle));
    height: calc(2rem / var(--echelle));
}

html[data-echelle] .popup-title,
html[data-echelle] .popup-structures {
    padding-right: calc(1.625rem / var(--echelle));
}

/* Smartphone : aucune media query de disposition — l'empilement des champs
   (data-champs-empiles) comme le passage du panneau sous la carte
   (data-panneau-dessous, qui vient bien avant : le panneau, 20 rem au
   moins, dépasse ses 40 % dès 50 rem de fenêtre) sont des critères
   mesurés, plus haut, valables pour toute fenêtre, définition, zoom ou
   taille de texte. */

/* --- Pied de page : décrit dans site-entete.css, comme le bandeau de
   titre — il est le même sur toutes les pages. --- */

/* Centralisation du style de la popup.
   Les longueurs de l'infobulle restent en px, comme tout ce qui vit sous
   #map : le conteneur est grossi d'un bloc par le transform ci-dessus, et
   des rem y seraient grossis deux fois. Seules les tailles de texte sont en
   rem, moyennant la division par --echelle (règles plus haut). */
.maplibregl-popup-content {
    padding: 10px;
    border-radius: 4px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    color: var(--texte); /* Ajouté ici plutôt que dans le JS */
    font-family: var(--police);
    /* Le cran « md » du DSFR, au-dessus des 12 px hérités de .maplibregl-map :
       toutes les tailles de l'infobulle en découlent (titre en em, mentions,
       liens). En rem, pour suivre le réglage de taille du texte (page
       Accessibilité) — la feuille MapLibre, elle, reste en px. */
    font-size: 1rem;
}

.maplibregl-ctrl-scale {
    text-align: right !important;
}

/* Pastille de conseil de l'appui long (UIManager.initConseilAppuiLong), en
   bas de la carte au-dessus de l'échelle, hors de portée du doigt. En px
   comme les contrôles de la carte (cf. note sur #map plus haut). */
.conseil-appui-long {
    position: absolute;
    left: 50%;
    bottom: 40px;
    transform: translateX(-50%);
    max-width: calc(100% - 24px);
    padding: 6px 12px;
    border-radius: 16px;
    background-color: rgba(0, 0, 0, 0.7);
    color: #fff;
    font: 14px/1.3 var(--police);
    text-align: center;
    pointer-events: none;
    z-index: 2;
}

/* Boutons d'export de la carte (ExportCarte.js), en haut à droite : libellés
   texte (PNG, SVG) plutôt que pictogrammes MapLibre. Hauteur des contrôles
   MapLibre (29 px), mais élargis à leur contenu, en corps accordé aux
   glyphes « + / − » du zoom. En px comme le reste des contrôles de la carte
   (cf. note sur #map plus haut). */
.export-carte button {
    width: auto;
    min-width: 29px;
    padding: 0 8px;
    font: 700 13px/29px var(--police);
    color: var(--texte);
}

.maplibregl-popup-close-button {
    font-size: 1.5rem;
    width: 2rem;
    height: 2rem;
    color: var(--texte-mention);
    border-radius: 0 4px 0 0;
}

.maplibregl-popup-close-button:hover {
    background-color: var(--fond-alt);
    color: var(--accent);
}

/* --- Styles internes des infobulles --- */

.popup-title {
    margin: 0 0 10px 0;
    color: var(--accent);
    border-bottom: 1px solid var(--bordure);
    padding-bottom: 5px;
    /* Laisse de la place pour la croix : 2rem de large, collée au bord droit
       du contenu qui n'a que 10 px de rembourrage, elle empiète sur la zone
       de texte — son fond survolé mordait sur la fin du titre. En rem comme
       elle, pour que le dégagement suive le réglage de taille du texte. */
    padding-right: 1.625rem;
}

.popup-stat {
    margin: 5px 0;
    line-height: 1.2;
}

/* Infobulle de pays, de région (drapeau) ou de département (blason) :
   emblème à gauche, nom à sa droite. Un nom long
   passe à la ligne dans sa colonne et reste ainsi au niveau du drapeau ; le
   trait de séparation du titre court alors au bas de la colonne de droite. */
.popup-entete {
    display: flex;
    align-items: stretch;
    gap: 10px;
    margin-bottom: 10px;
}

.popup-entete .popup-title {
    flex: 1;
    margin: 0;
    display: flex;
    align-items: center;
}

/* Le drapeau mène à l'article du pays, comme son nom */
.popup-drapeau-lien {
    align-self: flex-start;
    line-height: 0;
}

/* Ombre portée plutôt qu'un cadre (même parti que le projet anki_world) :
   elle épouse la forme réelle du dessin — le drapeau du Népal est un double
   fanion — tout en détachant les drapeaux à bords blancs (Japon, Corée du
   Sud…) du fond de l'infobulle */
/* Hauteur normalisée plutôt que largeur : les rapports vont de 0,82 (Népal)
   à 2,55 (Qatar), si bien qu'à largeur fixe les drapeaux allaient de 28 à
   88 px de haut. Ils font désormais de 36 à 112 px de large, ce que la
   colonne du nom absorbe sans plafond de largeur — lequel écraserait le
   dessin, la hauteur étant imposée. */
.popup-drapeau {
    display: block;
    height: 44px;
    width: auto;
    filter: drop-shadow(1px 1px 3px rgba(0, 0, 0, 0.3));
}

/* Territoire non souverain : rappel du territoire sous l'en-tête de son pays
   de rattachement — mêmes éléments, en plus petit, sans filet, les
   statistiques qui suivent étant les siennes */
.popup-entete-territoire {
    margin-bottom: 5px;
}
.popup-entete-territoire .popup-title {
    font-size: 1em;
    border-bottom: none;
    padding-bottom: 0;
}
.popup-entete-territoire .popup-drapeau {
    height: 28px;
}

/* Groupe n° / voie / id d'une même voie : lignes resserrées,
   écart marqué entre deux voies */
.popup-adresse {
    margin: 8px 0;
}
.popup-adresse .popup-stat {
    margin: 0;
}

/* Liste des adresses : hauteur fixe et défilement, la liste étant rendue
   entière dès l'ouverture (certaines parcelles portent plus d'un millier
   d'adresses). La taille de l'infobulle ne bouge donc plus après coup. */
.popup-adresses {
    max-height: 300px;
    overflow-y: auto;
}

/* Fiche de structures (clic droit sur une emprise) : une colonne par
   structure quand l'emprise est partagée ou en conflit. La fiche est bornée
   en largeur (trois colonnes, UIManager) comme en hauteur : au-delà, les
   colonnes passent à la ligne et la fiche défile verticalement — une
   emprise peut porter des dizaines de structures superposées. */
.popup-structures {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    max-height: 300px;
    overflow-y: auto;
    /* Pas de titre au-dessus pour dégager la croix (contrairement à
       .popup-title) : la barre d'ascenseur, au bord droit, y mordrait sans
       ce même rembourrage. */
    padding-right: 1.625rem;
}

.popup-structures .popup-colonne {
    display: flex;
    gap: 9px;
    flex: 1 1 170px;
    max-width: 240px;
}

/* Bandeau vertical pleine hauteur rappelant l'emprise de la structure, comme
   .info-bandeau dans le panneau d'information : contour foncé et fond clair
   posés en style inline. En px, comme tout ce qui vit sous
   .maplibregl-popup-content (cf. plus bas). */
.popup-bandeau {
    flex: 0 0 10px;
    align-self: stretch;
    /* Centre le carré de tête sur la première ligne du titre. */
    margin-top: 4px;
    border: 2px solid;
    /* Bord haut épaissi : avec le biseau des bordures adjacentes, il forme un
       carré plein de la couleur d'emprise en tête du bandeau. */
    border-top-width: 14px;
    border-radius: 2px;
}

.popup-corps {
    min-width: 0;
    flex: 1;
}

/* Infobulle combinée (RÈGLE 2.1 assouplie) : la géographie du point
   (département, commune, section, parcelle) en tête, et la fiche des
   structures dont l'emprise colorée couvre le point cliqué dessous, plutôt
   que l'une remplaçant l'autre — un filet les sépare comme sous les titres.
   Empilés plutôt que côte à côte, les deux blocs disposent chacun de toute
   la largeur de l'infobulle. */
.popup-combinee > .custom-popup {
    padding-bottom: 10px;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--bordure);
}

.popup-desc {
    margin: 8px 0;
    font-style: italic;
    line-height: 1.4;
}

/* Liens Wikipédia glissés dans les textes éditoriaux (descriptions des
   fiches, messages des chasses — habillerLiensWiki) : couleur d'accent,
   soulignés — au fil de la prose, la couleur seule ne suffirait pas. */
.popup-desc a,
.decouverte-encart a,
.decouverte-final a,
.decouverte-jalon a {
    color: var(--accent);
}

/* Note en bas de fiche (cf. showAstrePopup) : en romain — la description
   au-dessus est en italique — et plus petite. En em, comme les autres
   tailles internes de l'infobulle. */
.popup-note {
    margin: 8px 0 0;
    font-size: 0.875em;
    line-height: 1.4;
}

/* --- Repère groupé des structures : quand plusieurs structures partagent un
   même point, une seule épingle blanche (le marqueur MapLibre par défaut, à
   liseré gris) portant le nombre de structures dans sa tête, avec une rangée de
   petits carrés aux couleurs des emprises regroupées (débordement « +k »). Le
   marqueur par défaut porte déjà l'ancrage de la pointe sur la coordonnée. --- */
.repere-nombre {
    /* Nombre affiché dans la tête du marqueur blanc (SVG 27×41, cœur centré
       en x = 13,5 / y = 13,5). */
    position: absolute;
    top: 13.5px;
    left: 13.5px;
    transform: translate(-50%, -50%);
    color: #333;
    font: 700 14px/1 system-ui, sans-serif;
    pointer-events: none;
}
.repere-carres {
    position: absolute;
    top: calc(100% + 2px);
    /* Entier (et non 50 % = 13,5px) : évite le demi-pixel qui étalerait et
       éclaircirait le trait de 1px des carrés. Largeur du pavé toujours paire,
       donc translateX(-50%) reste entier. */
    left: 13px;
    transform: translateX(-50%);
    /* Colonne de rangées centrées : la dernière rangée, si elle est plus
       courte, se centre sous les autres (décalage multiple de 8px, entier).
       Le fond blanc est porté par chaque rangée : il épouse la silhouette
       en escalier, sans bandeau blanc au bout d'une rangée courte. L'ombre
       suit cette silhouette (drop-shadow, et non box-shadow du rectangle). */
    display: flex;
    flex-direction: column;
    align-items: center;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3));
    pointer-events: none;
}
.repere-carres > div {
    display: flex;
    gap: 2px;
    padding: 3px;
    border-radius: 3px;
    background: #fff;
}
/* Chevauchement des rangées : 3px + 3px de marges intérieures − 4px = 2px
   entre carrés voisins, comme au sein d'une rangée ; les coins arrondis des
   rangées se fondent (blanc sur blanc) sans jour dans la silhouette. */
.repere-carres > div + div {
    margin-top: -4px;
}
.repere-carres span {
    width: 14px;
    height: 14px;
    box-sizing: border-box;
    border: 1px solid;
    border-radius: 2px;
    /* Positionnés, les carrés se peignent après tous les fonds de rangée :
       le recouvrement de 4px (> 3px de marge blanche) ferait sinon mordre
       le blanc d'une rangée sur le bas des carrés de la précédente. */
    position: relative;
    /* Cliquable (le pavé reste transparent aux clics) : resserre la sélection
       sur le seul service du carré. */
    pointer-events: auto;
    cursor: pointer;
}

/* ==========================================================================
   Chasses (Decouvertes.js) : encarts persistants — messages marquants
   (invitation, bonus des 8 000, complétions) empilés en haut au centre
   depuis le haut ; jalons intermédiaires empilés de même tout à gauche,
   en cadres tous identiques. Les encarts du centre ne se ferment qu'à
   leur croix, les jalons s'effacent aussi d'eux-mêmes (Decouvertes.js).
   Le rembourrage et la position en rem suivent l'échelle de texte,
   filets et ombre restent en pixels.
   ========================================================================== */
.decouverte-pile {
    position: absolute;
    left: 50%;
    top: 1.5rem;
    transform: translateX(-50%);
    z-index: 10;
    max-width: min(26rem, 90%);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.decouverte-jalons {
    position: absolute;
    left: 0.75rem;
    top: 1.5rem;
    z-index: 10;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.decouverte-encart,
.decouverte-final,
.decouverte-jalon {
    /* Ancre la croix de chaque encart ; le rembourrage droit lui
       réserve sa place. */
    position: relative;
    padding: 0.625rem 2.25rem 0.625rem 1rem;
    border: 1px solid var(--accent);
    border-radius: 0.5rem;
    background-color: var(--fond);
    color: var(--texte);
    font-size: 0.875rem;
    line-height: 1.4;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}

.decouverte-jalon {
    /* Cadre fixe, identique quel que soit le texte. */
    box-sizing: border-box;
    width: 18rem;
    height: 5.25rem;
    overflow: hidden;
}

.decouverte-jalon-fondu {
    /* Fondu avant l'effacement automatique ; durée à garder alignée
       sur FONDU_JALON_MS (Decouvertes.js). */
    opacity: 0;
    transition: opacity 2s;
}

.decouverte-fermer {
    position: absolute;
    top: 0;
    right: 0;
    width: 2rem;
    height: 2rem;
    border: none;
    border-radius: 0 0.5rem 0 0;
    background: none;
    color: var(--texte-mention);
    font-size: 1.25rem;
    cursor: pointer;
}

.decouverte-fermer:hover {
    background-color: var(--fond-alt);
    color: var(--accent);
}

/* ==========================================================================
   Chasse aux étoiles (ChasseEtoiles.js) : fiche d'une étoile célèbre,
   élément DOM posé par UIManager à la position écran de l'étoile — hors
   du globe, pas de lngLat où ancrer une infobulle MapLibre. La mise en
   forme reprend celle des infobulles (custom-popup et ses classes) ; les
   longueurs en px comme tout ce qui vit sous #map (cf. l'infobulle
   centralisée plus bas), les tailles de texte en rem corrigées de
   l'échelle.
   ========================================================================== */
.popup-etoile {
    position: absolute;
    z-index: 10;
    width: max-content;
    max-width: 300px;
    padding: 10px;
    border-radius: 4px;
    background-color: var(--fond);
    color: var(--texte);
    font-family: var(--police);
    font-size: 1rem;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

html[data-echelle] .popup-etoile {
    font-size: calc(1rem / var(--echelle));
}

.popup-etoile-fermer {
    position: absolute;
    top: 0;
    right: 0;
    width: 2rem;
    height: 2rem;
    border: none;
    border-radius: 0 4px 0 0;
    background: none;
    color: var(--texte-mention);
    font-size: 1.5rem;
    cursor: pointer;
}

.popup-etoile-fermer:hover {
    background-color: var(--fond-alt);
    color: var(--accent);
}

html[data-echelle] .popup-etoile-fermer {
    font-size: calc(1.5rem / var(--echelle));
    width: calc(2rem / var(--echelle));
    height: calc(2rem / var(--echelle));
}

/* ==========================================================================
   Volet bas (VoletBas.js) : sur petit écran (data-panneau-dessous), les
   infobulles de la carte s'affichent dans un volet fixé au bas de la
   fenêtre, pleine largeur, plutôt qu'ancrées au point cliqué. Posé sur body,
   hors du conteneur grossi par transform : les rems sont ceux de la page,
   sans correction d'échelle — les règles html[data-echelle] des infobulles
   sont donc annulées ici. Au-dessus de la carte (contexte z-index 0), sous
   le tiroir du menu (30) et le bandeau collant (40).
   ========================================================================== */
.volet-bas {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    max-height: 45vh;
    max-height: 45svh;
    border-top: 1px solid var(--bordure);
    border-radius: 0.75rem 0.75rem 0 0;
    background-color: var(--fond);
    color: var(--texte);
    font-family: var(--police);
    font-size: 1rem;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.2);
}

/* Le glissé du doigt sur le volet ne doit jamais faire défiler la page
   (qui défile sur petit écran, cf. data-panneau-dessous) : en bout de
   course du contenu, le geste s'enchaînerait à la page et déplacerait la
   carte dessous. Le volet bloque tout geste, seul le contenu défile, sans
   enchaînement. */
.volet-bas {
    touch-action: none;
}

/* Seul le contenu défile : la croix reste en place. */
.volet-bas-contenu {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
}

.volet-bas-fermer {
    position: absolute;
    top: 0;
    right: 0;
    width: 2rem;
    height: 2rem;
    border: none;
    border-radius: 0 0.75rem 0 0;
    background: none;
    color: var(--texte-mention);
    font-size: 1.5rem;
    cursor: pointer;
}

.volet-bas-fermer:hover {
    background-color: var(--fond-alt);
    color: var(--accent);
}

/* Le volet défile d'un bloc : pas d'ascenseurs imbriqués (structures,
   adresses), et les colonnes de structures prennent toute la largeur. */
.volet-bas .popup-structures,
.volet-bas .popup-adresses {
    max-height: none;
    overflow-y: visible;
}

.volet-bas .popup-structures .popup-colonne {
    max-width: none;
}

html[data-echelle] .volet-bas .popup-title,
html[data-echelle] .volet-bas .popup-structures {
    padding-right: 1.625rem;
}
