/* =============================================================================
   Section Bazar — ce qui lui est propre.

   La composition vient de la charte Search (tools/assets/css/style.css) et de
   la mise en page commune des listes (css/section-liste.css) : même fil, même
   titre, même barre, mêmes filtres que Ressources. La couleur est celle du
   Bazar, posée par php/charte_section.php d'après php/config_theme.php.

   Restent ici les objets du Bazar : sa grille, ses tuiles — celles des sites de
   petites annonces, un cadre et ce qu'on lit dessous — et la fenêtre qui
   détaille une annonce.
   ============================================================================= */

/* Le bouton de gauche de la barre — déposer dans Annonces, mélanger dans la
   Bibliothèque — tient sa place et ne se rétrécit pas ; c'est le champ qui
   cède, comme pour #btn-proposer-entite dans Ressources. */
#btn-proposer-annonce,
#btn-melanger {
  flex: 0 0 auto;
  gap: .4rem;
  white-space: nowrap;
  text-decoration: none;
}

/* ---------- la grille du Bazar ---------------------------------------------

   Les deux listes du Bazar ont leur grille à elles :

     • CINQ colonnes au plus, sur grand écran ;
     • DEUX sur téléphone — le Bazar se parcourt comme une vitrine ;
     • UNE, au moins, là où deux tuiles ne tiendraient plus : sous trois cents
       pixels, un écran de montre ou un téléphone replié ;
     • entre les deux, autant que la place en donne, sans qu'une colonne passe
       sous deux cents pixels.

   Le plafond tient dans la largeur minimale elle-même : une colonne vaut au
   moins le cinquième de la ligne, écarts déduits, si bien qu'une sixième n'a
   jamais la place de se glisser. Le nombre de colonnes est lu sur la grille
   par javascript/pagination.js : une page reste de vingt-quatre lignes.

   Les tuiles n'ont pas de fond de carte : c'est l'écart vertical qui sépare le
   bas d'une tuile — son auteur — du cadre de la suivante. */
.grille-bazar {
  grid-template-columns: repeat(auto-fill, minmax(max(200px, calc((100% - 4 * .9rem) / 5)), 1fr));
  row-gap: 1.6rem;
}

@media (max-width: 600px) {
  .grille-bazar {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.2rem .65rem;
  }
}

@media (max-width: 300px) {
  .grille-bazar {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------- la tuile --------------------------------------------------------

   Un cadre, et en dessous ce qu'on regarde avant d'ouvrir. Les informations
   viennent en tête du document et le cadre est remonté par « order » : une
   lecture à voix haute commence par le titre. Le lien du titre s'étend à
   toute la tuile ; les étiquettes et le bouton du cadre passent au-dessus de lui. */
.tuile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .6rem;
  min-width: 0;
}

.tuile__cadre {
  order: -1;
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* Le survol éclaire le cadre sans le soulever : un déplacement ferait du cadre
   un contexte d'empilement, et le lien étendu passerait par-dessus son
   bouton. */
.tuile:hover .tuile__cadre {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-md);
}

.tuile:has(.tuile__lien:focus-visible) .tuile__cadre {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.tuile__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity .28s var(--ease);
}

/* La description dans le cadre : sous les étiquettes, et fondue en bas plutôt que
   coupée net — on devine qu'il y a une suite, qu'on lit en ouvrant. */
.tuile__description {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 2.55rem .95rem 1rem;
  font-size: .84rem;
  line-height: 1.5;
  color: var(--text-2);
  overflow: hidden;
  overflow-wrap: anywhere;
  background: var(--surface);
  -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent 97%);
  mask-image: linear-gradient(to bottom, #000 72%, transparent 97%);
  transition: opacity .28s var(--ease), visibility .28s;
}

/* Une annonce avec photo montre la photo ; son bouton retourne le cadre sur la
   description, et le retourne encore. */
.tuile__cadre--photo .tuile__description {
  opacity: 0;
  visibility: hidden;
}

.tuile__cadre--photo.est-retourne .tuile__description {
  opacity: 1;
  visibility: visible;
}

.tuile__cadre--photo.est-retourne .tuile__photo {
  opacity: 0;
}

/* Le type et la catégorie, en tête du cadre : ce qui trie une grille d'un coup
   d'œil, avant même le titre. Ils n'interceptent rien : un clic dessus ouvre
   l'annonce comme ailleurs.

   Une seule ligne, arrêtée avant le bouton du cadre. C'est la catégorie qui
   cède, coupée d'une ellipse, jamais le type : sur deux lignes, les
   étiquettes descendraient sur la description. */
.tuile__badges {
  position: absolute;
  top: .6rem;
  left: .6rem;
  right: .6rem;
  z-index: 2;
  display: flex;
  gap: .3rem;
  margin: 0;
  pointer-events: none;
}

/* La place du bouton : 34px, à .45rem du bord. */
.tuile__cadre--photo .tuile__badges {
  right: calc(.45rem + 34px + .35rem);
}

/* Sur une photo, une étiquette sans aplat deviendrait illisible : la demande
   « en creux » et la catégorie prennent un fond. */
.tuile__cadre--photo .tuile__badges .tag {
  box-shadow: 0 1px 6px rgb(0 0 0 / .18);
}

.tuile__cadre--photo .tag--demande,
.tuile__cadre--photo .tag--categorie {
  background: var(--surface);
}

.tuile__bascule {
  position: absolute;
  top: .45rem;
  right: .45rem;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.tuile__bascule:hover {
  border-color: var(--line-strong);
  color: var(--accent);
}

.tuile__bascule:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.tuile__bascule .icone--photo,
.tuile__cadre.est-retourne .tuile__bascule .icone--texte {
  display: none;
}

.tuile__cadre.est-retourne .tuile__bascule .icone--photo {
  display: block;
}

/* ---- signalée, pour l'administration --------------------------------------

   La marque des cartes de Logiciels (.card__attente, dans la charte), dans
   l'ambre des signalements : un liseré autour du cadre, et « Signalée » posé à
   son coin. Au coin du bas et non du haut : celui du haut porte déjà le bouton
   qui retourne la photo, et la marque se lit ainsi juste au-dessus du titre.

   Rien de tout cela en mode utilisateur : la marque porte .admin-only, et le
   liseré attend le mode administrateur. */
html:not([data-archiverse-role="user"]) .tuile--signalee .tuile__cadre {
  border-color: var(--warn);
}

.tuile__signalee {
  top: auto;
  right: auto;
  bottom: 0;
  left: 0;
  /* Le coin du cadre, pris de l'intérieur : son arrondi, moins le filet. */
  border-radius: 0 var(--r-card) 0 calc(var(--r-card) - 1px);
  /* Comme les étiquettes : un clic dessus ouvre l'annonce. */
  pointer-events: none;
}

/* Sous le cadre. */
.tuile__infos {
  display: grid;
  gap: .1rem;
  min-width: 0;
  padding-inline: .1rem;
}

.tuile__titre {
  margin: 0;
  font-family: var(--font-sans);
  font-size: .9rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.tuile__lien {
  color: inherit;
  text-decoration: none;
}

.tuile__lien::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.tuile__lien:focus-visible {
  outline: none;
}

.tuile__prix {
  margin-top: .15rem;
  font-size: .95rem;
  font-weight: 700;
  color: var(--text);
}

.tuile__prix--remunere {
  font-family: var(--font-mono);
}

.tuile__prix--echange {
  color: var(--text-2);
}

.tuile__prix--gratuit {
  color: var(--ok);
}

.tuile__meta,
.tuile__auteur {
  min-width: 0;
  font-size: .77rem;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tuile__auteur {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin-top: .2rem;
}

.tuile__auteur span:last-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- l'avatar et les étiquettes, sur la tuile et dans la fenêtre ---- */

/* L'initiale de l'auteur, à la couleur de la section, et sa photo posée
   dessus quand il en a une (bazar_avatar(), php/bazar_annonces.php). Une
   photo qui ne vient pas s'efface et l'initiale reste : le rond vide qu'on
   voyait ressemblait à une image qui n'a pas chargé — c'en était une. */
.annonce__avatar {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  overflow: hidden;
  border: 1px solid var(--accent-line);
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-display);
  font-weight: 650;
  font-size: 1.05rem;
  line-height: 1;
}

.annonce__avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Sous une photo, le filet redevient neutre : la couleur de la section est
   celle de l'initiale. */
.annonce__avatar:has(img) {
  border-color: var(--line);
}

.tuile__auteur .annonce__avatar {
  width: 20px;
  height: 20px;
  font-size: .62rem;
}

.tag--sens {
  flex: none;
  font-weight: 600;
}

.tag--offre {
  background: var(--accent-soft);
  color: var(--accent);
}

/* La demande en creux : même couleur, sans aplat. Les deux se distinguent d'un
   coup d'œil, et aucune ne ressemble à une alerte. */
.tag--demande {
  background: transparent;
  color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}

.tag--categorie {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- la tuile d'un tracé (Bibliothèque) ------------------------------ */

/* Le cadre est carré, comme celui d'une annonce, et l'aperçu y tient entier,
   au centre. Le fond est BLANC dans les deux thèmes : ce sont des dessins au
   trait noir, faits pour le papier. Sur le gris du mode sombre, ils
   disparaîtraient. */
.tuile--trace .tuile__cadre {
  --trace-marge: .9rem;
  display: grid;
  place-items: center;
  padding: var(--trace-marge);
  background: #fff;
}

/* L'aperçu est posé sur le cadre, marges déduites, et non rangé dans sa grille.
   Dans une grille, une hauteur en pourcentage se calcule contre la rangée — et
   la rangée, c'est l'image qui l'allonge : un dessin en hauteur, un personnage,
   dépassait du cadre et n'en montrait que le haut. Posé ainsi, il a la place
   exacte du cadre, et « contain » le centre sans rien couper. */
.tuile__trace {
  position: absolute;
  top: var(--trace-marge);
  left: var(--trace-marge);
  width: calc(100% - 2 * var(--trace-marge));
  height: calc(100% - 2 * var(--trace-marge));
  object-fit: contain;
}

/* L'aperçu qui ne vient pas : une mention, pas une icône cassée. */
.tuile__cadre--vide .tuile__trace {
  display: none;
}

.tuile__cadre--vide::after {
  content: "Aperçu indisponible";
  font-size: .78rem;
  color: #83878f;
}

.tuile--trace .tuile__meta {
  display: flex;
  align-items: center;
  gap: .3rem;
}

.tuile--trace .tuile__meta span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tuile--trace .tuile__meta svg {
  flex: none;
}

/* ---------- sur téléphone -----------------------------------------------------

   Deux colonnes laissent à une tuile cent soixante pixels : le texte se
   resserre, le cadre garde sa forme. */
@media (max-width: 600px) {
  .tuile {
    gap: .45rem;
  }

  .tuile__description {
    padding: 2.15rem .65rem .7rem;
    font-size: .74rem;
    line-height: 1.45;
  }

  .tuile__badges {
    top: .45rem;
    left: .45rem;
    right: .45rem;
    gap: .22rem;
  }

  .tuile__cadre--photo .tuile__badges {
    right: calc(.35rem + 30px + .3rem);
  }

  .tuile__badges .tag {
    font-size: .66rem;
    padding: .12rem .42rem;
  }

  .tuile__signalee {
    font-size: .66rem;
    padding: .14rem .45rem;
  }

  .tuile__bascule {
    top: .35rem;
    right: .35rem;
    width: 30px;
    height: 30px;
  }

  .tuile__titre {
    font-size: .82rem;
  }

  .tuile__prix {
    font-size: .86rem;
  }

  .tuile__meta,
  .tuile__auteur {
    font-size: .7rem;
  }

  .tuile__auteur .annonce__avatar {
    width: 16px;
    height: 16px;
    font-size: .52rem;
  }

  .tuile--trace .tuile__cadre {
    --trace-marge: .5rem;
  }
}

/* ---------- l'attente : la silhouette d'une tuile -----------------------------

   La forme de la tuile qu'elle remplace : un cadre de la même proportion, et
   la hauteur exacte des lignes du dessous — mesurée sur les vraies tuiles, voir
   les valeurs plus bas. La base des silhouettes — le balayage, les lignes —
   est dans tools/assets/css/style.css ; php/attente.php en écrit le balisage. */
.silhouette--tuile {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  gap: .6rem;
}

.silhouette--tuile .silhouette__cadre {
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background-color: var(--surface-2);
  background-image: linear-gradient(90deg,
    transparent 0%, var(--surface-3) 45%, var(--surface-3) 55%, transparent 100%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
  animation: silhouette-balayage 1.25s linear infinite;
}

.silhouette--tuile .silhouette__lignes {
  box-sizing: border-box;
  height: var(--silhouette-lignes, 80px);
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .2rem .1rem 0;
}

/* Une annonce : le titre sur deux lignes, le prix, le lieu et la date,
   l'auteur. La hauteur est celle d'une tuile au titre de deux lignes : c'est
   elle qui fixe presque toujours la hauteur d'une rangée. */
.silhouette--annonce {
  --silhouette-lignes: 110.4px;
}

.silhouette--annonce .silhouette__ligne--titre  { width: 90%; }
.silhouette--annonce .silhouette__ligne--suite  { width: 56%; }
.silhouette--annonce .silhouette__ligne--court  { width: 28%; }
.silhouette--annonce .silhouette__ligne--mi     { width: 70%; }
.silhouette--annonce .silhouette__ligne--auteur { width: 46%; }

/* Un tracé : son nom, sa catégorie et sa source. */
.silhouette--trace {
  --silhouette-lignes: 39.4px;
}

@media (max-width: 600px) {
  .silhouette--tuile {
    gap: .45rem;
  }

  .silhouette--annonce {
    --silhouette-lignes: 100.5px;
  }

  .silhouette--annonce .silhouette__lignes {
    gap: .42rem;
  }

  .silhouette--trace {
    --silhouette-lignes: 36px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .silhouette--tuile .silhouette__cadre {
    animation: none;
  }

  .tuile__photo,
  .tuile__description {
    transition: none;
  }
}

/* ---------- la fenêtre de détail ----------------------------------------- */

/* Le conteneur de la charte qui porte la fenêtre ne doit rien occuper : la
   fenêtre est fixe, lui reste dans le flux de la page. */
.bazar-fenetre {
  min-height: 0;
  background: transparent;
}

#annonce-modale .modal__box {
  position: relative;
}

/* L'annonce se compose sur SA largeur, et non sur celle de l'écran : en deux
   colonnes quand elle a la place, en une sinon ; ses photos prennent aussi
   leur hauteur sur elle (cqi). */
#annonce-contenu {
  container: annonce / inline-size;
}

/* ---- fermer, revenir --------------------------------------------------------

   La croix sur un écran large, la flèche de retour sur téléphone : les deux
   sont dans la boîte, une seule s'affiche. */
.bazar-fenetre__fermer,
.bazar-fenetre__retour {
  z-index: 4;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              background-color var(--dur) var(--ease);
}

/* La croix reste en vue quand on descend dans une longue description :
   collée comme la flèche du téléphone, dans la marge de la boîte, et sans place
   à elle dans le flux. */
.bazar-fenetre__fermer {
  position: sticky;
  top: calc(.9rem - var(--modal-pad-y, 1.4rem));
  display: grid;
  width: 36px;
  height: 36px;
  margin: calc(.9rem - var(--modal-pad-y, 1.4rem)) calc(.9rem - var(--modal-pad-x, 1.4rem))
          calc(-36px - .9rem + var(--modal-pad-y, 1.4rem)) auto;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text-2);
}

.bazar-fenetre__fermer:hover {
  color: var(--text);
  border-color: var(--line-strong);
}

.bazar-fenetre__retour {
  display: none;
}

.bazar-fenetre__fermer:focus-visible,
.bazar-fenetre__retour:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---- l'annonce, en une colonne ----------------------------------------------

   Dans l'ordre où l'on lit : les photos, le résumé — étiquettes, titre, prix,
   auteur, ce qu'il faut savoir —, les gestes, puis la description. Le côté
   (.annonce__cote) ne devient une boîte qu'en deux colonnes : en une, ses
   enfants se rangent avec ceux de l'annonce, ce qui permet au téléphone de
   passer les gestes après la description et de les coller au bas de l'écran. */
.annonce {
  display: flex;
  flex-direction: column;
}

.annonce__cote {
  display: contents;
}

.annonce__photos {
  order: 0;
  margin-bottom: 1.25rem;
}

.annonce__resume {
  order: 1;
  min-width: 0;
}

.annonce__actions {
  order: 2;
}

.annonce__detail {
  order: 3;
}

/* Hors du téléphone, la mosaïque ; la galerie, cachée, ne sert qu'au plein
   écran. Le téléphone fait l'inverse, plus bas. */
.annonce__galerie {
  display: none;
}

.annonce__tags {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  margin: 0 0 .6rem;
}

/* Sans photo, la croix tombe au bout des étiquettes : elles lui laissent la
   place. */
.annonce--sans-photo .annonce__tags {
  padding-right: 2.6rem;
}

.annonce .annonce__titre {
  margin: 0;
  font-size: 1.3rem;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

/* Le prix, en grand : c'est ce qu'on cherche juste après la photo. */
.annonce__prix {
  margin: .5rem 0 0;
  font-family: var(--font-display);
  font-size: 1.55rem;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -.01em;
  color: var(--text);
}

.annonce__prix--remunere {
  font-variant-numeric: tabular-nums;
}

.annonce__prix--echange,
.annonce__prix--gratuit {
  font-size: 1.2rem;
}

.annonce__prix--echange {
  color: var(--text-2);
}

.annonce__prix--gratuit {
  color: var(--ok);
}

.annonce__auteur {
  display: flex;
  align-items: center;
  gap: .55rem;
  margin: .85rem 0 0;
  font-size: .88rem;
  color: var(--text-2);
}

.annonce__auteur .annonce__avatar {
  width: 30px;
  height: 30px;
  font-size: .8rem;
}

.annonce__auteur span:last-child {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Ce qu'il faut savoir, en lignes : le nom à gauche, la valeur à droite. */
.annonce__faits {
  display: grid;
  gap: .6rem;
  margin: 1rem 0 0;
  padding: .85rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--bg);
}

.annonce__fait {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.annonce__fait dt {
  flex: none;
  font-family: var(--font-display);
  font-size: .68rem;
  font-weight: 640;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-3);
}

.annonce__fait dd {
  min-width: 0;
  margin: 0;
  font-size: .9rem;
  text-align: right;
  color: var(--text);
  overflow-wrap: anywhere;
}

.annonce__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: 1rem;
}

.annonce__actions .btn {
  flex: 1 1 auto;
}

.annonce__detail {
  margin-top: 1.6rem;
}

.annonce__rubrique {
  margin: 0 0 .5rem;
  font-family: var(--font-display);
  font-size: .7rem;
  font-weight: 640;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-3);
}

.annonce__texte {
  max-width: 70ch;
  font-size: .96rem;
  line-height: 1.65;
  color: var(--text);
  overflow-wrap: anywhere;
}

.annonce__contact {
  margin-top: 1rem;
  font-size: .86rem;
  color: var(--text-2);
}

.annonce__contact a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  overflow-wrap: anywhere;
}

.annonce__attente {
  font-size: .9rem;
  color: var(--text-3);
}

/* ---- gérer, signaler, administrer ------------------------------------------

   Sous les gestes de l'annonce, ce qu'on peut en faire d'autre selon qui la
   regarde (bazar_detail_gestion() et bazar_detail_admin(), dans
   php/bazar_annonces.php) : son auteur la supprime, les autres la signalent.
   Des gestes rares, écrits petit et en retrait : on ne les rencontre pas en
   visant le bouton pour écrire. L'administration a son bloc, le panneau de la
   charte, que le mode utilisateur cache.

   En une colonne, ils viennent après la description ; en deux, sous les gestes
   du côté ; sur téléphone, avant la barre collée au bas de l'écran. */
.annonce__gestion {
  order: 4;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .9rem;
}

.annonce__gestion > .annonce__message {
  flex-basis: 100%;
}

.annonce__admin {
  order: 5;
  margin-top: 1.1rem;
}

/* Un lien plus qu'un bouton : du texte gris souligné, son pictogramme devant. */
.annonce__geste {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .25rem 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: .84rem;
  color: var(--text-3);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
  cursor: pointer;
  transition: color var(--dur) var(--ease), text-decoration-color var(--dur) var(--ease);
}

.annonce__geste:hover {
  color: var(--text);
  text-decoration-color: currentColor;
}

/* Supprimer passe au rouge au survol, pas avant : au repos, il ne crie pas. */
.annonce__geste--danger:hover {
  color: var(--danger);
}

.annonce__geste:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.annonce__geste[aria-busy="true"] {
  cursor: progress;
  opacity: .6;
}

/* Le formulaire de signalement, déplié sous son lien. */
.annonce__signalement {
  display: grid;
  gap: .6rem;
  width: 100%;
  padding: .9rem 1rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--bg);
}

.annonce__signalement-titre {
  margin: 0;
  font-family: var(--font-display);
  font-size: .92rem;
  font-weight: 650;
  color: var(--text);
}

.annonce__signalement-lead {
  margin: -.4rem 0 .1rem;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--text-3);
}

.annonce__signalement .checks {
  gap: .35rem;
}

.annonce__signalement .check {
  padding: .3rem .65rem;
  font-size: .8rem;
}

.annonce__signalement-lab {
  margin-top: .15rem;
  font-size: .8rem;
  font-weight: 560;
  color: var(--text-2);
}

.annonce__signalement-lab span {
  font-weight: 400;
  color: var(--text-3);
}

.annonce__signalement .textarea {
  min-height: 4.6rem;
  margin-top: -.3rem;
  resize: vertical;
}

.annonce__signalement-gestes {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .5rem;
}

/* La phrase d'un geste : ce qui a été fait, ou pourquoi cela n'a pas pu
   l'être. */
.annonce__message {
  margin: 0;
  font-size: .82rem;
  line-height: 1.45;
  color: var(--text-2);
}

.annonce__message--erreur {
  font-weight: 560;
  color: var(--danger);
}

/* Signalée : l'accusé prend la place du lien, sous le même pictogramme. */
.annonce__signalee {
  display: flex;
  align-items: flex-start;
  gap: .45rem;
  margin: 0;
  font-size: .84rem;
  line-height: 1.45;
  color: var(--text-2);
}

.annonce__signalee svg {
  flex: none;
  margin-top: .1rem;
  color: var(--warn);
}

.annonce__signalee:focus {
  outline: none;
}

/* Le bloc d'administration : le panneau de la charte. Ce qui a été signalé s'y
   lit dans l'ambre du bandeau d'Annonces, avant les gestes. */
.annonce__admin .panel__title {
  margin: 0 0 .7rem;
}

.annonce__alerte {
  margin: 0 0 .8rem;
  padding: .55rem .7rem;
  border: 1px solid var(--warn-line);
  border-radius: var(--r-control);
  background: var(--warn-soft);
  font-size: .82rem;
  line-height: 1.45;
  color: var(--text);
}

.annonce__alerte b {
  font-weight: 650;
  color: var(--warn);
}

.annonce__admin .annonce__message {
  margin-top: .7rem;
}

/* ---- sur un écran large -----------------------------------------------------

   La boîte s'élargit pour ce qu'elle porte : une mosaïque et un côté. */
@media not all and (max-width: 600px) {
  #annonce-modale .modal__box {
    width: min(1080px, 100%);
  }
}

/* Entre le téléphone et 720 pixels, la charte ferait de la fenêtre une feuille
   collée au bas de l'écran (tools/assets/css/style.css). L'annonce garde sa
   fenêtre centrée — la composition intermédiaire, en une colonne sous la
   mosaïque — jusqu'au téléphone.

   « Au-delà du téléphone » s'écrit comme le contraire exact de sa règle —
   « not all and (max-width: 600px) » —, et non « min-width: 601px » : entre
   600 et 601 pixels, aucune des deux ne valait. Une fenêtre qu'on
   redimensionne passe par 600,5 px — Windows affiché à 125 % donne des
   largeurs à virgule —, et le temps de ce passage la feuille de la charte
   reprenait la main : la fenêtre tombait au bas de l'écran et remontait. */
@media not all and (max-width: 600px) {
@media (max-width: 720px) {
  #annonce-modale {
    place-items: center;
    padding: 1rem;
  }

  #annonce-modale .modal__box {
    --modal-pad-y: 1.4rem;
    --modal-pad-x: 1.4rem;
    --fenetre-depart: translateY(12px) scale(.98);
    max-height: 88dvh;
    padding: var(--modal-pad-y) var(--modal-pad-x);
    border-radius: var(--r-card);
    animation: pop .24s var(--ease);
  }
}
}

/* ---- l'annonce, en deux colonnes ------------------------------------------------

   Quand elle a la place : la mosaïque puis la description à gauche ; à droite,
   ce qui décide — le prix, le lieu, l'auteur, le bouton pour écrire —, qui
   reste en vue pendant qu'on descend dans la description. La croix de la
   fenêtre se pose au bout de la ligne des étiquettes. */
@container annonce (min-width: 780px) {
  .annonce {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(270px, 320px);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "photos cote"
      "detail cote";
    align-items: start;
    column-gap: 2.2rem;
  }

  .annonce--sans-photo {
    grid-template-rows: auto;
    grid-template-areas: "detail cote";
  }

  .annonce__photos {
    grid-area: photos;
    margin-bottom: 0;
  }

  .annonce__cote {
    grid-area: cote;
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    min-width: 0;
  }

  .annonce__tags {
    padding-right: 2.6rem;
  }

  .annonce .annonce__titre {
    font-size: 1.45rem;
  }

  .annonce__actions {
    flex-direction: column;
    margin-top: 1.1rem;
  }

  .annonce__actions .btn {
    flex: none;
    width: 100%;
  }

  .annonce__detail {
    grid-area: detail;
    margin-top: 1.8rem;
  }

  .annonce--sans-photo .annonce__detail {
    margin-top: 0;
  }

  /* Plus haut que la fenêtre, le côté défile avec le reste : collé, il
     cacherait son propre bas jusqu'à la fin de la description. C'est
     javascript/bazar.js qui mesure. */
  .annonce[data-cote-libre] .annonce__cote {
    position: static;
  }
}

/* ---- sur téléphone : une page ---------------------------------------------------

   L'annonce prend tout l'écran et arrive de la droite, comme une page qu'on
   ouvre ; on en revient par la flèche, en haut à gauche. Ses photos, bord à
   bord, se font glisser ; les gestes restent collés au bas de l'écran, sous le
   pouce. La boîte perd ses marges intérieures (--modal-pad-*) : chaque partie
   porte les siennes. */
/* Téléphone : jusqu'à 600 pixels de large — la largeur où la liste passe elle
   aussi en téléphone —, et un téléphone tenu en travers, large mais bas, qui
   se touche du doigt. */
@media (max-width: 600px), (pointer: coarse) and (max-height: 500px) {
  #annonce-modale {
    place-items: stretch;
    padding: 0;
    background: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    /* Pas de fondu : la page couvre la liste d'emblée. L'animation garde son
       nom, seul son départ change — voir @keyframes fade, dans la charte. */
    --voile-depart: 1;
  }

  #annonce-modale .modal__box {
    --modal-pad-y: 0px;
    --modal-pad-x: 0px;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: var(--bg);
    box-shadow: none;
    overscroll-behavior: contain;
    /* Elle arrive de la droite, comme une page : le mouvement de toutes les
       fenêtres, d'un autre point de départ (@keyframes pop, dans la charte).
       Un nom à part la faisait se rejouer à chaque passage d'un format à
       l'autre. */
    --fenetre-depart: translateX(8%);
    animation: pop .28s var(--ease);
  }

  #annonce-contenu {
    display: flex;
    flex-direction: column;
    min-height: 100%;
  }

  /* Une colonne, toujours : un téléphone en travers est assez large pour que
     l'annonce se croie sur un écran large (@container, plus haut). */
  .annonce {
    display: flex;
    flex: 1 0 auto;
  }

  .annonce__cote {
    display: contents;
  }

  .annonce__tags {
    padding-right: 0;
  }

  .bazar-fenetre__fermer {
    display: none;
  }

  /* La flèche reste en haut pendant qu'on descend : collée, mais sans place à
     elle — sa marge du bas la retire du flux, elle flotte sur la photo. */
  .bazar-fenetre__retour {
    position: sticky;
    top: calc(.7rem + env(safe-area-inset-top));
    display: grid;
    width: 40px;
    height: 40px;
    margin: calc(.7rem + env(safe-area-inset-top)) 0 calc(-40px - .7rem - env(safe-area-inset-top)) .8rem;
    border: 0;
    background: color-mix(in srgb, var(--surface) 86%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 2px 12px rgb(0 0 0 / .2);
    color: var(--text);
  }

  .annonce__photos {
    margin-bottom: 0;
  }

  .annonce__photos .mosaique {
    display: none;
  }

  .annonce__galerie {
    display: block;
    height: min(100vw, 72vh);
  }

  @supports (width: 1cqi) {
    .annonce__galerie {
      height: min(100cqi, 72svh);
    }
  }

  .annonce__resume {
    padding: 1.15rem 1.1rem 0;
  }

  .annonce--sans-photo .annonce__resume {
    padding-top: calc(4.2rem + env(safe-area-inset-top));
  }

  .annonce--sans-photo .annonce__tags {
    padding-right: 0;
  }

  .annonce .annonce__titre {
    font-size: 1.2rem;
  }

  .annonce__detail {
    order: 2;
    margin-top: 0;
    padding: 1.5rem 1.1rem 1.6rem;
  }

  /* Après la description et avant les gestes collés au bas de l'écran : ce
     qu'on fait rarement ne passe pas sous le pouce. */
  .annonce__gestion {
    order: 3;
    margin-top: 0;
    padding: 0 1.1rem 1.4rem;
  }

  .annonce__admin {
    order: 4;
    margin: 0 1.1rem 1.5rem;
  }

  .annonce__actions {
    order: 5;
    position: sticky;
    bottom: 0;
    z-index: 3;
    flex-direction: row;
    flex-wrap: nowrap;
    margin-top: auto;
    padding: .7rem 1.1rem calc(.7rem + env(safe-area-inset-bottom));
    border-top: 1px solid var(--line);
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }

  .annonce__actions .btn {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
  }

  .annonce__actions .btn--accent {
    flex-grow: 1.7;
  }

  #annonce-contenu > .annonce__attente,
  #annonce-contenu > .empty {
    padding: calc(4.2rem + env(safe-area-inset-top)) 1.1rem 1.5rem;
  }
}


@media (prefers-reduced-motion: reduce) {
  #annonce-modale .modal__box {
    animation: none;
  }
}
