/* ============================================================
   MOTEUR VIEWER — marcrenard.com — MOTEUR CSS
   Fichier : MOTEUR-serie.css
   Version : v6 -- 20 septembre 2026
   v6 (20/09/2026, demande Didier et Marc) : ligne serie de la legende du
   diaporama (.legend .serie) plus petite que la technique et le format,
   sur tous les profils (base 9px, desktop 8px, tablette/tactile 13px), et
   plus discrete (opacite 0.6). Remplace la reutilisation de .technique de v5.
   v5 (20/09/2026, demande Didier et Marc) : (a) titre de la vue grille :
   mot Series plus petit (.gt-suffix) et ligne d'annees centree dessous
   (.gt-years) ; (b) espace au-dessus du titre de la vue grille reduit de
   moitie (padding-haut de #grid-view : 12vh->6vh, 10vh->5vh, 12vh->6vh) ;
   (c) la ligne serie de la legende reutilise la classe .technique : meme
   taille que la technique dans tous les profils, aucune regle ajoutee.
   Numerotation : v4 sautee (l'en-tete v3 et le commentaire .sr-only v4
   etaient incoherents) ; JS et CSS alignes sur v5.
   (Nouvelle convention de nommage, decision Didier du 19/09/2026 --
   ancien nom : MOTEUR_new_resurgence_v1_16septembre2026.css)
   v3 : ajout de la classe utilitaire .sr-only (SEO/accessibilite,
   voir fin du fichier) -- masque visuellement le <h1> ajoute dans
   chaque fragment de serie, sans impact sur le rendu.
   Historique : v1 (16/09/2026, pilote, extrait de B v186 Resurgence).
   v191 (19/09/2026) : integration du correctif croix + dezoom 1.15
   (issu de B v190 unique) -- visibilite progressive du bouton retour
   pendant le dezoom tactile. Voir regle .rv-cross-only ci-dessous.
   Role    : CSS commun a TOUTES les series (DATA -> ENGINE -> VIEW,
             Architecture Fiche 06 §12). Un seul emplacement sur le site ;
             chaque page de serie le reference via <link rel="stylesheet">.
   Regle   : toute correction visuelle se fait ICI, jamais dans une page
             de serie individuelle. Une modification beneficie a toutes
             les series en meme temps (Fiche 06 §1).
   ============================================================ */

  * { margin: 0; padding: 0; box-sizing: border-box; }
  html, body { width: 100%; height: 100%; background: #ffffff; overflow: hidden; }
  #app {
    /* v152 : ancrage structurel du viewer au viewport.
       Le diagnostic v151 a etabli que, dans l'etat fautif, #app lui-meme
       commencait a top=10px, et toute la chaine interne reproduisait
       exactement ce decalage. Le viewer ne doit donc plus dependre de sa
       position naturelle dans le flux de la page hote (Elementor/WordPress).
       fixed + inset:0 l'ancre directement au viewport et supprime cette
       origine externe du decalage. */
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100vh; /*  : conserve comme fallback pour navigateurs anciens */
    /*  : BUG REEL CORRIGE, cause racine du bloc d'icones invisible sur
       mobile signale par Didier (capture ecran a l'appui). 100vh sur
       mobile se calcule par rapport a la plus grande hauteur d'ecran
       possible (barre d'adresse masquee), plus grande que la zone
       reellement visible quand cette barre est affichee -- le bloc
       d'icones, positionne en bas de cette zone surdimensionnee via
       bottom:2vh, se retrouvait hors ecran. Explique aussi les icones
       qui "bougeaient" ponctuellement (barre d'adresse qui apparait/
       disparait en cours de defilement). Corrige avec 100svh (smallest
       viewport height = hauteur cadree sur le pire cas, barre visible),
       qui elimine le decoupage ET l'instabilite, contrairement a 100dvh
       qui recalcule en continu et recree un effet de saut. Support
       navigateur : Safari 15.4+, Chrome/Edge 108+, Firefox 101+, largement
       couvert en 2026. Regle 100vh conservee au-dessus comme repli pour
       les tres rares navigateurs qui ne comprendraient pas 100svh (la
       regle CSS suivante, si comprise, prend le pas sur la precedente). */
    height: 100svh;
    background: #ffffff;
  }

  /* ============ VUE DIAPORAMA ============ */
  #diaporama-view { position: absolute; inset: 0; }
  /* v170: uniquement pendant l'entrée grille → viewer. Le viewer reste dans le layout mais l'ancien slide est invisible jusqu'à préparation de la bonne œuvre. Aucun effet sur le fondu normal. */
  #diaporama-view.rv-grid-opening { visibility: hidden !important; pointer-events: none !important; }
  .mySwiper {
    touch-action: none; width: 100%; height: 100%; }
  .swiper-slide {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #ffffff;
  }
  .mySwiper.rv-zoomed .swiper-slide-active img { cursor: grab; }
  .mySwiper.rv-panning .swiper-slide-active img { cursor: grabbing; }
body.rv-detail-zoom .control-block,
body.rv-detail-zoom .legend-popup,
body.rv-detail-zoom #legend {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  transition: none !important;
}
body.rv-detail-zoom .control-block *,
body.rv-detail-zoom .legend-popup *,
body.rv-detail-zoom #legend * {
  pointer-events: none !important;
}
/*  (31/08/2026, demande explicite Didier -- test reel Mac 15 pouces,
   Firefox et Safari) : sur petit ecran, la collision legende/icones vs
   oeuvre apparaissait deja au PREMIER agrandissement (Etat 1), pas
   seulement au grand zoom (Etat 2). Nouvelle classe rv-icons-hidden,
   dediee UNIQUEMENT a l'affichage des icones/legende -- ne pilote ni le
   pan (reserve au grand zoom, INCHANGE) ni getSafeRect (INCHANGE).
   Volontairement separee de rv-detail-zoom pour ne pas activer par effet
   de bord le pan ou la zone sure du grand zoom au premier agrandissement. */
body.rv-icons-hidden .control-block,
body.rv-icons-hidden .legend-popup,
body.rv-icons-hidden #legend {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  transition: none !important;
}
body.rv-icons-hidden .control-block *,
body.rv-icons-hidden .legend-popup *,
body.rv-icons-hidden #legend * {
  pointer-events: none !important;
}

/* v191 : sur tactile uniquement, pendant le dezoom, a scale <= 1.15,
   seule la commande Retour a Works (X) redevient visible. Les autres
   commandes restent masquees jusqu'au retour complet a scale 1.00. */
body.rv-icons-hidden.rv-cross-only .control-block {
  opacity: 1 !important;
  visibility: visible !important;
  pointer-events: none !important;
}
body.rv-icons-hidden.rv-cross-only .control-block * {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}
body.rv-icons-hidden.rv-cross-only .control-block #btn-works {
  opacity: 1 !important;
  visibility: visible !important;
  pointer-events: auto !important;
}
body.rv-icons-hidden.rv-cross-only .control-block #btn-works * {
  opacity: 1 !important;
  visibility: visible !important;
  pointer-events: auto !important;
}
/*  (point C/D, voile bleu Firefox, 01/09/2026) : hypothese retenue
   apres recherche web -- une selection de texte native, annulee mais
   jamais redessinee par Firefox (bug Mozilla documente), laisse
   subsister un voile bleu residuel. Interdiction etendue a l'ensemble
   du conteneur du viewer (#diaporama-view), plus large que l'image
   seule, active dès l'Etat 1 (rv-icons-hidden) et non seulement au
   grand zoom (rv-detail-zoom) -- couvre les deux etats d'agrandissement.
   Verifie : aucune regle user-select n'existait auparavant dans ce
   fichier, malgre une note anterieure qui presupposait son existence
   sur l'image seule -- corrige a cette occasion. */
body.rv-icons-hidden #diaporama-view,
body.rv-detail-zoom #diaporama-view {
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}

.rv-viewport-reconfig .swiper-slide img { opacity: 0 !important; }
.swiper-slide img {
    /*  (30/08/2026, decision Tampon E, point 5 et point 8) :
       REFONTE du mecanisme de transform. Auparavant chaque profil
       ecrivait sa propre regle "transform: ..." complete et exclusive,
       ce qui empechait de superposer proprement une correction
       anti-collision dynamique (point 5) et le zoom au pincement
       (point 8) par-dessus le positionnement de base. Desormais : UNE
       SEULE regle de transform, ici, qui combine trois couches via des
       proprietes CSS personnalisees --
         1. --rv-base-x / --rv-base-y : positionnement de base fixe,
            propre a chaque profil ;
         2. --rv-collision-x / --rv-collision-y : correction dynamique
            calculee en JS (prepareImageGeometry()) qui mesure reellement
            le chevauchement entre l'oeuvre affichee et les zones
            reservees (legende, bloc d'icones) et decale l'oeuvre du
            minimum necessaire pour l'eviter -- remplace l'ancien
            mecanisme a seuil fixe par format,
            portrait uniquement) par une regle qui s'applique
            automatiquement a TOUS les supports et orientations, oeuvre
            par oeuvre, sans seuil en cm (decision Tampon E, point 5) ;
         3. --rv-zoom-x / --rv-zoom-y / --rv-zoom-scale : zoom au
            pincement et glisser-deplacer mobile (point 8, voir JS).
       Valeur par defaut (var(...,0px) / 1) neutre si une couche n'est
       pas utilisee sur un profil donne -- aucun effet si aucune des
       trois n'est definie, comportement strictement identique a avant. */
    /*  : ordre des transformations corrige.
       La translation de pan doit etre appliquee AVANT le scale dans la
       liste CSS afin qu'elle reste une translation visuelle en pixels et
       ne soit pas elle-meme multipliee par l'echelle. */
    transform:
      translate(calc(var(--rv-base-x, 0px) + var(--rv-collision-x, 0px)), calc(var(--rv-base-y, 0px) + var(--rv-collision-y, 0px)))
      translate(var(--rv-zoom-x, 0px), var(--rv-zoom-y, 0px))
      scale(var(--rv-zoom-scale, 1));
    /*  (correction, decision Didier) : indice visuel du zoom/deplacement.
       Etat normal -- loupe (invite au clic). Zoomee -- main ouverte (invite
       au glisser). En cours de glisser -- main fermee. Classes posees/
       retirees en JS (voir rvToggleClickZoom, pointerdown/
       endPointer plus bas). */
    cursor: zoom-in;
    -webkit-user-drag: none;
    user-drag: none;
    max-width: 92vw;
    /*  : vh -> svh. #app utilise deja 100svh (corrige en ) mais
       l'image restait en 90vh (viewport instable sur mobile Android,
       recalcule differemment du svh pendant/apres la barre d'adresse
       qui apparait/disparait a la rotation) -- decalage d'unite entre
       conteneur et image identifie comme cause probable du filet blanc
       residuel apres rotation portrait->paysage sur mobile (diagnostic
       externe convergent, deux IA consultees le 16 aout). */
    max-height: 90svh;
    width: auto;
    height: auto;
    object-fit: contain;
    display: block;
    /* Opacite de depart fixee en ligne sur chaque <img>, voir
       renderSlideContent() -- apparition d'un coup une fois chargee. */
    transition: opacity 0.25s ease;
  }
  /* On masque les flèches natives Swiper : la navigation passe désormais
     exclusivement par le bloc de commandes centralisé en bas d'écran. */
  .swiper-button-prev, .swiper-button-next { display: none !important; }

  /*  (30/08/2026, decision Tampon E, point 7) : micro-animation de
     suggestion de balayage, mobile et tablette uniquement, jouee une
     seule fois via marqueur local (voir JS, maybePlaySwipeHint()).
     Applique sur .swiper-slide (pas sur l'image elle-meme) pour ne
     jamais entrer en conflit avec les nombreux reglages de transform
     deja en place sur .swiper-slide img selon le profil. Option
     principale retenue : leger glissement de l'oeuvre suivi d'un retour
     discret a sa position. */
  @keyframes swipe-hint {
    0%   { transform: translateX(0); }
    30%  { transform: translateX(-18px); }
    60%  { transform: translateX(4px); }
    100% { transform: translateX(0); }
  }
  .swiper-slide.swipe-hint-play { animation: swipe-hint 900ms ease-in-out; }

  /* ============ BLOC DE COMMANDES (marge droite, remonté) ============ */
  /* Retour à un positionnement dans la marge droite de l'écran (comme
     l'ancien viewer), mais remonté (bottom: 14svh au lieu de collé en bas)
     pour ne plus mordre sur l'œuvre, et icônes resserrées (gap 26px -> 14px).
     v153 : vh -> svh. Meme correctif que celui applique a l'image le 16
     aout (voir plus haut) mais qui n'avait pas ete etendu ici -- unite
     "vh" ordinaire suit la hauteur reelle du navigateur (qui varie quand
     la barre d'outils tablette se retracte/reapparait), alors que #app et
     l'image restent callees sur la petite valeur figee (svh). Diagnostic
     chiffre sur onze captures ?debug=1 tablette (07/09/2026, fiche
     dediee) : le bloc icones/legende se decalait seul, donnant une
     impression de decentrage global bien que l'image, elle, ne bougeait
     jamais. Meme correctif applique ligne ~610, ~640 (mobile) et ~776
     (tablette portrait). */
  /* v163-CORRECTIF (08/09/2026, dysfonctionnement persistant confirme
     sur tablette apres retrait de l'ecriture #app en v162) : verifie
     dans le code que #app n'est plus jamais ecrit dynamiquement (zero
     occurrence de "appEl.style.height" hors commentaires) -- le
     deplacement observe des icones n'est donc plus explicable par mon
     propre JS. Cause plus probable : #app est cale sur 100svh, et cette
     unite peut elle-meme se recalculer cote navigateur (rotation,
     transition plein ecran, passage grille) independamment de tout code
     ecrit ici -- observe dans les traces (appH variant sans aucune
     ecriture JS correspondante). Plutot que de continuer a chasser cette
     valeur, on supprime la dependance : .control-block passe de
     position:absolute (relatif a #app, donc a la merci de toute
     variation de #app quelle qu'en soit la cause) a position:fixed
     (relatif directement au vrai viewport de l'appareil, jamais a #app).
     Verifie : aucun ancetre (#app, #diaporama-view) ne porte de
     transform/filter/perspective qui creerait un containing block
     different du viewport reel pour un descendant fixed. La version
     grille (#grid-view .control-block) utilise deja position:fixed en
     ligne dans le HTML, donc strictement inchangee par ce correctif. */
  .control-block {
    position: fixed;
    right: 3vw;
    bottom: 14svh;
    z-index: 20;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    color: #1a1a1a;
  }
  /*  (corrige sur demande de Didier) : rangee du haut (grille/retour
     aux oeuvres), alignee a DROITE au-dessus de la rangee du bas
     (precedent/suivant/lecture-pause), tout le bloc restant cale sur le
     bord droit comme avant, sans centrage flottant. Corrige le
     chevauchement icone/oeuvre sur les toiles tres larges en PC, sans
     toucher a la taille ni au centrage des images (voir ). */
  .icon-row-top {
    gap: 12px;
  }

  /* Rangée des 4 icônes, toujours présente, en diaporama comme en grille */
  .icon-row {
    display: flex;
    align-items: center;
    gap: 12px; /*  : reduit de 14px a 12px sur demande de Didier, pour resserrer
       les icones (PC et par heritage tablette), notamment l'ecart entre
       les fleches precedent/suivant qui empietait sur les oeuvres tres larges */
    pointer-events: auto;
  }
  .icon-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: #1a1a1a;
    opacity: 0.4;
    transition: opacity 0.2s;
  }
  .icon-btn:hover { opacity: 0.95; }
  .icon-btn svg { width: 100%; height: 100%; display: block; }

  /*  : bouton legende masque par defaut (desktop) -- n'apparait
     qu'en mobile, voir media query plus bas. Sur desktop la legende
     reste affichee en permanence comme avant, sans changement. */
  #btn-legend { display: none; }

  /* Bloc signalétique : une ligne par information, centré, texte discret */
  .legend {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    pointer-events: none;
  }
  .legend .code { font-size: 13px; letter-spacing: 0.06em; font-weight: 600; line-height: 1.5; }
  .legend .technique { font-size: 11px; letter-spacing: 0.04em; opacity: 0.75; line-height: 1.5; }
  .legend .serie { font-size: 9px; letter-spacing: 0.04em; opacity: 0.6; line-height: 1.5; }
  .legend .dimyear { font-size: 11px; letter-spacing: 0.04em; opacity: 0.75; line-height: 1.5; }
  .legend .year { font-size: 11px; letter-spacing: 0.04em; opacity: 0.75; line-height: 1.5; }
  /*  : le conteneur .legend-popup n'a volontairement AUCUNE regle ici
     (hors media query) : sur desktop il reste un simple bloc neutre qui
     enveloppe .legend sans modifier son affichage permanent existant.
     Toutes les regles de pop-up (positionnement, fond, transition) sont
     definies exclusivement dans @media (max-width:600px) plus bas. */


  /* Indicateur de chargement discret */
  .loading-indicator {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #999;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 11px;
    letter-spacing: 0.1em;
    z-index: 5;
  }

  /* ============ VUE GRILLE ============ */
  #grid-view {
    position: absolute;
    inset: 0;
    background: #ffffff;
    overflow-y: auto;
    display: none;
    padding: 6vh 12vw 16vh 12vw;
  }
  #grid-view.active { display: block; }
  /*  (03/09/2026, decision validee avec Didier -- discussion croix vs
     hamburger) : la croix de fermeture de la grille (#btn-grid-back)
     partageait jusqu'ici .control-block avec le diaporama, positionnee
     en bas a droite -- peu visible, Marc mettait jusqu'a 20 secondes a
     la trouver. Hamburger explicitement ecarte (sobriete du site,
     coherence avec la fleche retour deja claire sur les oeuvres
     individuelles). Decision retenue : remonter la croix en haut a
     droite, uniquement dans la grille (le control-block du diaporama,
     lui, reste en bas a droite, inchange). Le bloc grille utilise deja
     un style="position:fixed" en ligne dans le HTML -- cible via
     #grid-view .control-block pour ne toucher que ce contexte precis. */
  #grid-view .control-block {
    top: calc(4vh - 3px);
    bottom: auto;
    right: 4vw;
  }
  /* v124-CORRECTIF (point 5, decision validee avec Didier) : croix remontee
     de 3px et agrandie a 34px (au lieu de 32px). Selection a specificite
     superieure aux regles generiques 28px/32px par breakpoint (deux ID
     contre un) : s'applique uniformement dans tous les contextes tactiles,
     sans toucher aux autres icones (le seul bouton de #grid-view
     .control-block est #btn-grid-back, voir HTML). */
  #grid-view .control-block #btn-grid-back {
    width: 34px;
    height: 34px;
  }
  #grid-view .control-block #btn-grid-back svg {
    width: 26px;
    height: 26px;
  }
  #diaporama-view.hidden { display: none; }

  /* Disposition sobre façon Jérôme Boutterin : 3 colonnes fixes,
     vignettes réduites et marges généreuses pour compenser la puissance
     visuelle des toiles de Marc (plus chargées que les œuvres de référence). */
  .grid-wrap {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    column-gap: 7vw;
    row-gap: 10vh;
    max-width: 1200px;
    margin: 0 auto;
  }
  .grid-item {
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center; /*  : centre les vignettes verticalement dans
      leur case, PC et mobile -- repartit l'espace blanc en haut et en bas
      au lieu de le concentrer en bas (alignement par defaut du haut) */
  }
  .grid-item .g-imgwrap {
    display: inline-block;
    max-width: 100%;
    line-height: 0;
    margin-bottom: 12px; /*  : gap retire du conteneur flex (etait
      applique aussi entre technique et dimension) -- reporte ici pour
      garder l'espacement image/texte, sans espace entre les deux lignes
      de texte (demande Didier 01/09/2026) */
  }
  .grid-item img {
    display: block;
    max-width: 100%;
    max-height: 32vh;
    width: auto;
    height: auto;
    object-fit: contain;
    background: #ffffff;
    transition: opacity 0.2s;
  }
  .grid-item:hover img { opacity: 0.75; }
  .grid-item .g-code {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 12px;
    font-weight: 400; /*  : gras retire (demande Didier 01/09/2026) */
    letter-spacing: 0.05em;
    color: #1a1a1a;
    opacity: 0;
    text-align: center;
    line-height: 1.3;
    margin: 0;
    transition: opacity 0.2s;
  }
  /*  : ligne technique, jumelle de .g-code, affichee au-dessus des
     dimensions dans le HTML (voir buildGrid()) -- taille rapprochee de
     celle des dimensions (agrandie depuis ), sans gras, et sans
     espace vertical avec la ligne des dimensions (demande Didier,
     01/09/2026). */
  .grid-item .g-technique {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0.04em;
    color: #1a1a1a;
    opacity: 0;
    text-align: center;
    line-height: 1.3;
    margin: 0;
    transition: opacity 0.2s;
  }
  .grid-item:hover .g-code { opacity: 0.85; }
  .grid-item:hover .g-technique { opacity: 0.7; }
  .grid-item.current .g-imgwrap { box-shadow: 0 2px 6px rgba(0,0,0,0.35); }
  .grid-item.current .g-code { opacity: 0.85; }
  .grid-item.current .g-technique { opacity: 0.7; }

  .grid-title {
    text-align: center;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 20px;
    letter-spacing: 0.1em;
    color: #1a1a1a;
    opacity: 0.6;
    margin-bottom: calc(4vh + 19px);
    text-transform: uppercase;
  }
  /* v5 : mot Series plus petit que le nom de la serie ; annees centrees dessous. */
  .grid-title .gt-suffix { font-size: 0.6em; letter-spacing: 0.1em; }
  .grid-title .gt-years {
    display: block;
    margin-top: 8px;
    font-size: 14px;
    letter-spacing: 0.08em;
    text-transform: none;
  }

  /* ============ CORRECTIFS MOBILE (->) ============
     N'affecte que les ecrans mobile, portrait ET paysage ( : condition
     etendue a (max-height:500px) and (orientation:landscape), en plus de
     (max-width:600px), pour couvrir aussi le paysage telephone --  ne
     couvrait que le portrait, incoherence relevee par Didier et Marc).
     Aucune regle desktop (PC) n'est modifiee par ce bloc. */
  @media (max-width: 600px), (max-height: 500px) and (orientation: landscape) {
    /*  : MOBILE UNIQUEMENT. Ecart des icones remis a 14px (au lieu des
       12px desormais appliques sur PC et tablette), doigt moins precis
       sur petit ecran -- prudence demandee explicitement par Didier. */
    .icon-row { gap: 14px; }
    .grid-wrap {
      grid-template-columns: repeat(2, 1fr);
      column-gap: 6vw;
      row-gap: 6vh;
      max-width: 100%;
    }
    .grid-item img { max-height: 24vh; }
    #grid-view { padding: 5vh 6vw 14vh 6vw; }

    html, body, #app { overflow-x: hidden; }

    /*  : REGRESSION  CORRIGEE. L'agrandissement symetrique (marge
       auto des deux cotes) cassait l'equilibre apprecie par Didier, qui
       gardait une marge fixe et minimale a droite (~1mm). Ici : la
       diapositive pousse l'image contre le bord droit (justify-content:
       flex-end) avec une marge fixe tres fine, et l'espace recupere par
       l'agrandissement se loge exclusivement a gauche. Leger recentrage
       vertical (~0.5cm vers le haut) en complement. */
    /* CORRECTIF (14 aout 2026, suite constat sur device reel) : la regle
       precedente utilisait justify-content: flex-end, qui pousse le
       contenu vers la DROITE du conteneur flex -- sens invalide, exact
       oppose de l'effet recherche. Corrige : flex-start pousse le contenu
       vers la gauche, laissant la marge fixe minimale a droite comme
       voulu, et l'espace recupere par l'agrandissement se loge bien a
       gauche. */
    /*  : abandon du bricolage a base de marges fixes asymetriques
       (flex-start + marge fixe a droite), impossible a caler precisement
       a l'aveugle (ecarts de 1-2mm non pilotables sans retour visuel).
       Reprise d'un centrage automatique strict, identique dans son
       principe a celui du bloc tablette portrait ci-dessous. */
    .swiper-slide { justify-content: center; }
    .swiper-slide img {
      max-width: 96vw;
      /*  : margin-left/right:auto retire -- redondant avec le centrage
         flexbox deja assure par justify-content:center sur .swiper-slide
         (regle de base). Empiler les deux mecanismes etait une des causes
         identifiees de l'instabilite chronique du recentrage horizontal.
         Un seul mecanisme desormais : le flexbox pur. */
      /*  : cm -> px. Unite cm potentiellement recalculee differemment
         selon le devicePixelRatio rapporte par le navigateur au moment
         de la rotation (diagnostic externe) -- remplacee par une unite
         fixe (reference pixel CSS), insensible a ce recalcul.
         -0.5cm = -18.9px, 0.5cm = 18.9px, arrondis a 19px. */
      margin-top: -19px;
      margin-bottom: 19px;
      /*  (30/08/2026) : ANCIEN PIEGE DEVENU STRUCTURELLEMENT IMPOSSIBLE.
         L'ancien mecanisme (chaque profil ecrivait sa propre regle
         "transform" complete et exclusive) pouvait laisser un bloc sans
         regle transform propre HERITER du translateX(-0.5cm) reserve au
         PC (bug corrige puis reintroduit deux fois,  et  -- voir
         historique en-tete de fichier). Le nouveau systeme (voir regle de
         base .swiper-slide img, non-media) compose le transform final a
         partir de proprietes CSS personnalisees (--rv-base-x/y) definies
         UNIQUEMENT dans la media query active pour la largeur d'ecran
         courante : mobile (<=600px) et PC (>=1451px) ne sont jamais actifs
         simultanement, donc plus aucun risque d'heritage croise, meme par
         erreur future. Valeurs neutres explicites ci-dessous, strictement
         equivalentes a l'ancien "transform: none". */
      --rv-base-x: 0px;
      --rv-base-y: 0px;
      /*  (decision Tampon E, point 8) : empeche le navigateur
         d'intercepter le pincement/deplacement nativement (zoom systeme
         non fluide, hors de tout controle) -- le geste est desormais
         gere entierement par le script de zoom/pan dedie, voir JS. */
      touch-action: none;
    }

    /*  (30/08/2026, decision Tampon E, point 1 et structure mobile) :
       le clic sur l'oeuvre n'activant plus l'autoplay, l'icone autoplay
       (#btn-playpause) redescend au niveau des 3 autres icones -- elle
       redevient visible, seuls precedent/suivant restent masques
       (redondants avec le glisser tactile). Masquage de prev/next
       renforce par !important (couvre mobile portrait ET paysage) --
       historique du renfort deja documente /, cause residuelle
       exterieure a chercher cote Elementor/theme si persistante. */
    #btn-prev, #btn-next { display: none !important; }
    /*  : icones et legende agrandies d'environ 25% (26px -> 32px),
       espace liberе par le retrait des icones de navigation. */
    #btn-legend, #btn-grid-back, #btn-grid-works { display: flex; width: 28px; height: 28px; }
    #btn-grid, #btn-works, #btn-grid-back, #btn-grid-works, #btn-playpause { width: 28px; height: 28px; }
    /*  : icone info (i) legerement agrandie par rapport aux 3 autres
       (decision point 3, "legerement agrandie pour une meilleure
       identification") -- [A CONFIRMER PAR DIDIER] sur appareil reel,
       ecart choisi modeste (28px -> 30px) pour rester coherent avec le
       reste du bloc. */
    #btn-legend { width: 30px; height: 30px; }
    /*  : ordre des 4 icones mobile (decision Tampon E, structure des
       icones, 30/08/2026) -- i, autoplay, grille, retour, dans cet ordre,
       quelle que soit l'orientation. L'ordre DOM reel (legend, grid,
       works, prev, next, playpause) ne correspond plus a cet ordre visuel
       depuis que playpause redevient visible : pilote ici via la
       propriete CSS "order" plutot qu'une reorganisation du HTML, pour ne
       pas toucher aux gestionnaires d'evenements JS existants. */
    #btn-legend { order: 1; }
    #btn-playpause { order: 2; }
    #btn-grid { order: 3; }
    #btn-works { order: 4; }
    /*  : ERREUR CORRIGEE. La disposition a deux rangees (icon-row-top
       / icon-row) demandee par Didier en  concernait UNIQUEMENT le PC
       et la tablette -- la restructuration HTML etant partagee entre tous
       les appareils, elle s'est appliquee par erreur aussi sur mobile,
       faisant paraitre les icones anormalement basses (signale par
       Didier). Correctif MOBILE UNIQUEMENT : les deux conteneurs de
       rangee sont neutralises visuellement (display:contents, ils
       disparaissent de l'arbre de mise en page mais leurs boutons
       restent), et .control-block repasse en ligne (flex-direction:row)
       pour ce seul contexte -- retour a une seule ligne d'icones, comme
       avant la , sans toucher au PC ni a la tablette. */
    .control-block {
      flex-direction: row;
      align-items: center;
      gap: 16px;
    }
    .icon-row-top, .icon-row {
      display: contents;
    }
    /*  : regles opacity #btn-prev/#btn-next retirees -- ces boutons
       sont maintenant en display:none sur mobile (voir plus haut). */

    /*  : marge de securite de la rangee d'icones face aux formats
       tres en hauteur (complement du recentrage vertical de l'image
       ci-dessus), et leger decalage vers la gauche pour redonner ~3mm
       de marge a l'icone maison par rapport au bord de l'ecran. */
    .control-block {
      /*  : REMONTEE ET DECALAGE, demande de Didier -- desormais une
         seule ligne compacte de 3 icones seulement (au lieu de 7 sur
         plusieurs rangees), il n'est plus necessaire de la coller au bord
         de l'ecran comme avant. Remontee de 2vh a 5vh, et decalage vers
         l'interieur (calc(3vw+3mm) -> calc(4vw+5mm)) pour qu'elle respire
         un peu par rapport au bord droit. */
      right: 5vw;
      bottom: 5svh;
    }

    /*  : legende pop-up repositionnee independamment du control-block,
       en bas a gauche de l'ecran au meme niveau que la rangee d'icones --
       evite toute superposition avec l'oeuvre sur les formats tres en
       hauteur. Cadre resserre au plus pres du texte. Fond blanc
       semi-transparent avec flou conserve (). */
    .legend-popup {
      position: fixed; /*  : fixed au lieu de absolute, car le parent
         .control-block est ancre a droite (right) -- un positionnement
         absolute heritait de ce contexte et annulait le "left" voulu.
         "fixed" ancre desormais le pop-up par rapport a l'ecran entier,
         independamment de son parent, ce qui garantit le "left" reel. */
      /*  : bottom descendu de 12.5vh a 8vh, sur demande de Didier/Marc --
         la boite (padding + texte) faisait paraitre la legende plus haute
         que les icones malgre une meme valeur "bottom" nominale ; objectif
         est d'aligner visuellement le bas de la legende sur le bas des
         icones pour degager le maximum d'espace sur les oeuvres tres
         hautes (ex. formats 150x100, 180x140). Un leger empietement sur
         ces formats extremes reste accepte par Didier. */
      left: 3vw;
      /*  : descendu legerement (8vh -> 5vh) sur demande de Didier --
         sur les toiles tres hautes, la pop-up chevauchait trop l'oeuvre
         (seuls ~9mm hors de la toile). Ajustement modeste et prudent :
         le bug qui faisait completement disparaitre la pop-up hors-ecran
         (100vh mobile, ) est maintenant corrige, ce qui donne de la
         marge pour descendre encore un peu sans risquer la disparition
         totale rencontree precedemment. A reverifier par Didier sur
         l'oeuvre tres haute concernee. */
      bottom: 5svh;
      right: auto;
      z-index: 25;
      background: rgba(255, 255, 255, 0.88);
      backdrop-filter: blur(6px);
      -webkit-backdrop-filter: blur(6px);
      padding: 8px 12px;
      border-radius: 2px;
      box-shadow: 0 2px 14px rgba(0,0,0,0.12);
      width: fit-content;
      max-width: 58vw;
      opacity: 0;
      visibility: hidden;
      transform: translateY(6px);
      transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s;
      pointer-events: none;
    }
    .legend-popup.visible {
      opacity: 1;
      visibility: visible;
      transform: translateY(0);
      pointer-events: auto;
    }
    .legend { align-items: flex-start; text-align: left; }
    /*  : legende agrandie d'environ 25% (13px/11px -> 16px/14px),
       demande de Didier -- pas assez lisible en comparaison des sites
       de reference. */
    .legend .code { font-size: 18px; }
    .legend .technique, .legend .dimyear, .legend .year { font-size: 16px; }
    .legend .serie { font-size: 13px; }
  }

  /* ---- MOBILE PAYSAGE (specifique) ---- */
  /* Hauteur d'ecran <=500px, orientation paysage. Rehausse la taille
     reelle des vignettes de grille par rapport au bloc combine
     (equivalent visuel au portrait), et applique des marges verticales
     propres au paysage (image legerement remontee et decalee). Aucune
     regle prev/next/playpause ici : ce bloc herite du masquage deja
     renforce (!important) du bloc mobile combine ci-dessus. transform:
     none explicite, meme piege que documente en en-tete. */
  @media (max-height: 500px) and (orientation: landscape) {
    .grid-item img { max-height: 48vh; }
    .swiper-slide img {
      /*  : CORRECTIF  ANNULE. La  utilisait object-fit:cover, qui
         rogne l'oeuvre pour remplir l'ecran -- INACCEPTABLE, constate par
         Didier sur capture d'ecran reelle (oeuvre gravement coupee).
         L'oeuvre entiere doit toujours rester visible. Retour a
         object-fit:contain, avec le meme principe que le correctif
         tablette paysage valide juste apres : marge fixe de 2mm (8px,
         unite fixe insensible au recalcul devicePixelRatio a la
         rotation) en haut et en bas, l'oeuvre occupant tout le reste de
         l'espace vertical SANS jamais etre rognee. */
      /*  (01/09/2026) : max-height/max-width en couple (au lieu de
         height explicite + width:auto) -- seule methode qui resout
         correctement les DEUX contraintes ensemble pour tout ratio,
         y compris les formats tres allonges/panoramiques identifies en
         regression par Didier (captures d'ecran, 01/09/2026). */
      max-height: calc(100% - 16px);
      max-width: 100%;
      width: auto;
      height: auto;
      margin-top: 8px;
      margin-bottom: 8px;
      object-fit: contain;
      /*  : voir note du bloc mobile combine ci-dessus (nouveau systeme
         de transform compose, plus aucun risque d'heritage PC). */
      --rv-base-x: 0px;
      --rv-base-y: 0px;
    }
    /*  (30/08/2026, decision Tampon E, structure des icones) : en
       mobile paysage uniquement, le bloc des 3 icones fonctionnelles
       (autoplay, grille, retour) est decale vers la droite d'environ
       4 a 5mm par rapport au i, sans resserrement entre elles -- une
       marge est ajoutee uniquement avant la premiere des 3 (playpause,
       #btn-playpause a l'ordre 2), ce qui deplace le groupe entier sans
       toucher au gap qui les separe. 17px ~= 4.5mm. Le mobile portrait
       n'est pas concerne (regle absente de son bloc, plus haut).
       [A CONFIRMER PAR DIDIER] valeur non mesuree sur appareil reel. */
    #btn-playpause { margin-left: 17px; }
  }

  /*  : bloc de compensation translateX mobile portrait () RETIRE.
     Diagnostic pose le 15 aout 2026 : la valeur -1.75mm etait une
     compensation devinee par le calcul, empilee sur un centrage flexbox
     deja en principe exact, elle-meme empilee sur une marge auto
     redondante -- accumulation de mecanismes contradictoires identifiee
     comme cause probable de l'instabilite chronique du recentrage.
     Solution radicale : un seul mecanisme (flexbox pur, voir regle de
     base .swiper-slide), sans aucune compensation. Si un ecart persiste
     malgre ce nettoyage, la cause ne sera plus une erreur de code mais un
     facteur physique de l'appareil (encoche, zone de securite, barre de
     navigateur), a diagnostiquer alors via capture d'ecran precise plutot
     que par description verbale en millimetres. */

  /* ==========================================================================
     BLOC TABLETTE (ajoute le 14 aout 2026, ) -- couvre les largeurs d'ecran
     logiques entre 601px et 1300px, non couvertes ni par le bloc PC (regles
     generales) ni par le bloc mobile ci-dessus (<=600px). Portrait et
     paysage traites separement. AUCUNE regle PC ni mobile n'est modifiee
     ou supprimee par ce bloc : ajout pur d'un troisieme profil independant.
     Reference terrain : Samsung Galaxy Tab S11 (largeur logique ~800px
     portrait, ~1200px paysage), plage choisie pour couvrir les tablettes
     courantes en general. */

  /* ---- TABLETTE PORTRAIT ---- */
  @media (min-width: 601px) and (max-width: 1450px) and (orientation: portrait) {

    /* Recentrage horizontal (mesure terrain Galaxy Tab S11+, ) +
       remontee verticale (demande distincte, conservee). Flexbox pur
       sur l'axe horizontal (regle de base .swiper-slide), aucune
       compensation empilee -- voir piege documente en en-tete. */
    .swiper-slide { justify-content: center; }
    .swiper-slide img {
      max-width: 97.6vw;
      max-height: 78vh;
      --rv-base-y: 0px;
    }
    /*  : aucune reduction CSS supplementaire sur tablette portrait.
       Les formats verticaux sont adaptes par la geometrie JS, avec priorite
       au deplacement vertical et plancher de 70% du viewer si une reduction
       devient reellement inevitable. */
    /*  (30/08/2026, decision Tampon E, point 5) : REGLE ABSOLUE DE
       PLEIN ECRAN SANS COLLISION. L'ancien mecanisme a seuil fixe
       (ancien seuil de format) est retire ici :
       aucune oeuvre n'est classee par seuil de ratio. La geometrie JS
       mesure directement la place disponible et la zone fonctionnelle,
       puis applique uniquement la correction necessaire. [A CONFIRMER
       PAR DIDIER] : mecanisme de mesure reelle, mais jamais teste sur
       appareil physique dans cette session (pas d'acces navigateur/
       mobile reel en environnement de developpement) -- a valider
       imperativement au premier essai, en particulier sur les 14
       oeuvres au format tres haut deja identifiees. */

    /* Bloc icones + legende descendu solidairement (correction historique
        : ne plus toucher a .legend isolement, toujours descendre le
       parent .control-block dans son ensemble). */
    .control-block {
      bottom: 2svh;
      right: calc(3vw + 4mm);
    }

    /*  (30/08/2026, decision Tampon E, structure des icones) :
       tablette portrait -- 3 icones en haut UNIQUEMENT (autoplay, grille,
       retour), pas de precedent/suivant (navigation par glissement,
       comme mobile). Auparavant #btn-playpause etait masque avec
       prev/next ; il redevient visible et rejoint la ligne du haut.
       Meme technique de mise a plat que mobile (icon-row-top/icon-row en
       display:contents, .control-block repasse en ligne) pour fusionner
       les deux rangees HTML en une seule ligne visuelle, sans toucher au
       HTML ni aux gestionnaires JS. */
    #btn-prev, #btn-next { display: none !important; }
    /*  : sur tablette portrait, les informations technique/dimensions
       sont deja visibles dans la legende ; l'icone info est donc inutile. */
    body.rv-touch #btn-legend { display: none !important; }
    /*  (01/09/2026, demande Didier) : icones jugees un peu petites,
       agrandies de 28px a 32px. */
    #btn-legend, #btn-grid, #btn-works, #btn-grid-back, #btn-grid-works, #btn-playpause { width: 32px; height: 32px; }
    /*  (correction regression, demande Didier 01/09/2026) : la 
       mettait .control-block en flex-direction:row, ce qui placait la
       legende-popup (item flex a part entiere, jamais transformee en
       "contents") a cote de la rangee d'icones -- deux blocs cote a
       cote au lieu d'une seule colonne. Corrige via la technique
       flex-wrap : rangee (row) + wrap, et legend-popup force en
       flex-basis:100% pour toujours passer a la ligne suivante, sous
       les icones, sans jamais se retrouver a cote d'elles. */
    .control-block {
      flex-direction: row;
      flex-wrap: wrap;
      justify-content: flex-end;
      align-items: center;
      /*  : icones rapprochees de la ligne de reference, espace
         superflu reduit par rapport au gap vertical d'origine (10px) --
         [A CONFIRMER PAR DIDIER] valeur non mesuree sur appareil reel. */
      gap: 10px;
    }
    .icon-row-top, .icon-row {
      display: contents;
    }
    /*  : ordre visuel autoplay, grille, retour -- #btn-legend (i)
       n'existe pas sur ce profil (reste display:none, regle de base). */
    #btn-playpause { order: 1; }
    #btn-grid { order: 2; }
    #btn-works { order: 3; }
    /*  : legende toujours en derniere position visuelle, sur sa
       propre ligne (flex-basis:100%, voir commentaire ci-dessus). */
    .legend-popup {
      order: 4;
      flex-basis: 100%;
      display: flex;
      justify-content: flex-end;
      margin-top: 4px;
    }
    .legend { align-items: flex-end; text-align: right; }
    .legend .code { font-size: 18px; }
    .legend .technique, .legend .dimyear, .legend .year { font-size: 16px; }
    .legend .serie { font-size: 13px; }

    /*  (01/09/2026, demande Didier) : marges exterieures #grid-view
       (heritees de la regle de base 12vw ~2,5-3cm sur ce gabarit, jugees
       trop larges) reduites a ~5,5vw (~1-1,5cm sur les largeurs tablette
       portrait usuelles). Column-gap/row-gap (ecart ENTRE les oeuvres)
       volontairement INCHANGES -- seul l'espace gagne sur les marges
       exterieures est reattribue a l'agrandissement des vignettes
       (max-height 30vh -> 34vh). */
    #grid-view {
      padding: 6vh 5.5vw 16vh 5.5vw;
    }
    .grid-wrap {
      grid-template-columns: repeat(3, 1fr);
      column-gap: 4vw;
      row-gap: 5vh;
      max-width: 100%;
    }
    .grid-item img { max-height: 34vh; }
  }

  /* ================================================================
     PROFILS D'INTERACTION -- 
     La largeur du viewport ne determine JAMAIS le profil PC/tactile.
     Le JavaScript pose body.rv-desktop ou body.rv-touch une seule fois.
     La largeur peut ensuite adapter l'espace disponible, mais ne peut
     jamais transformer un PC/Mac en tablette.
     ================================================================ */

  /* PACKAGE PC COMPLET -- identique quelle que soit la largeur de la
     fenetre (plein ecran, panneau de favoris ouvert, Mac 15", etc.). */
  body.rv-desktop .swiper-slide img {
    --rv-base-x: -0.5cm;
    margin-right: 0;
    max-height: 90svh;
    height: auto;
    margin-top: 0;
    margin-bottom: 0;
    max-width: 92vw;
  }
  body.rv-desktop .control-block {
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
    right: 3vw;
  }
  body.rv-desktop .icon-row-top,
  body.rv-desktop .icon-row {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  body.rv-desktop #btn-prev,
  body.rv-desktop #btn-next { display: flex; }
  body.rv-desktop #btn-legend { display: none; }
  body.rv-desktop #btn-playpause,
  body.rv-desktop #btn-grid,
  body.rv-desktop #btn-works,
  body.rv-desktop #btn-prev,
  body.rv-desktop #btn-next {
    width: 20px;
    height: 20px;
  }
  body.rv-desktop #btn-playpause,
  body.rv-desktop #btn-grid,
  body.rv-desktop #btn-works { order: initial; }
  body.rv-desktop .legend .code { font-size: 11px; }
  body.rv-desktop .legend .technique,
  body.rv-desktop .legend .dimyear,
  body.rv-desktop .legend .year { font-size: 9px; }
  body.rv-desktop .legend .serie { font-size: 8px; }

  /* TABLETTE PAYSAGE : seules les tablettes tactiles recoivent cette
     présentation. La largeur 900-1450px ne classe donc plus un PC. */
  @media (min-width: 900px) and (max-width: 1450px) and (orientation: landscape) {
    /*  : TABLETTE PAYSAGE -- structure PC-like, mais interaction tactile.
       Les commandes restent fixes a droite. Les icones NE SONT PAS
       supprimees : elles restent sur une seule rangee au-dessus de la
       legende, comme un bloc unique :
       [icones]
       [code]
       [technique]
       [dimensions/annee]
       Les fleches precedent/suivant restent masquees car la navigation
       entre oeuvres se fait par balayage tactile ; l'icone info, lecture,
       grille et retour restent visibles. */
    body.rv-touch .swiper-slide img {
      --rv-base-x: 0px !important;
      /* Paysage tablette : maximum vertical reel avec ~2,3 mm de
         respiration en haut et en bas, sans reduction arbitraire. */
      max-height: calc(100svh - 18px) !important;
    }
    body.rv-touch .control-block {
      flex-direction: row !important;
      flex-wrap: wrap !important;
      align-items: center !important;
      justify-content: flex-end !important;
      gap: 10px !important;
      right: 2.5vw !important;
    }
    body.rv-touch .icon-row-top,
    body.rv-touch .icon-row {
      display: contents !important;
    }
    body.rv-touch #btn-prev,
    body.rv-touch #btn-next {
      display: none !important;
    }
    /*  : tablette paysage -- l'icone information est retiree ; les
       informations sont deja presentes dans la legende. */
    body.rv-touch #btn-legend { display: none !important; }
    body.rv-touch #btn-playpause,
    body.rv-touch #btn-grid,
    body.rv-touch #btn-works {
      display: flex !important;
      width: 28px !important;
      height: 28px !important;
    }
    body.rv-touch #btn-playpause { order: 1 !important; }
    body.rv-touch #btn-grid { order: 2 !important; }
    body.rv-touch #btn-works { order: 3 !important; }

    /* La legende constitue la seconde et unique colonne du bloc. */
    body.rv-touch .legend-popup {
      order: 5 !important;
      flex-basis: 100% !important;
      display: flex !important;
      justify-content: flex-end !important;
      margin-top: 4px !important;
    }
    body.rv-touch .legend {
      align-items: flex-end !important;
      text-align: right !important;
    }
    body.rv-touch .legend .code { font-size: 18px !important; }
    body.rv-touch .legend .technique,
    body.rv-touch .legend .dimyear,
    body.rv-touch .legend .year { font-size: 16px !important; }
    body.rv-touch .legend .serie { font-size: 13px !important; }
  }

  /* PC : aucun media-query de largeur. Le package PC ci-dessus est
     volontairement indépendant de la taille du viewport. */

/* v4 (19/09/2026, SEO) : classe utilitaire .sr-only -- cache visuellement
   un element tout en le laissant lisible par Google et les lecteurs
   d'ecran (accessibilite). Utilisee pour le <h1> invisible ajoute dans
   chaque fragment de serie (titre reel de la page, absent de l'affichage
   visuel du diaporama). Technique standard, aucun impact sur le rendu. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
