/* ==========================================================================
   Grille de vignettes
   ==========================================================================
   Composant partagé par la page d'accueil, avec les destinations, et par
   /city-guide-paris/, avec les arrondissements. Quatre colonnes sur grand
   écran, deux sur mobile : en dessous, le nom de la destination deviendrait
   illisible sur la vignette.

   Deux états, selon qu'un visuel a été fourni ou non. Sans visuel, la vignette
   affiche un aplat de la charte, dont la teinte varie légèrement d'une
   vignette à l'autre. Voir infrarouge_vignette_teinte().

   ⚠️ Le signe d'ouverture de ce cartouche manquait : le découpage de l'ancienne
   feuille unique a tranché au milieu des commentaires. Sans lui, le navigateur
   lisait le cartouche comme un sélecteur et avalait la première règle du
   fichier, ici .grille-vignettes. Les feuilles 02, 04 et 05 ont le même défaut,
   signalé mais pas corrigé ici, elles sortent du périmètre.
   ========================================================================== */

/*
 * Le gris de texte secondaire --ir-texte-doux était redéclaré ici, à 62 %, soit
 * 4,0 pour 1 sur blanc, sous le seuil AA. Il est désormais unique et défini
 * dans 01-socle.css, à 72 %.
 */

/*
 * ⚠️ scroll-margin-top : sans lui, le saut d'ancre passe sous la barre.
 *
 * La barre de navigation est collée en haut. Le navigateur amène la cible au
 * ras du haut de la fenêtre, c'est-à-dire derrière la barre : le titre de
 * section « Nos 20 City Guides incontournables » se retrouvait masqué et le saut
 * paraissait avoir raté.
 *
 * La valeur reprend le jeton de hauteur de barre plutôt qu'une valeur recopiée,
 * qui cesserait d'être juste au prochain réglage de la barre. Le jeton passe de
 * 3rem à 3,5rem au-delà de 64rem, la marge suit sans règle supplémentaire.
 */
.grille-vignettes {
	margin-block: var(--ir-rythme-section);
	scroll-margin-top: var(--ir-hauteur-barre);
}

.grille-vignettes__entete {
	margin-bottom: var(--ir-rythme-bloc);
}

/* Titre et sous-titre forment un seul bloc : ils se touchent presque. */
.grille-vignettes__titre {
	margin-bottom: var(--ir-esp-2);
}

.grille-vignettes__sous-titre {
	margin: 0;
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-m);
}

.grille-vignettes__liste {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--ir-esp-3);
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 48rem) {
	.grille-vignettes__liste {
		grid-template-columns: repeat(3, 1fr);
	}
}

@media (min-width: 64rem) {
	.grille-vignettes__liste {
		grid-template-columns: repeat(4, 1fr);
		gap: var(--ir-esp-4);
	}
}

.vignette {
	position: relative;
	display: block;
	overflow: hidden;
	/* 6/5 d'après les maquettes, un peu plus haut que le 4/3 précédent. */
	aspect-ratio: 6 / 5;
	border-radius: var(--ir-arrondi-carte);
	background: var(--vignette-fond, var(--ir-accent));
	color: var(--ir-fond);
	text-decoration: none;
}

.vignette:hover,
.vignette:focus {
	color: var(--ir-fond);
}

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

.vignette__visuel img {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 0;
	object-fit: cover;
	transition: transform 0.3s ease;
}

/*
 * Voile uniquement quand il y a une image : sur un aplat, il ne ferait
 * qu'assombrir une couleur déjà choisie pour porter du texte blanc.
 *
 * Dégradé plutôt qu'aplat uniforme. Le voile plein à 0,6 tient la lisibilité
 * mais éteint la photo sur toute sa surface, et une grille de vingt vignettes
 * ternes n'a rien d'un magazine de voyage. Le dégradé concentre l'ombre là où
 * le texte se pose, en bas, et rend le haut de l'image au visiteur.
 */
.vignette--avec-image::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, var(--ir-voile) 0%, transparent 65%);
}

.vignette:hover .vignette__visuel img,
.vignette:focus-visible .vignette__visuel img {
	transform: scale(1.04);
}

/*
 * Le nom part petit. « Paris (75001) » en 24 px dans une colonne de 140 px sur
 * un téléphone se casse en trois lignes qui débordent de la vignette. Il
 * grandit ensuite avec la place disponible.
 *
 * L'ombre portée est une sécurité : sur une image claire en haut de dégradé,
 * un nom long qui passe à la ligne remonte hors de la zone assombrie.
 */
.vignette__nom {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: flex-end;
	height: 100%;
	padding: var(--ir-esp-3);
	font-family: var(--ir-police-titre);
	/*
	 * ⚠️ Corps qui s'écarte : 21 px dans les maquettes, T3 vaut 20 / 25. On
	 * part de T4 sur les colonnes étroites et on passe à T3 dès qu'il y a la
	 * place : « Courchevel / Méribel » en 21 px dans une vignette de 140 px se
	 * casse en trois lignes qui débordent.
	 */
	font-size: var(--ir-t-4);
	font-weight: 700;
	line-height: var(--ir-interligne-titre);
	text-shadow: 0 1px 4px var(--ir-voile);
}

@media (min-width: 48rem) {
	.vignette__nom {
		padding: var(--ir-esp-4);
		font-size: var(--ir-t-l);
	}
}

.page-chapo {
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-m);
}

.page-avertissement {
	padding: var(--ir-esp-3);
	border: 1px solid var(--ir-bordure-forte);
	border-radius: var(--ir-arrondi-carte);
	font-size: var(--ir-t-xs);
}

/* ==========================================================================
   Fil d'Ariane
   ========================================================================== */

.fil-ariane {
	margin-block: 0 var(--ir-rythme-bloc);
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-xs);
}

.fil-ariane__liste {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ir-esp-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * Le chevron est accroché à la fin du maillon précédent plutôt qu'au début du
 * suivant : posé en tête, il se retrouvait seul en début de ligne dès que le
 * fil passait à la ligne, ce qui arrive sur les noms de fiches longs.
 */
.fil-ariane__element:not(:last-child)::after {
	content: "›";
	margin-left: var(--ir-esp-2);
	color: var(--ir-bordure-forte);
}

.fil-ariane__lien {
	color: inherit;
	text-decoration: none;
}

.fil-ariane__lien:hover,
.fil-ariane__lien:focus {
	color: var(--ir-accent);
	text-decoration: underline;
}

/* Le maillon courant n'est pas cliquable, il n'a pas à en avoir l'air. */
.fil-ariane__element[aria-current="page"] {
	color: var(--ir-texte);
}

/* ==========================================================================
   Contenu seul : article et fiche
   ==========================================================================
   Deux largeurs, et pas une seule.

   La colonne de texte est bornée à --ir-largeur-lecture, environ 65 signes par
   ligne : c'est la demande la plus explicite du chantier, un article de
   magazine ne s'étale pas sur 1 200 px. Mais borner le conteneur entier à cette
   largeur écraserait aussi les photos, alors qu'un visuel de reportage gagne à
   respirer plus large que le texte.

   D'où le montage retenu : le conteneur tient la largeur des médias, le texte
   se recentre dedans. Les deux sont centrés sur le même axe, l'œil ne perçoit
   pas deux colonnes mais une colonne de texte et des images qui débordent.
   ========================================================================== */

.article-seul,
.fiche {
	/*
	 * --ir-largeur-media n'est plus déclarée ici mais dans 01-socle.css, au
	 * niveau du document : les blocs liés qui suivent l'article doivent s'aligner
	 * sur cette même largeur, or ils sont ses frères et n'héritent pas de lui.
	 */

	/*
	 * Largeur de lecture propre à l'article, plus large que celle des pages
	 * éditoriales. 42rem convient à des mentions légales lues d'une traite ;
	 * un article de magazine illustré y paraissait enfermé dans une colonne
	 * étroite au milieu du vide. 52rem tient encore la ligne à environ
	 * 80 signes, la limite haute du confortable.
	 */
	--ir-largeur-lecture: 52rem;

	max-width: var(--ir-largeur-media);
	margin-inline: auto;

	/*
	 * La colonne d'article est une surface blanche posée sur le gris de la page.
	 * Sans cela, le texte se lirait directement sur le fond et l'article
	 * perdrait sa matérialité de page.
	 */
	background: var(--ir-fond);
	border-radius: var(--ir-arrondi-carte);
	padding: var(--ir-rythme-bloc) var(--ir-gouttiere);

	/*
	 * <main> n'a aucune marge verticale et l'en-tête est collant : sans ce
	 * décrochage, le visuel d'ouverture démarre sous la barre de navigation.
	 */
	padding-block: var(--ir-rythme-bloc) var(--ir-rythme-section);
}

/*
 * Colonne de texte. Tout ce qui se lit ligne à ligne, y compris le mobilier de
 * la fiche : informations pratiques, carte, partage. Les étirer à la largeur
 * des médias casserait l'alignement de la colonne sans rien apporter.
 */
.article-entete,
.article-pied,
.fiche__entete,
.fil-ariane,
.infos-pratiques,
.carte-lieu,
.partage,
.article-contenu > *,
.fiche__contenu > * {
	max-width: var(--ir-largeur-lecture);
	margin-inline: auto;
}

/*
 * Médias, seuls autorisés à sortir de la colonne de texte. Ils ne sont pas
 * étirés pour autant : une image de 600 px reste à 600 px, centrée, l'image
 * n'est jamais agrandie au-delà de sa définition réelle.
 */
.article-visuel,
.fiche__visuel,
.article-contenu > figure,
.article-contenu > .galerie-migree,
.fiche__contenu > figure,
.fiche__contenu > .galerie-migree {
	max-width: 100%;
}

/* En-tête */

.article-entete,
.fiche__entete {
	margin-bottom: var(--ir-rythme-bloc);
}

/*
 * Le titre reste soudé à ce qui le suit, chapô ou métadonnées : ils forment un
 * seul bloc d'ouverture. C'est l'espace au-dessus, porté par le visuel, qui
 * l'en détache.
 */
.article-titre,
.fiche__titre {
	margin-bottom: var(--ir-esp-3);
	font-size: var(--ir-t-1);
	font-weight: var(--ir-w-1);
	letter-spacing: var(--ir-ls-1);
	line-height: var(--ir-lh-1);
}

.fiche__accroche {
	margin-bottom: var(--ir-esp-3);
	font-size: var(--ir-t-m);
}

@media (min-width: 48rem) {
	.fiche__accroche {
		font-size: var(--ir-t-l);
		line-height: 1.45;
	}
}

/*
 * Chapô d'article, rendu plus présent (retours du 23/09/2026).
 *
 * Ruda 600, un cran au-dessus du corps sur l'échelle : T4 (18 vers 19) pour
 * un corps à 16 vers 17. C'est la graisse qui le détache, pas la taille.
 * Couleur texte, jamais l'accent principal. Jamais d'italique : Ruda n'en a
 * pas, le navigateur en fabriquerait une fausse.
 *
 * La fiche City Guide garde son accroche telle quelle : la demande ne
 * portait que sur l'article.
 */
.article-chapo {
	margin-bottom: var(--ir-esp-3);
	color: var(--ir-texte);
	font-size: var(--ir-t-4);
	font-weight: 600;
	font-style: normal;
	line-height: 1.45;
}

/*
 * Variante à filet vertical, en attente d'arbitrage. Voir single.php pour
 * l'aperçu par ?chapo=filet.
 */
.article-chapo--filet {
	padding-left: var(--ir-esp-3);
	border-left: 3px solid var(--ir-accent-fonce);
}

/*
 * Ligne de métadonnées de l'en-tête : rubrique, auteur, dates. Volontairement
 * discrète, le titre doit dominer. Les séparateurs sont posés en CSS et non
 * dans le balisage : une puce écrite en dur serait lue par les lecteurs
 * d'écran, et sauterait mal quand une métadonnée manque.
 */
.article-meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ir-esp-2);
	align-items: baseline;
	/*
	 * margin-block et non margin : wp_link_pages réutilise cette classe pour la
	 * pagination interne d'un article, où elle est un enfant direct du contenu
	 * et doit garder le centrage de la colonne de texte.
	 */
	margin-block: 0;
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-xs);
}

/*
 * Le point est accroché à la fin de la métadonnée précédente, jamais au début
 * de la suivante. En flex, un ::before est un contenu du prochain élément :
 * quand la ligne passe à la ligne sur mobile, et elle y passe, la nouvelle
 * ligne commençait par un point orphelin. Ici la coupure tombe entre deux
 * éléments, et une ligne peut au pire se terminer par un point.
 */
.article-meta > *:not(:last-child)::after {
	content: "·";
	margin-left: var(--ir-esp-2);
	color: var(--ir-bordure-forte);
}

.article-meta__rubrique {
	color: var(--ir-accent);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	text-decoration: none;
}

.article-meta__rubrique:hover,
.article-meta__rubrique:focus {
	color: var(--ir-accent-fonce);
}

/* Le nom de l'auteur, sans lien ni encadré : les pages auteur sont supprimées. */
.article-meta__auteur {
	color: var(--ir-texte);
}

/* Visuel d'ouverture */

.article-visuel,
.fiche__visuel {
	margin: 0 0 var(--ir-rythme-bloc);
}

/*
 * Visuel d'ouverture de la fiche City Guide.
 *
 * ⚠️ Il ne passe pas en pleine largeur de fenêtre comme celui des articles,
 * c'est un choix, pas un oubli : la fiche est un encart, pas une ouverture de
 * reportage.
 *
 * Il laissait pourtant des bandes blanches et ne remplissait pas son cadre. Deux
 * causes se cumulaient, et corriger l'une sans l'autre ne changeait rien :
 *
 * - la figure n'imposait aucun rapport, elle prenait la hauteur naturelle de
 *   l'image ; deux fiches voisines n'avaient donc pas le même cadre, et une
 *   image basse laissait du blanc là où l'œil attend une bande pleine ;
 * - l'image n'était pas contrainte à remplir ce cadre, faute de hauteur et
 *   d'object-fit.
 *
 * La boîte porte donc le rapport, l'image le remplit en cover, sans marge
 * intérieure : elle affleure les quatre bords. Le recadrage est assumé, c'est le
 * prix d'un cadre régulier d'une fiche à l'autre.
 *
 * 3/2 comme les cartes et comme la taille infrarouge-carte : la fiche et sa
 * carte de listing montrent alors le même cadrage, ce qui évite l'impression de
 * deux photos différentes.
 *
 * L'arrondi est porté par la figure et non par l'image, avec overflow: hidden :
 * posé sur l'image, il serait ignoré au recadrage sur certains moteurs, et les
 * angles ressortiraient vifs.
 */
.fiche__visuel {
	/*
	 * ⚠️ max-width: none est indispensable, et c'est le second des deux défauts.
	 *
	 * Le groupe des médias, plus haut, borne cette figure à max-width: 100%, soit
	 * la largeur du bloc de contenu du parent, gouttières déduites. Les marges
	 * négatives ci-dessous élargiraient la figure et cette borne la ramènerait
	 * aussitôt à sa largeur d'avant : l'image resterait plus étroite que le bloc,
	 * décalée, avec du blanc rouvert d'un côté. Même piège que sur l'article.
	 */
	max-width: none;

	/*
	 * Le visuel affleure le bloc blanc en haut, à gauche et à droite.
	 *
	 * .fiche porte un rembourrage sur ses quatre côtés, qui doit rester en place
	 * pour le fil d'Ariane, le titre, le texte et les blocs : le retirer ferait
	 * coller tout le contenu aux bords. Le visuel le franchit donc pour lui seul,
	 * par des marges négatives exactement égales à ce rembourrage.
	 *
	 * Le bas garde son écart : c'est lui qui sépare l'image du fil d'Ariane qui
	 * la suit.
	 */
	margin-top: calc(-1 * var(--ir-rythme-bloc));
	margin-inline: calc(-1 * var(--ir-gouttiere));

	/* Ancrage de l'aplat de repli, voir .article-visuel. */
	position: relative;
	overflow: hidden;
	aspect-ratio: 3 / 2;

	/*
	 * ⚠️ Angles vifs, y compris en haut. Décision du 21/08/2026.
	 *
	 * Le visuel a d'abord porté l'arrondi de la carte sur ses deux coins hauts,
	 * pour épouser le sommet du bloc blanc. Une fois le rembourrage supprimé et
	 * l'image montée au ras du bord, ces deux petits arrondis se voyaient pour
	 * ce qu'ils étaient : un reste de cadre autour d'une photo qui n'en a plus.
	 *
	 * overflow: hidden reste nécessaire, mais pour le recadrage en cover, plus
	 * pour l'arrondi.
	 *
	 * ⚠️ Le bloc .fiche doit suivre, voir la règle juste en dessous : lui seul
	 * porte encore un arrondi, et une image à angles vifs posée sur un coin
	 * arrondi laisse dépasser deux pointes blanches.
	 */
	border-radius: 0;
	background: var(--ir-rose);
}

/*
 * Le sommet du bloc s'aplatit quand une photo l'occupe.
 *
 * L'arrondi du bas est conservé : il n'y a rien qui l'affleure de ce côté, la
 * surface blanche s'y termine seule.
 *
 * :has plutôt qu'une classe posée en PHP : 65 fiches publiées n'ont aucune
 * image à la une, et sur celles-là le bloc doit garder ses quatre coins
 * arrondis. La condition est portée par le rendu, pas par un attribut à tenir
 * à jour dans le gabarit.
 */
.fiche:has(> .fiche__visuel) {
	border-radius: 0 0 var(--ir-arrondi-carte) var(--ir-arrondi-carte);
}

.fiche__visuel img {
	height: 100%;
	border-radius: 0;
	object-fit: cover;
	object-position: center;
}

/*
 * Le visuel d'ouverture de l'article couvre toute la largeur du bloc blanc.
 *
 * .article-seul est une surface blanche qui porte une gouttière horizontale et
 * un décrochage en haut. Le visuel, posé dans ce flux, s'arrêtait à l'intérieur
 * de ce rembourrage et flottait donc au milieu d'un cadre blanc. Les marges
 * négatives lui font franchir ce rembourrage, exactement, sans le remettre en
 * cause pour le texte qui suit.
 *
 * ⚠️ max-width: none est indispensable. Le groupe des médias, plus haut, pose
 * max-width: 100%, soit la largeur du bloc de contenu du parent, gouttières
 * déduites : la marge négative élargirait la figure et cette borne la
 * ramènerait aussitôt à sa largeur d'avant, décalée vers la gauche, avec un
 * blanc rouvert à droite.
 *
 * Les coins hauts reprennent l'arrondi de la carte, sinon l'image ressortirait
 * en angle vif au sommet d'un bloc arrondi. overflow: hidden est nécessaire :
 * c'est l'image, et non la figure, qui déborderait de l'arrondi.
 *
 * La fiche City Guide n'est volontairement pas concernée, son visuel n'a pas
 * été remis en cause.
 */
.article-visuel {
	/*
	 * position: relative sert à l'aplat de repli, qui se cale en absolu sur
	 * cette figure quand l'article n'a pas d'image à la une. Sans ancrage, il
	 * remonterait au premier parent positionné, c'est-à-dire n'importe où.
	 */
	position: relative;
	max-width: none;
	width: 100vw;
	margin-top: calc(-1 * var(--ir-rythme-bloc));
	margin-inline: calc(50% - 50vw);
	overflow: hidden;
	border-radius: 0;
	background: var(--ir-rose);
	aspect-ratio: 21 / 9;
}

/*
 * Le recadrage est assumé : le visuel remplit la bande sur toute la largeur de
 * la fenêtre, quel que soit le rapport du fichier d'origine. Sans hauteur
 * imposée, une image très haute occuperait tout l'écran avant le titre.
 */
.article-visuel img {
	height: 100%;
	object-fit: cover;
}

/* ==========================================================================
   Ouverture sans image
   ==========================================================================
   216 articles et 65 fiches publiés n'ont pas d'image à la une. La page
   s'ouvrait alors sur une zone blanche qui se lisait comme une image qui n'a
   pas chargé.

   ⚠️ Une bande courte, jamais la hauteur de la photo qu'elle remplace. Au
   rapport d'ouverture, l'aplat occupait près de sept cents pixels sur une
   fiche : un écran entier de rose avant le titre. Le repli doit se voir comme
   un parti pris discret, pas comme une image de substitution.
   ========================================================================== */

.article-visuel--sans-visuel,
.fiche__visuel--sans-visuel {
	display: flex;
	align-items: center;
	justify-content: center;
	/* Le rapport d'ouverture ne s'applique plus, la hauteur est fixe. */
	aspect-ratio: auto;
	height: clamp(5rem, 3.5rem + 5vw, 7rem);
	background: color-mix(in srgb, var(--ir-rose) 55%, var(--ir-fond));
}

/*
 * Dans ce contexte, le pictogramme est centré par la figure elle-même : le
 * positionnement absolu des cartes n'a plus lieu d'être, la bande n'ayant pas
 * d'image à recouvrir.
 */
.article-visuel--sans-visuel .carte__visuel-absent,
.fiche__visuel--sans-visuel .carte__visuel-absent {
	position: static;
	background: none;
}

.article-visuel img,
.fiche__visuel img {
	display: block;
	width: 100%;
	margin-inline: auto;
}

/* ==========================================================================
   Corps de l'article et de la fiche
   ==========================================================================
   Rythme vertical : c'est ici que tout se joue. Le défaut du site actuel n'est
   pas que les espacements soient mauvais, c'est qu'ils se ressemblent tous.

   Trois niveaux, et l'écart entre deux niveaux est franc :
   - --ir-rythme-element entre deux paragraphes, ils appartiennent au même flux ;
   - --ir-rythme-bloc autour des médias et au-dessus d'un sous-titre ;
   - --ir-rythme-section au-dessus d'un titre de niveau 2, qui ouvre une partie.

   La marge sous un titre est toujours la plus petite du lot : c'est elle qui
   rattache le titre au texte qu'il annonce plutôt qu'à celui qui le précède.
   ========================================================================== */

.article-contenu,
.fiche__contenu {
	font-size: var(--ir-t-m);
}

.article-contenu > *:first-child,
.fiche__contenu > *:first-child {
	margin-top: 0;
}

.article-contenu p,
.fiche__contenu p,
.article-contenu ul,
.article-contenu ol,
.fiche__contenu ul,
.fiche__contenu ol {
	margin-bottom: var(--ir-rythme-element);
}

.article-contenu h2,
.fiche__contenu h2 {
	margin-top: var(--ir-rythme-section);
	margin-bottom: var(--ir-esp-3);
	font-size: var(--ir-t-xl);
}

.article-contenu h3,
.fiche__contenu h3 {
	margin-top: var(--ir-rythme-bloc);
	margin-bottom: var(--ir-esp-2);
	font-size: var(--ir-t-l);
}

/*
 * Les articles migrés emploient <h4> comme chapô de partie, pas comme titre :
 * deux ou trois lignes de prose posées sous un h2 ou un h3. En 24 px gras, la
 * taille que lui donne le socle, ce pavé faisait concurrence au titre qu'il
 * complète. Ramené à la taille du texte, en graisse normale, il redevient ce
 * qu'il est, un chapeau. Le corps et la couleur suffisent à le distinguer du
 * texte courant, la famille étant désormais la même partout.
 */
.article-contenu h4,
.fiche__contenu h4 {
	margin-top: var(--ir-rythme-bloc);
	margin-bottom: var(--ir-esp-3);
	font-size: var(--ir-t-m);
	font-weight: 400;
	line-height: var(--ir-interligne-texte);
}

/* Chapô collé au titre qu'il prolonge, comme dans la maquette imprimée. */
.article-contenu h2 + h4,
.article-contenu h3 + h4,
.fiche__contenu h2 + h4,
.fiche__contenu h3 + h4 {
	margin-top: var(--ir-esp-2);
}

.article-contenu ul,
.article-contenu ol,
.fiche__contenu ul,
.fiche__contenu ol {
	padding-left: var(--ir-esp-4);
}

.article-contenu li + li,
.fiche__contenu li + li {
	margin-top: var(--ir-esp-2);
}

.article-contenu blockquote,
.fiche__contenu blockquote {
	margin: var(--ir-rythme-bloc) 0;
	padding-left: var(--ir-esp-4);
	border-left: 3px solid var(--ir-accent);
	font-style: italic;
}

/*
 * Filets écrits dans le contenu.
 *
 * ⚠️ Ce ne sont pas les séparateurs du thème mais des <hr /> tapés dans le
 * corps des articles par l'ancien site, qui encadre ses renvois : on trouve
 * couramment la séquence <hr /> « Lire aussi : … » <hr />.
 *
 * Ils portaient --ir-rythme-section, soit jusqu'à 6 rem au-dessus ET en dessous.
 * Deux filets encadrant un renvoi produisaient donc un trou de plusieurs
 * centaines de pixels au milieu de la lecture. Un filet est une respiration,
 * pas une fin de chapitre : l'écart tombe au rythme d'élément.
 *
 * Le trait est aussi éclairci. À pleine valeur de --ir-bordure, il coupait
 * l'article en tranches plus nettement que les titres eux-mêmes.
 */
.article-contenu hr,
.fiche__contenu hr {
	margin-block: var(--ir-rythme-element);
	border: 0;
	border-top: 1px solid color-mix(in srgb, var(--ir-bordure) 60%, var(--ir-fond));
}

/*
 * Deux filets qui se suivent, sans rien entre eux, viennent des contenus
 * migrés. Le second ne sépare rien.
 */
.article-contenu hr + hr,
.fiche__contenu hr + hr {
	display: none;
}

/*
 * Le renvoi « Lire aussi » pris entre deux filets forme un bloc : on le resserre
 * contre eux plutôt que de laisser jouer la marge de paragraphe par-dessus.
 */
.article-contenu hr + p,
.fiche__contenu hr + p {
	margin-top: var(--ir-rythme-element);
}

/* Les tableaux hérités débordent sur mobile sans ce conteneur défilant. */
.article-contenu table,
.fiche__contenu table {
	display: block;
	width: 100%;
	overflow-x: auto;
	margin-bottom: var(--ir-rythme-element);
	font-size: var(--ir-t-s);
}

/* Figures du contenu */

.article-contenu figure,
.fiche__contenu figure {
	margin-block: var(--ir-rythme-bloc);
	margin-inline: auto;
}

.article-contenu figure img,
.fiche__contenu figure img {
	display: block;
	margin-inline: auto;
}

.article-contenu img,
.fiche__contenu img {
	height: auto;
}

.article-contenu figcaption,
.fiche__contenu figcaption {
	margin-top: var(--ir-esp-2);
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-xs);
	line-height: var(--ir-interligne-texte);
	text-align: center;
}

/* ==========================================================================
   Galeries issues de la migration
   ==========================================================================
   La migration a regroupé les suites d'images d'un même paragraphe dans un
   <div class="galerie-migree"> contenant plusieurs <figure>. Sans style, ces
   figures s'empilent en pleine largeur : sur « Le meilleur de chaque station »,
   douze galeries donnaient quarante images à la file, l'article se lisait en
   faisant défiler des photos.

   Une grille suffit. Les images d'une même galerie partagent leur cadrage,
   portrait ou paysage, les rangées s'alignent donc d'elles-mêmes sans avoir à
   recadrer quoi que ce soit.
   ========================================================================== */

.galerie-migree {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--ir-esp-2);
	margin-block: var(--ir-rythme-bloc);
	align-items: start;
}

/* Les figures perdent leurs marges propres, la gouttière de la grille suffit. */
.galerie-migree figure {
	margin: 0;
}

.galerie-migree img {
	display: block;
	width: 100%;
}

/* Une galerie d'une seule image n'est pas une galerie : elle reprend sa place. */
.galerie-migree figure:only-child {
	grid-column: 1 / -1;
}

@media (min-width: 48rem) {
	.galerie-migree {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--ir-esp-3);
	}

	/*
	 * Deux ou quatre images sur trois colonnes laissent une rangée boiteuse,
	 * avec un trou à droite. Deux colonnes tombent juste dans les deux cas, et
	 * ce sont les deux tailles de galerie les plus fréquentes après trois.
	 */
	.galerie-migree:has(> figure:nth-child(2):last-child),
	.galerie-migree:has(> figure:nth-child(4):last-child) {
		grid-template-columns: repeat(2, 1fr);
	}
}

/* ==========================================================================
   Pied d'article
   ========================================================================== */

.article-pied {
	margin-top: var(--ir-rythme-section);
}

.article-taxonomies {
	display: flex;
	flex-direction: column;
	gap: var(--ir-esp-2);
	margin-bottom: var(--ir-rythme-bloc);
}

.article-taxonomies__groupe {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ir-esp-2);
	align-items: baseline;
}

.article-taxonomies__libelle {
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-xs);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.etiquette {
	display: inline-block;
	padding: var(--ir-esp-1) var(--ir-esp-2);
	border: 1px solid var(--ir-bordure);
	border-radius: var(--ir-arrondi-bouton);
	color: var(--ir-texte);
	font-size: var(--ir-t-xs);
	text-decoration: none;
}

.etiquette:hover,
.etiquette:focus {
	border-color: var(--ir-accent);
	color: var(--ir-accent);
}

/* ==========================================================================
   Informations pratiques
   ==========================================================================
   Le bloc est un <dl> dont chaque ligne est un <div> portant un <dt> et un
   <dd>. Les marges par défaut du navigateur sont remises à zéro sur les deux :
   le <dl> apporte 1em au-dessus et en dessous, le <dd> un retrait gauche de
   40 px qui décalerait toutes les valeurs par rapport à leur libellé.
   ========================================================================== */

.infos-pratiques {
	margin-block: var(--ir-rythme-section);
	padding: var(--ir-esp-4);
	border: 1px solid var(--ir-bordure);
	border-radius: var(--ir-arrondi-carte);
}

.infos-pratiques__titre {
	margin-bottom: var(--ir-rythme-element);
	font-size: var(--ir-t-l);
}

.infos-pratiques__liste {
	display: grid;
	gap: var(--ir-esp-4);
	margin: 0;
	padding: 0;
}

@media (min-width: 48rem) {
	.infos-pratiques__liste {
		grid-template-columns: repeat(2, 1fr);
		gap: var(--ir-esp-4) var(--ir-esp-5);
	}
}

/*
 * Libellé et valeur sont collés l'un à l'autre, et c'est l'écart entre lignes
 * qui les sépare. Sans cette différence, les six lignes du bloc se lisent comme
 * douze informations sans lien entre elles.
 */
.infos-pratiques__ligne {
	display: flex;
	flex-direction: column;
	gap: var(--ir-esp-1);
	margin: 0;
}

.infos-pratiques__libelle {
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-xs);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.infos-pratiques__valeur {
	margin: 0;
	padding: 0;
}

/* ==========================================================================
   Carte cartographique
   ========================================================================== */

.carte-lieu {
	margin-block: var(--ir-rythme-section);
}

.carte-lieu__titre {
	margin-bottom: var(--ir-rythme-element);
	font-size: var(--ir-t-l);
}

/*
 * Hauteur imposée : sans elle, le conteneur de Leaflet est vide au moment de
 * l'initialisation et la carte se replie sur zéro pixel. Plus courte sur
 * mobile, où 22 rem occuperaient la moitié de l'écran pour un plan de quartier.
 */
.carte-lieu__carte {
	height: 15rem;
	margin-bottom: var(--ir-rythme-element);
	border: 1px solid var(--ir-bordure);
	border-radius: var(--ir-arrondi-carte);
	background: var(--ir-rose);
}

@media (min-width: 48rem) {
	.carte-lieu__carte {
		height: 22rem;
	}
}

.carte-lieu__carte .leaflet-container {
	border-radius: var(--ir-arrondi-carte);
	font-family: var(--ir-police-texte);
}

/* Les tuiles ne doivent pas hériter de l'arrondi global des images. */
.carte-lieu__carte img {
	border-radius: 0;
}

/*
 * Adresse et bouton côte à côte dès qu'il y a la place, empilés sinon. Sur un
 * téléphone, un bouton coincé à droite d'une adresse sur deux lignes se
 * retrouve réduit à sa largeur minimale et devient difficile à viser.
 */
.carte-lieu__pied {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ir-esp-3);
	align-items: center;
	justify-content: space-between;
}

.carte-lieu__adresse {
	flex: 1 1 14rem;
	margin: 0;
}

/* Signalé à la rédaction connectée seulement, jamais au visiteur. */
.carte-lieu__avertissement {
	flex: 1 0 100%;
	margin: 0;
	padding: var(--ir-esp-3);
	border: 1px dashed var(--ir-bordure-forte);
	border-radius: var(--ir-arrondi-carte);
	font-size: var(--ir-t-xs);
}

.carte-lieu__bouton {
	flex: 0 0 auto;
}

/* ==========================================================================
   Partage
   ========================================================================== */

.partage {
	margin-block: var(--ir-rythme-section) 0;
	padding-top: var(--ir-rythme-bloc);
	border-top: 1px solid var(--ir-bordure);
}

/*
 * Dans le pied d'article, le partage suit les étiquettes à l'intérieur d'un
 * ensemble déjà détaché du corps de texte : un second écart de section y ferait
 * un trou. Sur la fiche City Guide, où le partage est un bloc de premier
 * niveau, l'écart pleine section est conservé.
 */
.article-pied .partage {
	margin-top: var(--ir-rythme-bloc);
}

.partage__titre {
	margin-bottom: var(--ir-rythme-element);
	font-size: var(--ir-t-m);
}

/*
 * ⚠️ Les règles de partage sont regroupées en fin de fichier, avec le passage
 * en icônes seules. Elles étaient ici en version « boutons texte », et le fait
 * d'avoir laissé les deux jeux cohabiter a produit un bug muet : la marge
 * interne de 1,5 rem héritée d'ici, appliquée à un bouton devenu large de
 * 2,75 rem en border-box, écrasait la zone de contenu à zéro. Les icônes
 * étaient bien dans la page, mesurées à zéro pixel. Ne pas redéclarer
 * .partage__lien à deux endroits.
 */

/* ==========================================================================
   Contenus embarqués
   ==========================================================================
   Les articles migrés contiennent des embeds Instagram. Le conteneur borne leur
   largeur : laissés libres, ces iframes débordent de la colonne sur mobile.
   ========================================================================== */

.embed-conteneur,
.article-contenu .wp-block-embed,
.article-contenu iframe,
.fiche__contenu .wp-block-embed,
.fiche__contenu iframe {
	max-width: 100%;
}

/*
 * Le rapport est mesuré côté PHP sur les attributs width et height de l'iframe
 * et passé en propriété personnalisée. Le repli 16/9 couvre les iframes qui ne
 * déclarent pas leurs dimensions, fréquentes dans les contenus hérités.
 *
 * Bornée à la largeur de lecture : un embed Instagram est un contenu vertical,
 * l'étirer à la largeur des photos lui donnerait la hauteur d'un écran entier.
 */
.embed-conteneur {
	width: 100%;
	max-width: var(--ir-largeur-lecture);
	margin-block: var(--ir-rythme-bloc);
	margin-inline: auto;
	aspect-ratio: var(--embed-rapport, 16 / 9);
}

.embed-conteneur iframe {
	display: block;
	width: 100%;
	height: 100%;
	margin-inline: auto;
	border: 0;
}

/*
 * Repli quand l'embed n'a pas pu être résolu : un simple lien, pas de script
 * tiers. Même hauteur de cible que les liens de partage.
 */
/*
 * ⚠️ max-width, sans quoi ce lien déborde et se fait couper.
 *
 * Une boîte de niveau ligne se dimensionne sur son contenu, et ce libellé est
 * long : « Une publication partagée par » suivi du nom du compte. Relevé au
 * banc d'essai sur un article à 320 px, il montait jusqu'à 591 px, soit 271 px
 * hors de la colonne. Le texte n'était pas seulement en dehors de la page, il
 * était **découpé** par l'overflow-x: clip de .site-contenu, donc perdu, sans
 * défilement possible pour aller le lire.
 *
 * overflow-wrap parce que la coupure doit pouvoir tomber dans le nom du compte
 * lui-même : certains sont d'un seul tenant et plus larges qu'un téléphone.
 */
/*
 * ⚠️ Le bouton épouse son texte, il ne s'étale pas.
 *
 * min-height: 2.75rem imposait une hauteur de cible tactile à un bouton dont le
 * texte tient sur une ligne : il restait un vide au-dessus et au-dessous du mot,
 * et le cadre paraissait mal rempli. Le rembourrage suffit à atteindre la même
 * hauteur utile sans creuser le bouton.
 *
 * overflow-wrap: anywhere est retiré : il servait à casser une URL, or le libellé
 * est désormais une phrase courte qui n'a aucune raison d'être coupée en plein
 * mot.
 */
.embed-instagram {
	display: inline-flex;
	max-width: 100%;
	gap: var(--ir-esp-2);
	align-items: center;
	padding: var(--ir-esp-2) var(--ir-esp-3);
	border: 1px solid var(--ir-bordure);
	border-radius: var(--ir-arrondi-bouton);
	color: var(--ir-texte);
	font-size: var(--ir-t-s);
	text-decoration: none;
	transition: color 0.15s ease, border-color 0.15s ease;
}

/*
 * Une seule couleur au survol pour le texte et la bordure. Elles étaient
 * dissociées, la bordure passant au rouge quand le texte restait sombre : le
 * bouton semblait à moitié survolé.
 */
.embed-instagram:hover,
.embed-instagram:focus-visible {
	border-color: var(--ir-accent);
	color: var(--ir-accent);
}

/* ==========================================================================
   Reprise de fin de passe : partage, séparateurs, embeds
   ========================================================================== */

/*
 * Partage en icônes seules.
 *
 * Les libellés en toutes lettres formaient une rangée de quatre pavés de texte
 * qui pesait autant que la fin de l'article. Le nom du réseau reste porté par
 * aria-label, il n'est donc perdu pour personne.
 */
.partage__liste {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ir-esp-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

.partage__lien {
	display: inline-flex;
	width: 2.75rem;
	height: 2.75rem;
	align-items: center;
	justify-content: center;
	/* Sans cette remise à zéro, la moindre marge héritée écrase l'icône. */
	padding: 0;
	border: 1px solid var(--ir-bordure);
	border-radius: 50%;
	color: var(--ir-texte-doux);
	text-decoration: none;
	transition: color 0.15s ease, border-color 0.15s ease;
}

.partage__lien:hover,
.partage__lien:focus-visible {
	border-color: var(--ir-accent);
	color: var(--ir-accent);
}

.partage__icone {
	display: block;
}

/* Le titre « Partager » n'a plus à peser autant que les icônes qu'il annonce. */
.partage__titre {
	margin-bottom: var(--ir-esp-3);
	font-family: var(--ir-police-texte);
	font-size: var(--ir-t-xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ir-texte-doux);
}

/*
 * Séparateurs allégés.
 *
 * Le pied d'article empilait trois filets pleins et trois écarts de section, ce
 * qui découpait la fin de l'article en tranches. Les filets passent en gris très
 * clair et ne se répètent plus : un seul marque l'entrée dans le pied, les blocs
 * qui suivent se séparent par l'espace.
 */
.partage {
	margin-block: var(--ir-rythme-bloc) 0;
	padding-top: var(--ir-rythme-bloc);
	border-top: 1px solid color-mix(in srgb, var(--ir-bordure) 60%, var(--ir-fond));
}

.article-pied {
	margin-top: var(--ir-rythme-bloc);
}

.article-pied .partage {
	margin-top: var(--ir-rythme-bloc);
	padding-top: 0;
	border-top: 0;
}

/*
 * Blocs liés, « À lire aussi » et « Découvrir d'autres adresses ». Ils se
 * détachent déjà par leur grille de cartes : l'écart de section doublé d'un
 * filet plein en faisait des sections à part entière, alors qu'ils prolongent
 * l'article.
 */
/* .section-liee est déclarée une seule fois, plus bas dans ce fichier. */

/*
 * Légende du visuel d'ouverture, la « photo de une ». Elle était séparée de
 * l'image par un écart de bloc, ce qui la détachait de ce qu'elle légende.
 */
/*
 * Le visuel débordant désormais sur les gouttières du bloc blanc, sa légende
 * les retrouve par un rembourrage : sans cela elle se collerait au bord de la
 * page, seule ligne de texte à ne pas suivre la colonne.
 */
.article-visuel figcaption,
.article-visuel__legende {
	padding-inline: var(--ir-gouttiere);
	margin-top: var(--ir-esp-2);
	color: var(--ir-texte-doux);
	font-size: var(--ir-t-xs);
	line-height: 1.4;
}

/*
 * Embeds Instagram : largeur bornée par le thème, pas par Instagram.
 *
 * Instagram sert ses blocs avec un `max-width` et un `margin` écrits en ligne
 * dans le balisage, qui les décalent les uns des autres et les font occuper
 * toute la colonne. Un embed vertical à pleine largeur prend la hauteur d'un
 * écran au milieu de la lecture.
 *
 * On reprend la main avec un jeton dédié, réglable en un seul endroit. La
 * valeur l'emporte sur les attributs de style d'Instagram, d'où les !important :
 * c'est le seul moyen de battre du style en ligne sans JavaScript.
 *
 * ⚠️ Volontairement plus étroit que la colonne de texte. L'embed ne s'aligne
 * donc pas sur les bords du paragraphe : arbitrage assumé, la taille prime sur
 * l'alignement. Rien à faire côté rédaction, la règle s'applique à tout embed
 * inséré.
 */
.article-contenu,
.fiche__contenu {
	--ir-largeur-embed: 26rem;
}

.article-contenu .instagram-media,
.article-contenu blockquote.instagram-media,
.article-contenu iframe.instagram-media,
.article-contenu .embed-instagram,
.fiche__contenu .instagram-media,
.fiche__contenu blockquote.instagram-media,
.fiche__contenu iframe.instagram-media,
.fiche__contenu .embed-instagram {
	max-width: var(--ir-largeur-embed) !important;
	min-width: 0 !important;
	width: 100% !important;
	margin-inline: auto !important;
	margin-block: var(--ir-rythme-bloc) !important;
}

/* ==========================================================================
   Rythme de fin d'article
   ==========================================================================
   Le pied d'article enchaînait fin de texte, filet, « À lire aussi », filet et
   crédit photo, chaque passage valant un écart de section. Sur grand écran,
   --ir-rythme-section vaut 6 rem, et .conteneur > * + * le posait une fois de
   plus entre l'article et chaque bloc qui le suit : les trous atteignaient
   plusieurs centaines de pixels. Ces blocs prolongent l'article, ils doivent
   se suivre.
   ========================================================================== */

.conteneur > .article-seul + *,
.conteneur > .fiche + *,
.conteneur > .section-liee + * {
	margin-top: var(--ir-rythme-bloc);
}

.article-pied {
	margin-top: var(--ir-rythme-bloc);
	padding-top: var(--ir-rythme-element);
}

.article-taxonomies {
	margin-block: 0;
}

/*
 * Alignement sur la colonne d'article.
 *
 * .article-seul est borné à --ir-largeur-media et centré ; .section-liee ne
 * l'était pas et reprenait donc toute la largeur de .conteneur, soit 1200 px
 * contre 1024. Les deux blocs se suivent immédiatement et ne démarraient pas
 * au même endroit : environ 88 px d'écart de chaque côté, que l'œil repère
 * aussitôt puisque le filet du bloc lié dépassait des deux bords de l'article.
 *
 * Le rembourrage horizontal reprend celui de .article-seul pour que les cartes
 * s'alignent sur le texte et pas seulement sur la boîte.
 */
/*
 * ⚠️ Déclaration unique de .section-liee, à ne pas réessaimer.
 *
 * Elle était écrite à trois endroits, une fois dans 02-composants.css et deux
 * fois ici, chacune corrigeant partiellement la précédente. Le rendu final
 * n'était plus lisible dans aucune des trois : il fallait les superposer
 * mentalement pour savoir ce qui s'appliquait. Les valeurs ci-dessous sont
 * exactement ce que la cascade produisait, réunies en un seul bloc.
 *
 * Les blocs liés « À lire aussi » et « Découvrir d'autres adresses » ne servent
 * que sous un article ou une fiche : leur place est ici, avec les contenus, et
 * non dans les composants génériques.
 */
.section-liee {
	max-width: var(--ir-largeur-media);
	margin-block: var(--ir-rythme-bloc) 0;
	margin-inline: auto;
	padding-top: var(--ir-rythme-bloc);
	/*
	 * ⚠️ Aucune gouttière horizontale ici, et c'est ce qui aligne les deux blocs.
	 *
	 * Avec un rembourrage, les cartes rentraient d'une gouttière alors que le
	 * bloc blanc de l'article, lui, s'arrêtait au bord de sa propre boîte : les
	 * deux ne démarraient pas au même endroit. Sans lui, la boîte de la section,
	 * son filet, son titre et ses cartes partagent exactement les bords du bloc
	 * blanc. La gouttière d'écran est déjà portée par .conteneur, l'ajouter ici
	 * la comptait deux fois sur mobile.
	 */
	border-top: 1px solid color-mix(in srgb, var(--ir-bordure) 60%, var(--ir-fond));
}

/* Deux blocs liés qui se suivent : un seul filet les sépare de l'article. */
.section-liee + .section-liee {
	border-top: 0;
}

.section-liee__titre {
	margin-bottom: var(--ir-rythme-element);
	font-size: var(--ir-t-xl);
	text-wrap: balance;
}

