.map {
  position: absolute;
  inset: 0;
}

.map--picking {
  cursor: crosshair;
}

/* Le coin des réglages de la carte : les fonds, et dessous la surcouche des
   prix — en colonne, pour que chaque pilule garde sa largeur de pilule. */
.map__controls {
  position: absolute;
  top: var(--space-sm);
  left: var(--space-sm);
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2xs);
}

.map__modes {
  display: flex;
  padding: 3px;
  border-radius: var(--radius-full);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-md);
}

.map__mode {
  padding: var(--space-3xs) var(--space-sm);
  border-radius: var(--radius-full);
  color: var(--color-text-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.map__mode.is-active {
  background-color: var(--color-primary);
  color: #fff;
}

/* Le raccourci de la surcouche des prix, sous les fonds : l'interrupteur de
   la maison dans une pilule blanche — le curseur qui glisse dit « réglage »
   d'un regard, là où une pilule pleine se lisait comme un troisième fond.
   Allumé, le rail prend la teinte des ventes qu'il pose. `switch.css` arrive
   après ce fichier dans le paquet (ordre alphabétique) : les états gardent la
   pilule dans leur sélecteur pour peser plus lourd que le vert d'origine. */
.switch.map__sales {
  padding: var(--space-3xs) var(--space-sm) var(--space-3xs) var(--space-2xs);
  border-radius: var(--radius-full);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-md);
}

.switch.map__sales .switch__label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.switch.map__sales input:checked ~ .switch__track {
  background-color: #7c3aed;
}

.switch.map__sales:hover input:checked ~ .switch__track {
  background-color: #6d28d9;
}

/* Les deux filtres de la surcouche, sous leur interrupteur : les pilules de
   la liste des sauvegardées posées sur la carte — l'ombre en plus, le fond de
   carte ne leur fait pas de fond. Côte à côte : la colonne des réglages est
   déjà haute sur un petit écran. */
.map__filters {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
}

.map__filters .filter {
  box-shadow: var(--shadow-md);
}

/* Sur la carte, pas de barre pleine largeur où amarrer le menu : l'ancrage à
   la pilule que filter.css cède sous 30rem est repris ici. */
@media (max-width: 30rem) {
  .map__filters .filter-dropdown {
    position: relative;
  }

  .map__filters .filter-dropdown__menu {
    inset-inline: 0 auto;
    min-width: 14rem;
  }
}

/* Le dossier de l'annonce en cours, posé en haut de la carte, au centre :
   la pile laisse le coin gauche aux fonds de carte et le droit au zoom. Le
   cadre Turbo est mis au bloc pour que la colonne du dossier se centre. */
.map__photos {
  position: absolute;
  top: var(--space-sm);
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.map__photos turbo-frame {
  display: block;
}

.map__legend {
  position: absolute;
  right: var(--space-sm);
  bottom: var(--space-sm);
  z-index: 5;
  display: flex;
  gap: var(--space-sm);
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-full);
  background-color: rgb(255 255 255 / 0.92);
  box-shadow: var(--shadow-sm);
  font-size: var(--text-xs);
  color: var(--color-text-soft);
}

.map__key {
  display: flex;
  align-items: center;
  gap: var(--space-3xs);
}

.map__key::before {
  content: "";
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 2px;
  border: 1.5px solid currentcolor;
}

.map__key--land::before {
  border-color: var(--color-land);
  background-color: rgb(37 99 235 / 0.3);
}

.map__key--building::before {
  border-color: var(--color-building);
  background-color: rgb(220 38 38 / 0.45);
}

.map__key--saved::before {
  border-color: var(--color-saved);
  background-color: rgb(22 163 74 / 0.3);
}

/* La clé de la prospection n'existe que sur son onglet — voir plus bas. */
.map__key--prospect {
  display: none;
}

.map__key--prospect::before {
  border-color: var(--color-prospect);
  background-color: rgb(249 115 22 / 0.3);
}

/* Le médaillon d'une adresse gardée : la photo de l'annonce dans un cercle,
   le prix dessous — posé par map_controller au centre de la parcelle. Sa
   taille suit le zoom par la variable que le contrôleur tient sur le canevas.
   MapLibre place le bouton lui-même (transform inline) : tout effet visuel
   reste sur l'image, jamais sur la racine. */
.map-photo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 0;
}

.map-photo.is-active {
  z-index: 2;
}

.map-photo__img {
  width: var(--map-photo-size, 44px);
  height: var(--map-photo-size, 44px);
  border-radius: var(--radius-full);
  border: 2px solid #fff;
  box-shadow: var(--shadow-md);
  object-fit: cover;
  background-color: #fff;
  transition: transform 0.15s ease;
}

.map-photo.is-active .map-photo__img {
  transform: scale(1.08);
}

.map-photo--bare .map-photo__img {
  display: none;
}

/* Le prix tel que l'étiquette MapLibre l'écrit pour les parcelles sans photo :
   vert profond sous halo blanc — le halo en ombres, faute de mieux en CSS. */
.map-photo__label {
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.15;
  white-space: nowrap;
  color: #14532d;
  text-shadow:
    -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff,
    -1.5px 0 0 #fff, 1.5px 0 0 #fff, 0 -1.5px 0 #fff, 0 1.5px 0 #fff;
}

/* La bulle d'une vente passée, ouverte au clic sur un point. MapLibre fournit
   la boîte et sa flèche ; on lui reprend la typographie, les rayons et l'ombre,
   qui doivent être ceux du reste de l'app — la bulle livrée telle quelle,
   Helvetica 12px sur coins presque droits, jurait à côté des panneaux. */
.map .maplibregl-popup-content {
  padding: var(--space-sm);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  animation: sale-bubble-rise 0.18s ease-out;
}

/* La bulle entre en fondu, flèche comprise, pendant que son contenu monte
   d'un souffle (ci-dessus). L'opacité seule sur la racine : MapLibre y pose
   son transform de position en style inline, une animation de transform
   l'écraserait et enverrait la bulle à l'origine le temps de l'entrée. */
.map .maplibregl-popup {
  animation: sale-bubble-fade 0.18s ease-out;
}

@keyframes sale-bubble-fade {
  from {
    opacity: 0;
  }
}

@keyframes sale-bubble-rise {
  from {
    transform: translateY(3px);
  }
}

.sale-bubble {
  font-family: var(--font-body);
  line-height: var(--leading);
}

/* Le temps que la frise remplace l'aperçu, la bulle glisse de son ancienne
   taille à la nouvelle au lieu de claquer — les tailles inline sont posées
   par map_controller, la classe ne vit que le geste. Le débord se cache :
   c'est lui qui révèle la frise au fil du glissement. */
.sale-bubble--sizing {
  overflow: hidden;
  transition: width 0.22s ease, height 0.22s ease;
}

/* Le type du bien en étendard — la silhouette et le mot, en petites capitales
   sur fond enfoncé : un tampon plus qu'un titre, qui dit maison ou champ
   avant que l'œil ne descende dans les chiffres. */
.sale-bubble__kind {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  margin-bottom: var(--space-3xs);
  padding: var(--space-4xs) var(--space-xs);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-sunken);
  color: var(--color-text);
  font-size: 0.6875rem;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.sale-bubble__kind svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* L'adresse que la BAN donne à la parcelle, sous l'étendard — elle dit
   quelle maison avant que les chiffres ne disent combien. */
.sale-bubble__address {
  margin-bottom: var(--space-3xs);
  font-size: var(--text-xs);
  color: var(--color-text-soft);
}

.sale-bubble__price {
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  color: var(--color-text);
}

.sale-bubble__detail {
  font-size: var(--text-sm);
  color: var(--color-text-soft);
}

/* Le compte des ventes d'avant, le temps que leur liste arrive — et à sa
   place si le réseau ne la livre pas. */
.sale-bubble__wait {
  margin-top: var(--space-4xs);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
}

/* La frise : ventes et DPE dans la même colonne de dates, du plus récent au
   plus ancien, chaque ligne sous son filet. Tout s'aligne à gauche sous un
   en-tête en petites capitales — la bulle se lit comme une fiche, pas comme
   un livre de comptes. */
.sale-bubble__table {
  margin-top: var(--space-2xs);
  border-collapse: collapse;
  font-size: var(--text-xs);
  color: var(--color-text-soft);
}

.sale-bubble__table th,
.sale-bubble__table td {
  padding: var(--space-3xs) 0 var(--space-3xs) var(--space-sm);
  text-align: left;
  vertical-align: baseline;
  font-weight: var(--weight-regular);
  white-space: nowrap;
}

.sale-bubble__table th:first-child {
  padding-left: 0;
}

.sale-bubble__table thead tr {
  border-bottom: 1px solid var(--color-border);
}

.sale-bubble__table thead th {
  color: var(--color-text-faint);
  font-size: 0.625rem;
  font-weight: var(--weight-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.sale-bubble__table tbody tr + tr {
  border-top: 1px solid var(--color-border);
}

/* Chaque ligne ouvre sur sa pastille et sa date, dans l'encre de son fil —
   le bleu des ventes, l'orange du diagnostic. */
.sale-bubble__table tbody th {
  color: var(--timeline-ink, var(--color-land));
  font-weight: var(--weight-semibold);
}

.sale-bubble__dot {
  display: inline-block;
  width: 0.375rem;
  height: 0.375rem;
  margin-right: var(--space-2xs);
  border-radius: var(--radius-full);
  background-color: var(--timeline-ink, var(--color-land));
  vertical-align: middle;
}

.sale-bubble__row--dpe {
  --timeline-ink: var(--color-highlight);
}

/* Le prix au-dessus de son mètre carré ; la vente la plus récente — celle
   que le point affiche — parle un corps au-dessus des autres. */
.sale-bubble__amount strong {
  display: block;
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  line-height: 1.3;
}

.sale-bubble__row--latest .sale-bubble__amount strong {
  font-size: var(--text-md);
}

.sale-bubble__amount small {
  display: block;
  color: var(--color-text-faint);
  font-size: 0.6875rem;
  line-height: 1.4;
}

/* L'étiquette du diagnostic dans la couleur de partout, ramenée à la taille
   de la ligne, le mot DPE à sa suite. */
.sale-bubble__diagnosis .dpe {
  width: 1.125rem;
  height: 1.125rem;
  margin-right: var(--space-4xs);
  font-size: 0.6875rem;
}

/* Le glissement de taille est neutralisé côté contrôleur, qui applique les
   tailles sans transition quand le mouvement est refusé. */
@media (prefers-reduced-motion: reduce) {
  .map .maplibregl-popup,
  .map .maplibregl-popup-content {
    animation: none;
  }
}

/* Sur le panneau des sauvegardées, la carte se tait sur la recherche en cours.
   Les parcelles candidates s'effacent — voir map_controller — et le dossier de
   l'annonce quitte le haut de la carte : chaque adresse gardée porte le sien
   sur sa fiche, et celui-là appartient à une recherche qu'on ne regarde plus.
   La clé « parcelle » part avec elles, une couleur que plus rien ne porte se
   lisant comme une erreur ; le bâti reste, les adresses gardées dessinent le
   leur, du même rouge. */
.workspace--saved .map__photos,
.workspace--saved .map__key--land {
  display: none;
}

/* Sur l'onglet Prospection, même effacement — candidats et dossier d'annonce
   quittent la carte — et la clé orange prend la place des deux couleurs de la
   recherche. Le vert reste : les adresses gardées ne quittent jamais la
   carte, c'est le sens de les garder. */
.workspace--prospect .map__photos,
.workspace--prospect .map__key--land,
.workspace--prospect .map__key--building {
  display: none;
}

.workspace--prospect .map__key--prospect {
  display: flex;
}

@media (max-width: 52rem) {
  .map__legend {
    display: none;
  }
}
