/* La pile de photos d'une annonce : des tirages qui se chevauchent, légèrement
   tournés, comme posés en paquet. Seules les premières vignettes se montrent —
   le badge dit combien la pile en tient — et le paquet s'ouvre dans la
   visionneuse (.photo-viewer), posée par-dessus la page. */
.photo-stack {
  display: inline-flex;
  align-items: center;
  /* Les indices des tirages ne parlent qu'entre eux : sans cette isolation,
     un tirage (z-index jusqu'à 6) passait par-dessus la barre de filtres et
     les titres de commune, sticky à 4 et 2, en défilant sous eux. */
  isolation: isolate;
}

.photo-stack__item {
  position: relative;
  flex: none;
  width: 3.5rem;
  height: 3.5rem;
  padding: 0;
  border: 2px solid #fff;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background-color: var(--color-surface);
  box-shadow: var(--shadow-md);
  cursor: zoom-in;
  transition: transform 0.12s ease;
  transform: rotate(var(--tilt, 0deg));
}

.photo-stack__item + .photo-stack__item {
  margin-left: -2.25rem;
}

/* Le paquet, pas l'alignement : chaque tirage penche de son côté. En variable
   plutôt qu'en `transform` direct, pour que la donne (photo_stack_controller)
   sache sur quelle inclinaison chaque tirage doit finir. */
.photo-stack__item:nth-child(odd) {
  --tilt: -3deg;
}

.photo-stack__item:nth-child(even) {
  --tilt: 2.5deg;
}

/* La première photo dessus : c'est celle que l'annonce met en avant. Sans
   ceci l'ordre du document peindrait la dernière par-dessus toutes — et la
   donne fait maintenant glisser chaque nouvelle photo SOUS les précédentes,
   qui est bien le geste de ranger un tirage dans un paquet. */
.photo-stack__item:nth-child(1) { z-index: 5; }
.photo-stack__item:nth-child(2) { z-index: 4; }
.photo-stack__item:nth-child(3) { z-index: 3; }
.photo-stack__item:nth-child(4) { z-index: 2; }
.photo-stack__item:nth-child(5) { z-index: 1; }

/* Au-delà de cinq, la pile s'épaissit sans rien montrer de plus : le reste
   attend dans la visionneuse, et le badge l'annonce. */
.photo-stack__item:nth-child(n + 6) {
  display: none;
}

.photo-stack__item:hover,
.photo-stack__item:focus-visible {
  transform: rotate(0) scale(1.5);
  z-index: 6;
}

.photo-stack__item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Un bouton comme les tirages : il ouvre la même visionneuse, sur la première
   photo — la pile en cache la moitié, le chiffre est la poignée du reste. */
.photo-stack__count {
  margin-left: var(--space-2xs);
  padding: var(--space-3xs) var(--space-2xs);
  border-radius: var(--radius-full);
  background-color: rgb(255 255 255 / 0.92);
  box-shadow: var(--shadow-sm);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-text-soft);
  cursor: zoom-in;
}

.photo-stack__count:hover,
.photo-stack__count:focus-visible {
  background-color: #fff;
  color: var(--color-text);
}

/* Sur la carte, la pile parle de plus loin : tirages plus grands, et le
   chevauchement suit la taille. La donne — chaque photo paraît en grand au
   centre de la carte puis glisse se ranger sur le paquet — vit dans
   photo_stack_controller : le centre de la carte ne se mesure qu'en JS. */
.photo-stack--large .photo-stack__item {
  width: 6rem;
  height: 6rem;
}

.photo-stack--large .photo-stack__item + .photo-stack__item {
  margin-left: -3.9rem;
}

/* En attendant Firecrawl : la même capsule que le badge, sans photos. */
.photo-stack--pending {
  padding: var(--space-3xs) 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);
}

/* Le mot de l'attente : la part écrite, puis la part encore à écrire —
   invisible mais qui tient sa place, pour que la bulle prenne la largeur du
   mot entier dès le premier battement et ne bouge plus pendant la frappe.
   Sur une ligne : un reste qui replierait mentirait sur la largeur. */
.photo-stack__scanning {
  white-space: nowrap;
  font-weight: var(--weight-medium);
}

/* La part écrite, balayée de droite à gauche par un dégradé orange →
   violet : quelque chose travaille. Peint sur les lettres seules
   (background-clip) — la capsule garde son fond blanc. Les couleurs des deux
   bouts se répondent, le balayage boucle sans couture. */
.photo-stack__typed {
  background-image: linear-gradient(90deg,
    #b45309, #f97316 30%, #8b5cf6 60%, #b45309 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: photo-stack-scanning 1.8s linear infinite;
}

/* La part encore à écrire : sa place sans ses lettres. */
.photo-stack__rest {
  visibility: hidden;
}

@keyframes photo-stack-scanning {
  from {
    background-position-x: 200%;
  }

  to {
    background-position-x: 0%;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Sans mouvement : pas de balayage, et pas de frappe non plus —
     listing_scan_controller s'abstient, le mot se pose entier. */
  .photo-stack__typed {
    animation: none;
    color: var(--color-text-soft);
    background-image: none;
  }
}

/* La grille d'aperçu : toutes les photos de l'annonce, qui se parcourent en
   défilant — c'est elle que la pile ouvre. Un clic sur une photo passe à la
   visionneuse (.photo-viewer), posée par-dessus. */
.photo-grid {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  background-color: rgb(15 23 42 / 0.94);
}

.photo-grid__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-sm) var(--space-md);
}

.photo-grid__title {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: rgb(255 255 255 / 0.85);
}

.photo-grid__body {
  flex: 1;
  overflow-y: auto;
  padding: 0 var(--space-md) var(--space-xl);
}

.photo-grid__list {
  list-style: none;
  max-width: 44rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: 0;
}

.photo-grid__item {
  position: relative;
}

.photo-grid__shot {
  display: block;
  width: 100%;
  padding: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: zoom-in;
  background-color: rgb(255 255 255 / 0.06);
}

.photo-grid__shot img {
  display: block;
  width: 100%;
}

/* Le bouton d'enregistrement de chaque photo, posé sur son coin. Toujours
   visible : au doigt, il n'y a pas de survol pour le faire paraître. */
.photo-grid__download {
  position: absolute;
  top: var(--space-xs);
  right: var(--space-xs);
}

/* La visionneuse : la photo en plein écran, par-dessus la grille. Un clic
   sur la photo feuillette, tout le reste rend la grille — voir
   photo_stack_controller. */
.photo-viewer {
  position: fixed;
  inset: 0;
  z-index: 55;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  background-color: rgb(15 23 42 / 0.82);
}

.photo-viewer__frame {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2xs);
}

.photo-viewer__photo {
  max-width: min(56rem, 84vw);
  max-height: 76vh;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  cursor: pointer;
  transition: opacity 0.15s ease;
}

/* Le voyage d'une photo se voit : celle qui part s'estompe sous l'anneau qui
   tourne, et le compteur — déjà passé — annonce celle qui arrive. Sans cela,
   sur une connexion lente, l'ancienne photo restait pleine sous un numéro
   qui ne la désignait plus. */
.photo-viewer--loading .photo-viewer__photo {
  opacity: 0.2;
}

.photo-viewer__loader {
  position: absolute;
  top: calc(50% - 1.25rem);
  left: calc(50% - 1.25rem);
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  border: 3px solid rgb(255 255 255 / 0.25);
  border-top-color: #fff;
  opacity: 0;
  pointer-events: none;
  animation: photo-viewer-spin 0.8s linear infinite;
}

.photo-viewer--loading .photo-viewer__loader {
  opacity: 1;
}

@keyframes photo-viewer-spin {
  to {
    transform: rotate(1turn);
  }
}

@media (prefers-reduced-motion: reduce) {
  .photo-viewer__loader {
    animation: none;
  }
}

.photo-viewer__count {
  font-size: var(--text-sm);
  color: rgb(255 255 255 / 0.85);
}

.photo-viewer__step,
.photo-viewer__close,
.photo-viewer__download,
.photo-grid__close,
.photo-grid__download {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  background-color: rgb(255 255 255 / 0.14);
  color: #fff;
  font-size: var(--text-lg);
  line-height: 1;
}

.photo-viewer__step:hover,
.photo-viewer__close:hover,
.photo-viewer__download:hover,
.photo-grid__close:hover,
.photo-grid__download:hover {
  background-color: rgb(255 255 255 / 0.28);
}

.photo-viewer__download svg,
.photo-grid__download svg {
  width: 1.25rem;
  height: 1.25rem;
}

.photo-viewer__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
}

/* L'enregistrement à côté de la croix : les deux gestes qui ne feuillettent
   pas vivent ensemble, hors du chemin des flèches. */
.photo-viewer__download {
  position: absolute;
  top: var(--space-sm);
  right: calc(var(--space-sm) + 3rem);
}
