/* =========================================================================
   style.css — Galerie Energies Graphiques
   --------------------------------------------------------------------------
   Sommaire (par section) :
     1. Variables et base
     2. En-tête : titre, catégories, dégradé de fond en MEDIUM/MINI
     3. Layout de la page : <main>, cadre arrondi (.gallery-frame)
     4. Grille : structure commune + les 3 formats (LARGE/MEDIUM/MINI)
     5. Cases : image, légende, zoom au survol, filtrage par catégorie
     6. Cases texte
     7. Lightbox
     8. Pied de page
     9. Accessibilité : mouvement réduit
   ========================================================================= */

/* =========================================================================
   1. VARIABLES ET BASE
   ========================================================================= */

@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=Inter:wght@400;500&display=swap');

/* BG defaut #101114; */
:root{
  /* GRAIN : bruit fractal SVG (feTurbulence) généré en data-URI, donc
     aucun fichier image à charger. Il est converti en points BLANCS
     semi-transparents.
     RÉGLAGES ACTUELS (modifiés à la main) :
       baseFrequency='0.45'  → finesse du grain : plus haut = plus fin,
                               plus bas = plus gros (0.8 au départ)
       0.35 0 0 0 -0.2       → dernière ligne de feColorMatrix (alpha) :
                               0.35 = contraste du grain (0.5 au départ),
                               -0.2 = densité (plus proche de 0 = plus de
                               points visibles)
     Tuile de 240px (--grain-size), répétée. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0.15 0 0 0 -0.2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-size: 240px;

  /* PARALLAXE du dégradé de fond (le script est dans index.html).
     Le dégradé bouge PLUS LENTEMENT que le contenu, et réagit aussi à
     la SOURIS (indispensable : en LARGE la page ne défile souvent pas du
     tout, la galerie tenant dans l'écran). Le grain, lui, reste fixe.
       --parallax-speed : vitesse du fond par rapport au défilement
                          (0 = fond immobile, 1 = colle au contenu)
       --parallax-range : déplacement maximum dû au défilement (px) ;
                          le mouvement ralentit en douceur en s'en approchant
       --parallax-mouse : amplitude du déplacement dû à la souris (px),
                          dans le sens OPPOSÉ au curseur ; 0 = désactivé
     Les valeurs --par-x / --par-y (décalage courant) sont posées par le
     script sur <html> ; sans script elles valent 0 (dégradé au repos). */
  --parallax-speed: 0.15;
  --parallax-range: 200px;
  --parallax-mouse: 50px;

  /* IMAGE DE FOND (images/fond_homepage2026.jpg, 2115 x 1205).
     --bg-w = largeur d'affichage de l'image : la plus grande entre
     "tout le calque en largeur" et "tout le calque en hauteur" (ratio
     2115/1205 = 1.7552), ce qui équivaut à background-size: cover sur
     le calque, mais en valeur partagée avec la barre d'en-tête (voir
     .site-header::after) pour qu'elles restent parfaitement raccord.
     Si tu changes d'image, adapte 1.7552 (largeur / hauteur).
	 fond_homepage2026.jpg	 */
  --bg-image: url("../images/homepage2026 BG upgrade.webp");
  --parallax-extra: calc(var(--parallax-range) + var(--parallax-mouse));
  --bg-w: max(calc(100vw + var(--parallax-extra)), calc((100vh + var(--parallax-extra)) * 1.7552));
  --bg-body: var(--grain) 0 0 / var(--grain-size) var(--grain-size) repeat,
             radial-gradient(farthest-side at 0% 0%, #281f3f, #101114);
  --bg:#101114; --bg-raised:#17181c; --line:#2a2c31; --text:#ECE8E1; --text-dim:#97999f;
  --accent-cyan:#4FD6C4; --accent-orange:#FFCC00; --accent-orange-light:#FFE066;
  --gap:1px; --radius:2px;
  /* Hauteur de l'en-tête : partagée par plusieurs règles (padding de
     compensation dans <main>, masquage du dégradé, etc.) — garder une
     variable évite de corriger 5 endroits si elle change. */
  --header-h: 120px;
  --page-pad-x: clamp(20px,4vw,56px); /* marge horizontale partagée : aligne le logo et le bord de la grille */
  --font-display:'Space Grotesk','Helvetica Neue',Arial,sans-serif;
  --font-body:'Inter','Helvetica Neue',Arial,sans-serif;
}

*{ box-sizing:border-box; }

/* FOND : html ne porte plus que la couleur de base. Le dégradé et le
   grain sont deux calques FIXES (body::before et body::after, juste
   dessous) : ça permet de déplacer le dégradé en parallaxe sans bouger
   le grain, et ça évite le "background-attachment: fixed", mal
   supporté sur mobile. Le body doit donc rester transparent. */
html{
  color-scheme:dark;
  background:#101114;
}

body{
  margin:0;
  background:none; /* fond = calques body::before (dégradé) et body::after (grain) */
  color:var(--text);
  font-family:var(--font-body);
  -webkit-font-smoothing:antialiased;
}

/* Calque 1 : image de fond, coin haut-gauche (la lueur violette) calé
   dans le coin de l'écran au repos. Le calque dépasse de
   --parallax-extra à droite et en bas, et il est décalé vers le
   haut/gauche par transform (composité par le GPU, pas de repeinture) :
   jamais de bord vide visible. Le dégradé radial en 2e couche ne sert
   que de secours si l'image n'est pas trouvée (mauvais chemin). */
body::before{
  content:'';
  position:fixed;
  top:0; left:0;
  right:calc(-1 * var(--parallax-extra));
  bottom:calc(-1 * var(--parallax-extra));
  z-index:-1;
  pointer-events:none;
  background-image: var(--bg-image), radial-gradient(circle max(100vw, 100vh) at 0 0, #281f3f, #101114);
  background-size: var(--bg-w) auto, auto;
  background-position: 0 0, 0 0;
  background-repeat: no-repeat;
  transform: translate3d(calc(-1 * var(--par-x, 0px)), calc(-1 * var(--par-y, 0px)), 0);
  will-change: transform;
}
/* Calque 2 : grain, immobile, par-dessus le dégradé */
body::after{
  content:'';
  position:fixed;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background: var(--grain) 0 0 / var(--grain-size) var(--grain-size) repeat;
}

img{ max-width:100%; display:block; }
a{ color:#FA0; }
a:hover{ color:#FC0; }

/* =========================================================================
   2. EN-TÊTE : titre, catégories, dégradé de fond en MEDIUM/MINI
   ========================================================================= */

/* L'en-tête est FIXE : quand la galerie LARGE déborde de l'écran, la
   page défile à l'horizontale — sans ça, le bloc titre glisserait avec
   le scroll. Fixé en haut, il reste immobile en haut à gauche, et la
   grille commence --header-h plus bas (voir <main>).
   Hauteur TOUJOURS fixe, quel que soit le format ou l'état (catégories
   visibles ou non) : jamais de débordement sur la grille en dessous.
   brand-wrap est une colonne centrée verticalement dans cette hauteur
   fixe — centrer un bloc donne mécaniquement la même marge au-dessus
   du logo qu'en dessous des catégories. Quand les catégories
   apparaissent, le bloc [logo+titre / catégories] grandit et reste
   centré : le logo remonte visuellement pour laisser la place. */
.site-header{
  position: fixed;
  top: 0; left: 0;
  width: 100%;
  z-index: 50;
  height: var(--header-h);
  padding: 0 var(--page-pad-x);
  /* [TEST — barre de séparation sous le titre masquée]
     Pour rétablir la barre, retirer le "outline: none" ci-dessous et
     décommenter la ligne border-bottom. */
  /* border-bottom: 1px solid var(--line); */
  outline: none;
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  overflow:hidden; /* garde-fou : jamais de débordement visuel sur la grille */
  box-sizing: border-box;
}

.site-header .meta{ font-size:13px; color:var(--text-dim); }
.site-header .meta a{ text-decoration:none; } /* couleur : règle globale a / a:hover */

/* ---- bloc logo + titre + catégories ---- */

.brand-wrap{
  height:100%;
  display:flex; flex-direction:column; justify-content:center; align-items:flex-start;
  min-width:0;
}
.brand-row{ display:flex; align-items:center; gap:12px; flex:0 0 auto; }
.brand-logo{ width:40px; height:40px; display:block; flex:0 0 auto; }
.brand{
  font-family: var(--font-display);
  font-weight:700;
  font-size: clamp(22px,3vw,30px);
  letter-spacing:-0.01em;
  text-decoration:none;
  color:var(--accent-orange);
  cursor:default;
}

/* ---- catégories : révélées au survol du titre (comportement par défaut,
     actif en MEDIUM/MINI : elles apparaissent SOUS le titre) ---- */

.categories{
  display:flex; flex-wrap:nowrap; gap:8px;
  max-width: 90vw;
  overflow-x:auto; overflow-y:hidden;
  white-space:nowrap;
  scrollbar-width: thin;
  max-height:0; opacity:0; margin-top:0;
  transition: max-height .3s ease, opacity .25s ease, margin-top .3s ease;
}
.cat-pill{ flex:0 0 auto; }
.brand-wrap:hover .categories,
.brand-wrap:focus-within .categories{ max-height:60px; opacity:1; margin-top:10px; }

.cat-pill{
  font-family:var(--font-body); font-size:12px;
  background:var(--bg-raised); color:var(--text-dim);
  border:1px solid var(--line); border-radius:20px;
  padding:6px 13px; cursor:pointer;
}
.cat-pill:hover{ color:var(--text); border-color:var(--accent-orange); }
.cat-pill.is-active{ color:#0b0b0c; background:var(--accent-orange); border-color:var(--accent-orange); }

/* ---- catégories à droite du titre en format LARGE ---- */
/* En LARGE (desktop paysage), les catégories se révèlent À CÔTÉ du
   titre, sur la même ligne (au lieu d'en dessous). Le format actif est
   posé sur <body> par applyFormat() dans gallery.js. */

body[data-format="large"] .brand-wrap{
  position:relative; /* sert d'ancrage au positionnement absolu des catégories */
  /* Le titre suit le même mouvement vertical que la grille, plus doux :
     - fenêtre ≥ 1030px de haut → translateY(0)    (titre à sa place)
     - fenêtre ≤ 860px de haut  → translateY(-15px) (titre remonté)
     Interpolation linéaire continue entre les deux (170px de plage,
     170px × 0.088235 ≈ 15px), bornée par clamp. */
  transform: translateY(clamp(-15px, calc((100vh - 1030px) * 0.088235), 0px));
}
body[data-format="large"] .categories{
  position:absolute;
  left:100%;            /* collées juste après la largeur réelle du bloc titre */
  top:50%;
  transform:translateY(-50%);
  margin-top:0;
  margin-left:20px;      /* respiration entre le titre et les pills */
  max-height:0; opacity:0;   /* repliées par défaut : révélées au survol du titre */
  transition: max-height .3s ease, opacity .25s ease, margin-top .3s ease;
}
body[data-format="large"] .brand-wrap:hover .categories,
body[data-format="large"] .brand-wrap:focus-within .categories{
  max-height:60px; opacity:1; margin-top:0;
}

/* ---- catégories affichées par CLIC sur le titre ---- */
/* Un clic sur le titre pose la classe .cats-open sur l'en-tête (script
   de index.html) : les catégories restent affichées jusqu'au prochain
   clic, SANS recharger la page ni rejouer l'animation d'intro (l'ancien
   lien <a href="index.html"> rechargait tout à chaque clic). Le survol
   du titre continue de fonctionner par-dessus (ordinateurs). */
.site-header.cats-open .categories{ max-height:60px; opacity:1; margin-top:10px; }
body[data-format="large"] .site-header.cats-open .categories{ max-height:60px; opacity:1; margin-top:0; }

/* ---- curseur "_" à côté du titre ---- */
/* Clignote doucement en continu. Se rapproche du titre (annule presque
   le gap de 12px du bloc). S'efface en fondu (fade-out de .5s) dès que
   les catégories sont visibles : au survol du titre (ordinateurs) ou
   après un clic (.cats-open posé sur l'en-tête). */
.brand-cursor{
  flex:0 0 auto;
  font-family: var(--font-display);
  font-weight:700;
  font-size: clamp(22px,3vw,30px);
  line-height:1;
  color: var(--accent-orange);
  margin-left:-9px;
  /* Fade-in TRÈS LENT au démarrage : invisible pendant l'arrivée du
     titre (délai .8s), puis fondu de 3s vers l'opacité pleine ; le
     clignotement doux ne prend le relais qu'une fois le fondu terminé
     (délai 3.8s = .8 + 3), sans aucun saut. */
  animation:
    cursor-soft-in 3s ease .8s both,
    cursor-soft-blink 3.2s ease-in-out 3.8s infinite;
}
@keyframes cursor-soft-in{ from{ opacity:0; } to{ opacity:1; } }
@keyframes cursor-soft-blink{ 0%,100%{ opacity:1; } 50%{ opacity:.1; } }
@keyframes cursor-fade-out{ from{ opacity:1; } to{ opacity:0; } }
.brand-wrap:hover .brand-cursor,
.brand-wrap:focus-within .brand-cursor,
.site-header.cats-open .brand-cursor{
  animation: cursor-fade-out .5s ease forwards; /* disparition en douceur, sans saut */
}

/* ---- dégradé de fond de l'en-tête en MEDIUM/MINI ---- */
/* Le contenu défile SOUS l'en-tête fixe en MEDIUM/MINI : les images
   passeraient derrière le titre, illisibles. On plaque donc derrière
   le bloc titre un dégradé LINÉAIRE HORIZONTAL qui reprend la lecture
   du fond de page (violet #281f3f près de l'angle haut-gauche →
   #101114 vers la droite) : un radial serait compressé dans les 120px
   de hauteur de l'en-tête et ne ressemblerait jamais au fond réel.
   Le fondu d'opacité vers le bas (mask) n'affecte que ce fond, jamais
   le contenu du titre.
   Règle de déclenchement = l'inverse exact du format LARGE de
   detectFormat() : présent en permanence en MEDIUM et MINI, absent
   uniquement en LARGE. */

.site-header::after{
  content:'';
  position:absolute;
  inset:0;
  /* même image, même taille et même décalage de parallaxe que le fond,
     pour que la barre reste invisible ; grain par-dessus */
  background-color: #101114;
  background-image: var(--grain), var(--bg-image);
  background-size: var(--grain-size) var(--grain-size), var(--bg-w) auto;
  background-position: 0 0, calc(-1 * var(--par-x, 0px)) calc(-1 * var(--par-y, 0px));
  background-repeat: repeat, no-repeat;
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
  mask-image: linear-gradient(to bottom, #000 55%, transparent); /* fondu d'opacité sur le bas */
  z-index:-1; /* derrière le contenu de l'en-tête */
}
/* en LARGE : pas de dégradé, l'en-tête reste transparent */
@media (min-width: 700px) and (min-height: 660px) and (orientation: landscape){
  .site-header::after{ content:none; }
}

/* ---- barre de titre plus basse en MEDIUM / MINI ---- */
/* La hauteur de l'en-tête est portée par --header-h, partagée par le
   centrage de <main> et la hauteur disponible de la grille : tout
   s'ajuste automatiquement. 95px en MEDIUM, 80px en MINI (LARGE
   garde 120px). Le format actif est posé sur <body> par applyFormat()
   dans gallery.js. */
body[data-format="medium"]{ --header-h: 95px; }
body[data-format="mini"]{ --header-h: 80px; }

/* =========================================================================
   3. LAYOUT DE LA PAGE : <main> et le cadre arrondi (.gallery-frame)
   ========================================================================= */

/* <main> assure le centrage vertical du cadre sous l'en-tête fixe et
   réserve la marge minimale (20px) quand la galerie LARGE déborde de
   l'écran (dans ce cas le scroll de la page prend le relais). */
main{
  min-height: calc(100vh - var(--header-h));
  padding-top: var(--header-h);    /* compense l'en-tête fixe */
  display: flex;
  align-items: center;
  padding-left: 20px;
  padding-right: 20px;
}

/* Div intermédiaire (voir index.html) : elle porte le cadre arrondi et
   épouse exactement l'ensemble des cases (fit-content, 16px de débord
   tout autour), SANS toucher au comportement de la grille elle-même
   (centrage, défilement, hauteurs de lignes). */
/* position:relative : sert d'ancre aux liens .frame-links, placés visuellement
   SOUS le cadre (voir plus bas) */
.gallery-frame{
  position: relative;
  display: block;
  width: fit-content;           /* le cadre épouse la largeur réelle des images */
  max-width: none;              /* si plus large que l'écran : débordement à droite + scroll de la page */
  margin: 10px auto 50px;       /* marges auto : centré horizontalement si le cadre tient à
                                   l'écran ; retombées à 0 s'il déborde → calé à gauche
                                   (20px via le padding de <main>) avec scroll de la page —
                                   même logique que l'ancien "safe center", portée sur la div */
  background: rgba(10,11,13,.35); /* fond du cadre : plus transparent */
  border: 1px solid #2b2143;     /* contour violet sombre, même famille que le dégradé de fond */
  border-radius: 24px;
  padding: 16px;
  box-shadow: 0 10px 40px rgba(0,0,0,.35); /* léger relief pour bien marquer le bord du cadre */
}

/* IMPORTANT : la grille repeint par défaut son propre fond radial
   (var(--bg-body)) — à l'intérieur du cadre, ce fond recouvre la teinte
   du cadre et le rend invisible. On le neutralise ici, uniquement pour
   la galerie publique (l'éditeur garde son fond). C'était la cause du
   "cadre invisible". */
.gallery-frame .gallery{ background: transparent; }

/* Liens JUSTE SOUS le cadre, alignés à droite. Ils restent dans la div du
   cadre (donc suivent son centrage, son décalage et son débord selon le
   format) mais sont posés en absolu hors de la boîte : ni fond, ni contour
   du cadre autour d'eux. top:100% = bord bas du cadre ; margin-top = 10px
   d'espace en hauteur. Ils tiennent dans les 50px de marge basse du cadre. */
.frame-links{
  position: absolute;
  top: 100%;
  right: 16px;
  margin-top: 10px;
  text-align: right;
  font-size: 12px;
  color: var(--text-dim);
}
.frame-links a{ text-decoration:none; }
.frame-links a:hover{ text-decoration:underline; }

/* MEDIUM / MINI : la grille est centrée à l'écran, le cadre suit.
   Le format actif est posé sur la div par le script de index.html
   (frame.dataset.format = format) : pas de sélecteur :has, dont le
   support n'est pas garanti partout. */
.gallery-frame[data-format="medium"],
.gallery-frame[data-format="mini"]{
  margin-left: auto;
  margin-right: auto;
}

/* Décalage vertical du cadre en LARGE, animé selon la hauteur de la
   fenêtre :
     - 860px de haut ou moins  → translateY(-40px) (bloc remonté)
     - 1030px de haut ou plus  → translateY(0)      (bloc au centre vrai)
   Entre les deux, interpolation linéaire continue : clamp fige le
   résultat aux bornes, et calc() fait descendre le décalage de -40px
   vers 0px au fil des 170px gagnés (170px × 0.235294 ≈ 40px).
   PAS de transition : le navigateur recalcule 100vh à chaque frame
   pendant un redimensionnement, la valeur suit donc déjà la fenêtre
   instantanément — une transition ne ferait qu'ajouter de l'inertie. */
main .gallery-frame[data-format="large"]{
  transform: translateY(clamp(-40px, calc((100vh - 1030px) * 0.235294), 0px));
}

/* =========================================================================
   4. GRILLE : structure commune + les 3 formats
   ========================================================================= */

/* Le span de chaque case (grid-column/grid-row) est posé en JS, en
   style inline, par applyFormat() dans gallery.js — il dépend du
   format actif, donc il ne peut pas être une règle CSS statique par
   data-w/data-h comme avant. Ici on ne définit que la structure de
   grille (nombre de colonnes/lignes, sens de remplissage) par format. */

.gallery{
  display:grid;
  gap: var(--gap);
  margin: 10px;
  background: var(--bg-body);
  grid-auto-rows: 100px; /* unité verticale fixe, quel que soit le format */
}

/* ---- LARGE — desktop / tablette paysage : grille de 8 lignes fixes, se
   remplit en colonnes et défile à l'horizontale une fois plus large que
   l'écran (glisser à la souris/au doigt, voir enableDragScroll) ---- */

.gallery[data-format="large"]{
  grid-auto-flow: column;
  /* 100px au repos ; se réduit doucement si la fenêtre manque de hauteur
     (le "rescale" démarre maintenant ~50px plus tôt, vers 1000px de
     hauteur au lieu de ~950px), jusqu'à la bascule complète en MEDIUM
     (voir detectFormat, 660px) */
  grid-template-rows: repeat(8, clamp(70px, 10vh, 100px));
  grid-auto-columns: 133px;
  grid-auto-rows: unset;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
  /* largeur = 100% de l'écran, ni plus ni moins : la boîte elle-même ne
     change jamais de taille (donc jamais de scrollbar de la page en
     plus de celle de la grille). Le centrage horizontal ET vertical se
     fait par l'alignement natif de CSS Grid (justify/align-content),
     pas en redimensionnant la boîte : "safe center" centre les cases
     seulement si elles rentrent, et retombe sur un alignement normal
     (départ à gauche/en haut, défilement à droite) sinon — exactement
     le comportement demandé, sans les soucis de fit-content d'avant. */
  box-sizing: border-box;
  width: 100%;
  min-height: calc(100vh - var(--header-h)); /* hauteur dispo sous l'en-tête fixe, pour pouvoir centrer verticalement */
  margin: 10px 0 50px 0;
  justify-content: safe center;
  align-content: safe center;
  padding-left: var(--page-pad-x);
  padding-right: var(--page-pad-x);
}

/* Dans le cadre, la galerie LARGE n'a plus à se dimensionner ni se
   centrer elle-même : la div cadre s'en charge. On neutralise donc ses
   marges/paddings/hauteur mini, qui servaient quand la grille était
   seule à l'écran. Le centrage d'origine (justify/align-content) reste
   intact sur les cases à l'intérieur. */
.gallery-frame .gallery[data-format="large"]{
  width: auto;
  min-height: 0;
  height: fit-content;
  margin: 0;
  padding: 0;
  justify-content: start;
  align-content: start;
  overflow: visible;             /* le défilement est géré par la page quand le cadre déborde */
}

/* CORRECTIF (cadre trop épais en MEDIUM/MINI) : en LARGE la grille
   n'a plus de marge propre (règle ci-dessus), mais la règle de base
   .gallery{ margin:10px } s'appliquait ENCORE en MEDIUM et MINI — le
   cadre paraissait donc 10px plus épais en haut et en bas que dans
   le format LARGE. On aligne tous les formats : l'écart entre le
   contour arrondi et les cases vient uniquement du padding du cadre
   (16px). */
.gallery-frame .gallery[data-format="medium"],
.gallery-frame .gallery[data-format="mini"]{ margin: 0; }

/* ---- MEDIUM — desktop / tablette portrait : 6 colonnes fixes, remplissage
   en lignes classique (défilement vertical) ---- */

.gallery[data-format="medium"]{
  grid-auto-flow: row;
  grid-template-columns: repeat(var(--medium-cols, 6), 1fr);
  max-width: 820px;   /* largeur réaliste d'une tablette portrait */
  margin-left:auto; margin-right:auto;
}

/* ---- MINI — mobile : 3 colonnes fixes, remplissage en lignes ---- */

.gallery[data-format="mini"]{
  grid-auto-flow: row;
  grid-template-columns: repeat(3, 1fr);
  max-width: 420px;   /* largeur réaliste d'un mobile */
  margin-left:auto; margin-right:auto;
}

/* =========================================================================
   5. CASES : image, légende, zoom au survol, filtrage par catégorie
   ========================================================================= */

.item{
  position:relative;
  overflow:hidden; /* le zoom au survol reste contenu dans la case */
  cursor:pointer;
  border-radius: var(--radius);
}
.item .frame{ width:100%; height:100%; overflow:hidden; position:relative; background:var(--bg-raised); }
.item img{ width:100%; height:100%; object-fit:cover; display:block; transition: transform .4s ease; }

.item .caption{
  position:absolute; inset:auto -1px -1px -1px; /* +1px sur les bords : évite un écart d'arrondi sub-pixel avec l'image */
  padding: 14px 16px;
  background: linear-gradient(to top, rgba(10,10,12,.92), rgba(10,10,12,0));
  transform: translateY(8px); opacity:0;
  transition: opacity .3s ease, transform .3s ease;
  pointer-events:none;
}
.item .caption .num{ font-family:var(--font-display); font-size:11px; color:var(--text); letter-spacing:.02em; }
.item .caption h3{ margin:2px 0 0; font-family:var(--font-display); font-size:15px; font-weight:500; color:var(--accent-orange); }
.item .caption .desc{
  margin-top:0; font-size:12px; color:var(--text-dim); line-height:1.35;
  max-height:0; opacity:0; overflow:hidden;
  transition: opacity .3s ease, max-height .3s ease, margin-top .3s ease; /* repli rapide dès qu'on quitte la case */
}

/* Rollover : zoom de l'image À L'INTÉRIEUR de sa case (pas de débordement
   sur les voisines, pas de recalcul de la grille). Réservé aux pointeurs
   avec un vrai survol. */
@media (hover:hover) and (pointer:fine){
  .item.can-expand:hover img, .item.can-expand:focus-visible img{ transform: scale(1.12); }
  .item.can-expand:hover .caption, .item.can-expand:focus-visible .caption{ opacity:1; transform:translateY(0); }
  /* la description n'apparaît (et ne pousse le bloc vers le haut) qu'après 2s de survol continu */
  .item.can-expand:hover .caption .desc, .item.can-expand:focus-visible .caption .desc{
    max-height:120px; opacity:1; margin-top:4px;
    transition: opacity .4s ease 2s, max-height .4s ease 2s, margin-top .4s ease 2s;
  }
}
/* Sur tactile (pas de vrai survol) : les légendes sont CACHÉES par
   défaut — c'est le glissement du doigt sur une case qui les révèle
   (la classe .is-peeked est posée par le script de index.html au
   touchmove ; elle se nettoie dès que le doigt quitte la case). */
@media not all and (hover:hover){
  .item .caption{ opacity:0; transform:translateY(8px); }
  .item.is-peeked .caption{ opacity:1; transform:translateY(0); }
}
/* jamais de description en format MINI, quel que soit l'appareil */
.gallery[data-format="mini"] .item .caption .desc{ display:none !important; }

/* ---- filtrage par catégorie : atténuation (tous formats) ---- */
/* Cliquer sur une catégorie ne masque ni ne ré-arrange rien, quel que
   soit le format (LARGE, MEDIUM, MINI) : les cases restent à leur
   position enregistrée et celles hors catégorie passent en opacité .2 —
   un fondu fluide, réversible en un clic. */
.gallery.is-dimmed .item{ transition: opacity .3s ease; }
.gallery.is-dimmed .item.is-dimmed-out{ opacity:.2; }
.gallery.is-dimmed .item.is-dimmed-out .caption{ opacity:0 !important; transform:translateY(8px) !important; } /* légendes coupées sur les cases atténuées */
.gallery.is-dimmed .item.is-dimmed-out img{ transform:none !important; } /* pas de zoom au survol non plus */

/* =========================================================================
   6. CASES TEXTE
   ========================================================================= */

.item-text{ background:var(--bg); }
.item-text .text-box{
  width:100%; height:100%;
  /* CORRECTIF (texte complet en MINI) : bloc, et PLUS flex column.
     En flex, les enfants du .text-box (titres, paragraphes, textes
     anonymes) sont des flex items qui se rétractent pour tenir dans
     la case : scrollHeight ne mesurait alors qu'une PARTIE du
     contenu — surtout en MINI, où la case est petite face au texte —
     et le défilement n'atteignait jamais la fin (le texte hors champ
     restait invisible, alors qu'il est lisible dans les autres
     formats). En bloc, le contenu déborde simplement vers le bas et
     scrollHeight — utilisé par startTextScroll dans index.html —
     mesure le texte COMPLET, partie hors champ comprise. Le début
     reste ancré en haut comme avant, aucun centrage vertical. */
  display:block;
  padding: 18px;
  font-family: var(--font-display);
  font-size: 15px;               /* même taille sur ordinateur et mobile — aucune réduction en MINI */
  line-height:1.4;
  color: var(--text-dim);
  cursor:text;
  white-space: pre-line;
  overflow:hidden;                /* pas de scroll manuel : le défilement doux est animé (voir classes tb-reading/tb-returning) */
}
/* Texte plus grand que sa case : au survol (desktop) ou au glissement
   du doigt (tactile), le texte DÉFILE DOUCEMENT jusqu'en bas, puis
   REVIENT RAPIDEMENT à sa position initiale (haut) quand on relâche.
   Les distances/durées sont posées en variables par le script. */
@keyframes tb-scroll{ from{ transform:translateY(0); } to{ transform:translateY(var(--tb-shift, 0px)); } }
@keyframes tb-return{ from{ transform:translateY(var(--tb-shift, 0px)); } to{ transform:translateY(0); } }
.item-text.tb-reading .text-box{ animation: tb-scroll var(--tb-dur, 10s) linear forwards; }
.item-text.tb-returning .text-box{ animation: tb-return .4s ease forwards; }
.item-text .text-box h1{ font-size:1.8em; font-weight:700; margin:.3em 0; color:var(--text); white-space:normal; }
.item-text .text-box h2{ font-size:1.4em; font-weight:700; margin:.3em 0; color:var(--text); white-space:normal; }
.item-text .text-box h3{ font-size:1.15em; font-weight:500; margin:.3em 0; color:var(--text); white-space:normal; }
/* La taille du texte est IDENTIQUE sur mobile et sur ordinateur : on ne
   réduit plus la police en MINI (l'ancien 12px rendait le texte
   proportionnellement plus gros dans les petites cases et le faisait
   déborder). */
.item-text .text-box img{ max-width:100%; border-radius:4px; margin:6px 0; }
/* liens des cases texte : couleur par la règle globale a / a:hover */

/* =========================================================================
   7. LIGHTBOX
   ========================================================================= */

/* Structure : colonne plein écran = [aperçus] / [scène centrale] / [légende].
   La scène prend toute la place restante ; le script (fitLightboxFrame)
   y inscrit le cadre au ratio exact du média, sans jamais rogner. */
.lightbox{
  position:fixed; inset:0; background:rgba(8,8,10,.95);
  display:flex; flex-direction:column;
  opacity:0; visibility:hidden; transition:opacity .3s ease; z-index:100;
  padding:14px 84px 12px;   /* réserve les côtés pour les flèches */
  box-sizing:border-box;
}
.lightbox.is-open{ opacity:1; visibility:visible; }
.lightbox-stage{
  flex:1 1 auto; min-height:0; min-width:0;
  display:flex; align-items:center; justify-content:center;
}
.lightbox-frame{
  position:relative; background:#000; overflow:hidden;
  width:0; height:0; flex:none;         /* dimensions posées par le script */
  opacity:0; transition:opacity .25s ease;
}
.lightbox-frame.is-ready{ opacity:1; }
.lightbox-frame img, .lightbox-frame video, .lightbox-frame iframe{
  position:absolute; inset:0; width:100%; height:100%; border:0; display:block;
}
.lightbox-frame img, .lightbox-frame video{ object-fit:contain; }
/* Vidéo de plateforme non embarquable (ex : Dailymotion) : rond "play"
   qui indique que le clic ouvre la vidéo dans un nouvel onglet. */
.lightbox-frame.is-video-link::after{
  content:'\25B6';
  position:absolute; top:50%; left:50%;
  transform:translate(-50%,-50%);
  width:58px; height:58px; line-height:58px;
  border-radius:50%;
  background:rgba(8,8,10,.75);
  border:2px solid var(--accent-orange);
  color:var(--accent-orange);
  text-align:center; font-size:22px;
  pointer-events:none;
}
.lightbox-info{ flex:none; padding-top:12px; display:grid; gap:6px; justify-items:center; text-align:center; }
.lightbox-caption{ display:flex; flex-wrap:wrap; align-items:baseline; justify-content:center; gap:12px; }
.lightbox-caption h3{ font-family:var(--font-display); font-weight:500; font-size:18px; margin:0; color:var(--accent-orange); }
.lightbox-link{ font-family:var(--font-display); font-size:13px; color:var(--text-dim); text-decoration:none; border:1px solid var(--line); border-radius:4px; padding:4px 10px; white-space:nowrap; }
.lightbox-link:hover{ color:var(--accent-orange); border-color:var(--accent-orange); }
.lightbox-desc{ margin:0; font-size:13px; color:var(--text-dim); line-height:1.4; max-width:90ch; }

/* ---- boutons : une seule icône SVG chacun (couleur = currentColor) ---- */
.lightbox-close, .lightbox-nav{
  position:absolute; z-index:5;
  display:flex; align-items:center; justify-content:center;
  background:transparent; border:0; padding:0;
  color:var(--accent-orange);
  cursor:pointer; opacity:.6; transition:opacity .25s ease;
  filter:drop-shadow(0 0 3px rgba(0,0,0,.7));
}
.lightbox-close:hover, .lightbox-nav:hover{ opacity:1; }
.lightbox-nav{ width:64px; height:96px; top:50%; transform:translateY(-50%); }
.lightbox-nav.prev{ left:10px; }
.lightbox-nav.next{ right:10px; }
.lightbox-close{ width:48px; height:48px; top:10px; right:10px; }

/* Interface effacée après 3 s d'inactivité (souris uniquement) */
.lightbox-close, .lightbox-nav, .lightbox-info, .lightbox-thumbs{ transition:opacity .35s ease; }
@media (hover:hover){
  .lightbox.is-ui-idle .lightbox-close,
  .lightbox.is-ui-idle .lightbox-nav,
  .lightbox.is-ui-idle .lightbox-info,
  .lightbox.is-ui-idle .lightbox-thumbs{ opacity:0; pointer-events:none; }
}

/* ---- rangée d'aperçus (plusieurs médias) ---- */
.lightbox-thumbs{
  display:none; flex:none;
  gap:8px; flex-wrap:wrap; justify-content:center;
  padding:0 40px 12px;      /* évite le bouton ✕ */
}
.lightbox.is-gallery .lightbox-thumbs{ display:flex; }
.lightbox-thumbs button{
  position:relative; background:none; border:2px solid var(--line); border-radius:4px;
  padding:0; cursor:pointer; line-height:0; overflow:hidden; opacity:.7;
}
.lightbox-thumbs button img{ width:64px; height:44px; object-fit:cover; display:block; }
.lightbox-thumbs button:hover{ opacity:1; border-color:var(--text-dim); }
.lightbox-thumbs button.is-current{ opacity:1; border-color:var(--accent-orange); }
.lightbox-thumbs .thumb-play{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  color:#fff; font-size:14px; line-height:1; background:rgba(0,0,0,.35);
}

/* ---- smartphone / très petits écrans : méthode Fresco ---- */
/* Média sur tout l'écran ; interface rangée dans les coins du bas. */
@media all and (max-width:699px), all and (orientation:landscape) and (max-height:500px){
  .lightbox{ padding:0; }
  .lightbox-stage{ position:absolute; inset:0; }
  .lightbox-thumbs{ position:absolute; top:8px; left:0; right:0; z-index:3; padding:0 8px; }
  .lightbox-info{
    position:absolute; left:0; right:130px; bottom:0; z-index:3;
    padding:44px 16px 12px; justify-items:start; text-align:left;
    background:linear-gradient(to top, rgba(8,8,10,.92), rgba(8,8,10,0));
  }
  .lightbox-caption{ justify-content:flex-start; flex-direction:column; align-items:flex-start; gap:6px; }
  .lightbox-caption h3{ font-size:15px; }
  .lightbox-desc{ font-size:12px; max-height:3em; overflow:hidden; }
  .lightbox-close{ top:auto; bottom:6px; right:6px; }
  .lightbox-nav{ top:auto; bottom:0; transform:none; width:48px; height:60px; opacity:.85; }
  .lightbox-nav.prev{ left:auto; right:102px; }
  .lightbox-nav.next{ right:54px; }
}

/* =========================================================================
   8. PIED DE PAGE
   ========================================================================= */

.site-footer{ padding:24px clamp(20px,4vw,56px) 48px; color:var(--text-dim); font-size:12px; display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap; }
.site-footer a{ text-decoration:none; } /* couleur : règle globale a / a:hover */

/* =========================================================================
   9. ACCESSIBILITÉ : MOUVEMENT RÉDUIT
   ========================================================================= */

@media (prefers-reduced-motion: reduce){
  .item, .item .caption, .lightbox, .lightbox-frame{ transition:none !important; }
  .brand-cursor{ animation:none !important; } /* pas de clignotement si mouvement réduit */
}