/*
Theme Name: Galerie Lamy
Theme URI: https://galerielamychabolle.com
Author: Galerie Lamy Chabolle
Description: Thème classique pour le catalogue et le journal de la Galerie Lamy Chabolle.
Version: 1.0.0
Requires at least: 6.5
Requires PHP: 7.4
Text Domain: galerie-lamy
*/

/* ⚠  FICHIER VERSIONNÉ (Git) — NE PAS MODIFIER DEPUIS WP-ADMIN NI EN SFTP.
      Déployé par rsync --delete : toute retouche faite sur le serveur sera ÉCRASÉE
      au prochain déploiement, sans avertissement et sans trace.
      Les CONTENUS et RÉGLAGES (base de données) ne sont pas concernés : wp-admin
      reste entièrement libre pour eux.
      Procédure de modification du code : DEPLOIEMENT.md, à la racine du dépôt. */

/* Base rem = 14.616px, identique au --base-size calculé par Cargo
   (vérifié : bodycopy 1.3rem rendu à 19.0008px → 1rem = 14.616px).
   14.616 / 16 = 0.9135. Les valeurs rem du modèle Cargo sont donc justes
   au pixel près. NB : Cargo recalcule --base-size selon le viewport ;
   91.35% le reproduit aux largeurs desktop courantes (cf. note fluide). */
html {
	font-size: 91.35%;
}

/* ---------------------------------------------------------------------------
   Variables
--------------------------------------------------------------------------- */
/* Point focal du dégradé : propriétés ENREGISTRÉES (typées <percentage>) pour
   qu'elles s'ANIMENT — la navigation AJAX fait alors glisser le centre du fond
   d'une page à l'autre au lieu de le faire sauter. Navigateurs sans @property :
   changement instantané (repli gracieux, comportement d'avant). */
@property --bg-focal-x { syntax: '<percentage>'; inherits: true; initial-value: 50%; }
@property --bg-focal-y { syntax: '<percentage>'; inherits: true; initial-value: 50%; }
/* Le point focal glisse d'une page à l'autre (navigation AJAX). Les couleurs et
   leurs positions (--color-bg-* / --grad-stop-*) sont pilotées dynamiquement par
   le plugin galerie-lamy-core (admin « Dégradés ») ; ici uniquement les valeurs
   de repli si le plugin est désactivé. Le dégradé lui-même n'est défini qu'ici. */

:root {
	--color-bg-1: #2D0603;
	--color-bg-2: #260502;
	--color-bg-3: #1A0402;
	--color-bg-4: #1A0402;                     /* 4e stop optionnel ; = 3e par défaut (invisible) */
	--grad-stop-1: 0%;                          /* positions des stops (répartition régulière par défaut) */
	--grad-stop-2: 50%;
	--grad-stop-3: 100%;
	--grad-stop-4: 100%;
	--color-text: rgba(255, 255, 255, 0.75);
	--color-accent: #FFC600;
	--font-display: 'EB Garamond', serif;
	--font-ui: 'Type Deux', sans-serif;
	/* Pied de page : Accident (cf. @font-face fonts.css) ; repli Helvetica/Arial. */
	--font-footer: 'Accident', 'Helvetica Neue', Helvetica, Arial, sans-serif;
	--img-radius: 0.4rem;                     /* arrondi standard des images du site (sauf exceptions) */
	/* Ombre EXTERNE discrète au survol (source unique) : galerie Collection + œuvres
	   exposées/liées + images agrandissables. Uniquement l'ombre externe (pas de dégradé). */
	--img-hover-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.28);

	/* Épaisseur UNIQUE des chevrons/flèches du site (bouton Retour, lightbox, Related
	   Works) : flèches simples SANS cercle, fines, identiques partout. */
	--chevron-weight: 1.5px;

	/* POINTS de position — source UNIQUE partagée par tout le site : lightbox, carrousel
	   des actualités et bandes d'images des œuvres. Minuscules (« presque un pixel »),
	   blanc discret au repos, jaune accent à l'état courant/survol. */
	--dot-size: 3px;
	--dot-gap: 0.5rem;

	/* Gouttières des flèches de la bande d'images d'une fiche œuvre (desktop) :
	   --oeuvre-nav-w = largeur du bouton (= .actualite-carousel-nav) ; --oeuvre-nav-gap =
	   écart bouton/image (= column-gap de .actualite-carousel). Reprises pour poser la
	   grille [flèche][bande][flèche] (3+ images) ET pour insérer TOUJOURS d'autant
	   .oeuvre-gallery (image(s) et texte), même à 1 ou 2 images, sans bande ni flèches
	   — même largeur de corps sur toutes les fiches œuvre (cf. .oeuvre-gallery plus bas). */
	--oeuvre-nav-w: 2.5rem;
	--oeuvre-nav-gap: 0.5rem;

	/* Marge horizontale STANDARD du contenu = largeur réelle du logo au repos.
	   Valeur de repli ici (~13rem ≈ largeur "GALERIE LAMY" à 1.8rem) ; header.js
	   mesure le logo rendu au chargement et écrase --marge-site (px exacts). */
	--marge-site: 13rem;
	--page-padding: var(--marge-site);

	/* Largeur rendue du sélecteur « FR / EN » (Type Deux à --nav-size) ; sert au calcul de
	   la marge droite. À réajuster si la police ou la taille de la nav change. */
	--lang-switcher-width: 4.34rem;

	/* Marge DROITE du contenu (pages à grand padding) : le bord droit tombe pile à la FIN
	   (le « t ») du dernier lien de nav « Contact ». La position de Contact est EXACTE en
	   CSS = bord droit de la nav (--header-padding-side) + espacement Contact→FR/EN
	   (--link-gap) + largeur de « FR / EN ». Calculée en CSS pur (média-requête desktop
	   ci-dessous) → appliquée DÈS le 1er rendu, aucun saut. Hors desktop : repli symétrique
	   (= --page-padding), identique au comportement d'origine. */
	--marge-site-right: var(--page-padding);

	/* Header : padding PROPRE (valeurs Cargo d'origine), indépendant de --marge-site. */
	--header-padding-side: 3vw;               /* horizontal (Cargo) */
	--header-padding-y: 2vw;                  /* haut (Cargo) ; bas = 0 */
	--header-padding-y-scrolled: 1.2vw;       /* haut au scroll : réduit modérément */
	/* ---------------------------------------------------------------------------
	   Typographie — échelle modulaire √φ (≈ 1.272 par pas ; φ ≈ 1.618 tous les deux
	   pas). Pivot : H1 = Logo = 26px = 1.78rem. Base html 91.35% → 1rem ≈ 14.62px.
	   TOUTE taille de texte référence un token --fs-* : source unique de vérité.
	--------------------------------------------------------------------------- */
	--fs-h1: 1.78rem;   /* 26.0px — Logo / H1 (pivot φ) */
	--fs-h2: 1.40rem;   /* 20.4px — corps, logo au scroll, titres de carte / News */
	--fs-h3: 1.10rem;   /* 16.1px — navigation (2e ancre), sélecteur de langue */
	--fs-h4: 0.86rem;   /* 12.6px — légendes, dates ~14px, « Retour », sous-titres */
	--fs-h5: 0.68rem;   /* 10.0px — capitales fines : pastille, boutons, labels */
	--fs-d1: clamp(2.88rem, 1.6rem + 4vw, 4.66rem);   /* 42.1→68.1 — hero de repli */
	--fs-d2: clamp(2.26rem, 1.4rem + 3vw, 3.66rem);   /* 33.1→53.5 — titre de fiche News */
	--fs-d3: clamp(1.78rem, 1.2rem + 2vw, 2.88rem);   /* 26→42.1 — titre de page, une News */
	--fs-d4: clamp(1.78rem, 1.4rem + 1.2vw, 2.26rem); /* 26→33.1 — h2 de page, filtres Collection */
	--fs-title-fluid: clamp(1.40rem, 1.1rem + 1vw, 1.78rem); /* 20.4→26 — titres de marge / majeure */

	/* Ancres historiques redéfinies À PARTIR des tokens (une seule source de vérité).
	   Tout var(--logo-size) / var(--nav-size) existant résout donc vers un token :
	   Logo au repos = H1 et navigation = H3, exactement. */
	--logo-size: var(--fs-h1);                /* logo au repos = H1 (pivot) ; sert aussi au calcul de --header-height */
	--logo-size-scrolled: var(--fs-h2);       /* logo compact au scroll = H2 */
	--nav-size: var(--fs-h3);                 /* liens de navigation (Type Deux) = H3 (2e ancre) */

	/* Espacement uniforme entre les liens du menu (nav ramassée à droite). */
	--link-gap: 4.5rem;

	/* Hauteur du header au repos (logo 2 lignes + padding haut) → dégagement du contenu.
	   + env(safe-area-inset-top) : sous viewport-fit=cover, le header descend sous la barre
	   d'état (cf. .site-header) ; le contenu doit donc se dégager d'autant. =0 sans encoche. */
	--header-height: calc(2.4 * var(--logo-size) + var(--header-padding-y) + env(safe-area-inset-top, 0px));

	/* Écart vertical entre la NAV (header) et le contenu de la page — levier UNIQUE, valable
	   sur tout le site. --nav-gap = écart standard ; --nav-gap-lg = variante ample (×φ) des
	   fiches œuvres et de la Collection. Augmenter --nav-gap agrandit le padding partout
	   (et décale d'autant le point d'épinglage de la marge collante des fiches œuvres). */
	--nav-gap: 4rem;
	--nav-gap-lg: calc(var(--nav-gap) * 1.618);
	--bg-focal-x: 50%;
	--bg-focal-y: 50%;

	/* Courbe d'accélération commune, douce (transitions ponctuelles, jamais le layout). */
	--ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
}

/* Sélection de texte (copier, etc.) : fond jaune accent, texte noir — convention du site. */
::selection {
	background: var(--color-accent);
	color: #000;
}
::-moz-selection {
	background: var(--color-accent);
	color: #000;
}

/* Desktop (nav horizontale, > 900px = seuil du burger) : la marge droite du contenu
   s'aligne sur la fin de « Contact ». En pur CSS → aucun recalcul JS, aucun saut au
   chargement. En dessous, la nav passe en panneau : on garde le repli symétrique. */
@media (min-width: 901px) {
	:root {
		--marge-site-right: calc(var(--header-padding-side) + var(--link-gap) + var(--lang-switcher-width));
	}
}

/* ---------------------------------------------------------------------------
   Reset / base
--------------------------------------------------------------------------- */
*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	/* Défilement NATIF partout (pas de scroll-behavior:smooth) : à l'ouverture d'une page,
	   aucun effet de « remontée ». Le smooth-scroll « Lenis » a été RETIRÉ (cf. functions.php) :
	   plus d'inertie JS, seul le scroll natif du navigateur. */
	overscroll-behavior-y: none;
	/* SITE-WIDE : pas de rectangle de surbrillance natif au toucher (bleu Android Chrome,
	   gris iOS) sur les liens/boutons — seuls nos propres retours tactiles (couleur, scale,
	   lueur, tous gérés via @media (hover:hover)/(hover:none) ailleurs dans ce fichier)
	   doivent répondre au toucher. Posé jusqu'ici seulement sur .oeuvre-thumb (cf. plus
	   bas) : trop étroit, le halo bleu restait visible sur tous les autres liens internes. */
	-webkit-tap-highlight-color: transparent;
}

/* ---------------------------------------------------------------------------
   Barre de défilement OVERLAY — OverlayScrollbars, thème « lamy »
   Une barre FLOTTANTE, gris clair translucide, qui s'efface au repos (comme iOS)
   et ne prend AUCUNE place : plus de saut de largeur du site, plus de gouttière
   sombre. La lib (assets/vendor/overlayscrollbars) masque la barre native et pose
   la sienne ; initialisée sur <body> dans assets/js/scrollbar.js.
   Le rail (« track ») reste transparent par défaut (base .os-scrollbar) → seul le
   pouce (« handle ») est visible.
--------------------------------------------------------------------------- */
/* Sélecteur doublé `.os-scrollbar.os-theme-lamy` (spécificité 0,2,0) : il l'emporte
   TOUJOURS sur les valeurs par défaut `.os-scrollbar{--os-size:0;…}` de la lib, quel que
   soit l'ordre de chargement des CSS. */
.os-scrollbar.os-theme-lamy {
	--os-size: 12px;                                  /* épaisseur de la barre */
	--os-padding-perpendicular: 3px;                  /* marge → pouce détaché du bord */
	--os-padding-axis: 3px;
	--os-track-border-radius: 999px;
	--os-handle-border-radius: 999px;
	--os-handle-interactive-area-offset: 4px;         /* zone cliquable un peu plus large */
	--os-handle-min-size: 40px;
	--os-handle-bg: rgba(210, 210, 210, 0.45);        /* gris clair translucide */
	--os-handle-bg-hover: rgba(225, 225, 225, 0.65);
	--os-handle-bg-active: rgba(235, 235, 235, 0.85);
	box-sizing: border-box;
}

body {
	margin: 0;
	min-height: 100vh;
	/* Garde-fou : aucun défilement horizontal accidentel (on ne scrolle jamais latéralement
	   le site). « clip » n'établit PAS de conteneur de défilement → ne casse ni le header
	   fixe ni les éléments sticky (rail des fiches œuvre), contrairement à overflow:hidden. */
	overflow-x: clip;
	color: var(--color-text);
	font-family: var(--font-display);
	font-style: normal;
	font-size: var(--fs-h2);
	font-weight: 400;
	letter-spacing: 0;
	line-height: 1.6; /* interligne « Cargo » (EB Garamond Regular) — appliqué site-wide */
	-webkit-font-smoothing: antialiased; /* évite le rendu épaissi (subpixel) sur macOS, comme Cargo */
	-moz-osx-font-smoothing: grayscale;
	background-color: var(--color-bg-4);
	/* Variation aléatoire (plugin Dégradés) : --bg-jitter-* posées sur <html> décalent
	   focal et stops de ± quelques % à chaque page. Repli 0% → aucun effet si absentes. */
	background-image: radial-gradient( circle at calc(var(--bg-focal-x) + var(--bg-jitter-x, 0%)) calc(var(--bg-focal-y) + var(--bg-jitter-y, 0%)),
		var(--color-bg-1) calc(var(--grad-stop-1) + var(--bg-jitter-s, 0%)),
		var(--color-bg-2) calc(var(--grad-stop-2) + var(--bg-jitter-s, 0%)),
		var(--color-bg-3) calc(var(--grad-stop-3) + var(--bg-jitter-s, 0%)),
		var(--color-bg-4) calc(var(--grad-stop-4) + var(--bg-jitter-s, 0%)) );
	/* Desktop : dégradé FIXE au viewport (il ne défile pas avec la page). */
	background-attachment: fixed;
	/* Le centre du dégradé glisse d'une page à l'autre (navigation AJAX) au lieu de sauter. */
	transition: --bg-focal-x 1.2s ease, --bg-focal-y 1.2s ease;
}

/* Fond mobile — ne pas réintroduire un dégradé RADIAL étiré sur la hauteur du document,
   ni une couche épinglée : cf. le bloc @media plus bas.
   PIÈGE D'ÉCRITURE : ne jamais accoler une étoile et une barre oblique dans un commentaire
   (un glob du type « --bg-<etoile>/ »). La séquence ferme le commentaire par surprise, la
   suite devient du CSS invalide et la récupération d'erreur AVALE le bloc @media suivant —
   c'est arrivé ici, le bloc mobile n'a jamais été appliqué pendant des mois. */
@media (max-width: 1280px) {
	/* Jitter neutralisé sur mobile : le réglage (admin « Dégradés ») est unique et partagé
	   avec le bureau, où il reste discret. !important car le JS le pose en inline sur <html>. */
	:root {
		--bg-jitter-x: 0% !important;
		--bg-jitter-y: 0% !important;
		--bg-jitter-s: 0% !important;
	}

	/* Fond mobile. L'image (couches comprises) est composée par galerie-lamy-core, variante
	   Mobile, et servie dans --glc-grad-image / -size / -pos / -anim.
	   Deux invariants à ne pas casser :
	   1. Le fond reste sur le <body> : seul celui-là se propage au canvas, donc aux barres
	      du navigateur. Une couche épinglée ne les atteint pas.
	   2. LINÉAIRE par défaut : il se laisse étirer sur la hauteur du document sans dommage,
	      donc rien à animer → aucun décrochage au défilement rapide. Le RADIAL, lui, doit
	      rester à une taille d'écran et dériver (glc-bg-drift) ; sa position animée se
	      repeint sur le thread principal et peut se faire prendre de vitesse. */
	body {
		/* Noir, pas --color-bg-4 : c'est ce que voient les barres du navigateur et le rebond
		   de défilement au-delà de l'image ; en brique, les bandeaux d'extrémité ne s'y
		   fondaient pas. */
		background-color: #000;
		background-image: var(--glc-grad-image);
		background-repeat: no-repeat;
		background-attachment: scroll;
		background-size: var(--glc-grad-size, 100% 100%);
		background-position: var(--glc-grad-pos, center top);
	}

	/* Dérive du RADIAL uniquement : --glc-grad-anim vaut « none » en linéaire. */
	@supports (animation-timeline: scroll()) {
		@media (prefers-reduced-motion: no-preference) {
			body {
				animation-name: var(--glc-grad-anim, none);
				animation-duration: 1s;
				animation-timing-function: linear;
				animation-fill-mode: both;
				animation-timeline: scroll(root block);
			}
		}
	}
}

@keyframes glc-bg-drift {
	from { background-position-y: calc(-1 * var(--glc-bg-slack, 14.5lvh)); }
	to   { background-position-y: calc(100% + var(--glc-bg-slack, 14.5lvh)); }
}


/* Point focal + couleurs du dégradé par gabarit : désormais injectés en CSS inline
   par le plugin galerie-lamy-core (classes body.glc-grad-*), réglables depuis
   l'admin « Dégradés ». Les valeurs de repli sont celles de :root ci-dessus. */

img {
	max-width: 100%;
	display: block;
	border-radius: var(--img-radius); /* arrondi standard ; exceptions surchargent à 0 */
}

/* Images AGRANDISSABLES (lightbox) : la classe .is-zoomable est posée en JS sur
   EXACTEMENT les images liées au lightbox (front-page.js — hors œuvres exposées et
   clones de carrousel). Au survol : même ombre externe discrète que la galerie
   Collection, rien d'autre (aucun dégradé/ombre interne à ce stade). */
.is-zoomable {
	transition: box-shadow 0.2s ease;
}
.is-zoomable:hover {
	box-shadow: var(--img-hover-shadow);
}

a {
	color: var(--color-text);
	text-decoration: none;
}

h1, h2, h3, h4 {
	font-family: var(--font-display);
	font-weight: 400; /* aucun titre en gras sur le site — graisse normale partout */
	margin: 0 0 1rem;
}

.screen-reader-text {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	height: 1px;
	width: 1px;
	overflow: hidden;
	position: absolute !important;
	word-wrap: normal !important;
}

/* ---------------------------------------------------------------------------
   Header
--------------------------------------------------------------------------- */
.site-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 100;
	display: flex;
	align-items: flex-start; /* logo (2 lignes) et nav alignés en haut */
	gap: 1.5rem;
	/* padding PROPRE du header : horizontal réduit (proche des bords), bas = 0.
	   Le padding HAUT est CONSTANT (--header-padding-y) : il ne change JAMAIS au scroll —
	   toute l'esthétique du site en dépend, et le logo réduit conserve ce même dégagement. */
	/* + env(safe-area-inset-top) : sous viewport-fit=cover, le logo et la nav restent SOUS
	   la barre d'état / l'encoche au lieu de passer dessous. =0 sur les écrans sans encoche. */
	padding: calc(var(--header-padding-y) + env(safe-area-inset-top, 0px)) var(--header-padding-side) 0;
	background: transparent;
}

/* OMBRE DE LISIBILITÉ (inspiration iOS 26) : le texte de l'en-tête (logo, menu, FR/EN)
   est blanc. Une ombre SOMBRE et douce est posée derrière lui — mais comme elle est
   quasi-noire, elle est INVISIBLE sur le fond près-noir du site (ombre sombre sur fond
   sombre) : au repos, rien ne change. Dès qu'un contenu CLAIR/BLANC défile derrière le
   texte (image d'œuvre lumineuse, etc.), l'ombre ressort et redonne du contraste — donc
   elle n'apparaît QUE par-dessus du clair, automatiquement, sans détecter la luminance.
   text-shadow est héritée → une seule déclaration sur .site-header couvre logo + nav.
   Réglage : --nav-legibility-shadow. */
.site-header {
	--nav-legibility-shadow:
		0 0 14px rgba( 0, 0, 0, 0.34 ),
		0 1px 3px rgba( 0, 0, 0, 0.28 );
	text-shadow: var(--nav-legibility-shadow);
}

body.admin-bar .site-header {
	top: 32px;
}

.site-logo {
	flex: 0 0 auto;
	display: grid; /* logo complet + version compacte empilés dans la même cellule */
	font-family: var(--font-display);
	font-style: normal;
	font-weight: 500;
	letter-spacing: 0;
	text-transform: uppercase;
	color: var(--color-text);
	white-space: nowrap;
}

/* pas de surbrillance jaune au survol du logo : il garde sa couleur */
.site-logo:hover {
	color: var(--color-text);
}

/* Les deux versions occupent la même cellule de grille (superposées). */
.logo-full,
.logo-compact {
	grid-area: 1 / 1;
}

/* Repos : logo complet sur 2 lignes ("GALERIE LAMY" / "CHABOLLE"). */
.logo-full {
	font-size: var(--logo-size);
	line-height: 1.2;
	transition: transform 0.65s var(--ease-smooth);
}

/* Scroll : le grand logo remonte complètement hors de l'écran. */
.site-header.header-scrolled .logo-full {
	transform: translateY(calc(-1 * var(--header-height) - 1rem));
	pointer-events: none;
}

/* Version compacte "LAMY CHABOLLE" : conteneur-MASQUE (overflow:hidden) calé sur
   --marge-site. Au repos, le texte est remonté hors champ (derrière la bordure
   haute) ; en .header-scrolled il redescend en slide-in, comme un rideau qui se
   lève à l'envers. Au retour en haut, il repart vers le haut et disparaît. */
.logo-compact {
	overflow: hidden;
	font-size: var(--logo-size-scrolled);
	line-height: 1.2;
	transform: translateX(calc(var(--marge-site) - var(--header-padding-side)));
	pointer-events: none;
}

.logo-compact-text {
	display: block;
	transform: translateY(-100%); /* caché au-dessus, derrière la bordure */
	transition: transform 0.95s var(--ease-smooth); /* slide-in plus lent que la sortie du grand logo */
}

.site-header.header-scrolled .logo-compact {
	pointer-events: auto;
}

.site-header.header-scrolled .logo-compact-text {
	transform: translateY(0); /* émerge de la bordure haute (slide-in) */
}

/* Navigation : ramassée vers la droite (margin-left:auto). Son bord droit est
   ancré au bord du header ; quand le logo rétrécit au scroll, seul l'espace à
   gauche change → la nav NE BOUGE PAS. */
.site-nav {
	margin-left: auto;
	display: flex;
	align-items: center;
	gap: var(--link-gap); /* Contact → FR/EN : même espacement que le menu */
}

/* Menu : liens à espacement uniforme, ramassés à droite. */
.site-nav > ul:not(.lang-switcher) {
	display: flex;
	align-items: center;
	gap: var(--link-gap);
	list-style: none;
	margin: 0;
	padding: 0;
}

.site-nav > ul:not(.lang-switcher) > li {
	display: flex;
	align-items: center;
}

.site-nav a {
	font-family: var(--font-ui);
	font-style: normal;
	font-size: var(--nav-size);
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: 0;
	text-transform: none;
	text-decoration: none;
	white-space: nowrap;
	color: var(--color-text);
	display: block;
	transition: color 0.2s ease;
}

.site-nav .current-menu-item > a,
.site-nav .current_page_item > a {
	color: var(--color-accent);
	text-decoration: none;
}

/* :hover réservé aux pointeurs FINS : sur le panneau plein écran mobile, :hover
   « colle » après un tap → un lien touché restait jaune en permanence, comme s'il
   était la page courante. */
@media (hover: hover) {
	.site-nav a:hover {
		color: var(--color-accent);
		text-decoration: none;
	}
}

/* FR/EN : dernier élément du nav, après Contact. */
.lang-switcher {
	display: flex;
	align-items: center;
	list-style: none;
	margin: 0;
	padding: 0;
	gap: 0.5rem; /* distance FR — / — EN */
	font-size: var(--nav-size);  /* sinon "/" hérite du body et gonfle la hauteur */
	line-height: 1.2;
	/* FR/EN défile AVEC la page, comme s'il était ANCRÉ dans le flux — du texte qu'on
	   fait défiler : sa translation verticale suit la position de scroll (--lang-shift,
	   posée par header.js). Il disparaît par le haut quand on descend et revient quand on
	   remonte. Aucune transition → suivi au pixel près, PAS de fondu (simple ancrage). */
	transform: translateY(var(--lang-shift, 0px));
}

.lang-switcher a {
	font-family: var(--font-ui);
	font-style: normal;
	font-size: inherit;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: 0;
	color: var(--color-text);
	text-decoration: none;
	display: block;
}

.lang-switcher .current-lang a,
.lang-switcher a:hover {
	color: var(--color-accent);
}

/* Bouton burger : masqué en desktop (affiché en mobile, cf. media query). */
.nav-toggle {
	display: none;
}

/* ---------------------------------------------------------------------------
   Footer
--------------------------------------------------------------------------- */
.site-footer {
	position: relative;
	/* Bas + env(safe-area-inset-bottom) : sous viewport-fit=cover, le contenu descend sous
	   l'indicateur d'accueil ; on dégage le pied de page d'autant. =0 sans encoche. */
	padding: 2.25rem var(--page-padding) calc(2.5rem + env(safe-area-inset-bottom, 0px)); /* gauche/droite = --page-padding */
	text-align: center;
}

.site-footer .footer-name {
	font-family: var(--font-footer);
	letter-spacing: 0.12em;
	text-transform: uppercase;
	font-size: var(--fs-h2);
	margin-bottom: 0.5rem;
}

.site-footer .footer-meta {
	font-family: var(--font-footer);
	font-size: var(--fs-h4);
	opacity: 0.6;
}

/* Pied de page (markup fourni par le plugin « Galerie Lamy — Pied de page ») :
   les deux colonnes de contact (adresse | horaires/contact) sont GROUPÉES À
   GAUCHE ; le bloc marque (logo + accroche + icônes sociales) est poussé À
   DROITE. Texte sans-serif, sans capitales. */
.site-footer .footer-inner {
	display: flex;
	justify-content: space-between;
	align-items: flex-start; /* logo aligné en HAUT avec le texte des colonnes */
	gap: 3rem;
	font-family: var(--font-footer);
	/* Séparateur : porté par .footer-inner (inséré dans le padding latéral du
	   footer) → borné aux mêmes marges --page-padding que le contenu du site. */
	border-top: 1px solid rgba(255, 255, 255, 0.12);
	padding-top: 2.25rem;
}

.site-footer .footer-columns {
	display: grid;
	grid-template-columns: auto auto;
	gap: 1.5rem 3.5rem;
	align-items: stretch; /* colonnes de même hauteur → la 2 a un « bas » où ancrer les liens */
	text-align: left;
	font-size: var(--fs-h3);
	line-height: 1.6; /* interligne « Cargo », cohérent avec le corps du site */
}

/* Colonnes en flux vertical : texte en haut, liens à icônes ancrés EN BAS À GAUCHE.
   Appliqué à TOUTES les colonnes → les icônes s'ancrent en bas quelle que soit la colonne
   choisie (réglage « Afficher ces icônes sous : » du plugin Pied de page). */
.site-footer .footer-col {
	display: flex;
	flex-direction: column;
}

.site-footer .footer-col .footer-line {
	margin: 0 0 0.2rem;
	font-weight: 400;
	text-transform: none;
	letter-spacing: 0;
}

/* Mise en forme « **gras** » du texte (plugin Pied de page) : on vise le MEDIUM réel
   (500), pas le 700 par défaut de <strong>. EB Garamond n'est chargée qu'en 300–600 →
   700 serait un faux gras synthétique ; 500 est une graisse dessinée, disponible aussi
   pour Accident et Type Deux. Idem pour *italique* (<em>) et ***gras italique***. */
.site-footer .footer-col .footer-line strong,
.site-footer .footer-col .footer-line b {
	font-weight: 500;
}

/* Ligne vide saisie = espacement voulu : paragraphe d'une ligne de hauteur, non lu. */
.site-footer .footer-col .footer-line-space {
	margin: 0 0 0.2rem;
}

.site-footer .footer-link {
	color: inherit;
	text-decoration: none;
	transition: color 0.25s ease;
}

.site-footer .footer-link:hover,
.site-footer .footer-social a:hover {
	color: var(--color-accent);
}

/* --- Bloc marque à droite : logo, accroche, icônes sociales --- */
.site-footer .footer-brand {
	text-align: right;
	flex-shrink: 0;
}

.site-footer .footer-logo-wrap {
	display: flex;
	justify-content: flex-end;
}

.site-footer .footer-logo {
	display: block;
	max-width: 100%;
}

.site-footer .footer-logo-name {
	font-family: var(--font-footer);
	text-transform: uppercase;
	letter-spacing: 0.14em;
	font-size: var(--fs-h2);
}

.site-footer .footer-social {
	display: flex;
	justify-content: flex-start; /* ancrés à GAUCHE */
	gap: 1.1rem;
	margin-top: auto;     /* poussés EN BAS de leur colonne */
	padding-top: 1.5rem;  /* écart minimal avec le texte au-dessus */
	/* Les icônes remplissent leur boîte jusqu'au bas de la colonne, alors que le
	   texte de la colonne voisine (l'e-mail) s'arrête sur sa ligne de base, un peu
	   plus haut (interligne). On remonte donc la rangée d'icônes pour que son bas
	   s'aligne au PIXEL sur le bas de l'e-mail. Valeur = espace sous la ligne de
	   base (≈ interligne/2 + descente), ajustable. */
	margin-bottom: 0.35em;
}

.site-footer .footer-social a {
	color: inherit;
	opacity: 0.75;
	transition: color 0.25s ease, opacity 0.25s ease;
}

.site-footer .footer-social a:hover {
	opacity: 1;
}

.site-footer .footer-social svg {
	width: 1.4rem;
	height: 1.4rem;
	display: block;
}

/* --- Module d'inscription « Stay in the know », sous le pied de page --------
   Inséré par le plugin Pied de page au bas de TOUTES les pages sauf Contact (qui
   l'intègre déjà à son contenu). Le markup vient du plugin Newsletter
   (gln_render_form) et ne change pas d'un emplacement à l'autre : mêmes classes
   .glc-news-*, réinterprétées ici à l'échelle du pied de page — la feuille
   contact.css n'étant chargée que sur la page Contact, ces règles ne peuvent
   jamais s'y superposer. Renommer ces classes casserait les deux emplacements.
   FILET : même valeur que celui de .footer-inner, borné aux mêmes marges latérales
   (--page-padding, portées par .site-footer). */
.site-footer .footer-newsletter {
	border-top: 1px solid rgba(255, 255, 255, 0.12);
	margin-top: 2.25rem;
	padding-top: 2.25rem;
	text-align: left;
}

/* EN REGARD : libellés à gauche, champ à droite — la page Contact, elle, les empile
   (sa colonne est étroite) ; ici la pleine largeur du pied de page permet la rangée. */
.site-footer .glc-news-band {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: clamp(2rem, 1rem + 3vw, 3.75rem);
}

.site-footer .glc-news-label {
	max-width: 42rem;
}

/* Titre : un cran SOUS le token de page --fs-d4 (÷√φ ≈ ×0.786), comme les filtres
   Collection — présent sans concurrencer les titres de page. */
.site-footer .glc-news-heading {
	font-family: var(--font-display);
	font-size: calc(var(--fs-d4) * 0.786);
	font-weight: 400;
	line-height: 1.15;
	letter-spacing: 0;
	margin: 0 0 0.3rem;
	color: rgba(255, 255, 255, 0.9);
}

/* Sous-texte : Garamond italique grisé, un cran sous le titre (√φ). */
.site-footer .glc-news-sub {
	font-family: var(--font-display);
	font-style: italic;
	font-size: var(--fs-h3);
	line-height: 1.4;
	margin: 0;
	color: rgba(255, 255, 255, 0.5);
}

/* Formulaire : souligné SEUL (pas de boîte), comme sur la page Contact.
   LARGEUR : le champ doit pouvoir afficher une adresse ENTIÈRE. C'est la colonne
   droite qui la porte, en base flexible (35rem visées) — une largeur posée sur le
   formulaire lui-même ne servirait à rien : sa boîte est ajustée à son contenu,
   donc un pourcentage s'y résoudrait circulairement et le champ resterait à sa
   taille intrinsèque (~20 caractères). Le module s'étend ainsi VERS LE CENTRE ;
   la rangée étant en space-between, il reste ancré à droite sur la marge du site
   (--page-padding) et ne peut pas la déborder. Il rétrécit si les libellés ont
   besoin de la place, sans jamais passer sous sa taille minimale (bouton + champ).
   26rem = une adresse courante en entier, sans que le champ ne traverse la page. */
.site-footer .glc-news-right {
	flex: 0 1 26rem;
}

.site-footer .glc-news-form {
	display: flex;
	align-items: center;
	width: 100%;
	border-bottom: 1px solid rgba(255, 255, 255, 0.35);
}

.site-footer .glc-news-input {
	flex: 1;
	min-width: 0;
	background: transparent;
	border: 0;
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: var(--fs-h3);
	padding: 8px 4px;
}

.site-footer .glc-news-input::placeholder {
	color: #ffffff;
	opacity: 0.5;
}

.site-footer .glc-news-input:focus {
	outline: none;
}

/* Saisie assistée du navigateur : pas de boîte blanche, on garde le fond du site. La
   transition quasi infinie empêche Chrome/Safari d’appliquer son fond ; le texte garde
   la police et la couleur du champ. */
.site-footer .glc-news-input:-webkit-autofill,
.site-footer .glc-news-input:-webkit-autofill:hover,
.site-footer .glc-news-input:-webkit-autofill:focus,
.site-footer .glc-news-input:-webkit-autofill:active {
	-webkit-text-fill-color: var(--color-text, #ffffff);
	caret-color: var(--color-text, #ffffff);
	transition: background-color 600000s 0s, color 600000s 0s;
}

.site-footer .glc-news-input:autofill {
	background: transparent;
	color: var(--color-text, #ffffff);
}

/* Bouton : texte seul, Type Deux capitales espacées ; la lueur au survol est celle du
   site (cf. bloc « Lueur (glow) jaune sur survol » plus bas). */
.site-footer .glc-news-submit {
	flex: none;
	background: transparent;
	border: 0;
	cursor: pointer;
	color: var(--color-accent);
	font-family: var(--font-ui);
	font-size: var(--fs-h5);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	white-space: nowrap;
	padding: 8px 4px 8px 1.25rem;
	transition: color 0.25s ease;
}

/* Pot de miel anti-robot : hors écran (jamais vu ni tabulé par un humain). */
.site-footer .glc-news-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Message de confirmation / erreur (Type Deux, discret ; accent si succès). */
.site-footer .glc-news-msg {
	margin: 0.6rem 0 0;
	font-family: var(--font-ui);
	font-size: var(--fs-h5);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.6);
}

.site-footer .glc-news-msg--ok {
	color: var(--color-accent);
}

/* ---------------------------------------------------------------------------
   Contenu générique (page, archive, single)
--------------------------------------------------------------------------- */
/* #site-content = zone échangée en navigation AJAX. Caché tant que JS n'a pas préparé
   l'apparition (.js posé tôt dans <head>) ; révélé INSTANTANÉMENT (le fondu est porté
   par chaque bloc, en cascade — cf. .gl-fade-item). Sans JS : contenu visible normalement. */
.js #site-content {
	opacity: 0;
}

.js #site-content.is-loaded {
	opacity: 1;
}

/* PAS d'anneau de focus sur #site-content. Après chaque navigation AJAX, header.js pose
   le focus sur ce conteneur (tabindex="-1") pour replacer clavier et lecteurs d'écran en
   tête du contenu neuf. Les navigateurs dessinent alors leur ANNEAU DE FOCUS autour de
   lui : un grand rectangle bleu aux dimensions exactes de la zone de contenu — d'où le
   « cadre bleu qui épouse des bordures invisibles » sur bureau, et, sur iPhone une fois
   descendu dans la page, le simple TRAIT BLEU horizontal juste au-dessus du pied de page
   (le bord bas de ce rectangle : #site-content s'arrête précisément là où commence
   .site-footer). Intermittent, car l'anneau ne se dessine que lorsque :focus-visible
   s'active — d'où la difficulté à le reproduire. Le conteneur n'est JAMAIS atteignable au
   clavier (tabindex="-1") : l'anneau n'indique donc rien d'actionnable. On retire son
   DESSIN seulement ; le focus, lui, reste posé — c'est lui qui porte l'accessibilité. */
#site-content:focus,
#site-content:focus-visible {
	outline: none;
}

/* Apparition EN CASCADE : à l'ouverture (et après chaque navigation), chaque bloc de
   premier niveau du contenu entre en fondu avec un très léger décalage successif. Tout
   est géré EN JS (opacité/transition en ligne, cf. front-page.js → initStaggerFadeIn) pour
   rester fiable quel que soit le bloc et respecter prefers-reduced-motion. */

.content-wrap {
	/* Marge GAUCHE = --page-padding (largeur du logo) ; marge DROITE = --marge-site-right
	   (alignée sur la fin de « Contact »). Haut = dégagement sous le header fixe (CONSTANT,
	   jamais animé) ; bas = 4rem. Ordre 4-valeurs : haut · droite · bas · gauche. */
	padding: calc(var(--header-height) + var(--nav-gap)) var(--marge-site-right) 4rem var(--page-padding);
}

.page-title {
	font-size: var(--fs-d3);
}

/* ---------------------------------------------------------------------------
   Pages WordPress (About, Créations, Notable Sales…) : TOUT le texte du contenu
   adopte le registre du site, QUELLES QUE SOIENT les options de typo/couleur posées
   dans Gutenberg. Les compositions toutes faites injectent souvent des styles EN LIGNE
   (couleur noire, tailles fixes, gras…) pensés pour un thème clair ; on les neutralise
   avec !important — seul moyen de battre un style inline — pour une lecture homogène,
   claire, sur le fond sombre. Limité à body.page → n'affecte pas œuvres / actualités.
--------------------------------------------------------------------------- */
body.page .content-wrap :where( p, li, dd, dt, blockquote, cite, address ) {
	font-family: var(--font-display) !important;
	font-size: var(--fs-h2) !important;        /* = corps du site */
	font-weight: 400 !important;
	line-height: 1.6 !important; /* interligne « Cargo » — cohérent avec la base body */
	letter-spacing: 0 !important;
	color: var(--color-text) !important;
}

body.page .content-wrap :where( h1, h2, h3, h4, h5, h6 ) {
	font-family: var(--font-display) !important;
	font-weight: 400 !important;         /* titres non gras, comme le reste du site */
	letter-spacing: 0 !important;
	line-height: 1.25 !important;
	color: var(--color-text) !important;
}

/* Échelle de titres sobre, dans le même registre (sur-classe les tailles inline). */
body.page .content-wrap :where( h1 ) { font-size: var(--fs-d3) !important; }
body.page .content-wrap :where( h2 ) { font-size: var(--fs-d4) !important; }
body.page .content-wrap :where( h3 ) { font-size: var(--fs-title-fluid) !important; }
body.page .content-wrap :where( h4, h5, h6 ) { font-size: var(--fs-h2) !important; }

/* Liens du contenu : couleur du texte, accent jaune au survol (convention du site). */
body.page .content-wrap :where( a ) { color: var(--color-text) !important; }
body.page .content-wrap :where( a:hover, a:focus-visible ) { color: var(--color-accent) !important; }

/* ---------------------------------------------------------------------------
   LÉGENDES (captions) — homogènes sur TOUT le site (fiches œuvre, actualités, pages).
   MÊME registre que la page « À propos » (galerie-lamy-about/about.css) : Type Deux,
   petites (11px), interligne aéré, capitales légèrement espacées, gris atténué, alignées
   à GAUCHE sous le visuel. !important pour battre les styles EN LIGNE (tailles/police/
   couleur) que les compositions Gutenberg posent parfois sur les légendes.
--------------------------------------------------------------------------- */
figcaption,
.wp-element-caption,
.wp-caption-text {
	font-family: var(--font-ui, sans-serif) !important;
	font-size: var(--fs-h4) !important; /* un cran √φ au-dessus de l'ancien 11px, sur la grille */
	font-weight: 400 !important;
	line-height: 1.6 !important;
	letter-spacing: 0.04em !important;
	color: rgba(255, 255, 255, 0.5) !important;
	margin-top: 0.75rem !important;
	text-align: left;
}

/* Page Collection : menu de filtres (gauche) + grille (droite). */
.oeuvre-archive {
	display: grid;
	/* Colonne = largeur de la catégorie la plus longue (Drawings & Prints), pas plus.
	   (Le rebond lettre par lettre tient dans sa largeur → n'élargit pas la colonne.)
	   Cette largeur est la MÊME en français et en anglais : elle est fixée par le
	   gabarit .collection-nav-sizer (libellés anglais), pas par la langue affichée. */
	grid-template-columns: max-content minmax(0, 1fr);
	gap: 3rem 1.5rem; /* colonne menu→grille resserrée (1.5rem, comme les gaps de la grille) */
	align-items: start;
	/* Bords gauche ET droit alignés sur le logo au repos (--header-padding-side, marges
	   égales) ; padding haut plus généreux dérivé du nombre d'or (3rem × φ). */
	padding: calc(var(--header-height) + var(--nav-gap-lg)) var(--header-padding-side) 4rem;
}

/* Menu de filtres : EB Garamond, empilé verticalement, et STICKY → reste visible
   (collé sous le header) pendant le défilement de la galerie. Terme actif = accent. */
.collection-nav {
	position: sticky;
	top: calc(var(--header-height) + 1.5rem);
	/* Taille des libellés de catégories (filtres) et de la recherche : un cran √φ
	   sous le token de page --fs-d4 (÷1.272 ≈ ×0.786), tout en gardant son clamp fluide.
	   Un seul réglage pour le bouton, le champ et son placeholder → ils restent alignés. */
	--collection-nav-fs: calc(var(--fs-d4) * 0.786);
}

.collection-nav ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.1rem; /* items rapprochés, cohérent avec l'interligne resserré */
}

.collection-nav-link {
	display: block;
	width: 100%;
	/* boutons de filtre : on neutralise le style natif de <button> */
	background: none;
	border: 0;
	padding: 0;
	margin: 0;
	cursor: pointer;
	text-align: left;
	font-family: var(--font-display);
	font-size: var(--collection-nav-fs); /* filtres Collection : un cran sous --fs-d4 */
	line-height: 0.95; /* interligne resserré */
	color: var(--color-text);
	transition: color 0.2s ease;
}

.collection-nav-link.is-active {
	color: var(--color-accent);
}

/* :hover séparé de .is-active et réservé aux pointeurs FINS : sur écran tactile,
   :hover « colle » après un tap (pas de mouseleave) et la catégorie touchée restait
   jaune en permanence, comme si elle était sélectionnée. */
@media (hover: hover) {
	.collection-nav-link:hover {
		color: var(--color-accent);
	}
}

/* Gabarit de largeur du menu (cf. archive-oeuvre.php) : les libellés ANGLAIS empilés,
   dans la typographie EXACTE des catégories — c'est lui qui fixe le `max-content` de
   la colonne, donc la même largeur de menu en FR et en EN. Invisible et sans hauteur :
   `height:0 + overflow:hidden` rogne le rendu mais laisse la contribution de largeur
   intacte (le dimensionnement intrinsèque se calcule toujours sur le contenu). */
.collection-nav-sizer {
	height: 0;
	overflow: hidden;
	visibility: hidden;
	pointer-events: none;
	font-family: var(--font-display);
	font-size: var(--collection-nav-fs);
	line-height: 0.95;
}

.collection-nav-sizer span {
	display: block;
	white-space: nowrap;
}

/* « Créations » : séparée des catégories classiques par le même espace que celui qui
   la sépare déjà de « Rechercher… » en dessous (.collection-search, margin-top:
   1.4rem) — le <ul> porte déjà un gap de 0.1rem entre items, on complète donc avec
   1.3rem pour retomber pile sur 1.4rem au total. Desktop ET mobile (même <ul>). */
.collection-nav-item-break {
	margin-top: 1.3rem;
}

/* Recherche, tout en bas des catégories : le libellé « Recherche… » (même
   typographie que les catégories) se transforme EN PLACE en champ de saisie au
   clic (cf. front-page.js → initCollectionFilter). Hauteur FIGÉE (une ligne, celle
   du bouton fermé) : bouton, champ ET placeholder sont superposés en position
   absolue sur ce même repère (top:0/left:0, cf. règle groupée ci-dessous) — ouvrir
   la recherche ne fait donc JAMAIS varier la hauteur de la colonne (mobile : la
   galerie ne saute plus quand le champ s'ouvre), et le champ peut prendre plus de
   hauteur que ce repère sans rien pousser, quitte à déborder par-dessus la galerie
   (cf. .collection-search-input, jambages g q j p y). */
.collection-search {
	margin-top: 1.4rem;
	position: relative;
	font-size: var(--collection-nav-fs);
	height: 1.2em;
}

/* Bouton, champ et placeholder : même coin haut-gauche → l'ouverture ne déplace
   jamais le texte visible, quelle que soit la hauteur prise par le champ. */
.collection-search-toggle,
.collection-search-input,
.collection-search-ph {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
}

/* Libellé du bouton fermé : line-height 0.95 des catégories serait trop compact vu
   l'agrandissement du repère (.collection-search, 1.2em) — on garde son line-height
   propre à 1.2 pour rester calé sur ce repère, MÊME s'il n'a plus besoin d'égaler
   celui du champ (1.45) : bouton et champ ne se recouvrent que par top:0/left:0, pas
   par une hauteur de ligne partagée (cf. .collection-search ci-dessus). */
.collection-search-toggle {
	padding: 0;
	line-height: 1.2;
}

.collection-search-toggle .collection-nav-label {
	display: block;
	line-height: 1.2;
}

/* Recherche : aucun effet de survol (couleur inchangée au hover). */
.collection-search-toggle:hover {
	color: var(--color-text);
}

.collection-search.is-open .collection-search-toggle {
	display: none;
}

.collection-search-input {
	display: none;
	min-width: 0; /* le champ ne doit jamais imposer sa largeur à la colonne du menu */
	/* content-box, hauteur AUTO d'une ligne COMPLÈTE (jambages compris). L'<input> CLIPPE
	   son contenu (contrairement au libellé <button>, en overflow visible) : la hauteur du
	   contenu = line-height, donc 1.2 (celle du bouton) rognait encore le bas des lettres
	   (g q j p y) en EB Garamond. On passe à 1.45 pour leur laisser toute la place — sans
	   risque pour la mise en page puisque le champ est positionné en absolu (ci-dessus) :
	   il peut désormais dépasser le repère d'une ligne sans rien pousser. */
	box-sizing: content-box;
	background: none;
	border: 0;
	border-radius: 0;
	margin: 0;
	padding: 0 0 0.15em;
	font-family: var(--font-display);
	font-size: var(--collection-nav-fs); /* aligné sur les libellés de catégories */
	line-height: 1.45;
	/* Passer de 1.2 (bouton) à 1.45 ajoute du DEMI-interligne au-dessus ET en dessous
	   du texte à parts égales (modèle CSS du half-leading) : (1.45 − 1.2) / 2 = 0.125em
	   de chaque côté. Le bas gagné évite le rognage des jambages (g q j p y) — mais le
	   haut gagné pousse la ligne de base 0.125em plus bas que celle du bouton fermé
	   (même repère top:0/left:0, cf. .collection-search-toggle ci-dessus). On remonte
	   donc le champ de ce même 0.125em pour que les deux lignes de base retombent
	   exactement l'une sur l'autre, sans réduire l'espace sous le texte qui protège les
	   jambages. */
	top: -0.125em;
	height: auto;
	min-height: 0;
	color: var(--color-text);
	vertical-align: top;
	-webkit-appearance: none;
	appearance: none;
	outline: none;
	z-index: 1; /* déborde au-dessus de la galerie, jamais dessous */
}

.collection-search.is-open .collection-search-input {
	display: block;
}

.collection-search-input::placeholder {
	color: currentColor;
	opacity: 0.4;
}

/* Pas de bouton « effacer » natif (évite un scintillement au focus/saisie). */
.collection-search-input::-webkit-search-cancel-button,
.collection-search-input::-webkit-search-decoration {
	-webkit-appearance: none;
	appearance: none;
}

/* Recherche : AUCUNE lueur au survol (contrairement aux autres filtres) — on neutralise
   la lueur site-wide (.collection-nav-link:hover) par une spécificité supérieure. */
.collection-search .collection-search-toggle:hover,
.collection-search .collection-search-toggle:focus-visible {
	animation: none;
	filter: none;
}

/* …remplacée par une animation des points après « Search » : un point, deux, trois, un…
   Au repos, une ellipse « … ». Les points s'animent au survol/focus du bouton. */
.collection-search-dots::after {
	content: "…";
}

@keyframes glc-search-dots {
	0%,   33%  { content: "."; }
	34%,  66%  { content: ".."; }
	67%,  100% { content: "..."; }
}

/* Focus clavier + placeholder du champ ouvert : toujours animés. */
.collection-search-toggle:focus-visible .collection-search-dots::after,
.collection-search-ph .collection-search-dots::after {
	animation: glc-search-dots 1.4s infinite;
}

/* Survol : UNIQUEMENT sur les périphériques dotés d'un vrai pointeur. Sur le tactile,
   le :hover reste « collé » après le tap (les points s'animeraient en continu) — on
   n'active donc aucun effet de survol sur mobile. */
@media (hover: hover) {
	.collection-search-toggle:hover .collection-search-dots::after {
		animation: glc-search-dots 1.4s infinite;
	}
}

/* Mouvement réduit : points fixes (l'ellipse), pas d'animation. */
@media (prefers-reduced-motion: reduce) {
	.collection-search-toggle:hover .collection-search-dots::after,
	.collection-search-toggle:focus-visible .collection-search-dots::after,
	.collection-search-ph .collection-search-dots::after {
		content: "…";
		animation: none;
	}
}

/* Placeholder ANIMÉ du champ ouvert : « Search… » grisé dont les points défilent, calqué
   EXACTEMENT sur la position du texte du champ (mêmes police, taille, line-height,
   top:-0.125em — cf. .collection-search-input pour la raison de ce décalage). Affiché
   uniquement quand le champ est OUVERT et VIDE ; masqué dès la saisie. */
.collection-search-ph {
	display: none;
	font-family: var(--font-display);
	font-size: var(--collection-nav-fs); /* aligné sur les libellés de catégories */
	line-height: 1.45; /* même ligne que .collection-search-input (jambages non rognés) */
	top: -0.125em; /* même remontée que .collection-search-input, ligne de base sur le bouton */
	color: var(--color-text);
	opacity: 0.4; /* même grisé que le placeholder natif */
	pointer-events: none;
	white-space: nowrap;
}

.collection-search.is-open .collection-search-input:placeholder-shown ~ .collection-search-ph {
	display: block;
}

/* « New Arrivals / Nouveautés » : effet BOUNCE (rebond) lettre par lettre, posé par le
   JS (cf. front-page.js → setupCollectionBounce) sur bureau comme sur mobile. Le
   libellé tient dans sa largeur (pas de rognage) et rebondit périodiquement. */
.collection-nav-link.is-bounce {
	overflow: visible;
	white-space: nowrap;
}

/* Le libellé ne bouge plus en bloc : chaque LETTRE (.bounce-letter, posée en JS)
   rebondit avec un délai décalé → effet de vague (calqué sur l'exemple fourni). */
.collection-nav-link.is-bounce .collection-nav-label {
	display: inline-block;
}

.collection-nav-link.is-bounce .bounce-letter {
	display: inline-block;
	/* Vitesse du rebond RESTAURÉE (le mouvement lui-même dure ~0.6s comme à l'origine) +
	   temps de REPOS au nombre d'or : le rebond occupe 38,2 % du cycle (= 1/(1+φ)), le repos
	   61,8 % (= φ/(1+φ)) → repos = φ × durée du rebond. 0.6 ÷ 0.382 ≈ 1.57s de cycle. */
	animation: collection-bounce 1.57s infinite ease-in-out;
}

/* Rebond dans les premiers 38,2 % du cycle (haut à 19,1 %, retour à 38,2 %), puis REPOS
   jusqu'à 100 %. -0.3em ≈ les -15px de l'exemple, rapportés à la taille de police. */
@keyframes collection-bounce {
	0%    { transform: translateY(0); }
	19.1% { transform: translateY(-0.3em); }
	38.2% { transform: translateY(0); }
	100%  { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
	.collection-nav-link.is-bounce .bounce-letter {
		animation: none;
	}
}

/* ---------------------------------------------------------------------------
   Page CRÉATIONS — gabarit page-creations.php (cf. functions.php →
   galerie_lamy_creations_page_template). Page à part entière (elle a quitté le filtre
   client de la page Collection) : même registre que les fiches News / Work —
   .content-wrap, bouton .oeuvre-back au-dessus du titre.
--------------------------------------------------------------------------- */

/* En-tête en deux colonnes : titre étroit à gauche, texte à droite, alignés en haut —
   proportions propres à cette page (pas de token sitewide équivalent). */
.creations-page {
	--creations-col-title: 260px;
	--creations-col-gap: 40px;
	--creations-gutter: 14px;
}

.creations-head {
	display: grid;
	grid-template-columns: var(--creations-col-title) minmax(0, 1fr);
	gap: 0 var(--creations-col-gap);
	align-items: start;
	margin-bottom: 4rem;
}

/* Même registre que .page-title / .actualite-single-title (titre de page / de News). */
.creations-page-title {
	margin: 0;
	font-family: var(--font-display);
	font-size: var(--fs-d3);
	font-weight: 400;
	line-height: 1.05;
	color: #fff;
}

/* Même registre que le corps du site (body.page p, cf. plus haut). */
.creations-head-text {
	margin: 0;
	max-width: 60ch;
	font-family: var(--font-display);
	font-size: var(--fs-h2);
	line-height: 1.6;
	color: var(--color-text);
}
.creations-head-text p + p {
	margin-top: 1em;
}

/* Carrousel de vignettes : réutilise TEL QUEL le moteur .js-actualite-carousel
   (flèches, défilement borné, grab souris, swipe — cf. assets/js/actualite.js)
   avec une présentation propre, comme la « pellicule » de la page À propos
   (cf. galerie-lamy-about/assets/about.css) : trois vignettes par vue, recadrées 3:4,
   chacune un LIEN direct vers sa fiche œuvre (pas de lightbox) — MAIS avec sa légende
   EN DESSOUS, dans le registre du slider « Œuvres en rapport / Related works »
   (.we-slide-title, cf. assets/css/front-page.css) : c'est pourquoi le recadrage 3:4 est
   posé sur .creations-thumb-media (la vignette SEULE), pas sur .actualite-slide (le lien
   ENTIER, image + légende) — .we-slide/.we-slide-media suivent le même principe. Pas de
   points de position (un par image serait surchargé à trois vignettes visibles à la
   fois) : les points ne sont simplement pas rendus par le gabarit PHP.
   Sélecteurs à 4 classes (.creations-page en tête) : le moteur partagé définit
   .actualite-slide / -track PLUS BAS dans ce fichier (source des « slides » News) — il
   faut battre sa spécificité (3 classes) quel que soit l'ordre, sans !important. */
.creations-page .actualite-carousel.creations-thumbs .actualite-slide {
	display: block;
	flex: 0 0 calc( ( 100% - 2 * var( --creations-gutter ) ) / 3 );
	aspect-ratio: auto;
	gap: 0;
	background: none;
	scroll-snap-align: start;
	text-decoration: none;
	color: var(--color-text);
}

.creations-page .creations-thumb-media {
	display: block;
	aspect-ratio: 3 / 4;
	border-radius: var(--img-radius);
	overflow: hidden;
	transition: box-shadow 0.2s var(--ease-smooth);
}

.creations-page .actualite-slide:hover .creations-thumb-media {
	box-shadow: var(--img-hover-shadow);
}

.creations-page .actualite-carousel.creations-thumbs .actualite-carousel-track {
	align-items: flex-start; /* légendes de hauteurs inégales : vignettes alignées en haut */
	gap: var(--creations-gutter);
}

.creations-page .actualite-carousel.creations-thumbs .actualite-slide-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	cursor: pointer; /* lien direct, pas la loupe de la lightbox */
}

/* Légende = désignation de l'œuvre, MÊME registre que .we-slide-title (slider « Œuvres
   en rapport ») : Garamond, alignée à gauche, accent au survol/focus. */
.creations-page .creations-thumb-title {
	display: block;
	margin-top: 0.7rem;
	font-family: var(--font-display);
	font-size: var(--fs-h2);
	line-height: 1.3;
	text-align: left;
	color: inherit;
}

.creations-page .actualite-slide:focus-visible .creations-thumb-title {
	color: var(--color-accent);
}
@media (hover: hover) {
	.creations-page .actualite-slide:hover .creations-thumb-title {
		color: var(--color-accent);
	}
}

@media (max-width: 900px) {
	.creations-head {
		grid-template-columns: 1fr;
		gap: 1.5rem;
		margin-bottom: 3rem;
	}
	.creations-head-text {
		max-width: none;
	}
	/* Une vignette pleine largeur à la fois (comme les fiches actualité), plutôt que
	   trois rétrécies. */
	.creations-page .actualite-carousel.creations-thumbs .actualite-slide {
		flex: 0 0 100%;
	}
	.creations-page .creations-thumb-title {
		font-size: var(--fs-h3);
		margin-top: 0.5rem;
	}
}

/* Galerie « justified rows » (style Google Photos) : les images, dans l'ordre
   chronologique strict, sont mises à l'échelle à une hauteur de rangée commune pour
   que chaque rangée remplisse EXACTEMENT la largeur du conteneur — sans recadrage ni
   espace perdu. La dernière rangée garde la hauteur cible (non étirée), alignée à gauche.
   Positions et dimensions des cartes sont calculées en JS (front-page.js → initCollectionLayout) :
   conteneur en position relative, cartes en absolu. */
.oeuvre-grid {
	position: relative;
	margin: 0;
}

.oeuvre-card {
	position: absolute;
	top: 0;
	left: 0;
	/* Position/taille posées en px par le JS. On NE transitionne PAS la position
	   (reflow instantané au resize) — seulement l'opacité (fondu au filtrage). */
	margin: 0;
	transition: opacity 0.4s ease;
}

/* Filtrage Collection (cf. front-page.js, animation FLIP) :
   .is-hiding  = carte sortante en fondu, exclue du recalcul (reste sur place) ;
   .is-hidden  = retirée du flux une fois le fondu terminé ;
   .is-entering = carte entrante, déjà positionnée mais transparente le temps d'un frame,
                  puis le retrait de la classe déclenche le fondu d'entrée. */
.oeuvre-card.is-hiding {
	opacity: 0;
}

.oeuvre-card.is-hidden {
	display: none;
}

.oeuvre-card.is-entering {
	opacity: 0;
}

.oeuvre-card .oeuvre-thumb {
	position: relative; /* repère du cartel en overlay */
	display: block;
	overflow: hidden;
	width: 100%;
	height: 100%; /* remplit la carte dimensionnée par le JS */
	-webkit-tap-highlight-color: transparent; /* pas de flash gris iOS : seul le scale répond au toucher */
	/* Coins arrondis portés par le conteneur (clippe l'image ET l'overlay cartel) ;
	   pas de fond → les coins laissent voir le dégradé de la page (transparents). */
	border-radius: var(--img-radius);
	/* Survol : légère élévation (style Google Photos). transform : effet de pression
	   tactile (mobile, cf. média (hover:none) plus bas) — le release revient en fondu. */
	transition: box-shadow 0.2s ease, transform 0.38s ease;
}

/* Mobile / tactile : au toucher, la vignette se réduit légèrement (façon Pinterest iOS),
   en gardant ses coins arrondis (scale uniforme). Réservé aux écrans SANS survol pour ne
   pas rétrécir la vignette au simple clic sur desktop. La descente est posée (0.2s), la
   remontée douce (0.38s héritée ci-dessus) → ressenti « rebond » légèrement plus lent. */
@media (hover: none) and (pointer: coarse) {
	.oeuvre-card .oeuvre-thumb:active {
		transform: scale(0.95);
		transition: transform 0.2s ease-out;
	}
}

/* La carte a déjà le ratio exact de l'image (largeur = hauteur × ratio, posé en JS),
   donc object-fit: cover ne recadre pas — il absorbe juste l'arrondi sous-pixel. */
.oeuvre-card .oeuvre-thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: filter 0.2s ease;
}

/* Survol : élévation + léger éclaircissement — POINTEURS FINS uniquement. Sur écran
   tactile, :hover « colle » après un tap et fige l'effet (ombre + éclaircissement) →
   on ne l'active que sous @media (hover: hover) : AUCUN effet de survol sur mobile. */
@media (hover: hover) {
	.oeuvre-card .oeuvre-thumb:hover {
		box-shadow: var(--img-hover-shadow);
	}

	.oeuvre-card .oeuvre-thumb:hover img {
		filter: brightness(1.05);
	}
}

/* Cartel au survol : contenu du 3e bloc de la fiche (cf. galerie_lamy_oeuvre_cartel_html).
   Fondu doux ; pointer-events:none → le clic atteint le lien (→ fiche single). */
.oeuvre-cartel {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	padding: 1.25rem;
	background: linear-gradient( to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.35) 55%, rgba(0, 0, 0, 0) 100% );
	color: #fff;
	font-size: var(--fs-h4);
	line-height: 1.4;
	opacity: 0;
	transition: opacity 0.4s ease;
	pointer-events: none;
}

/* Cartel révélé au focus CLAVIER : toujours actif (accessibilité). */
.oeuvre-thumb:focus-visible .oeuvre-cartel {
	opacity: 1;
}
/* Cartel révélé au SURVOL : pointeurs fins uniquement → pas de cartel « collé » au tap. */
@media (hover: hover) {
	.oeuvre-thumb:hover .oeuvre-cartel {
		opacity: 1;
	}
}

.oeuvre-cartel :where( p, h1, h2, h3, h4 ) {
	margin: 0 0 0.35rem;
	font-weight: 400; /* pas de gras dans le cartel (titre compris), comme dans le rail */
}

.oeuvre-cartel :last-child {
	margin-bottom: 0;
}

/* Créations : vignette à DOUBLE image. La 2e image (1re image de la fiche) est posée en
   overlay, recadrée en cover (jamais redimensionnée) et révélée en fondu au survol —
   sous le cartel (title-only) qui reste au-dessus. Aucune incidence sur la mise en page :
   la carte garde le ratio de l'image à la une, l'overlay la remplit. */
/* Sélecteur volontairement à 3 classes (.oeuvre-card .oeuvre-thumb .oeuvre-hover-img)
   pour l'emporter sur « .oeuvre-card .oeuvre-thumb img » (qui impose transition: filter) :
   sans cela, l'opacité ne serait PAS animée et le passage d'une image à l'autre serait sec.
   Ici l'image de survol apparaît en FONDU au-dessus de l'image à la une. */
.oeuvre-card .oeuvre-thumb .oeuvre-hover-img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover; /* recadre si nécessaire, ne déforme pas */
	opacity: 0;
	transition: opacity 0.5s ease;
	pointer-events: none;
}

/* Image de survol (créations) au focus CLAVIER : toujours actif (accessibilité). */
.oeuvre-card .oeuvre-thumb:focus-visible .oeuvre-hover-img {
	opacity: 1;
}
/* Image de survol au SURVOL : pointeurs fins uniquement → rien ne « colle » au tap mobile. */
@media (hover: hover) {
	.oeuvre-card .oeuvre-thumb:hover .oeuvre-hover-img {
		opacity: 1;
	}
}

/* Pastille « Réservé / On Hold » en haut à droite de la vignette, visible en permanence
   sur les œuvres réservées. */
.oeuvre-badge {
	position: absolute;
	top: 0.6rem;
	right: 0.6rem;
	z-index: 2; /* au-dessus de l'image ET du cartel (qui apparaît au survol) */
	display: inline-flex;
	align-items: center;
	/* CORRECTION VERTICALE (2026-09, signalée sur iPhone) — la police « Type Deux » a un
	   ascendant/descendant asymétrique autour de la hauteur de capitale (tables DE LA
	   POLICE, donc identique sur tout moteur/appareil — pas une différence de rendu
	   Chrome/Safari), ET align-items:center ne répartit pas non plus l'espace négatif
	   (line-height:1 < métriques naturelles de la police) de façon symétrique. Somme des
	   deux effets, étalonnée EMPIRIQUEMENT sur CETTE pastille précise (mesure Canvas
	   TextMetrics + Range, plusieurs valeurs testées jusqu'à annuler l'écart haut/bas
	   réel — pas déduite en théorie) : ≈ 0.0955em pour un mot sans descendante ni accent
	   (« ON HOLD ») — l'encre flotte trop HAUT, plus de vide sous le texte qu'au-dessus.
	   NOTE : ce chiffre est plus grand que celui de .gl-button (0.0725em) bien que les
	   deux soient inline-flex + align-items:center sur la même police — la pastille est
	   en `position:absolute`, ce qui change la répartition ; les deux valeurs viennent
	   chacune de leur propre étalonnage, ne pas les fusionner. On corrige en augmentant
	   le padding HAUT et en réduisant le BAS du même montant (somme inchangée → la
	   pastille garde sa hauteur). Un mot avec accent (« RÉSERVÉ ») ou descendante
	   (« ENQUIRE », le Q) a un écart réel différent : compromis pour l'ensemble des
	   libellés, pas un centrage parfait de CHACUN. */
	padding-top: calc(0.32em + 0.0955em);
	padding-bottom: calc(0.32em - 0.0955em);
	/* Le suivi de lettres (letter-spacing) ajoute un espace APRÈS CHAQUE caractère, y
	   compris le DERNIER (vérifié par mesure : glyphes + suivi = lettres × suivi, pas
	   (lettres-1) × suivi) — ce fantôme invisible en fin de texte n'a pas d'équivalent
	   en début. Résultat : même avec un padding symétrique, l'ENCRE (« RÉSERVÉ »/« ON
	   HOLD ») paraît décalée à gauche du vrai centre de la pastille. On corrige en
	   retirant la moitié du suivi au padding droit et en l'ajoutant au padding gauche —
	   ça recentre l'encre sans toucher au texte ni au tracé de la pilule. */
	padding-inline-start: calc(0.7em + 0.05em);
	padding-inline-end: calc(0.7em - 0.05em);
	background: rgba( 0, 0, 0, 0.55 );
	color: #fff;
	font-family: var(--font-ui);
	font-size: var(--fs-h5);
	font-weight: 500;
	letter-spacing: 0.1em;
	line-height: 1;
	text-transform: uppercase;
	border-radius: 999px;
	pointer-events: none; /* le clic atteint le lien de la vignette */
	backdrop-filter: blur( 2px );
}

/* Cartel adaptatif : quand la vignette (donc l'image) est trop petite pour afficher le
   cartel ENTIER au survol, on ne montre que le TITRE (1er bloc), pas les spécifications.
   On interroge la taille RÉELLE de chaque carte (container query) → fonctionne aussi bien
   quand l'écran est petit que lorsque l'admin force 2/3 colonnes. Front uniquement
   (l'aperçu admin n'établit pas de conteneur). */
.oeuvre-archive:not( .glc-admin ) .oeuvre-card {
	container-type: size;
}

@container (max-height: 220px) or (max-width: 190px) {
	.oeuvre-cartel > :not(:first-child) {
		display: none;
	}
}

/* Grille « CARGO » (alternative expérimentale) : rangées JUSTIFIÉES à bas irrégulier,
   pilotées par le MÊME moteur JS que la masonry (collection-layout.js → cargoLayout, qui
   détecte la classe .oeuvre-grid--cargo). Les cartes gardent donc le modèle de base
   (position:absolute, .oeuvre-thumb en height:100% + object-fit:cover, la carte ayant le
   ratio exact de l'image → aucun recadrage). Aucune règle CSS spécifique n'est nécessaire :
   le style de carte partagé suffit ; seule la mise en page (JS) diffère. Écart vertical
   entre rangées = écart horizontal × φ (cf. cargoLayout). */

/* Page Collection (desktop, deux colonnes ≥1281px) : vue VERROUILLÉE à la hauteur de
   l'écran. La PAGE ne défile pas — le menu de filtres reste au repos à gauche et SEULE
   la galerie (panneau de droite) défile, dans son propre conteneur. Sous 1281px (menu
   empilé au-dessus de la grille, cf. @media max-width:1280px), on garde le défilement
   de page normal. Le pied de page n'est pas visible sur cette vue verrouillée. */
@media (min-width: 1281px) {
	body.post-type-archive-oeuvre {
		height: 100vh;
		overflow: hidden; /* la page elle-même ne défile jamais */
	}

	/* Pages Œuvre : un peu plus d'air, cohérent avec le dégagement de l'archive
	   Collection (haut dérivé du nombre d'or, 3rem × φ) ; bas légèrement plus généreux. */
	body.single-oeuvre .content-wrap {
		padding-top: calc(var(--header-height) + var(--nav-gap-lg));
		padding-bottom: 5rem;
	}

	/* Pages News (Journal) : MÊME dégagement en tête que les fiches œuvre / la Collection
	   (nombre d'or) — sinon le Journal démarrait plus haut sous le header que le reste
	   du site, incohérent d'une section à l'autre. */
	body.single-actualite .content-wrap,
	body.post-type-archive-actualite .content-wrap {
		padding-top: calc(var(--header-height) + var(--nav-gap-lg));
	}

	.post-type-archive-oeuvre .oeuvre-archive {
		height: 100vh;
		box-sizing: border-box;
		/* Une seule rangée occupant toute la hauteur dispo → le panneau galerie peut être
		   plus court que son contenu (donc défiler). minmax(0,1fr) autorise ce rétrécissement. */
		grid-template-rows: minmax(0, 1fr);
		align-items: stretch; /* le panneau galerie remplit la hauteur (≠ base align-items:start) */
		overflow: hidden;
		/* Aucune marge haut/bas sur le conteneur : la galerie occupe TOUTE la hauteur de
		   l'écran (jusqu'au bord inférieur). Le dégagement sous le header est reporté DANS
		   chaque colonne (padding-top ci-dessous) → la galerie peut défiler jusqu'en haut. */
		padding-top: 0;
		padding-bottom: 0;
	}

	/* Le menu de filtres reste au repos, calé sous le header (il ne défile pas). */
	.post-type-archive-oeuvre .collection-nav {
		padding-top: calc(var(--header-height) + var(--nav-gap-lg));
	}

	/* Le panneau galerie est le SEUL conteneur défilant ; il part du HAUT de l'écran
	   (y=0, sous le header fixe). Le dégagement interne (padding-top) place les premières
	   images sous le header AU REPOS, mais il défile avec le contenu → les images passent
	   SOUS le header quand on défile. Aucune marge en bas : la dernière rangée vient au ras
	   du bord inférieur. */
	.post-type-archive-oeuvre .collection-main {
		min-height: 0;        /* autorise le panneau à être plus court que la grille */
		overflow-y: auto;
		overflow-x: hidden;   /* SEUL le défilement vertical est possible (jamais horizontal) */
		overscroll-behavior: contain; /* le défilement ne « déborde » pas sur la page */
		padding-top: calc(var(--header-height) + var(--nav-gap-lg));
		scrollbar-width: none; /* Firefox : barre de défilement masquée (le scroll reste actif) */
	}
	/* Chrome/Safari : masque la barre de défilement du panneau galerie. */
	.post-type-archive-oeuvre .collection-main::-webkit-scrollbar {
		display: none;
	}
}

/* Page Collection : AUCUN pied de page. Le pied de page global (enfant direct de
   <body>, après #site-content) est masqué et aucun pied de page n'est rendu dans la
   galerie (cf. archive-oeuvre.php). */
body.post-type-archive-oeuvre > .site-footer {
	display: none;
}

/* ---------------------------------------------------------------------------
   Lightbox plein écran (pages œuvre & actualité)
--------------------------------------------------------------------------- */
.lightbox-open {
	overflow: hidden; /* fige le scroll de la page quand la lightbox est ouverte */
}

.lightbox {
	position: fixed;
	inset: 0;
	z-index: 2000;
	/* Fond au repos = TRANSPARENT ; l'état plein (.is-open, posé en JS) = VOILE SOMBRE
	   quasi opaque. On N'UTILISE PLUS backdrop-filter (flou) : sur iOS/Safari, un ancêtre
	   flouté fait « fuir » le rognage `overflow:hidden` d'un enfant TRANSFORMÉ — la piste
	   (.lightbox-track) laissait alors voir un bord de la diapo voisine (un quart de
	   l'image précédente) au repos, et le flou plein écran gelait le rendu à l'ouverture.
	   Un voile sombre plein (0.92) masque proprement la page, sans ces deux défauts. */
	background-color: transparent;
	transition: background-color 0.2s ease;
	user-select: none;     /* le glissement ne sélectionne pas */
	cursor: grab;          /* indique le swipe (comme le carrousel d'accueil) */
	/* Le geste HORIZONTAL appartient au JS (settle/swipe), comme pour le carrousel
	   d'accueil (.hero). Sans cela, iOS/Safari traite le glissement latéral comme un
	   défilement natif. */
	touch-action: pan-y;
	overscroll-behavior: contain;
}

.lightbox.is-open {
	background-color: rgba(0, 0, 0, 0.92);
}

.lightbox[hidden] {
	display: none;
}

/* Contrôles (croix, flèches, points) : fondent avec le fond (opacité pilotée par .is-open).
   À la fermeture, ils s'effacent → l'image rétrécit par-dessus la page, sans chrome ni noir. */
.lightbox-close,
.lightbox-nav,
.lightbox-dots {
	opacity: 0;
	transition: opacity 0.2s ease;
}
.lightbox.is-open .lightbox-close,
.lightbox.is-open .lightbox-nav,
.lightbox.is-open .lightbox-dots {
	opacity: 1;
}

/* Scène = fenêtre qui rogne ; piste = 3 slides (préc./courante/suiv.) qu'on
   translate horizontalement (suivi au drag + glissement à la flèche, en boucle). */
.lightbox-stage {
	position: absolute;
	inset: 0;
	overflow: hidden;
	z-index: 0;
	/* Ouverture/fermeture = FONDU de la scène (opacity, piloté par .is-open). La
	   NAVIGATION entre images (lightbox à plusieurs visuels) est en revanche un
	   GLISSEMENT horizontal de la piste — cf. settle() dans front-page.js — et non un
	   crossfade. */
	opacity: 0;
	transition: opacity 0.2s ease;
}

.lightbox.is-open .lightbox-stage {
	opacity: 1;
}

.lightbox-track {
	display: flex;
	width: 100%;
	height: 100%;
	will-change: transform;
	/* transform posé en JS : translateX(-100%) recentre la slide du milieu */
}

.lightbox-slide {
	flex: 0 0 100%;
	/* min-width:0 IMPÉRATIF : sans lui, le défaut flex `min-width:auto` laisse la diapo
	   s'ÉLARGIR jusqu'à la largeur de son image quand celle-ci dépasse la base flex (cas
	   des écrans étroits / images portrait). Les diapos devenaient alors plus larges que
	   le viewport → la piste (translateX(-100%)) ne tombait plus sur UNE diapo : l'image
	   courante glissait à droite et on voyait un bord des voisines. min-width:0 force la
	   diapo à EXACTEMENT 100 % du viewport ; l'image (max-width:90vw) y est centrée. */
	min-width: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.lightbox-img {
	max-width: 90vw;
	max-height: 85vh;
	width: auto;
	height: auto;
	object-fit: contain;
	border-radius: 0; /* plein écran : coins VIFS (surcharge l'arrondi global des <img>) */
	-webkit-user-drag: none; /* pas de drag natif de l'image pendant le swipe */
}

/* Croix, flèches et points : blancs, passent à l'accent jaune au survol. */
.lightbox-close,
.lightbox-nav,
.lightbox-dot {
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
	color: #fff;
	z-index: 2; /* au-dessus de la scène glissante */
	transition: color 0.2s ease, background-color 0.2s ease;
}

.lightbox-close:hover,
.lightbox-nav:hover,
.lightbox-close:focus-visible,
.lightbox-nav:focus-visible {
	color: var(--color-accent);
}

.lightbox-close {
	position: absolute;
	top: 1.25rem;
	right: 1.5rem;
}

.lightbox-close svg {
	display: block;
	width: 1.75rem;
	height: 1.75rem;
}

.lightbox-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	padding: 0 1rem;
}

/* Flèches du lightbox : même chevron FIN par bordures que le bouton Retour / Related
   Works (plus de SVG), sans cercle. Pivoté vers la gauche (préc.) / la droite (suiv.). */
.lightbox-chevron {
	display: block;
	width: 1.3rem;
	height: 1.3rem;
	border-left: var(--chevron-weight) solid currentColor;
	border-bottom: var(--chevron-weight) solid currentColor;
}

.lightbox-prev {
	left: 0.5rem;
}
.lightbox-prev .lightbox-chevron {
	transform: rotate(45deg); /* pointe à gauche */
}

.lightbox-next {
	right: 0.5rem;
}
.lightbox-next .lightbox-chevron {
	transform: rotate(-135deg); /* pointe à droite */
}

/* Points de position (style « homescreen iPhone »). */
.lightbox-dots {
	position: absolute;
	/* Centrés verticalement dans la bande vide SOUS l'image : celle-ci est centrée dans la
	   scène et haute d'au plus 85vh (cf. .lightbox-img), donc la marge basse réservée vaut
	   (100vh − 85vh)/2 = 7.5vh ; on pose les points au MILIEU de cette marge = 3.75vh du bas
	   (au lieu d'un décalage fixe, qui les collait trop bas). */
	bottom: calc((100vh - 85vh) / 4);
	left: 50%;
	transform: translateX(-50%);
	display: flex;
	gap: var(--dot-gap);
}

.lightbox-dot {
	width: var(--dot-size);
	height: var(--dot-size);
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.4);
}

.lightbox-dot:hover,
.lightbox-dot.is-active {
	background: var(--color-accent); /* position courante en jaune */
}

/* Une seule image : pas de flèches ni de points. */
.lightbox--solo .lightbox-nav,
.lightbox--solo .lightbox-dots {
	display: none;
}


.pagination {
	margin-top: 4rem;
	display: flex;
	justify-content: center;
	gap: 1rem;
	font-family: var(--font-ui);
}

.pagination a,
.pagination span {
	color: var(--color-text);
}

.pagination .current {
	color: var(--color-accent);
}

/* Single oeuvre — disposition type galerie (cf. galeriekugel.com) :
   rail méta étroit à gauche + zone images/description à droite. La marge gauche
   du rail = --page-padding (3vw), donc le contenu est aligné sur le header. */
.oeuvre-single {
	display: grid;
	grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
	gap: 5rem;
	/* stretch : la colonne de marge s'étire sur toute la hauteur des visuels → ses deux
	   blocs sticky (tête + corps) restent épinglés pendant tout le défilement, et le corps
	   ne se décolle (pour remonter sous la tête) qu'au bas de page. */
	align-items: stretch;
}

/* Lien « ‹ Retour » : au-dessus du titre, aligné sur la marge de la PAGE (bord
   gauche du contenu = padding latéral de .content-wrap, là où commence le titre).
   Même registre typographique que les méta du cartel (Type Deux, capitales espacées). */
.oeuvre-back {
	display: flex;          /* bloc à largeur de contenu */
	width: fit-content;
	align-items: center;
	gap: 0.45em;
	/* Dans la tête ÉPINGLÉE du rail (.oeuvre-rail-head) avec le titre : c'est la tête qui
	   est sticky, le bouton la suit. Ici, simple bloc au-dessus du titre. */
	margin-bottom: 0.6rem; /* écart sous le bouton, avant le titre */
	font-family: var(--font-ui);
	font-size: var(--fs-h4);     /* le chevron, en em, suit */
	letter-spacing: 0.14em;
	text-transform: uppercase;
	text-decoration: none;
	color: var(--color-text);
	transition: color 0.2s ease;
}

.oeuvre-back:hover,
.oeuvre-back:focus-visible {
	color: var(--color-accent);
}

/* Chevron dessiné en CSS (deux bordures d'un carré pivoté) → grand mais au trait
   FIN : la taille (width/height) et l'épaisseur (border-width) sont indépendantes. */
.oeuvre-back-chevron {
	display: inline-block;
	width: 0.72em;
	height: 0.72em;
	border-left: var(--chevron-weight) solid currentColor;
	border-bottom: var(--chevron-weight) solid currentColor;
	transform: rotate(45deg);
}

/* --- Rail méta (gauche) = cartel. Un SEUL bloc sticky (Retour + titre + cartel +
   provenance + bibliographie + Enquire) épinglé sous le header : tant que le bloc TIENT
   dans l'écran, il est immobile — RIEN n'en défile ni ne s'en détache séparément. Il ne se
   décolle qu'en toute fin de page, quand le bas de la colonne (bornée à la hauteur des
   visuels, cf. align-items:stretch sur .oeuvre-single) rattrape son propre bas. */
.oeuvre-rail {
	font-family: var(--font-ui);
	font-weight: 400; /* regular : pas de gras dans la marge */
}

.oeuvre-rail-head {
	position: sticky;
	top: calc(var(--header-height) + 1.5rem);
	z-index: 2;
}

/* Aucun gras dans la marge, y compris l'emphase en ligne (<strong>/<b>). */
.oeuvre-rail strong,
.oeuvre-rail b {
	font-weight: 400;
}

/* Titre (désignation) = 1er bloc (un h2), en tête de la marge. Ciblé sur le h2 UNIQUEMENT
   (les spécifications du cartel sont des h3/h4, cf. règle suivante) → pas de débordement. */
/* Descendant (pas « > ») : le contenu de la tête est encapsulé en JS dans
   .oeuvre-rail-head-inner (amorti d'épinglage) → le titre n'est plus enfant DIRECT. */
.oeuvre-rail-head h2:first-of-type {
	font-family: var(--font-display); /* titre = Garamond (le reste du cartel est en Type Deux) */
	font-size: var(--fs-title-fluid);
	font-weight: 400; /* titre non gras */
	line-height: 1.15;
	margin: 0 0 1rem; /* écart avant le cartel, aéré */
}

/* blocs suivants du rail (spécifications, etc.) */
.oeuvre-rail h3,
.oeuvre-rail h4 {
	font-family: var(--font-ui);
	font-size: var(--fs-h5);
	font-weight: 400;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	opacity: 0.55;
	margin: 0 0 1.35rem; /* même rythme uniforme, aéré, que le reste de la marge */
}

/* Cartel, provenance, bibliographie : EB Garamond GRISÉ (romain) — couleur reprise du
   sous-texte « Exhibitions & notable sales… » de la page Contact (.glc-news-sub). La
   désignation (titre, ci-dessus) reste en Garamond non grisé → contraste net entre le
   titre et les métadonnées. Écart entre blocs conservé (1.35rem, rythme du rail). */
.oeuvre-rail p {
	font-family: var(--font-display);
	font-size: var(--nav-size);
	font-weight: 400;
	letter-spacing: 0;
	line-height: 1.5;
	color: rgba(255, 255, 255, 0.5);
	margin: 0 0 1.35rem;
}

.oeuvre-rail p:last-child {
	margin-bottom: 0;
}

/* En-têtes PROVENANCE / BIBLIOGRAPHIE (injectés par single-oeuvre.php quand le champ
   est rempli) : EB Garamond (var(--font-display)), capitales espacées. Couleur héritée
   comme le reste de la fiche. Même espacement (1rem) que le reste de la marge : rythme
   vertical uniforme entre désignation, cartel, provenance, bibliographie.
   Sélecteur ANCRÉ dans .oeuvre-rail pour battre « .oeuvre-rail p » en spécificité
   (sinon le sous-titre, qui est un <p>, hériterait du Type Deux Regular du corps). */
.oeuvre-rail .oeuvre-subtitle {
	margin: 0 0 1.35rem; /* rythme du rail, aéré */
	font-family: var(--font-display);
	font-size: var(--fs-h4);
	font-weight: 400;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	/* Les en-têtes PROVENANCE/BIBLIOGRAPHIE restent en PLEINE COULEUR (labels) : ils ne
	   suivent pas le gris du cartel (.oeuvre-rail p, dont ils héritent la couleur). */
	color: var(--color-text);
}

/* Bouton générique du site. UN SEUL point de vérité pour l'apparence des boutons :
   tout élément .gl-button (lien « Enquire », indicateur « On Hold », et boutons à venir)
   partage ce style → restyler ici les change tous. Sobre, assorti aux méta du cartel
   (Type Deux, capitales espacées) ; coins arrondis identiques aux images. */
.gl-button {
	display: inline-flex;          /* centrage vertical fiable du texte (capitales sans */
	align-items: center;           /* jambage → l'interligne fausserait le centrage en  */
	justify-content: center;       /* display:block) */
	line-height: 1;
	/* CORRECTION VERTICALE (2026-09, signalée sur iPhone — pas un souci de moteur/
	   navigateur : la police « Type Deux » a un ascendant/descendant asymétrique autour
	   de la hauteur de capitale, tables DE LA POLICE donc identiques sur tout appareil
	   qui la rend ; ET align-items:center ne répartit pas non plus l'espace négatif
	   (line-height:1 plus petit que les métriques naturelles de la police) de façon
	   symétrique. Somme des deux effets, étalonnée EMPIRIQUEMENT sur ce bouton précis
	   (mesure Canvas TextMetrics + Range, plusieurs valeurs testées jusqu'à annuler
	   l'écart haut/bas réel — pas déduite en théorie, qui sous-estimait l'écart de
	   presque moitié) : ≈ 0.0725em pour un libellé sans descendante ni accent (« ON
	   HOLD », « DEMANDE D'INFORMATION ») — l'ENCRE flotte trop HAUT dans le bouton, plus
	   de vide dessous que dessus, invisible dans le rect. de MISE EN PAGE (line-height)
	   mais bien réel à l'oeil. On corrige en augmentant le padding HAUT et réduisant le
	   BAS du même montant (somme inchangée → le bouton garde sa hauteur). Un libellé
	   accentué (« RÉSERVÉ ») ou à descendante (« ENQUIRE », le Q) a un écart réel
	   différent : ce chiffre est un compromis pour l'ensemble des libellés, pas un
	   centrage parfait de CHACUN. Le bouton On Hold/Sold (.oeuvre-enquire-swap) a une
	   boîte intermédiaire en plus (le <span> qui anime la largeur) qui change encore
	   cette répartition — dérive un écart PLUS GRAND, corrigé séparément plus bas
	   (.oeuvre-enquire.is-on-hold/.is-sold), ne pas fusionner les deux valeurs. */
	padding-top: calc(0.75rem + 0.0725em);
	padding-bottom: calc(0.75rem - 0.0725em);
	/* Le suivi de lettres (letter-spacing, ci-dessous) ajoute un espace APRÈS CHAQUE
	   caractère, y compris le DERNIER (vérifié par mesure : glyphes + suivi = lettres ×
	   suivi, pas (lettres-1) × suivi) — ce fantôme invisible en fin de texte n'a pas
	   d'équivalent en début de texte. Conséquence : même avec un padding symétrique,
	   l'ENCRE du libellé (« ENQUIRE », « ON HOLD »…) paraît décalée à gauche du vrai
	   centre du bouton — ce même calcul s'applique aussi au bouton On Hold/Sold
	   (.oeuvre-enquire-swap, ci-dessous : sa largeur JS mesurée via Range inclut le même
	   fantôme, donc la même correction le recentre). On corrige en retirant la moitié du
	   suivi au padding droit et en l'ajoutant au gauche — recentre l'encre sans toucher
	   au texte ni à la largeur du contour animé. */
	padding-inline-start: calc(1.5rem + 0.07em);
	padding-inline-end: calc(1.5rem - 0.07em);
	font-family: var(--font-ui);
	font-size: var(--fs-h5);
	font-weight: 400; /* pas de gras dans la marge */
	letter-spacing: 0.14em;
	text-transform: uppercase;
	text-decoration: none;
	color: var(--color-text);
	border: 1px solid currentColor;
	border-radius: var(--img-radius); /* mêmes coins arrondis que les images du site */
	transition: color 0.25s ease, border-color 0.25s ease;
}

/* Rangée de boutons d'action, dans la tête épinglée (« Enquire » + éventuel « On Hold »). */
.oeuvre-actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 0.75rem;
	margin-top: 2rem;
}

/* « Enquire » : seul bouton interactif → passe à l'accent + lueur au survol (cf. accent-glow). */
.oeuvre-enquire:hover,
.oeuvre-enquire:focus-visible {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

/* Variante « Réservé / On Hold » et « Vendu / Sold » du bouton Enquire (.is-on-hold /
   .is-sold). AU REPOS il affiche « On Hold » ou « Sold » en couleur normale ; AU SURVOL/FOCUS
   il révèle « Enquire » + l'accent et la lueur (cf. .oeuvre-enquire:hover, accent-glow) et
   reste cliquable (mailto) → on peut faire une demande même sur une œuvre réservée ou vendue.
   Le bouton ANIME sa largeur d'un libellé à l'autre : « On Hold » reste dans le flux (il
   donne la hauteur du bouton), « Enquire » est superposé en absolu et CENTRÉ ; le libellé
   caché est en opacity:0 donc invisible même s'il dépasse → aucun rognage nécessaire. Les
   largeurs sont mesurées en px par le JS (--w-rest / --w-hover ; cf. initOnHoldButtons),
   une largeur auto ne se transitionnant pas. */
/* Correction verticale du bouton On Hold/Sold — voir le commentaire sur .gl-button.
   La boîte .oeuvre-enquire-swap ci-dessous (un <span> BLOCK intermédiaire pour animer la
   largeur) change encore la façon dont le navigateur répartit l'espace au-dessus/en
   dessous du texte : étalonnée EMPIRIQUEMENT sur CE bouton précis (même méthode que
   .gl-button), l'écart réel est PLUS GRAND ici (≈ 0.0955em, pas 0.0725em) — d'où cette
   surcharge dédiée plutôt que de partager la valeur de .gl-button. */
.oeuvre-enquire.is-on-hold,
.oeuvre-enquire.is-sold {
	padding-top: calc(0.75rem + 0.0955em);
	padding-bottom: calc(0.75rem - 0.0955em);
}

.oeuvre-enquire .oeuvre-enquire-swap {
	position: relative;
	display: inline-block;
	width: var( --w-rest, max-content );
	text-align: center;
	white-space: nowrap;
	/* Rognage HORIZONTAL uniquement (le texte « Enquire » est dévoilé par le contour qui
	   s'ouvre) ; vertical NON rogné → les accents (É de RÉSERVÉ) ne sont jamais coupés. */
	clip-path: inset( -100% 0px );
	transition: width 0.28s ease; /* contour rapide */
}

.oeuvre-enquire .oeuvre-enquire-rest,
.oeuvre-enquire .oeuvre-enquire-hover {
	/* Opacité rapide (< durée du contour) : le texte est déjà visible pendant que le
	   contour finit de s'ouvrir → il apparaît DEPUIS L'EXTÉRIEUR, pas après coup. */
	transition: opacity 0.18s ease;
}

.oeuvre-enquire .oeuvre-enquire-hover {
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	transform: translateY( -50% );
}

.oeuvre-enquire.is-on-hold:hover .oeuvre-enquire-swap,
.oeuvre-enquire.is-on-hold:focus-visible .oeuvre-enquire-swap,
.oeuvre-enquire.is-sold:hover .oeuvre-enquire-swap,
.oeuvre-enquire.is-sold:focus-visible .oeuvre-enquire-swap {
	width: var( --w-hover, max-content );
}

.oeuvre-enquire.is-on-hold .oeuvre-enquire-hover,
.oeuvre-enquire.is-sold .oeuvre-enquire-hover {
	opacity: 0; /* « Enquire » masqué au repos */
}

.oeuvre-enquire.is-on-hold:hover .oeuvre-enquire-rest,
.oeuvre-enquire.is-on-hold:focus-visible .oeuvre-enquire-rest,
.oeuvre-enquire.is-sold:hover .oeuvre-enquire-rest,
.oeuvre-enquire.is-sold:focus-visible .oeuvre-enquire-rest {
	opacity: 0; /* « On Hold » / « Sold » s'efface au survol… */
}

.oeuvre-enquire.is-on-hold:hover .oeuvre-enquire-hover,
.oeuvre-enquire.is-on-hold:focus-visible .oeuvre-enquire-hover,
.oeuvre-enquire.is-sold:hover .oeuvre-enquire-hover,
.oeuvre-enquire.is-sold:focus-visible .oeuvre-enquire-hover {
	opacity: 1; /* …et « Enquire » apparaît */
}

/* --- Colonne de droite : contenu rendu TEL QU'ÉDITÉ dans Gutenberg ---
   (description + images/galeries placées dans l'éditeur). Flux normal : les
   espacements sont gérés par les blocs eux-mêmes. */
.oeuvre-gallery {
	min-width: 0; /* évite le débordement d'images larges dans la colonne 1fr */
}

/* Visuels Gutenberg : ratio préservé, jamais étirés (largeur via le global img). */
.oeuvre-gallery img {
	height: auto;
}

/* Filet de sécurité — GROUPE « Grille » AUTOUR de la bande d'images (artefact d'import/
   copier-coller dans Gutenberg : les images de tête se retrouvent parfois entourées d'un
   bloc Groupe réglé en disposition GRILLE). Sans cette règle, ce groupe se comporte comme
   une grille à plusieurs colonnes et n'accorde à la bande (.gl-strip/.gl-hscroll, posée par
   le JS) que la largeur d'UNE seule colonne (~1/5e de la page) au lieu de la pleine largeur
   du corps — la « carrousel » apparaît alors minuscule. On neutralise la grille : ce groupe
   ne sert jamais volontairement de mise en page à colonnes dans une fiche œuvre. */
.oeuvre-gallery .wp-block-group.is-layout-grid {
	display: block;
}

/* Image ILLUSTRATIVE légendée dans le corps (photo de comparaison, détail, contexte) :
   dès qu'un visuel AUTONOME porte une LÉGENDE (figcaption), il n'est plus l'œuvre en
   pleine largeur mais une illustration → CENTRÉ et réduit à 65 % de la largeur du
   corps (colonne galerie = largeur de page moins marges moins cartel). Ciblage en ENFANT
   DIRECT : les images groupées en bande (.gl-hscroll) ou rassemblées en tête sur mobile
   ne sont plus enfants directs → non concernées ; seul le visuel resté dans le flux l'est. */
.oeuvre-gallery > figure.wp-block-image:has( figcaption ) {
	width: 65%;
	margin-left: auto;
	margin-right: auto;
}
/* Respiration AU-DESSUS et EN DESSOUS d'un visuel légendé (image isolée ou bande d'images
   légendées) : marges HAUT et BAS ÉGALES, plus généreuses que l'interligne de paragraphe
   (~20 px, trop serré autour d'une image). Elles fusionnent avec les marges des paragraphes
   voisins (la plus grande l'emporte), donc jamais de cumul. */
.oeuvre-gallery > figure.wp-block-image:has( figcaption ),
.oeuvre-gallery > .gl-strip--captioned {
	--gl-cap-gap: 2.75rem;
	margin-top: var(--gl-cap-gap);
	margin-bottom: var(--gl-cap-gap);
}
/* Une source plus petite que la figure (ex. vignette 219 px issue de l ancien site) reste à sa
   taille naturelle : sans ceci elle colle au bord gauche de la figure, décentrée. */
.oeuvre-gallery > figure.wp-block-image:has( figcaption ) img {
	margin-left: auto;
	margin-right: auto;
}

/* Légende d'une image PRISE DANS UNE GALERIE (wp:gallery, "has-nested-images") : le CORE de
   WordPress la pose en incrustation SUR la photo (fond dégradé/flou, texte blanc,
   position:absolute — cf. wp-includes/blocks/gallery/style.css). Un visuel AUTONOME, lui,
   affiche sa légende DESSOUS, en flux normal (règle ci-dessus + le style global des légendes
   plus haut dans ce fichier) — deux images légendées différemment selon qu'elles sont ou non
   dans une galerie, ALORS QUE Gutenberg permet d'ajouter une légende dans les deux cas, sans
   prévenir que le rendu diffère. On neutralise donc ici l'incrustation du cœur pour que TOUTE
   légende, groupée en galerie ou non, s'affiche pareil : dessous, jamais sur la photo. Les
   images de bande (.gl-hscroll) sont EXCLUES : leur légende est déjà extraite par le JS
   (consolidateStripCaption, cf. front-page.js) et rendue dans une figure à part, sans
   incrustation à neutraliser — mais rien n'empêche de garder la règle générale pour le cas
   où une bande resterait, exceptionnellement, sans être transformée (JS désactivé). */
.oeuvre-gallery .wp-block-gallery.has-nested-images figure.wp-block-image:has( figcaption )::before {
	content: none !important;
}
/* Même plafond de largeur (65%, cf. règle plus haut) pour une image légendée SEULE dans sa
   galerie : sans lui, une galerie réduite à cette unique image (`flex-grow:1` du cœur, rien
   pour la contenir face à un unique élément dans la rangée) l'étire sur toute la largeur du
   corps dès que sa légende cesse d'être une incrustation — la légende INVITE À restreindre,
   comme pour un visuel autonome. Ciblage :only-child DÉLIBÉRÉ : dans une galerie à 2+ images,
   chacune tient déjà ≤ 50% de la rangée nativement (cf. largeur calc(50%…) du cœur) — y
   forcer width + margin:auto casserait l'alignement CÔTE À CÔTE (l'image légendée se
   centrerait dans l'espace libre au lieu de rester alignée avec ses voisines, renvoyant
   celles-ci à la ligne suivante). */
.oeuvre-gallery .wp-block-gallery.has-nested-images figure.wp-block-image:only-child:has( figcaption ) {
	flex-grow: 0 !important;
	width: 65% !important;
	margin-left: auto !important;
	margin-right: auto !important;
}
.oeuvre-gallery .wp-block-gallery.has-nested-images figure.wp-block-image figcaption {
	position: static !important;
	background: none !important;
	text-shadow: none !important;
	padding: 0 !important;
}

/* ---------------------------------------------------------------------------
   BANDE HORIZONTALE d'images (> 2 images côte à côte OU qui se suivent).
   Au lieu de les entasser / empiler, on les met en FILMSTRIP à HAUTEUR COMMUNE
   qu'on fait défiler horizontalement pour toutes les voir — en MOBILE ET DESKTOP.
   La classe .gl-hscroll est posée par le JS (front-page.js → initImageStrips) sur les
   galeries de +2 images ET sur les suites de +2 images autonomes qui se suivent.
   La barre ne défile QUE si les images débordent (overflow-x:auto) : ≤2 non concernées.
--------------------------------------------------------------------------- */
.gl-hscroll {
	--gl-strip-gap: clamp(0.6rem, 1.5vw, 1.1rem);
	display: flex !important;
	flex-wrap: nowrap !important;
	align-items: flex-start;
	gap: var(--gl-strip-gap);
	overflow-x: auto;
	overscroll-behavior-x: contain;
	-webkit-overflow-scrolling: touch;
	scroll-snap-type: x proximity;
	scrollbar-width: none; /* Firefox : barre masquée (les .gl-strip-dots servent d'indicateur) */
	max-width: 100%; /* défile DANS son conteneur : la page ne défile jamais en X */
	/* Coins arrondis du CONTENEUR : le rognage suit l'arrondi → les bords des images
	   restent ARRONDIS même pendant le rebond (surtout la 1re image la plus à gauche, qui
	   glisse sous le masque arrondi au lieu d'être coupée droit). */
	border-radius: var(--img-radius);
}

/* Chrome / Safari : masque la barre de défilement native (le défilement reste
   possible à la molette, au glisser et au tactile ; repère visuel = .gl-strip-dots). */
.gl-hscroll::-webkit-scrollbar {
	display: none;
}

/* Galeries À L'INTÉRIEUR d'une bande : rendues TRANSPARENTES (display:contents) pour que
   LEURS images deviennent directement des éléments du filmstrip — ainsi une suite de
   galeries (ex. deux galeries de 2 côte à côte) forme UNE SEULE bande continue. */
.gl-hscroll .wp-block-gallery {
	display: contents !important;
}

/* Descendant (et non enfant direct) : couvre à la fois les images autonomes enveloppées
   ET les images issues de galeries rendues transparentes ci-dessus. */
.gl-hscroll figure.wp-block-image {
	flex: 0 0 auto !important;
	margin: 0 !important;
	max-width: none !important;
	scroll-snap-align: center;
	/* Défaut (mobile) : hauteur commune, largeur au ratio. */
	width: auto !important;
	height: clamp(15rem, 42vh, 26rem);
}

.gl-hscroll figure.wp-block-image > a,
.gl-hscroll figure.wp-block-image > div {
	display: block;
	height: 100%;
}

.gl-hscroll figure.wp-block-image img {
	height: 100% !important;
	width: auto !important;
	max-width: none !important;
	object-fit: contain !important; /* ratio préservé, pas de recadrage */
}

/* DESKTOP : DEUX images REMPLISSENT la largeur du corps (colonne galerie = page moins le
   cartel) — MÊME taille qu'il y en ait 2 ou plus (chaque image = la moitié, moins la
   gouttière). Au-delà de 2, la bande DÉFILE ; la barre de points (.gl-strip-dots) sous
   elle indique combien d'images il y a et laquelle est vue. Comme le reste de la fiche
   œuvre (cf. .oeuvre-single plus bas), ce mode DESKTOP s'étend aussi à la TABLETTE EN
   PAYSAGE (1024–1280px, orientation:landscape) : seule la barre de navigation y reste
   mobile (bouton « Menu »), le contenu se comporte comme sur bureau. */
@media (min-width: 1281px), (min-width: 1024px) and (max-width: 1280px) and (orientation: landscape) {
	.gl-hscroll figure.wp-block-image {
		width: calc((100% - var(--gl-strip-gap)) / 2) !important;
		height: auto;
		scroll-snap-align: start;
	}
	.gl-hscroll figure.wp-block-image > a,
	.gl-hscroll figure.wp-block-image > div {
		height: auto;
	}
	.gl-hscroll figure.wp-block-image img {
		width: 100% !important;
		height: auto !important;
	}

	/* Bande MIXTE (paysage + portrait) : classes posées en JS (front-page.js →
	   markOeuvreMixedOrientation), même principe que le carrousel des actualités (cf.
	   galerie_lamy_core_actualite_carrousel_html) — un paysage NE PARTAGE JAMAIS sa diapo
	   avec un portrait : seul (.oeuvre-mix-solo) ou resté impair (.oeuvre-mix-portrait), il
	   occupe TOUTE la largeur de la bande, comme une diapo du carrousel des actualités. Les
	   portraits appariés (.oeuvre-mix-pair-a/-b) se PARTAGENT cette même pleine largeur À
	   DEUX (donc la moitié chacun — la règle générale ci-dessus leur suffit déjà), recadrés
	   (cover) à la hauteur commune du paysage : leur hauteur ne peut donc jamais la dépasser.
	   Seul un portrait resté SEUL (nombre impair) n'est pas recadré (contain, letterbox).
	   scroll-snap-align retiré du second portrait de la paire : la paire s'aborde comme UNE
	   diapo, pas deux arrêts de défilement distincts. N'agit que si la bande mélange
	   RÉELLEMENT les deux orientations (.gl-hscroll--mixed) ; sinon la règle générale
	   ci-dessus s'applique inchangée. */
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image {
		aspect-ratio: 3 / 2;
		height: auto !important;
	}
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image > a,
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image > div {
		height: 100% !important;
	}
	/* Spécificité ÉGALE à la règle .gl-hscroll--mixed.gl-hscroll figure.wp-block-image
	   ci-dessus (même chaîne de sélecteurs) : sans ça, la règle générale (largeur : moitié
	   de la bande) l'emporterait sur celle-ci en cas d'égalité de poids !important, l'ordre
	   de sortie CSS ne suffisant pas à garantir la priorité voulue. */
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-solo,
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-portrait {
		width: 100% !important;
	}
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-pair-a,
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-pair-b {
		aspect-ratio: 3 / 4 !important;
	}
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-pair-b {
		scroll-snap-align: none !important;
	}
	/* Même chaîne de sélecteurs que .gl-hscroll figure.wp-block-image img (largeur/hauteur
	   ci-dessus, hors mode mixte) pour battre à coup sûr son height:auto !important —
	   ici l'image doit couvrir TOUTE la hauteur commune de la diapo (cf. plus haut). */
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-solo img,
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-pair-a img,
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-pair-b img {
		width: 100% !important;
		height: 100% !important;
		object-fit: cover !important;
	}
	.gl-hscroll--mixed .oeuvre-mix-portrait {
		background: rgba(0, 0, 0, 0.18);
	}
	.gl-hscroll--mixed.gl-hscroll figure.wp-block-image.oeuvre-mix-portrait img {
		width: auto !important;
		height: 100% !important;
		object-fit: contain !important;
	}

	/* Fiche œuvre (desktop/tablette paysage) : à partir de 3 images, la bande DÉFILE et
	   reçoit des flèches prev/next — MÊME apparence que le carrousel des actualités
	   (classes .actualite-carousel-nav réutilisées telles quelles, posées par le JS,
	   cf. front-page.js → wrapImageRuns/buildStripDots). Grille [flèche][bande][flèche],
	   MÊME principe que .actualite-carousel : les flèches vivent HORS des images, dans des
	   gouttières dédiées, qui ne mordent donc jamais sur les photos. Sous 3 images (1 ou 2)
	   aucune flèche n'est posée par le JS (donc pas de bande du tout) → cette grille reste
	   inerte sur ces fiches-là ; les GOUTTIÈRES, elles, restent réservées quand même (cf.
	   inset inconditionnel sur .oeuvre-gallery plus bas) pour que toutes les fiches œuvre
	   partagent la même largeur de corps, avec ou sans flèches. :not(.gl-oeuvre-strip)
	   exclut la bande MOBILE (même classe de base .gl-strip, jamais de flèches) — filet de
	   sécurité en plus de l'exclusivité des modes bureau/mobile (cf. initOeuvreLayout). */
	.oeuvre-gallery > .gl-strip:not( .gl-oeuvre-strip ) {
		display: grid;
		grid-template-columns: auto minmax(0, 1fr) auto;
		column-gap: var(--oeuvre-nav-gap);
		align-items: start;
	}
	.oeuvre-gallery > .gl-strip:not( .gl-oeuvre-strip ) > .gl-hscroll {
		grid-column: 2;
		grid-row: 1;
	}
	.oeuvre-gallery > .gl-strip:not( .gl-oeuvre-strip ) > .gl-strip-dots {
		grid-column: 1 / -1;
		grid-row: 2;
	}
	/* Centrées sur la hauteur de la bande plutôt qu'en haut de grille (align-items:start
	   ci-dessus, nécessaire par ailleurs pour ne pas étirer les flèches sur toute une
	   bande à hauteur variable). */
	.oeuvre-gallery > .gl-strip:not( .gl-oeuvre-strip ) > .actualite-carousel-nav {
		align-self: center;
	}

	/* INSET INCONDITIONNEL, sur TOUTE fiche œuvre (desktop) : la largeur du corps (images
	   ET texte — description, Provenance/Bibliographie éventuelles, Œuvres en rapport…)
	   est TOUJOURS celle réservée aux flèches, que la fiche compte 1, 2 ou 3+ images —
	   sinon des fiches voisines afficheraient des largeurs de corps différentes selon leur
	   nombre d'images, incohérent en feuilletant la Collection. À 3+ images, les flèches
	   sont RÉELLEMENT posées (cf. grille ci-dessus) ; à 1 ou 2, il n'y a pas de bande du
	   tout (JS, wrapImageRuns : bande seulement si total > 2) donc pas de flèches non
	   plus — MAIS l'inset reste (aucune bande à annuler), et l'image (ou les 2 images
	   côte à côte, cf. .gl-hscroll figure.wp-block-image plus haut) comme le texte suivent
	   alors simplement la largeur, déjà réduite, de .oeuvre-gallery : même largeur de corps
	   partout, flèches visibles seulement quand il y a réellement de quoi naviguer.
	   Implémentation : un padding sur .oeuvre-gallery lui-même (donc sur TOUT son contenu,
	   y compris les règles existantes en % de sa largeur, ex. figure légendée à 50 % plus
	   haut — qui restent correctement proportionnées à la largeur RÉDUITE) que SEULE la
	   bande à flèches annule par une marge négative égale, pour retrouver les bords réels
	   du corps (mêmes bords que les flèches, cf. grille ci-dessus) — une fiche à 1 ou 2
	   images n'a pas de bande, donc rien à annuler : l'inset s'applique directement à
	   l'image/aux images, qui suivent le flux normal de .oeuvre-gallery. --oeuvre-nav-gap
	   = gouttière entre flèche et image (colonne « auto » plus haut) ; --oeuvre-nav-w =
	   largeur de la flèche elle-même (cf. .actualite-carousel-nav) : l'inset total est
	   leur somme. */
	.oeuvre-gallery {
		padding-left: calc(var(--oeuvre-nav-w) + var(--oeuvre-nav-gap));
		padding-right: calc(var(--oeuvre-nav-w) + var(--oeuvre-nav-gap));
	}
	.oeuvre-gallery > .gl-strip:not( .gl-oeuvre-strip ) {
		margin-left: calc(-1 * (var(--oeuvre-nav-w) + var(--oeuvre-nav-gap)));
		margin-right: calc(-1 * (var(--oeuvre-nav-w) + var(--oeuvre-nav-gap)));
	}
}

/* MOBILE — bande d'images d'une FICHE ŒUVRE (.gl-oeuvre-strip) : chaque image occupe
   TOUTE la largeur du conteneur (une « diapo » par image, on glisse entre elles) et tient
   à l'écran quelle que soit son orientation. Un PAYSAGE n'est plus mis à hauteur fixe (ce
   qui le rendait plus large que l'écran → débordement, effet « rogné ») mais ajusté à la
   LARGEUR, hauteur libre ; un PORTRAIT tient aussi, plafonné en hauteur. object-fit:contain
   → jamais recadré. Une seule image = simplement pleine largeur, sans défilement.
   EXCEPTION tablette en paysage (1024–1280px) : exclue de ce mode mobile, cf. règle
   groupée ci-dessus (elle y reçoit le mode DESKTOP « deux images côte à côte »). */
@media (max-width: 1280px) and (not ((min-width: 1024px) and (orientation: landscape))) {
	.gl-oeuvre-strip .gl-hscroll {
		scroll-snap-type: x mandatory;
		align-items: center; /* image plus courte que la bande → centrée verticalement */
	}
	.gl-oeuvre-strip .gl-hscroll figure.wp-block-image {
		flex: 0 0 100% !important;
		width: 100% !important;
		/* Hauteur COMMUNE à toutes les diapos = celle de la 1re image (paysage à la une)
		   ajustée à la largeur, mesurée en JS (initOeuvreLayout → --gl-oeuvre-h). Repli
		   auto avant mesure. Garde-fou 90vh si l'image de tête est très haute. */
		height: var(--gl-oeuvre-h, auto) !important;
		max-height: 90vh;
		scroll-snap-align: start;
	}
	.gl-oeuvre-strip .gl-hscroll figure.wp-block-image > a,
	.gl-oeuvre-strip .gl-hscroll figure.wp-block-image > div {
		display: block;
		height: 100%;
	}
	.gl-oeuvre-strip .gl-hscroll figure.wp-block-image img {
		width: 100% !important;
		height: 100% !important;
		object-fit: contain !important; /* tient dans la hauteur commune, jamais recadré */
	}
}

/* ---------------------------------------------------------------------------
   BANDE LÉGENDÉE (fiche œuvre, desktop ET mobile) : dès qu'une image de la bande porte une
   légende, le JS pose .gl-hscroll--captioned (front-page.js → markCaptionedStrip). Images
   PAR DEUX (desktop ; une par une en mobile) à hauteur ÉGALISÉE DANS CHAQUE PAIRE, jamais
   recadrées : le JS (sizeCaptionedStrip) donne à chaque figure sa largeur = ratio × hauteur
   de sa paire, centre une paire qui ne remplit pas la largeur, et pose l'alignement de
   défilement (1re image de chaque paire). Ici : l'image suit la largeur de
   sa figure, hauteur libre (donc = la hauteur commune), et SA légende reste dessous,
   défilant avec elle. Spécificité (0,4,1) + !important : bat les règles desktop, mobile
   (.gl-oeuvre-strip) et mixtes (non posées sur une bande légendée).
--------------------------------------------------------------------------- */
.gl-hscroll.gl-hscroll--captioned {
	align-items: flex-start !important;
}
.gl-hscroll.gl-hscroll--captioned figure.wp-block-image {
	flex: 0 0 auto !important;
	height: auto !important;
	max-height: none !important;
	aspect-ratio: auto !important;
	background: none !important;
}
/* Points d'une bande légendée : plus près de la légende que dans une bande nue (0.9rem) —
   l'écart légende → points doit rester du même ordre que celui image → légende (~13 px),
   pas le double. Les marges haut/bas de la bande (--gl-cap-gap, plus haut) restent
   inchangées. */
.gl-strip--captioned > .gl-strip-dots {
	margin-top: 0.25rem;
}
.gl-hscroll.gl-hscroll--captioned figure.wp-block-image > a,
.gl-hscroll.gl-hscroll--captioned figure.wp-block-image > div {
	height: auto !important;
}
.gl-hscroll.gl-hscroll--captioned figure.wp-block-image img {
	width: 100% !important;
	height: auto !important;
	object-fit: contain !important;
}

/* ---------------------------------------------------------------------------
   POINTS de la bande horizontale (.gl-strip-dots) : posés par le JS sous le
   filmstrip quand il compte plus de 2 images. Un point par image, celui de
   l'image la plus centrée est actif (jaune) ; cliquer un point y fait défiler
   la bande. Même langage visuel que les points de la lightbox.
--------------------------------------------------------------------------- */
.gl-strip-dots {
	display: flex;
	justify-content: center;
	gap: var(--dot-gap);
	margin-top: 0.9rem;
}

.gl-strip-dot {
	position: relative;
	width: var(--dot-size);
	height: var(--dot-size);
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.4);
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.gl-strip-dot:hover,
.gl-strip-dot.is-active {
	background: var(--color-accent); /* image montrée en jaune */
}

/* Deux images montrées CÔTE À CÔTE : le point de gauche (.is-linked) étire une PILULE
   pleine qui COUVRE les deux points (du bord gauche du 1er au bord droit du 2e) → ils se
   RELIENT en un seul stade lisse. Au repos elle est réduite (scaleX 0). Principe et
   géométrie identiques au carrousel des actualités (.acd-dot.is-pair-start).

   FORMATION RETARDÉE : le JS bascule .is-linked dès que deux images se chevauchent à
   l'écran — ce qui arrive fugacement quand on FAIT DÉFILER VITE la bande. Un délai avant
   l'expansion (transition-delay sur .is-linked) fait que la pilule ne se forme QUE si les
   deux images restent montrées au-delà du délai (l'utilisateur s'est posé) : lors d'un
   défilement rapide, .is-linked s'active puis se désactive AVANT la fin du délai, donc
   l'expansion ne démarre jamais et aucune pilule ne clignote. La rétraction, elle, reste
   immédiate (transition du ::after de base) pour disparaître dès qu'on repart. */
.gl-strip-dot::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	height: var(--dot-size);
	width: calc(var(--dot-size) * 2 + var(--dot-gap)); /* couvre les deux points */
	background: var(--color-accent);
	border-radius: 999px;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.25s ease; /* rétraction : rapide, sans délai */
	pointer-events: none;
}

.gl-strip-dot.is-linked::after {
	transform: scaleX(1);
	transition: transform 0.35s ease 0.45s; /* formation : plus lente + retardée de 0.45 s */
}

/* Sous-titre « Bibliographie / Literature » en fin de corps (posé par single-oeuvre.php
   quand le paragraphe .oeuvre-literature est rempli). Même registre « label de section »
   que « Related works » (.we-title) et « About » (.about-subtitle) : capitales espacées,
   Type Deux, discret — un cran AU-DESSUS du corps de la fiche (le paragraphe qui suit hérite
   du style de la description). Marge haute pour détacher la section des visuels. */
.oeuvre-literature-title {
	margin: 3.5rem 0 1rem;
	font-family: var(--font-ui);
	font-size: var(--fs-h4); /* section « Literature » : un cran plus grand (H5 → H4) */
	font-weight: 400;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	opacity: 0.6;
}

/* Fiche d'une actualité : pleine largeur dans .content-wrap → marges latérales
   = --page-padding, identiques au reste du site (œuvres, archives, pages). Le texte
   reste lisible grâce au max-width de .actualite-single-content. Les méta
   (.actualite-soustitre/.actualite-dates/.actualite-lieu) sont partagées avec les
   cartes (cf. front-page.css). */
.actualite-single {
	margin: 0;
}

/* Bouton retour en haut de fiche News (style .oeuvre-back partagé) : dégagement
   avant l'en-tête. */
.actualite-back {
	margin-bottom: 1.75rem;
}

/* En-tête deux colonnes : titre + détails À GAUCHE, carrousel À DROITE ;
   puis le texte et les œuvres exposées en pleine largeur en dessous. */
.actualite-single-top {
	display: grid;
	grid-template-columns: minmax(200px, 2fr) minmax(0, 3.6fr);
	gap: 3rem;
	align-items: start;
	margin-bottom: 1.5rem;
}

/* Sans image : le titre reprend toute la largeur. */
.actualite-single-top.no-media {
	grid-template-columns: 1fr;
}

.actualite-single-header {
	text-align: left;
	margin: 0;
}

.actualite-single-title {
	font-size: var(--fs-d3); /* titre de fiche News réduit d'un cran (D2 → D3) */
	margin-bottom: 0.5rem;
}

.actualite-single-header .actualite-soustitre,
.actualite-single-header .actualite-dates,
.actualite-single-header .actualite-lieu {
	margin: 0.15rem 0;
}

/* Sous 900px : on empile (détails au-dessus, carrousel en dessous). Au-dessus, la
   colonne de texte (3.6fr) borne déjà la longueur de ligne → lecture confortable. */
@media (max-width: 900px) {
	.actualite-single-top {
		grid-template-columns: 1fr;
		gap: 1.5rem;
	}
}

/* --- Carrousel d'images (colonne de droite) ----------------------------- */
/* Grille : [flèche prev] [viewport images] [flèche next], points sur une 2e rangée.
   Les flèches sont DANS les gouttières latérales (hors des images) ; les images
   n'occupent que la colonne centrale (1fr) et rétrécissent d'autant. */
.actualite-carousel {
	margin: 0;
	min-width: 0; /* autorise le viewport à rétrécir dans la grille */
	display: grid;
	grid-template-columns: auto minmax(0, 1fr) auto;
	/* start, PAS center : centrer sur la ligne de grille centrerait les flèches sur
	   diapo + légende quand la diapo en porte une (cf. .creations-thumb-title,
	   page-creations.php) — la légende n'existe pas partout mais la ligne de grille est
	   commune. Le centrage RÉEL, sur la hauteur de l'image seule, est pilote par JS
	   (cf. alignNav(), assets/js/actualite.js) via margin-top sur .actualite-carousel-nav :
	   sans légende (fiches actualité, pellicule À propos) l'image occupe déjà toute la
	   diapo, ce décalage JS vaut alors 0 et le rendu ne change pas. */
	align-items: start;
	column-gap: 0.5rem;
}

.actualite-carousel .actualite-carousel-viewport {
	grid-column: 2;
	grid-row: 1;
}

/* Défilement horizontal natif (scroll-snap) : swipe tactile gratuit, une image
   par vue. Les flèches pilotent le scroll ; les points suivent la position. */
.actualite-carousel-viewport {
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.actualite-carousel-viewport::-webkit-scrollbar {
	display: none;
}

.actualite-carousel-track {
	display: flex;
}

.actualite-slide {
	margin: 0;
	flex: 0 0 100%;
	scroll-snap-align: center;
	display: flex;
	gap: 1.75rem; /* écart entre deux portraits côte à côte */
	background: rgba(0, 0, 0, 0.18);
}

/* Paire de portraits : les deux images sont TOUJOURS recadrées en « cover » et
   remplissent entièrement leur moitié (voir .actualite-slide-img plus bas) — pas
   de letterbox à assombrir ici, contrairement au portrait esseulé (.is-portrait).
   Sans ce reset, le fond sombre de .actualite-slide ci-dessus transparaissait dans
   l'écart (gap) entre les deux images. */
.actualite-slide.is-pair {
	background: none;
}

/* Multi-diapos : TOUTES au même format paysage ; images recadrées (cover) pour
   remplir la boîte. Les portraits (voir .is-pair) occupent une moitié chacun. */
.actualite-carousel:not(.is-single) .actualite-slide {
	aspect-ratio: 3 / 2;
}

.actualite-slide-img {
	flex: 1 1 0;
	min-width: 0;
	width: 100%;
	height: 100%;
	object-fit: cover; /* recadrage paysage / carré */
	display: block;
	cursor: zoom-in; /* clic = plein écran via .js-lightbox */
	-webkit-user-drag: none; /* pas de « fantôme » de drag natif pendant le grab */
}

/* Portrait esseulé (nombre impair) : centré, NON recadré (letterbox sombre). */
.actualite-carousel:not(.is-single) .actualite-slide.is-portrait {
	justify-content: center;
}

.actualite-carousel:not(.is-single) .actualite-slide.is-portrait .actualite-slide-img {
	flex: 0 1 auto;
	width: auto;
	max-width: 100%;
	object-fit: contain;
}

/* Une seule image : format naturel, pas de recadrage, ni scroll-snap ni flèches.
   Pas de gouttières de flèches → l'image occupe toute la largeur. */
.actualite-carousel.is-single {
	grid-template-columns: 1fr;
	column-gap: 0;
}

.actualite-carousel.is-single .actualite-carousel-viewport {
	grid-column: 1;
	scroll-snap-type: none;
	overflow: hidden;
}

.actualite-carousel.is-single .actualite-slide {
	display: block;
	background: none;
}

.actualite-carousel.is-single .actualite-slide-img {
	height: auto;
	object-fit: contain;
}

/* EXCEPTION : une seule diapo, mais composée de DEUX PORTRAITS appariés. « is-single »
   ne veut pas dire « une seule image » — deux portraits tiennent sur une diapo unique
   (cf. le groupement dans galerie_lamy_core_actualite_carrousel_html). Les règles
   ci-dessus, écrites pour une image isolée (display:block, height:auto), empileraient
   alors les deux portraits l'un SOUS l'autre, chacun en pleine largeur : un carrousel
   démesurément haut, qui ne défile pas. La paire garde donc la mise en page normale du
   carrousel — côte à côte dans un cadre paysage, recadrage « cover » ; seules les
   flèches et les points disparaissent, faute de seconde diapo. */
.actualite-carousel.is-single .actualite-slide.is-pair {
	display: flex;
	aspect-ratio: 3 / 2;
}

.actualite-carousel.is-single .actualite-slide.is-pair .actualite-slide-img {
	height: 100%;
	object-fit: cover;
}

/* Flèches HORS des images, dans les gouttières latérales de la grille. */
.actualite-carousel-nav {
	grid-row: 1;
	/* Boîte, couleur et transition IDENTIQUES à .we-nav (Related works / Œuvres
	   exposées) : ce sont les deux mêmes flèches de slider dans le fil de la page. */
	width: 2.5rem;
	height: 2.5rem;
	border: 0;
	background: transparent;   /* flèche SIMPLE, sans cercle (comme lightbox / Retour) */
	color: var(--color-text);
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: color 0.2s ease, opacity 0.2s ease;
}

.actualite-carousel-nav:hover:not([disabled]) {
	color: var(--color-accent);
}

/* Bout de piste atteint (défilement borné, pas de boucle — cf. actualite.js) : même
   registre que .we-nav[disabled] (Related works, assets/css/front-page.css). */
.actualite-carousel-nav[disabled] {
	opacity: 0.25;
	cursor: default;
}

/* Le glyphe (::before, 0.85rem) est bien plus étroit que la boîte cliquable (2.5rem,
   cf. .actualite-carousel-nav) : centré (justify-content:center, hérité), il laisse
   un blanc visible entre la pointe de la flèche et le bord RÉEL de la gouttière — bord
   qui, lui, est exactement celui du corps de page (cf. .content-wrap, aligné sur
   « Contact »). Sur une fiche œuvre, cette gouttière est une zone de fond nue à côté
   de l'image : le blanc y saute d'autant plus aux yeux (constat 2026-09-17, capture
   d'écran à l'appui). On colle donc chaque glyphe vers le bord EXTÉRIEUR de sa propre
   gouttière — gauche pour "prev" (bord du cartel), droite pour "next" (bord de page) —
   au lieu de le centrer dans la boîte : la flèche visible affleure enfin le bord, plutôt
   que sa seule boîte cliquable (invisible) qui l'était déjà. Change TOUS les usages du
   composant (fiches actualité, pellicule À propos, vignettes Créations, fiches œuvre). */
.actualite-carousel-nav.prev {
	grid-column: 1;
	justify-content: flex-start;
}

.actualite-carousel-nav.next {
	grid-column: 3;
	justify-content: flex-end;
}

/* Chevron FIN par bordures — MÊME construction que .we-chevron / .lightbox-chevron /
   le bouton Retour : bordures GAUCHE + BAS, rotate(45deg) pointe à gauche (préc.),
   rotate(-135deg) pointe à droite (suiv.). Même taille que Related works (0.85rem).
   Hors des images (dans la gouttière), sans cercle ni ombre. */
.actualite-carousel-nav::before {
	content: "";
	width: 0.85rem;
	height: 0.85rem;
	border-left: var(--chevron-weight) solid currentColor;
	border-bottom: var(--chevron-weight) solid currentColor;
}

.actualite-carousel-nav.prev::before {
	transform: rotate(45deg); /* pointe à gauche */
}

.actualite-carousel-nav.next::before {
	transform: rotate(-135deg); /* pointe à droite */
}

/* Cachées aux extrémités (pas de boucle) : géré par le JS via [hidden]. */
.actualite-carousel-nav[hidden] {
	display: none;
}

/* Points de position : un point par image ; point courant en --color-accent ; une
   diapo à deux portraits = pilule reliant ses deux points (cf. .is-pair-start). */
.actualite-carousel-dots {
	--acd-size: var(--dot-size);
	--acd-gap: var(--dot-gap);
	grid-column: 1 / -1; /* sous les images, centré sur toute la largeur */
	grid-row: 2;
	display: flex;
	justify-content: center;
	align-items: center;
	gap: var(--acd-gap);
	margin-top: 1rem;
}

.actualite-carousel-dots .acd-dot {
	position: relative;
	width: var(--acd-size);
	height: var(--acd-size);
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.4);
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.actualite-carousel-dots .acd-dot:hover,
.actualite-carousel-dots .acd-dot.is-active {
	background: var(--color-accent); /* position courante en jaune */
}

/* Paire de portraits = deux points. Le 1er porte une PILULE pleine (stadium propre)
   qui COUVRE les deux points (du bord gauche du 1er au bord droit du 2e). Au repos
   elle est réduite (scaleX 0) → on voit deux points. À l'état actif elle s'étire
   depuis le point de gauche pour engloutir celui de droite → les deux se RELIENT en
   une seule pilule lisse. Ses extrémités arrondies coïncident avec les points. */
.actualite-carousel-dots .acd-dot.is-pair-start::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	height: var(--acd-size);
	width: calc(var(--acd-size) * 2 + var(--acd-gap)); /* couvre les deux points */
	background: var(--color-accent);
	border-radius: 999px;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.22s ease;
}

.actualite-carousel-dots .acd-dot.is-pair-start.is-active::after {
	transform: scaleX(1);
}

/* Grab & dérouler à la souris (le tactile garde le scroll natif). */
.actualite-carousel:not(.is-single) .actualite-carousel-viewport {
	cursor: grab;
}

.actualite-carousel:not(.is-single) .actualite-carousel-viewport .actualite-slide-img {
	cursor: inherit; /* même curseur « grab » que le viewport */
}

.actualite-carousel-viewport.is-grabbing,
.actualite-carousel-viewport.is-grabbing .actualite-slide-img {
	cursor: grabbing;
	user-select: none;
}

/* Mobile : PAS de flèches — simple défilement par SWIPE (comme les fiches œuvre). Le
   carrousel occupe toute la largeur ; les points restent sous les images. */
@media (max-width: 1280px) {
	.actualite-carousel {
		grid-template-columns: 1fr;
		column-gap: 0;
	}
	.actualite-carousel .actualite-carousel-viewport {
		grid-column: 1;
	}
	.actualite-carousel-nav {
		display: none;
	}
}

.actualite-single .actualite-single-image {
	margin: 2.5rem 0;
}

.actualite-single .actualite-single-image img {
	width: 100%;
	height: auto;
}

/* Corps du texte calé SOUS le carrousel : même grille que .actualite-single-top,
   le texte occupe la colonne de DROITE (colonne de gauche = marge, sous le titre).
   Les blocs larges (image d'intro, œuvres exposées) débordent en pleine largeur. */
.actualite-single-content {
	display: grid;
	grid-template-columns: minmax(200px, 2fr) minmax(0, 3.6fr);
	column-gap: 3rem;
}

.actualite-single-content > * {
	grid-column: 2; /* texte dans la colonne de droite, aligné sur le carrousel */
	min-width: 0;
}

/* Pas de marge haute sur le 1er bloc du corps → l'écart sous le carrousel est piloté
   uniquement par .actualite-single-top (margin-bottom), sans surplus. */
.actualite-single-content > *:first-child {
	margin-top: 0;
}

.actualite-single-content > figure.wp-block-image,
.actualite-single-content > .works-exhibited,
.actualite-single-content > .wp-block-galerie-lamy-works-exhibited {
	grid-column: 1 / -1; /* image & œuvres exposées : toute la largeur */
}

/* Sous-titre « About » retiré. */
.actualite-single-content .about-subtitle {
	display: none;
}

@media (max-width: 900px) {
	.actualite-single-content {
		grid-template-columns: 1fr;
	}
	.actualite-single-content > * {
		grid-column: 1;
	}
}

/* En-dessous de 1280px : version mobile (menu latéral). */
@media (max-width: 1280px) {
	.site-header {
		/* Padding haut du logo repris de --header-padding-y (ci-dessous). L'air qui doit
		   « détacher » le logo est mis SOUS lui (entre l'en-tête et le corps de page), via
		   le dégagement du contenu (cf. --header-gap ci-dessous), pas au-dessus.
		   Marge LATÉRALE = --header-padding-side (la marge « sitewide » du contenu) : logo et
		   bouton Menu tombent ainsi exactement sur les bords du contenu du site. */
		padding: var(--header-padding-y) var(--header-padding-side) 0;
	}

	/* Logo (et burger, calé sur UNE ligne de logo) réduits en mobile. Le burger vaut
	   calc(var(--logo-size) * 1.2) et --header-height dérive aussi de --logo-size : les
	   deux rétrécissent ensemble et l'en-tête reste proportionné. */
	:root {
		--logo-size: 1.4rem;
		/* Marge latérale mobile « sitewide » (Collection, fiche œuvre, footer…) AUGMENTÉE
		   au nombre d'or : 3vw × φ ≈ 4.85vw. RÉFÉRENCE unique du cadrage mobile/tablette :
		   les 4 bords (haut, gauche, droite, bas) du viewport doivent s'en tenir à cette
		   MÊME valeur, sur tout le site — cf. --header-padding-y juste dessous, et la
		   légende hero / le pied de page qui la reprennent aussi (front-page.css, plus bas). */
		--header-padding-side: calc(3vw * 1.618);
		/* air AU-DESSUS du logo = ANCIEN 1rem fixe, désormais ALIGNÉ sur la marge latérale
		   (--header-padding-side) : sinon le cadre haut ne « pèse » pas le même poids que
		   les cadres gauche/droite (écart qui se creuse encore plus sur tablette, où le vw
		   grandit et le rem fixe reste identique). */
		--header-padding-y: var(--header-padding-side);
		/* Air SOUS le logo = écart entre l'en-tête et le corps de chaque page. C'est CE
		   padding-là qui « détache » le logo ; les dégagements de contenu l'utilisent.
		   Il valait exactement la gouttière latérale (cadre uniforme) : or celle-ci est en
		   vw, si bien que l'écart TOMBAIT à ~21px sur téléphone (contre ~62px à 1280px).
		   Un titre placé juste sous le logo s'y collait — visible sur Contact, masqué
		   ailleurs par une image de tête. On garde donc la même expression, avec un PLANCHER
		   qui l'empêche de s'effondrer sur les petits écrans (≈40px sous ~830px de large,
		   comportement inchangé au-dessus). Jeton MOBILE : le bureau n'est pas concerné. */
		--header-gap: max(2.75rem, var(--header-padding-side));
	}

	/* Mobile : TOUJOURS le grand logo complet (« GALERIE LAMY / CHABOLLE »), jamais la
	   version compacte. Il ne glisse pas hors champ au scroll : on neutralise le transform
	   de .header-scrolled (qui ne pilote le logo grand↔compact qu'en desktop). */
	/* Logo posé AU-DESSUS du voile du menu (comme le bouton Fermer) : quand le panneau est
	   ouvert, le logo reste visible en haut à gauche et la navigation s'ouvre EN DESSOUS. */
	.site-logo {
		position: relative;
		z-index: 1200;
	}
	.logo-full {
		display: block;
	}
	.site-header.header-scrolled .logo-full {
		transform: none;
		pointer-events: auto;
	}
	.logo-compact {
		display: none; /* la petite version n'apparaît jamais en mobile */
	}

	/* Bouton burger, poussé à droite ; reste au-dessus du panneau (z-index)
	   pour pouvoir refermer le menu. */
	/* Bouton « Menu » : à la place des trois traits, un libellé TEXTE sobre en Garamond
	   (petite police, même registre que la nav). Les deux libellés (« Menu » au repos,
	   « Fermer / Close » quand le panneau est ouvert) sont EMPILÉS dans la même cellule de
	   grille → un seul visible à la fois, largeur du bouton stable (pas de saut). */
	.nav-toggle {
		display: inline-grid;
		place-items: center end;
		margin-left: auto;
		/* La zone de touche déborde À DROITE de la marge du site (padding-right ci-dessous) :
		   sans ce correctif, le LIBELLÉ (« MENU » / « FERMER »), lui, restait en retrait de
		   cette même valeur — visiblement pas aligné sur le bord droit du site (logo, images,
		   pied de page…). Une marge négative égale au padding ramène le texte exactement sur
		   la marge, sans réduire la zone de touche tactile. */
		margin-right: -0.2rem;
		position: relative;
		z-index: 1200;
		padding: 0.35rem 0.2rem; /* petite zone de touche autour du texte */
		background: none;
		border: 0;
		cursor: pointer;
		font-family: var(--font-display); /* Garamond, sobre */
		font-size: var(--fs-h4);          /* un cran √φ au-dessus des labels (registre légendes) */
		font-weight: 400;
		text-transform: uppercase;        /* « MENU » / « FERMER » en capitales */
		letter-spacing: 0.08em;           /* respiration des capitales (taille inchangée) */
		line-height: 1.2;
		color: var(--color-text);
	}
	/* PAS d'effet de survol : sur mobile (tactile) le :hover reste « collé » après le
	   toucher — d'où un MENU qui restait jaune après fermeture. Les couleurs sont donc
	   FIXES par libellé : « MENU » toujours blanc, « FERMER / CLOSE » toujours jaune. */
	.nav-toggle-label {
		grid-area: 1 / 1;
		transition: opacity 0.2s ease;
	}
	.nav-toggle-label--open {
		color: var(--color-text);   /* MENU : toujours blanc */
	}
	/* Repos : « Menu » visible, « Fermer » caché. Ouvert : l'inverse. */
	.nav-toggle-label--close {
		color: var(--color-accent); /* FERMER / CLOSE : toujours jaune */
		opacity: 0;
		visibility: hidden;
	}
	.site-header.nav-open .nav-toggle-label--open {
		opacity: 0;
		visibility: hidden;
	}
	.site-header.nav-open .nav-toggle-label--close {
		opacity: 1;
		visibility: visible;
	}

	/* Navigation = MENU PLEIN ÉCRAN : couvre TOUT l'écran et apparaît/disparaît en simple
	   FONDU (opacity), sans glissement. Le bouton Menu (z-index supérieur) reste au-dessus
	   pour refermer ; les liens s'ouvrent sous l'en-tête. */
	.site-nav {
		position: fixed;
		inset: 0; /* plein écran */
		z-index: 1100;
		width: 100%;
		height: 100vh;
		height: 100dvh;
		margin-left: 0;
		flex-direction: column;
		align-items: flex-start;
		justify-content: flex-start;
		gap: 1.5rem;
		/* Navigation ouverte EN DESSOUS du logo, au MÊME emplacement que les catégories de la
		   page Collection : même origine haute (var(--header-height) + var(--header-gap)) → l'écart
		   logo→navigation est identique à l'écart logo→catégories, et même origine gauche
		   (var(--header-padding-side)) → alignée sur le logo. */
		padding: calc(var(--header-height) + var(--header-gap)) var(--header-padding-side) 2rem;
		/* Fond = VOILE NOIR TRANSLUCIDE + FLOU (plein écran → un cran plus opaque), même
		   registre que la lightbox / les infobulles : on laisse deviner la page derrière. */
		background-color: rgba(0, 0, 0, 0.72);
		-webkit-backdrop-filter: blur(10px);
		backdrop-filter: blur(10px);
		/* Fondu RAPIDE d'ouverture/fermeture. FERMÉ = display:none, et NON un simple
		   opacity/visibility : sous iOS 26 (Safari « Liquid Glass »), le navigateur teinte
		   la barre d'état et la barre d'adresse avec le background-color/backdrop-filter des
		   éléments FIXES touchant les bords du viewport — et il les échantillonne MÊME
		   invisibles (opacity:0 / visibility:hidden). Ce voile noir plein écran teintait donc
		   en permanence les barres du navigateur. display:none le retire de l'échantillonnage ;
		   `allow-discrete` + @starting-style conservent le fondu. */
		display: none;
		opacity: 0;
		transition: opacity 0.22s ease, display 0.22s allow-discrete;
		overflow-y: auto;
		overscroll-behavior: contain;
	}
	.site-header.nav-open .site-nav {
		display: flex;
		opacity: 1;
	}
	@starting-style {
		.site-header.nav-open .site-nav {
			opacity: 0;
		}
	}

	.site-nav > ul:not(.lang-switcher) {
		flex: 0 0 auto;
		width: 100%;
		flex-direction: column;
		align-items: flex-start;
		justify-content: flex-start;
		gap: 1.25rem;
	}

	/* FR/EN toujours visible et EN PLACE dans le panneau : il NE défile PAS avec la
	   page (on annule le suivi de scroll du desktop). */
	.lang-switcher {
		font-size: var(--nav-size);
		justify-content: flex-start;
		transform: none;
	}

	.content-wrap {
		padding: calc(var(--header-height) + var(--header-gap)) var(--header-padding-side) 3rem;
	}

	/* (Marges latérales mobile de .content-wrap = --header-padding-side pour TOUTES les
	   pages : réglé directement sur .content-wrap ci-dessus. --marge-site, calée sur le
	   logo, était trop large en mobile — d'où le passage au repère « sitewide ».) */

	/* Collection : menu au-dessus de la grille (plus de sticky), une seule colonne.
	   Padding latéral réduit (3vw, aligné sur le header) : la marge --marge-site (calée
	   sur le logo, ~190px) est pensée pour le desktop et étoufferait la galerie justifiée
	   sur tablette/mobile. On rend ainsi sa pleine largeur au conteneur de la grille. */
	.oeuvre-archive {
		grid-template-columns: 1fr;
		gap: 2rem;
		padding-left: var(--header-padding-side);
		padding-right: var(--header-padding-side);
	}

	.collection-nav {
		position: static;
		/* Mobile : filtres/recherche remontés d'un cran √φ (×0.786 → ×1) → pile sur
		   le token de page --fs-d4, une itération du nombre d'or au-dessus du desktop. */
		--collection-nav-fs: var(--fs-d4);
	}

	/* MOBILE — Recherche : MÊME système que le desktop. Le libellé « Rechercher… »
	   reste tout en bas des catégories et se transforme EN PLACE en champ de saisie au
	   clic (cf. desktop, .collection-search / front-page.js → initCollectionFilter).
	   Plus de bouton flottant, de barre fixe ni de croix « vider » : on laisse jouer les
	   règles desktop ci-dessus. Seule la taille de police change, déjà portée par
	   --collection-nav-fs sur .collection-nav (réglé juste au-dessus). */

	/* Pied de page : tout empilé et centré sur mobile. */
	/* Footer mobile : EMPILÉ (comme aujourd'hui) mais NON centré → aligné à GAUCHE, sur le
	   BORD gauche du contenu = marge latérale mobile sitewide (--header-padding-side). */
	.site-footer {
		padding-left: var(--header-padding-side);
		padding-right: var(--header-padding-side);
		/* Bas du pied de page = dernier bord AVANT le bord réel du viewport (le bureau
		   utilise --page-padding, cadré sur le logo ; ici on reprend la même référence que
		   les 3 autres bords mobiles, + env(safe-area-inset-bottom) déjà porté par la
		   règle de base ci-dessus (calc(2.5rem + env(...))) qu'on remplace pour ce seuil. */
		padding-bottom: calc(var(--header-padding-side) + env(safe-area-inset-bottom, 0px));
	}
	.site-footer .footer-inner {
		/* Le logo étant retiré en mobile (cf. .footer-brand ci-dessous), il ne reste
		   que les colonnes : elles occupent toute la largeur, alignées à gauche. */
		flex-direction: row;
		justify-content: flex-start;
		align-items: flex-start;
		gap: 1.5rem;
		text-align: left;
	}

	/* Colonnes EMPILÉES et, surtout, liens à icônes (site + Instagram) REJETÉS EN
	   DERNIÈRE LIGNE, sous les DEUX colonnes — en desktop ils ferment leur propre
	   colonne, ici ils ferment le pied de page. Les colonnes sont donc « aplaties »
	   (display:contents) : leurs lignes deviennent les éléments du même flux vertical,
	   ce qui permet d'ordonner la rangée d'icônes après TOUT le texte (order:1) sans
	   toucher ni au markup du plugin Pied de page, ni au desktop. Le gap repasse à 0 :
	   il s'appliquerait sinon entre CHAQUE ligne ; les écarts entre groupes sont posés
	   à la main juste dessous. */
	.site-footer .footer-columns {
		display: flex;
		flex-direction: column;
		gap: 0;
		text-align: left;
		align-items: flex-start;
	}

	.site-footer .footer-col {
		display: contents;
	}

	/* Écart entre la colonne 1 et la colonne 2 : le gap ne peut plus le porter, on le
	   pose sur le premier élément de la colonne 2 (son titre s'il existe, sinon sa
	   première ligne). */
	.site-footer .footer-col-2 > *:first-child {
		margin-top: 1.5rem;
	}

	/* Logo RETIRÉ en mobile (demande galerie : il prend trop de place à côté du texte).
	   Le nom de la galerie ouvre déjà la colonne 1 — aucune information n'est perdue. */
	.site-footer .footer-brand {
		display: none;
	}

	.site-footer .footer-social {
		order: 1; /* après toutes les lignes des deux colonnes = dernière ligne */
		justify-content: flex-start;
		/* Neutralise le calage desktop (margin-top:auto pour tomber au bas de la colonne,
		   margin-bottom:.35em pour aligner sur la ligne de base de l'e-mail voisin) :
		   ici la rangée est seule sur sa ligne. */
		margin: 1.5rem 0 0;
		padding-top: 0;
	}

	/* Module d'inscription : libellés PUIS champ, empilés et pleine largeur — le
	   « en regard » desktop ne tient pas sous le seuil du burger. */
	.site-footer .footer-newsletter {
		margin-top: 1.75rem;
		padding-top: 1.75rem;
	}

	.site-footer .glc-news-band {
		flex-direction: column;
		align-items: stretch;
		gap: 1.25rem;
	}

	.site-footer .glc-news-right,
	.site-footer .glc-news-form {
		width: 100%;
		min-width: 0;
	}

	/* La rangée est ici EMPILÉE : la base flexible du desktop (35rem, largeur visée
	   du champ) porterait sur la HAUTEUR une fois l'axe principal vertical. On la
	   remet à « auto » — la largeur ci-dessus suffit à occuper toute la colonne. */
	.site-footer .glc-news-right {
		flex: 0 0 auto;
	}
}

/* Fiche œuvre (gabarit standard) : EXTRAIT du bloc mobile ci-dessus pour recevoir une
   exception que la navigation (bloc ci-dessus, inchangé) ne reçoit pas — sur TABLETTE EN
   PAYSAGE (1024–1280px), le contenu reprend l'agencement DESKTOP (cartel en colonne,
   galerie épinglée) alors que la barre de navigation y reste mobile (bouton « Menu »).
   Même exception que .gl-hscroll / .gl-oeuvre-strip plus haut. */
@media (max-width: 1280px) and (not ((min-width: 1024px) and (orientation: landscape))) {
	.oeuvre-single {
		grid-template-columns: 1fr;
		gap: 2.5rem;
	}

	/* Sur mobile : plus rien d'épinglé — le rail s'empile au-dessus des visuels et défile
	   normalement. */
	.oeuvre-rail-head {
		position: static;
	}

	/* Mobile : PLUS de bouton « Retour » sur la fiche œuvre standard (classe .oeuvre-back
	   seule, sans compagne). Exclut explicitement .actualite-back (page News, hors
	   exception tablette : elle garde ce comportement à tout seuil ≤1280px) et .mp-back
	   (œuvre majeure, gabarit non concerné par cette exception). */
	.oeuvre-back:not(.actualite-back):not(.mp-back) {
		display: none;
	}

	/* Mobile — position du CARTEL (rail), posée par le JS (initOeuvreLayout) :
	   • si le corps OUVRE par une suite de 2+ images, cette bande de tête est hissée AU-DESSUS
	     du cartel DANS la galerie, et le cartel est glissé juste dessous (.oeuvre-gallery >
	     .oeuvre-rail) → de l'air au-dessus et en dessous ;
	   • sinon, le cartel reste rangée 1 de la grille (au-dessus de la galerie), espacé par son
	     « gap » (2.5rem). */
	.oeuvre-gallery > .oeuvre-rail {
		margin: 2.5rem 0;
	}
}

/* ---------------------------------------------------------------------------
   Lueur (glow) jaune sur survol — SITE-WIDE
   Tout élément qui passe (ou est) au jaune accent diffuse, au survol, une très
   faible lueur PULSANTE de la même teinte (#FFC600). On utilise filter:drop-shadow,
   qui suit la forme réellement rendue → fonctionne uniformément sur le texte, les
   icônes SVG (lightbox) et les bordures (bouton « Enquire »). Très subtil.
--------------------------------------------------------------------------- */
@keyframes accent-glow {
	0%, 100% { filter: drop-shadow(0 0 1px rgba(255, 198, 0, 0.18)); }
	50%      { filter: drop-shadow(0 0 4px rgba(255, 198, 0, 0.45)); }
}

/* :focus-visible (navigation clavier) : TOUJOURS actif, quel que soit le pointeur —
   contrairement au :hover ci-dessous, il ne « colle » jamais au toucher. */
.lightbox-close:focus-visible,
.lightbox-nav:focus-visible,
.oeuvre-enquire:focus-visible,
.site-footer .glc-news-submit:focus-visible {
	animation: accent-glow 4.5s ease-in-out infinite;
}

/* :hover réservé aux pointeurs FINS (souris/trackpad). Sur écran tactile, :hover
   « colle » après un tap (pas de mouseleave) : sans ce garde-fou, un lien de nav, une
   catégorie Collection, une carte Actualité… restait jaune/lumineux en permanence
   après le premier toucher, comme figé en survol. Regroupe aussi l'ex-cas particulier
   de la légende hero (même règle, mêmes pointeurs fins). */
@media (hover: hover) {
	.site-nav a:hover,
	.lang-switcher a:hover,
	.collection-nav-link:hover,
	.lightbox-close:hover,
	.lightbox-nav:hover,
	.lightbox-dot:hover,
	.oeuvre-enquire:hover,
	.actualite-featured .actualite-title a:hover,
	.actualite-card:hover .actualite-title,
	.actualite-more:hover,
	.site-footer .glc-news-submit:hover,
	a.hero-legend:hover .hero-legend-title {
		animation: accent-glow 4.5s ease-in-out infinite;
	}
}

/* Mouvement réduit : on garde une lueur légère mais FIXE (pas de pulsation). */
@media (prefers-reduced-motion: reduce) {
	.lightbox-close:focus-visible,
	.lightbox-nav:focus-visible,
	.oeuvre-enquire:focus-visible,
	.site-footer .glc-news-submit:focus-visible {
		animation: none;
		filter: drop-shadow(0 0 3px rgba(255, 198, 0, 0.4));
	}
}

@media (hover: hover) and (prefers-reduced-motion: reduce) {
	.site-nav a:hover,
	.lang-switcher a:hover,
	.collection-nav-link:hover,
	.lightbox-close:hover,
	.lightbox-nav:hover,
	.lightbox-dot:hover,
	.oeuvre-enquire:hover,
	.actualite-featured .actualite-title a:hover,
	.actualite-card:hover .actualite-title,
	.actualite-more:hover,
	.site-footer .glc-news-submit:hover,
	a.hero-legend:hover .hero-legend-title {
		animation: none;
		filter: drop-shadow(0 0 3px rgba(255, 198, 0, 0.4));
	}
}

/* ======================================================================
   NOTES DE BAS DE PAGE (core/footnotes) + infobulle au survol
   ====================================================================== */

/* La LISTE des notes (en bas de contenu) est masquée VISUELLEMENT mais conservée dans le
   DOM et l'arbre d'accessibilité (repli sans JS + lecteurs d'écran) — même technique que
   .screen-reader-text. Le contenu s'affiche en infobulle au survol de l'appel de note
   (cf. front-page.js → initFootnotes). */
.wp-block-footnotes {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	height: 1px;
	width: 1px;
	overflow: hidden;
	position: absolute !important;
	white-space: nowrap;
	word-wrap: normal !important;
}

/* Appel de note : petit exposant discret (accent), curseur d'aide. Le <sup> natif gère
   déjà l'exposant ; on ne stylise que le lien. */
sup.fn a {
	color: var(--color-accent);
	text-decoration: none;
	cursor: help;
	padding: 0 0.1em;
}
sup.fn a:hover,
sup.fn a:focus-visible {
	text-decoration: underline;
}

/* Infobulle : reprend le registre de la pastille « On Hold » des vignettes (fond sombre
   translucide, texte blanc Type Deux, léger flou) — mais coins arrondis comme les images du
   site (--img-radius) au lieu de la pilule. Texte de note = phrase → casse normale et
   interligne lisible (pas de capitales ni d'interlettrage serré). Positionnée en JS. */
.gl-footnote-tip {
	position: fixed;
	z-index: 1500;
	max-width: min(26rem, 90vw);
	padding-inline: 0.85rem;
	/* CORRECTION VERTICALE (2026-09, signalée sur iPhone) : même police (--font-ui,
	   « Type Deux ») que .gl-button/.oeuvre-badge, même genre d'écart d'ascendant/
	   descendant — donc la même ENCRE trop haute, ici sur la 1ère/dernière ligne de la
	   phrase plutôt que sur un mot capitalisé seul. Pas de flex ici (bloc simple, texte
	   en flux normal) donc pas le second effet (répartition de l'espace négatif par
	   align-items) qui complique .gl-button — valeur étalonnée séparément, EMPIRIQUEMENT
	   (Canvas TextMetrics + Range sur 1ère/dernière ligne, plusieurs valeurs testées) :
	   ≈ 0.0525em, à ne pas réutiliser telle quelle sur .gl-button ni l'inverse. */
	padding-top: calc(0.6rem + 0.0525em);
	padding-bottom: calc(0.6rem - 0.0525em);
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
	font-family: var(--font-ui);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: 1.45;
	/* Pas de letter-spacing ici (texte en phrase, pas en capitales) donc pas de fantôme
	   de fin de texte à corriger comme sur .gl-button/.oeuvre-badge (cf. leurs
	   commentaires) : le texte s'appuyait simplement à gauche par défaut (bloc). Centré
	   pour reprendre le même registre visuel que la pastille On Hold. */
	text-align: center;
	border-radius: var(--img-radius);
	backdrop-filter: blur(2px);
	box-shadow: 0 0.4rem 1.4rem rgba(0, 0, 0, 0.3);
	pointer-events: none;
	/* Apparition/disparition = FONDU seul (aucun mouvement directionnel). */
	opacity: 0;
	transition: opacity 0.15s ease;
}
.gl-footnote-tip.is-visible {
	opacity: 1;
}

/* ---------------------------------------------------------------------------
   PAGE « NOTABLE SALES » / « VENTES MAJEURES »
   Page COMPOSÉE DANS GUTENBERG (gabarit page-notable-sales.php + bloc
   galerie-lamy/notable-sales du plugin galerie-lamy-core). Deux volets :
     1. cadre de page (.notable-editorial) : marges, titre, blocs de texte courants ;
     2. rendu des bandes .gl-notable (rangée / pleine largeur) : image + légende saisie.
   Autonome : uniquement des tokens stables + tailles clamp() locales ; n'utilise pas
   .content-wrap (pour échapper aux surcharges !important de body.page).
   --------------------------------------------------------------------------- */

/* -- Cadre de la page ---------------------------------------------------- */
/* MÊME padding que les fiches œuvre (.content-wrap) : gauche = --page-padding
   (largeur du logo), droite = --marge-site-right (fin de « Contact »). Fallbacks
   pour rester valide même sans les tokens de la refonte typo. */
.notable-editorial {
	padding: calc(var(--header-height) + var(--nav-gap, 3rem)) var(--marge-site-right, var(--page-padding)) 4rem var(--page-padding);
}

@media (max-width: 1280px) {
	.notable-editorial {
		padding: calc(var(--header-height) + var(--header-gap)) var(--header-padding-side) 3rem;
	}
}

.notable-head {
	margin-bottom: clamp(2.5rem, 6vw, 5rem);
}

.notable-title {
	margin: 0;
	font-family: var(--font-display);
	font-weight: 400;
	font-size: var(--fs-d3);   /* échelle √φ : titre de page, aligné sur .page-title */
	line-height: 1.1;
	color: var(--color-text);
}

/* Blocs de texte courants ajoutés dans l'éditeur (intro, intertitres…). */
.notable-content > p,
.notable-content > .wp-block-paragraph {
	max-width: 46rem;
	margin: 0 0 1.2rem;
	font-family: var(--font-ui);
	font-size: var(--fs-h2);   /* échelle √φ : corps du site */
	line-height: 1.6;
	color: var(--color-text);
}

.notable-content > h2,
.notable-content > h3 {
	margin: 2.5rem 0 1rem;
	font-family: var(--font-display);
	font-weight: 400;
	line-height: 1.2;
	color: var(--color-text);
}

.notable-content > h2 { font-size: var(--fs-d4); }            /* échelle √φ : h2 de page */
.notable-content > h3 { font-size: var(--fs-title-fluid); }  /* échelle √φ : h3 de page */

.notable-content a {
	color: var(--color-accent);
}

/* -- Bande de bloc : plusieurs bandes espacées verticalement -------------- */
.gl-notable {
	margin: clamp(3rem, 7vw, 6rem) 0;
}

.gl-notable:first-child { margin-top: 0; }
.gl-notable:last-child { margin-bottom: 0; }

.gl-notable-items {
	display: flex;
	gap: clamp(1.5rem, 4vw, 3.5rem);
}

/* Rangée : œuvres côte à côte, largeurs égales, alignées en haut. */
.gl-notable--row .gl-notable-items {
	flex-direction: row;
	flex-wrap: wrap;
	align-items: flex-start;
}

.gl-notable--row .gl-notable-item {
	flex: 1 1 220px;
	min-width: 0;
}

/* Rangée de TROIS : les trois images partagent le même axe horizontal (centrées dans la bande
   de la plus haute), donc celle du milieu est toujours centrée verticalement. Grille à 3 colonnes ; chaque item reprend les 2 lignes de la
   grille (sous-grille) — ligne 1 = image, ligne 2 = cartel — pour que la bande soit commune.
   Au-dessous de 861px la rangée retombe en flex (retour à la ligne, puis colonne). */
@media (min-width: 861px) {
	.gl-notable--row .gl-notable-items:has(> .gl-notable-item:nth-child(3):last-child) {
		display: grid;
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 0 clamp(1.5rem, 4vw, 3.5rem);
		align-items: start;
	}
	.gl-notable--row .gl-notable-items:has(> .gl-notable-item:nth-child(3):last-child) > .gl-notable-item {
		display: grid;
		grid-row: span 2;
		grid-template-rows: subgrid;
	}
	.gl-notable--row .gl-notable-items:has(> .gl-notable-item:nth-child(3):last-child) > .gl-notable-item > .gl-notable-media {
		align-self: center;
	}
}

/* Exception voulue (page Notable Sales) : le CENTRE du crabe est aligné sur le centre du tableau
   des Pillement, cimier du cadre exclu : 300 px au-dessus de leur ligne de base sur une image de
   694 px de haut, soit 300/694 de la hauteur de l'image. Hauteur des Pillement = largeur de colonne
   x 1636/1810 ; hauteur du crabe = largeur x 683/1024. Marge basse (en % = largeur de colonne) =
   centre voulu - demi-hauteur du crabe. */
@media (min-width: 861px) {
	.gl-notable--row .gl-notable-items:has(> .gl-notable-item:nth-child(3):last-child) > .gl-notable-item > .gl-notable-media:has(img[src*="crabe-padouan"]) {
		align-self: end;
		margin-bottom: calc((300 / 694 * 1636 / 1810 - 683 / 1024 / 2) * 100%);
	}
}

/* Pleine largeur ET deux visuels : chaque item sur une ligne — MÉDIA d'un côté, titre +
   cartel de l'AUTRE (image à gauche par défaut, inversable via .gl-notable--reversed). Les
   items s'empilent. « Deux visuels » partage exactement cette disposition ; seule différence :
   son bloc média contient DEUX images côte à côte (cf. plus bas) au lieu d'une grande. */
.gl-notable--full .gl-notable-items,
.gl-notable--duo .gl-notable-items {
	flex-direction: column;
	gap: clamp(3rem, 7vw, 6rem);
}

.gl-notable--full .gl-notable-item,
.gl-notable--duo .gl-notable-item {
	display: flex;
	align-items: flex-start;
	gap: clamp(2rem, 5vw, 4.5rem);
	width: 100%;
}

.gl-notable--full.gl-notable--reversed .gl-notable-item,
.gl-notable--duo.gl-notable--reversed .gl-notable-item {
	flex-direction: row-reverse;
}

.gl-notable--full .gl-notable-media,
.gl-notable--duo .gl-notable-media {
	flex: 1 1 55%;
	min-width: 0;
}

.gl-notable--full .gl-notable-legend,
.gl-notable--duo .gl-notable-legend {
	flex: 1 1 45%;
	min-width: 0;
}

/* Deux visuels : les DEUX images du même objet côte à côte À L'INTÉRIEUR du bloc média
   (lui-même sur son côté de la ligne, comme la grande image de la pleine largeur). */
.gl-notable--duo .gl-notable-media {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp(0.75rem, 2vw, 1.5rem);
	align-items: start;
	justify-items: center;
}

.gl-notable--duo .gl-notable-media img {
	width: 100%;
	height: auto;
	max-height: 62vh;
	object-fit: contain;
}

/* -- Œuvre (image + légende) --------------------------------------------- */
.gl-notable-item {
	margin: 0;
}

.gl-notable-media img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--img-radius);
}

.gl-notable--full .gl-notable-media img {
	width: auto;
	max-width: 100%;
	max-height: 62vh;
	margin: 0 auto;
}

/* Rangée : légende sous l'image ; pleine largeur : légende à côté, alignée en HAUT de l'image. */
.gl-notable--row .gl-notable-legend {
	margin-top: 1rem;
}

.gl-notable-item-title {
	margin: 0 0 1.1rem;
	font-family: var(--font-display);
	font-weight: 400;
	font-size: var(--fs-h2);   /* échelle √φ : titre d'œuvre, un cran sous title-fluid */
	line-height: 1.25;
	color: var(--color-text);
}

/* Cartel (légende de l'œuvre) : Garamond GRISÉ (romain), même traitement que le cartel
   des fiches — cf. .mp-rail-cartel p. Le titre au-dessus (.gl-notable-item-title) reste
   en Garamond pleine couleur. */
.gl-notable-desc p {
	margin: 0 0 0.6rem;
	font-family: var(--font-display);
	font-size: var(--nav-size);
	letter-spacing: 0;
	line-height: 1.55;
	color: rgba(255, 255, 255, 0.5);
}

.gl-notable-desc p:last-child {
	margin-bottom: 0;
}

/* Pleine largeur ET deux visuels sous 860px : le média passe AU-DESSUS du texte (colonne). */
@media (max-width: 860px) {
	.gl-notable--full .gl-notable-item,
	.gl-notable--full.gl-notable--reversed .gl-notable-item,
	.gl-notable--duo .gl-notable-item,
	.gl-notable--duo.gl-notable--reversed .gl-notable-item {
		flex-direction: column;
		align-items: stretch;
		gap: 1.25rem;
	}
	.gl-notable--full .gl-notable-media img {
		width: 100%;
		max-height: none;
	}
	/* Deux visuels : le média occupe toute la largeur, les deux images restent côte à côte. */
	.gl-notable--duo .gl-notable-media img {
		max-height: none;
	}
}

/* Deux visuels sous 540px : les deux images s'empilent enfin (trop étroites côte à côte). */
@media (max-width: 540px) {
	.gl-notable--duo .gl-notable-media {
		grid-template-columns: 1fr;
	}
}

/* Empilement sous 700px : les rangées passent en colonne. align-items reste à
   flex-start (hérité, pensé pour aligner les hauts d'une RANGÉE) : en colonne, cet
   axe devient l'axe TRANSVERSE (largeur) — flex-start y fait alors RÉTRÉCIR chaque
   item à la largeur intrinsèque de son contenu au lieu de l'étirer sur toute la
   largeur disponible. Image et titre débordaient alors silencieusement du viewport
   (masqués par le garde-fou overflow-x:clip du site, cf. body plus haut) au lieu de
   se réduire et de passer à la ligne. stretch rétablit la largeur pleine, comme
   toutes les autres grilles du site en colonne unique. */
@media (max-width: 700px) {
	.gl-notable--row .gl-notable-items {
		flex-direction: column;
		align-items: stretch;
	}
	.gl-notable--row .gl-notable-item {
		flex-basis: auto;
	}
}

/* Images de fiche : la place est réservée (width/height) ; teinte douce + fondu à l'arrivée
   de l'image. .is-img-pending est posée en JS (front-page.js) uniquement sur les images pas
   encore chargées, et retirée au load/error : sans JS, l'image reste visible. */
.oeuvre-gallery figure.wp-block-image,
.mp-main figure.wp-block-image {
	background: rgba( 128, 128, 128, 0.08 );
}
.oeuvre-gallery figure.wp-block-image img,
.mp-main figure.wp-block-image img {
	transition: opacity 0.45s ease;
}
.oeuvre-gallery figure.wp-block-image img.is-img-pending,
.mp-main figure.wp-block-image img.is-img-pending {
	opacity: 0;
}
