/* ===========================================================================
   PAGES INTÉRIEURES — le langage visuel de l'accueil, hors de l'accueil
   ===========================================================================
   POURQUOI CETTE FEUILLE EXISTE.

   L'accueil a son propre vocabulaire — grandes capitales d'affichage, panneaux
   dépolis, gros textes, filets bleus — et il est écrit dans `accueil.css`.
   Or `cda_assets()` ne charge cette feuille QUE sur l'accueil :

       if (is_front_page() || is_home()) { … wp_enqueue_style('cda-accueil') … }

   Aucune classe `ac-*` ne fonctionne donc ailleurs, et c'est la vraie raison
   pour laquelle le catalogue, le contact, la page du peintre et l'espace client
   ressemblaient encore à un autre site : ils n'avaient pas accès au dessin.

   La solution n'est pas de charger `accueil.css` partout. Cette feuille contient
   des règles qui appartiennent au premier écran et qui casseraient les autres
   pages si elles s'y invitaient :

     · `#cda-nav{background:transparent}` — la barre de navigation deviendrait
       illisible dès qu'elle passerait au-dessus d'un texte ;
     · `html{scroll-behavior:auto}` — posé pour neutraliser l'inertie du moteur
       de l'accueil, il n'a pas lieu d'être ailleurs ;
     · `.ac-hero{min-height:100svh}`, le canevas WebGL, le voile de chargement,
       le champ d'œuvres — autant de choses qui n'existent que là-bas.

   On reprend donc le VOCABULAIRE, pas le fichier. Les composants sont réécrits
   ici sous le préfixe `ip-` (« intérieur de page »), ce qui garantit qu'aucun
   sélecteur ne peut entrer en conflit avec `ac-*` si les deux feuilles se
   croisaient un jour.

   AUCUNE DÉPENDANCE AU JAVASCRIPT. `accueil.js` ne tourne pas ici : les
   attributs `data-ac-*` n'auraient aucun effet, et un texte qui attend un
   observateur qui ne viendra jamais reste invisible pour toujours. Les
   apparitions sont donc des animations CSS autonomes, et elles ne masquent
   rien : elles partent d'une opacité nulle mais se déclenchent au chargement,
   pas au défilement. `data-cursor-hover` et `data-magnetic` restent valables —
   ils sont gérés par `site.js`, chargé sur tout le site.
   =========================================================================== */

.ip{
  --ip-bleu:#004aad;
  --ip-papier:#fff;
  --ip-encre:#0d1117;
  --ip-encre-2:#333d48;
  --ip-trait:rgba(13,17,23,.14);

  /* La gouttière et le rythme vertical sont copiés à l'identique sur ceux de
     l'accueil : c'est ce qui fait qu'on passe d'une page à l'autre sans sentir
     de rupture, bien plus que les couleurs ou les polices. */
  --ip-marge:clamp(20px,5vw,110px);
  /* Le rythme vertical. Il valait clamp(96px,14vh,210px) : mesuré sur le
     catalogue, deux sections successives cumulaient alors 210 px de bas et
     96 px de haut, soit plus de trois cents pixels de blanc entre le bandeau
     de garanties et la première œuvre. Un intervalle de cette taille ne se
     lit pas comme une respiration, il se lit comme la fin de la page. */
  --ip-section:clamp(60px,8vh,120px);

  /* Les trois corps de texte. Un seul jeu pour tout le site intérieur : dès
     qu'une page invente sa propre échelle, la cohérence se perd là et nulle
     part ailleurs. */
  --ip-gros:clamp(21px,2.3vw,34px);
  --ip-gros-petit:clamp(18px,1.7vw,24px);
  --ip-suite:clamp(16.5px,1.3vw,19px);

  display:block;
  background:var(--ip-papier);
  color:var(--ip-encre);
  overflow-x:clip;
}

/* Le dégradé d'ambiance — le FOND DE SECOURS, et il n'a pas disparu.
   C'est ce que voit quelqu'un dont le navigateur n'a pas WebGL, dont le
   contexte graphique a été repris par le système, ou qui a demandé qu'on
   réduise les animations. Il reste donc en place, inconditionnel : le
   canevas se pose par-dessus quand il est prêt, jamais l'inverse. */
.ip::before{
  content:'';position:fixed;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(120% 80% at 12% 0%, rgba(0,74,173,.07), transparent 60%),
    radial-gradient(100% 70% at 100% 8%, rgba(61,127,214,.06), transparent 62%);
}
.ip > *{position:relative;z-index:1}

/* ---------------------------------------------------------------------------
   LE FOND DE PIGMENT SUR LES PAGES INTÉRIEURES
   ---------------------------------------------------------------------------
   Le même champ de pigment que l'accueil, à la même force, sur le
   catalogue, le contact, la page du peintre et l'espace client.

   TROIS PRÉCAUTIONS, ET AUCUNE N'EST FACULTATIVE.

   1. LE PAPIER NE DEVIENT TRANSPARENT QU'UNE FOIS LE CANEVAS PRÊT.
      `.cda-fond` dit « cette page a demandé le fond » ; `cda-fond-on`,
      posée par le module WebGL après sa première image, dit « il est
      là ». Seule la seconde retire le blanc. Sans cette distinction, un
      téléphone sans WebGL afficherait du texte sur du vide.

   2. LE CANEVAS EST DERRIÈRE, ET IL NE PREND AUCUN ÉVÉNEMENT.
      z-index 0, pointer-events none : il ne peut ni couvrir un lien ni
      intercepter un geste.

   3. LE TEXTE NE SE POSE JAMAIS DIRECTEMENT SUR LE PIGMENT.
      Un catalogue et un formulaire, ce sont des paragraphes entiers, pas
      un titre de trois mots. Ils vivent donc sur les panneaux — dont le
      voile est renforcé ici, parce qu'un fond animé derrière du texte
      demande plus de couverture qu'un fond fixe.
   --------------------------------------------------------------------------- */
.cda-fond [data-fond]{position:fixed;inset:0;z-index:0;pointer-events:none}
.cda-fond .ac-gl{
  position:fixed;inset:0;width:100%;height:100%;
  pointer-events:none;
  opacity:0;transition:opacity 1.2s ease .2s;
}
.cda-fond [data-fond].ac-gl-on .ac-gl{opacity:1}

/* Le papier s'efface — mais seulement maintenant. */
html.cda-fond-on .ip{background:transparent}
html.cda-fond-on .ip::before{opacity:.35}

/* ═══ LE VOILE DE LISIBILITÉ, ET IL N'EST PAS DÉCORATIF ═══
   Le pigment n'a pas une couleur, il en a une gamme : selon l'endroit de
   l'écran, le fond va de l'écume presque blanche à un bleu de mer soutenu.
   Mesuré sur l'image réellement rendue, un paragraphe d'encre sur les zones
   les plus denses tombait à 4,41:1 — sous le seuil AA de 4,5, et pour du
   texte courant, pas pour un titre.

   Trois réponses possibles, deux mauvaises : éclaircir la palette (le fond
   ne serait plus celui de l'accueil), ou poser un cartouche derrière chaque
   paragraphe (des rectangles partout). La troisième est ce voile — un blanc
   à douze pour cent, fixe, sur toute la page. Il RELÈVE LE PLANCHER de
   luminosité sans toucher aux teintes : les zones claires ne bougent pas,
   les zones denses s'éclaircissent juste assez. Le fond reste celui de
   l'accueil ; c'est la lecture qui gagne la marge qui lui manquait.

   En mode sombre le raisonnement s'inverse : c'est le PLAFOND qu'il faut
   abaisser, donc le voile est sombre. */
/* ═══ LE VOILE PASSE SUR LE CANEVAS, PAS SUR LE CONTENU ═══
   Il était porté par `.ip`, c'est-à-dire par le `<main>` des pages
   intérieures. Deux conséquences, et les deux étaient des défauts :

   · LES FICHES D'ŒUVRE N'ONT PAS DE `.ip` — leur gabarit appelle
     directement le contenu produit. Le voile ne s'y appliquait donc pas,
     et le pigment y aurait été plus vif que partout ailleurs.
   · Douze pour cent de blanc, c'était BEAUCOUP. Ajoutés à la clarté
     locale posée sous les titres, le fond des pages intérieures ne
     ressemblait plus à celui de l'accueil — c'est ce qui se voyait.

   Le voile est donc posé sur le conteneur du canevas lui-même : il suit
   le pigment partout où il existe, quelle que soit la page, et il tombe à
   sept pour cent — assez pour relever le plancher de luminosité des zones
   les plus denses, trop peu pour délaver la matière. */
.cda-fond [data-fond]::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:rgba(255,255,255,.07);
}
html.cda-dark .cda-fond [data-fond]::after{background:rgba(5,7,11,.12)}

/* Le voile des panneaux, renforcé au-dessus d'un fond qui bouge. */
/* Au-dessus du pigment animé, le panneau reste du VERRE : on ne renforce
   plus le voile. C'est justement là qu'il doit laisser passer la matière —
   voir la recette dans site.css, et la mesure dans `essai/verre.js`. */
html.cda-fond-on .ip-panneau,
html.cda-dark.cda-fond-on .ip-panneau{background:var(--cda-verre-lumiere),var(--cda-verre)}

/* LE FLOU D'ARRIÈRE-PLAN DES PANNEAUX EST RETIRÉ SUR CES PAGES.
   `.ip-panneau` portait `backdrop-filter: blur(18px)`. Tant que ce qu'il
   y avait derrière était un dégradé FIXE, le navigateur pouvait garder le
   résultat en cache : le flou ne se calculait qu'une fois. Avec un
   canevas qui se redessine derrière, ce cache ne vaut plus rien — le flou
   doit être refait à chaque image, sur toute la surface du panneau, et
   c'est très exactement la dépense que la page d'accueil s'interdit.
   Un voile plat de même valeur donne le même dessin pour rien. */
html.cda-fond-on .ip-panneau,
html.cda-fond-on .ip-filtres{
  -webkit-backdrop-filter:none;backdrop-filter:none;
}
/* La barre de filtres est COLLANTE : elle est donc repeinte à chaque
   image du défilement. Un flou d'arrière-plan dessus, au-dessus d'un
   canevas qui se redessine, c'est le flou refait soixante fois par
   seconde sur toute sa largeur — le pire des deux mondes.

   Elle avait d'abord reçu un voile plat à la place. C'était encore un
   rectangle opaque en travers de la page, et c'est ce que le client a
   vu : « un énorme rectangle blanc ». Elle n'a donc plus aucun fond du
   tout — ce sont les commandes elles-mêmes qui portent le leur, en
   pastilles. Voir « LA BARRE DE FILTRES N'EST PLUS UN BANDEAU ». */

/* ---------------------------------------------------------------------------
   LES APPARITIONS
   ---------------------------------------------------------------------------
   En CSS seul, et jouées une fois au chargement. Le décalage se règle avec
   `--r`, exactement comme sur l'accueil, pour que l'écriture du balisage soit
   la même d'un bout à l'autre du site. */
@keyframes ip-parait{
  from{opacity:0;transform:translate3d(0,22px,0)}
  to{opacity:1;transform:none}
}
.ip [data-parait]{
  animation:ip-parait .9s cubic-bezier(.16,1,.3,1) both;
  animation-delay:calc(var(--r,0) * 90ms);
}
@media (prefers-reduced-motion:reduce){
  .ip [data-parait]{animation:none !important;opacity:1 !important;transform:none !important}
}

/* ---------------------------------------------------------------------------
   L'OUVERTURE DE PAGE
   ---------------------------------------------------------------------------
   L'équivalent du premier écran de l'accueil, en version posée : on ne fait pas
   attendre quelqu'un qui vient chercher un prix ou un formulaire derrière cent
   pour cent de hauteur de fenêtre. Le titre garde la police d'affichage et les
   capitales — c'est la signature de la marque — mais la page commence tout de
   suite en dessous. */
.ip-ouv{
  /* Le retrait haut ne dégage plus que la barre de navigation. Il montait à
     13vh, soit près de 170 px sur un portable : sur le catalogue et le
     contact, cela suffisait à repousser sous la ligne de flottaison la seule
     chose qu'on vient y chercher — la première œuvre, ou le premier champ.
     Une ouverture de page n'est pas un premier écran ; elle annonce, elle ne
     retient pas. */
  padding:clamp(88px,10vh,124px) var(--ip-marge) clamp(26px,3.2vw,44px);
  border-bottom:1px solid var(--ip-trait);
}
/* Variante courte, pour les pages où le contenu EST le sujet : le catalogue
   et le contact. Le titre garde sa taille, c'est l'air autour qui se retire. */
.ip-ouv--court{padding-bottom:clamp(20px,2.4vw,32px)}
.ip-ouv--court .ip-ouv__mot{
  font-size:var(--ip-gros-petit);max-width:46ch;
  margin-top:clamp(16px,2vw,26px);
}
.ip-ouv--court .ip-ouv__reperes{margin-top:clamp(20px,2.4vw,30px)}
.ip-ouv__sur{
  margin:0 0 clamp(14px,1.8vh,24px);
  font-size:clamp(10px,.78vw,12px);letter-spacing:.34em;text-transform:uppercase;
  color:var(--ip-bleu);font-weight:600;
}
.ip-ouv__titre{
  margin:0;
  font-family:var(--cda-display,'Oswald',system-ui,sans-serif);
  font-weight:var(--cda-display-poids,500);
  font-size:clamp(40px,7.2vw,116px);
  line-height:.9;letter-spacing:-.02em;text-transform:uppercase;
  color:var(--ip-encre);text-wrap:balance;
}
/* Le mot mis en valeur passe en azur, comme le dernier mot du titre de
   l'accueil. Là-bas c'est le module de typo cinétique qui le fait ; ici une
   simple balise suffit, et le résultat se lit pareil. */
.ip-ouv__titre em{font-style:normal;color:var(--ip-bleu)}

/* LE GROS TEXTE D'ENTRÉE.
   Sa mesure est bornée en caractères, pas en pixels : à 34 px une ligne pleine
   largeur d'écran ferait plus de cent signes, et l'œil perdrait le retour à la
   ligne. */
.ip-ouv__mot{
  margin:clamp(22px,2.8vw,38px) 0 0;
  max-width:34ch;
  font-size:var(--ip-gros);line-height:1.34;letter-spacing:-.008em;
  color:var(--ip-encre);text-wrap:pretty;
}
.ip-ouv__suite{
  margin:clamp(14px,1.6vw,22px) 0 0;max-width:58ch;
  font-size:var(--ip-suite);line-height:1.78;color:var(--ip-encre-2);
}

/* LES REPÈRES.
   Ferrés à gauche sous le titre, et non calés à droite comme sur l'ancienne
   ligne d'ouverture. La version à droite se cassait dès que le titre repliait :
   les repères, alignés en bas de grille, se retrouvaient à hauteur de la
   seconde ligne, dans le blanc laissé par la première. Sous le titre, la
   question ne se pose plus, quelle que soit la longueur du titre.

   Règle de rédaction, pas de style : la mention du bas doit rester plus courte
   que la valeur du haut. C'est le plus large des deux qui donne sa largeur au
   bloc ; une légende trop longue pousse le filet de séparation sur le repère
   suivant, et la ligne se lit comme un empilement. */
.ip-ouv__reperes{
  list-style:none;margin:clamp(26px,3vw,40px) 0 0;padding:0;
  display:flex;flex-wrap:wrap;gap:14px clamp(18px,2.4vw,40px);
}
.ip-ouv__reperes li{
  flex:0 0 auto;display:flex;flex-direction:column;gap:3px;
  position:relative;padding-left:clamp(18px,2.4vw,40px);
}
.ip-ouv__reperes li:first-child{padding-left:0}
.ip-ouv__reperes li + li::before{
  content:'';position:absolute;left:0;top:.3em;bottom:.1em;width:1px;
  background:var(--ip-trait);
}
.ip-ouv__reperes b{
  font-family:'Playfair Display',Georgia,serif;
  font-size:clamp(19px,2vw,28px);font-weight:600;color:var(--ip-bleu);line-height:1.1;
  white-space:nowrap;
}
.ip-ouv__reperes span{
  font-size:clamp(9.5px,.8vw,11px);letter-spacing:.2em;text-transform:uppercase;
  color:var(--ip-encre-2);white-space:nowrap;
}
/* Sous 560 px les repères passent sur deux rangées. Le filet et le retrait sont
   dessinés par `li + li`, qui ne sait rien des retours à la ligne : le premier
   repère de la seconde rangée héritait donc d'un trait sans rien à sa gauche. */
@media (max-width:560px){
  .ip-ouv__reperes{gap:16px 26px}
  .ip-ouv__reperes li{padding-left:0}
  .ip-ouv__reperes li + li::before{display:none}
}

/* ---------------------------------------------------------------------------
   LES SECTIONS ET LEUR TÊTE
   --------------------------------------------------------------------------- */
.ip-sect{padding:var(--ip-section) var(--ip-marge)}
.ip-sect--serre{
  padding-top:clamp(34px,4vw,56px);
  padding-bottom:clamp(34px,4vw,56px);
}
/* DEUX SECTIONS QUI SE SUIVENT NE COMPTENT QU'UN SEUL INTERVALLE.
   C'est le défaut classique du rythme vertical posé en `padding` : chaque
   section réserve son air en haut ET en bas, donc entre deux voisines
   l'espace est doublé. On annule le retrait haut de la suivante — l'air du
   bas de la précédente le fournit déjà, et une seule fois. */
.ip-sect + .ip-sect{padding-top:0}

/* Même dessin que `.ac-tete` : titre à gauche, accroche à droite, filet
   dessous. Comme là-bas, les enfants sont ciblés par leur balise — le balisage
   reste donc identique d'une page à l'autre. */
.ip-tete{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-end;
  gap:clamp(14px,2vw,40px);
  padding-bottom:clamp(18px,2vw,30px);
  border-bottom:1px solid var(--ip-trait);
  margin-bottom:clamp(34px,4.4vw,68px);
}
.ip-tete h2{
  margin:0;
  font-family:var(--cda-display,'Oswald',system-ui,sans-serif);
  font-weight:var(--cda-display-poids,500);
  font-size:clamp(26px,3.4vw,54px);line-height:.96;letter-spacing:-.015em;
  text-transform:uppercase;color:var(--ip-encre);
}
.ip-tete p{
  margin:0;max-width:38ch;
  font-size:clamp(16px,1.35vw,21px);line-height:1.55;color:var(--ip-encre-2);
}

/* ---------------------------------------------------------------------------
   LE PANNEAU DÉPOLI — l'équivalent de `.ac-panneau`
   ---------------------------------------------------------------------------
   Sans WebGL derrière, on garde le verre dépoli en CSS pur : c'est déjà ce que
   fait l'accueil quand le canevas ne démarre pas, donc les deux pages se
   ressemblent exactement dans ce cas-là. */
.ip-panneau{
  border-radius:26px;
  padding:clamp(30px,4.2vw,72px);
  background:var(--cda-verre-lumiere),var(--cda-verre);
  -webkit-backdrop-filter:blur(18px) saturate(1.08);
  backdrop-filter:blur(18px) saturate(1.08);
  border:1px solid var(--cda-verre-bord);
  box-shadow:var(--cda-verre-ombre);
}
@media (max-width:640px){
  .ip-panneau{border-radius:18px;padding:clamp(24px,6vw,34px)}
}

/* ---------------------------------------------------------------------------
   LE CHAPITRE, LES POINTS
   --------------------------------------------------------------------------- */
.ip-chap h2{
  margin:0 0 clamp(16px,1.8vw,26px);
  font-family:'Playfair Display',Georgia,serif;
  font-weight:600;font-size:clamp(24px,2.6vw,40px);line-height:1.1;
  color:var(--ip-encre);text-wrap:balance;
}
.ip-chap h2 em{font-style:italic;color:var(--ip-bleu)}
.ip-chap p{
  margin:0 0 1.05em;max-width:62ch;
  font-size:var(--ip-suite);line-height:1.78;color:var(--ip-encre-2);
}
.ip-chap p:last-child{margin-bottom:0}
/* Le premier paragraphe porte l'idée : corps d'accroche et encre pleine. */
.ip-chap .ip-gros{
  font-size:var(--ip-gros) !important;line-height:1.34 !important;
  color:var(--ip-encre) !important;max-width:34ch;
  letter-spacing:-.008em;margin-bottom:.7em !important;text-wrap:pretty;
}
/* La voix du peintre. Les `!important` sont nécessaires : ce paragraphe est un
   `p` dans un `.ip-chap`, et il doit battre la règle de corps ci-dessus. */
.ip-chap__voix{
  font-family:'Playfair Display',Georgia,serif;font-style:italic;
  font-size:clamp(19px,1.9vw,30px) !important;
  line-height:1.32 !important;color:var(--ip-encre) !important;
  max-width:30ch;margin:clamp(22px,2.4vw,34px) 0 0 !important;
}

.ip-points{list-style:none;margin:clamp(26px,3vw,40px) 0 0;padding:0}
.ip-points li{position:relative;padding:0 0 0 20px;margin-bottom:clamp(18px,2vw,26px)}
.ip-points li:last-child{margin-bottom:0}
.ip-points li::before{
  content:'';position:absolute;left:0;top:.52em;
  width:6px;height:6px;background:var(--ip-bleu);transform:rotate(45deg);
}
.ip-points em{
  display:block;font-style:normal;font-weight:600;
  font-size:clamp(15px,1.15vw,18px);color:var(--ip-encre);margin-bottom:5px;
}
.ip-points span{font-size:var(--ip-suite);line-height:1.7;color:var(--ip-encre-2)}

/* En trois colonnes quand la liste sert de spécification et non de récit. */
.ip-points--large{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:clamp(22px,3vw,54px);
}
.ip-points--large li{margin-bottom:0}

/* ---------------------------------------------------------------------------
   LES BOUTONS ET PASTILLES
   --------------------------------------------------------------------------- */
.ip-btn{
  position:relative;overflow:hidden;
  display:inline-flex;align-items:center;justify-content:center;
  min-height:52px;padding:0 clamp(24px,2.4vw,38px);
  border:1px solid var(--ip-encre);border-radius:999px;
  color:var(--ip-encre);text-decoration:none;
  font-size:clamp(12.5px,1vw,14px);letter-spacing:.14em;text-transform:uppercase;
  font-weight:600;
  transition:color .45s cubic-bezier(.76,0,.24,1),border-color .45s;
}
.ip-btn span{position:relative;z-index:1;display:inline-block}
.ip-btn::before{
  content:'';position:absolute;left:0;right:0;bottom:0;height:0;
  background:var(--ip-bleu);transition:height .45s cubic-bezier(.76,0,.24,1);
}
.ip-btn:hover,.ip-btn:focus-visible{color:#fff;border-color:var(--ip-bleu)}
.ip-btn:hover::before,.ip-btn:focus-visible::before{height:100%}
.ip-btn--plein{background:var(--ip-bleu);border-color:var(--ip-bleu);color:#fff}
.ip-btn--plein::before{background:#00306e}

.ip-liens{display:flex;flex-wrap:wrap;gap:10px 12px;margin-top:clamp(18px,2vw,28px)}
.ip-lienf{
  display:inline-flex;align-items:center;gap:.55em;
  min-height:44px;padding:0 20px;border-radius:999px;
  border:1px solid var(--ip-trait);color:var(--ip-encre);text-decoration:none;
  font-size:clamp(13px,1.05vw,15px);
  transition:background .3s,color .3s,border-color .3s;
}
.ip-lienf i{font-style:normal;font-size:.76em;opacity:.55;font-variant-numeric:tabular-nums}
.ip-lienf:hover,.ip-lienf:focus-visible{background:var(--ip-bleu);border-color:var(--ip-bleu);color:#fff}
.ip-lienf:hover i{opacity:.8}
@media (max-width:640px){
  .ip-btn{width:100%}
  .ip-lienf{flex:1 1 auto;justify-content:center}
}

/* ---------------------------------------------------------------------------
   LES DEUX COLONNES
   --------------------------------------------------------------------------- */
.ip-duo{
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(30px,4vw,80px);align-items:start;
}
/* `--egal` PORTE SA PROPRE MISE EN GRILLE.
   Elle ne réglait que les colonnes, en supposant que `.ip-duo` soit écrite à
   côté d'elle pour fournir le `display:grid`. La page de connexion, elle,
   n'écrit que `ip-duo--egal` : la mise en grille n'existait donc pas, les deux
   panneaux — « Se connecter » et « Créer un compte » — se posaient l'un sous
   l'autre en pleine largeur, et leurs champs traversaient l'écran.

   Une variante qui ne fonctionne qu'accompagnée est un piège : rien dans son
   nom ne le dit, et l'oubli ne produit pas d'erreur, seulement une page qui a
   l'air mal réglée. Elle est donc autonome. */
.ip-duo--egal{
  display:grid;align-items:start;
  gap:clamp(30px,4vw,80px);
  grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
}
@media (max-width:1080px){
  .ip-duo,.ip-duo--egal{grid-template-columns:1fr;gap:clamp(28px,5vw,44px)}
}

.ip-portrait{margin:0}
.ip-portrait img{
  display:block;width:100%;height:auto;border-radius:18px;
  aspect-ratio:4/5;object-fit:cover;object-position:center 20%;
  box-shadow:0 40px 80px -44px rgba(13,17,23,.45);
}
.ip-portrait figcaption{
  margin-top:14px;font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ip-encre-2);
}

/* ---------------------------------------------------------------------------
   LE RÉCIT EN ACTES
   ---------------------------------------------------------------------------
   Une marque à gauche — une date, un lieu — et le corps à droite. La marque
   reste collée en haut pendant qu'on lit : sur un paragraphe de trois lignes en
   34 px, un repère qui défile sort du cadre avant la fin du texte, et on ne
   sait plus de quelle époque on parle. */
.ip-acte{
  display:grid;grid-template-columns:minmax(140px,190px) minmax(0,1fr);
  gap:clamp(24px,3.4vw,64px);
  padding:clamp(34px,4vw,56px) 0;
  border-top:1px solid var(--ip-trait);
}
.ip-acte:first-of-type{border-top:0;padding-top:0}
.ip-acte__marque{position:sticky;top:clamp(90px,12vh,130px);align-self:start}
.ip-acte__marque b{
  display:block;font-family:'Playfair Display',Georgia,serif;
  font-size:clamp(26px,2.6vw,38px);font-weight:600;line-height:1;color:var(--ip-bleu);
}
.ip-acte__marque i{
  display:block;margin-top:8px;font-style:normal;
  font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--ip-encre-2);
}
.ip-acte__corps{max-width:640px}
.ip-acte__corps p{
  margin:0 0 .85em;max-width:62ch;
  font-size:var(--ip-suite);line-height:1.78;color:var(--ip-encre-2);
}
.ip-acte__corps p:last-child{margin-bottom:0}
.ip-acte__corps .ip-gros{
  font-size:var(--ip-gros) !important;line-height:1.34 !important;
  color:var(--ip-encre) !important;max-width:none;
  letter-spacing:-.008em;margin-bottom:.7em !important;text-wrap:pretty;
}
@media (max-width:860px){
  .ip-acte{grid-template-columns:1fr;gap:16px}
  .ip-acte__marque{position:static}
  .ip-acte__marque b{font-size:26px}
}
@media (prefers-reduced-motion:reduce){
  .ip-acte__marque{position:static}
}

/* ---------------------------------------------------------------------------
   LE BANDEAU DE FIN — deux portes, comme sur l'accueil
   --------------------------------------------------------------------------- */
.ip-fin{padding:0 var(--ip-marge) var(--ip-section)}
.ip-fin h2{
  margin:0 0 clamp(12px,1.4vw,18px);
  font-family:var(--cda-display,'Oswald',system-ui,sans-serif);
  font-weight:var(--cda-display-poids,500);
  font-size:clamp(24px,3vw,46px);line-height:1;letter-spacing:-.015em;
  text-transform:uppercase;color:var(--ip-encre);
}
.ip-fin p{
  margin:0;max-width:44ch;
  font-size:var(--ip-suite);line-height:1.7;color:var(--ip-encre-2);
}

/* ---------------------------------------------------------------------------
   LES CARTES D'ŒUVRE — reprise fidèle de `.ac-carte`
   ---------------------------------------------------------------------------
   Mêmes proportions, même pied, même filet de couleur dominante. Sans le
   shader ni l'inclinaison : ce sont les seules choses que l'accueil a en plus,
   et elles ne portent aucune information. */
.ip-grille{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(28px,3.4vw,64px) clamp(20px,2.6vw,48px);
}
/* LES CARTELS SONT ALIGNÉS D'UNE CARTE À L'AUTRE.
   C'est le seul point où une grille d'œuvres se distingue d'une grille de
   produits. Les toiles n'ont pas toutes le même format — un carton entoilé en
   30 × 40 et une marine en 55 × 46 n'ont ni la même hauteur ni le même
   rapport — et chaque image imposait donc sa hauteur à sa carte. Les titres
   démarraient en escalier, les prix aussi, et les boutons finissaient à trois
   hauteurs différentes sur la même rangée. L'œil lisait un désordre là où il
   n'y avait qu'une différence de châssis.

   Deux mécanismes, et il faut les deux :

   1. UN CADRE D'ACCROCHAGE COMMUN. Le bloc image prend un rapport fixe et
      l'œuvre s'y inscrit ENTIÈRE, centrée — `object-fit:contain`, jamais
      `cover`. C'est exactement ce que fait un mur de galerie : la cimaise a
      une hauteur, les tableaux ont la leur, et personne ne recadre une toile
      pour qu'elle rentre. Un recadrage automatique sur une œuvre d'art est un
      défaut, pas une commodité.

   2. LE PIED CHASSÉ VERS LE BAS. Même à hauteur d'image égale, un titre sur
      deux lignes décalait le prix. La carte devient une colonne flexible de
      hauteur pleine, et le filet — donc le prix qui le suit — est poussé au
      bas par `margin-top:auto`. Les prix d'une rangée tombent alors sur la
      même ligne, quel que soit le nombre de lignes des légendes. */
.ip-carte{margin:0;min-width:0;display:flex;flex-direction:column;height:100%}
.ip-carte__lien{display:flex;flex-direction:column;flex:1;text-decoration:none;color:inherit}
.ip-carte__media{
  display:block;position:relative;overflow:hidden;border-radius:14px;
  /* ═══ LE CADRE REPREND LE RAPPORT RÉEL DE L'ŒUVRE ═══
     Il était en 4/5 pour tout le monde, avec l'image en `contain` : une
     marine large laissait donc une plage de passe-partout au-dessus
     d'elle — parfois un tiers de la carte — et un liseré là où le blanc
     rencontrait la peinture. C'est le même défaut qui avait été corrigé
     sur l'accueil ; il était resté ici.

     `--ar` est déjà écrit dans le balisage par le gabarit, à partir des
     dimensions réelles du fichier. Le cadre le reprend : plus de bande,
     et les formats se distinguent enfin les uns des autres.

     `margin-top:auto` fait le reste : tout l'espace libre de la carte
     passe AU-DESSUS du cadre, là où il ne se voit pas puisque la carte
     n'a pas de fond, et les toiles s'alignent par leur base comme sur
     une cimaise — leur titre juste dessous. */
  aspect-ratio:var(--ar, 4 / 5);
  margin-top:auto;
  background:linear-gradient(160deg,#f7f5f0,#eef0f2);
  box-shadow:0 30px 60px -34px rgba(13,17,23,.42);
}
.ip-carte__media img{
  width:100%;height:100%;display:block;
  /* `cover` et `contain` donnent désormais le même résultat — le cadre a
     exactement la forme de l'image — mais `cover` garantit qu'un arrondi
     de calcul ne laisse jamais un cheveu de fond visible sur un bord. */
  object-fit:cover;object-position:50% 50%;
  transition:transform 1s cubic-bezier(.16,1,.3,1);
}
.ip-carte:hover .ip-carte__media img{transform:scale(1.045)}
/* ═══ LE PIED NE MANGE PLUS L'ESPACE LIBRE ═══
   Il était en `flex:1` : il absorbait toute la hauteur restante, et le
   `margin-top:auto` du cadre n'avait donc plus rien à pousser — les
   toiles seraient restées accrochées en haut malgré la correction
   ci-dessus. Il redevient de la taille de son contenu.

   Pour que les cartels et les prix restent alignés d'une carte à
   l'autre, on réserve deux lignes au titre et une à la technique,
   occupées ou non : c'est ce qui remplace le `flex:1` dans son autre
   rôle. */
.ip-carte__pied{display:flex;flex-direction:column;gap:7px;padding-top:16px;min-width:0;flex:0 0 auto}
/* La réservation du titre n'est plus écrite ici : elle est MESURÉE
   rangée par rangée par site.js — voir le module d'accrochage. Deux
   lignes réservées pour tout le monde faisaient trente pixels de vide
   sous chaque titre d'une ligne, au bénéfice des seuls titres longs. */
.ip-carte__pied > b{min-height:0}
.ip-carte__pied > i:not(.ip-carte__filet){min-height:1.35em}
.ip-carte__pied b{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(17px,1.45vw,24px);line-height:1.15;color:var(--ip-encre);
  overflow-wrap:anywhere;hyphens:auto;
}
.ip-carte__pied i{font-style:normal;font-size:clamp(13px,1.02vw,15.5px);color:var(--ip-encre-2)}
/* Le prix en encre forte et non en bleu de marque : sur un fond marine,
   le bleu sur bleu tombait à 3,62:1. Voir accueil.css pour le détail. */
.ip-carte__pied em{font-style:normal;font-weight:600;font-size:clamp(14px,1.1vw,17px);color:var(--ip-encre)}
/* ═══ LA COULEUR DU FILET REDEVIENT UN ÉVÉNEMENT ═══
   Chaque filet porte la couleur dominante de sa toile. Sur UNE carte,
   c'est juste et c'est beau : la barre prolonge l'œuvre. Sur une grille
   de neuf, ce sont neuf couleurs franches alignées à intervalle régulier
   — un arc-en-ciel qui bat le rythme de la grille et qui concurrence
   précisément ce qu'on est venu regarder. Le cadre d'une exposition est
   toujours neutre, et pour cette raison-là.

   Au repos, le filet passe donc en gris de trait ; la couleur revient au
   survol et à la mise au point, sur la seule carte visée. La donnée n'est
   pas perdue — `--ac-c` reste écrit sur l'élément — elle attend qu'on la
   demande.

   Sur un appareil tactile il n'y a pas de survol : la couleur y resterait
   invisible. La règle est donc conditionnée à `hover:hover`, et partout
   ailleurs le filet garde sa couleur comme avant — au doigt, la grille se
   parcourt d'un coup d'œil, et la couleur y sert de repère. */
.ip-carte__filet{
  height:3px;width:100%;
  background:var(--ac-c,var(--ip-bleu));
  transition:height .35s ease,background-color .35s ease;
  /* C'est cette ligne qui aligne les prix : tout l'espace disponible du
     cartel est repoussé AU-DESSUS du filet, donc le filet et le prix se
     calent au bas de la carte, à la même hauteur sur toute la rangée. */
  margin-top:auto;
}
@media (hover:hover) and (pointer:fine){
  .ip-carte__filet{background:var(--ip-trait)}
  .ip-carte:hover .ip-carte__filet,
  .ip-carte:focus-within .ip-carte__filet{background:var(--ac-c,var(--ip-bleu))}
}
.ip-carte:hover .ip-carte__filet,
.ip-carte:focus-within .ip-carte__filet{height:6px}
.ip-carte__vendue{
  position:absolute;top:12px;left:12px;
  background:#f4ece9;color:#b3462f;
  font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  padding:6px 12px;border-radius:2px;
}
.ip-carte--vendue .ip-carte__media img{filter:saturate(.4) brightness(.94)}

/* =====================================================================
   LA SCÈNE 3D DU CATALOGUE — LE MUR QUI RÉPOND
   ---------------------------------------------------------------------
   Le vocabulaire est celui des pages primées : une perspective unique
   sur la grille, chaque toile qui s'incline selon sa place dans l'écran
   (courbure du mur), pivote sous la main, rapproche au survol, et porte
   une lumière qui suit le geste. Tout est piloté par
   `catalogue-motion.js` ; cette feuille ne pose que les décors.

   L'ŒUVRE N'EST JAMAIS TOUCHÉE : les transformations vont sur
   `.ip-carte__lien` (l'encadrement), l'image reste nette au pixel.
   ===================================================================== */

/* LA PERSPECTIVE EST SUR LA GRILLE, PAS SUR LA CARTE.
   C'est le point de fuite du mur : `catalogue-motion.js` déplace son
   origine à chaque image pour la tenir au centre de l'ÉCRAN, pas au
   centre de la grille — une grille de soixante toiles a son milieu six
   écrans plus bas, et un point de fuite là-bas rendrait la courbure
   invisible ici. */
.ip-grille{
  perspective:1500px;
  perspective-origin:50% 50%;   /* reprise chaque image par le script */
}
/* LA CHAÎNE 3D EST CONTINUE, DE LA GRILLE AU LIEN.
   `preserve-3d` sur la carte : les transformations du lien (courbure,
   inclinaison, levée) se résolvent dans la perspective de la GRILLE —
   un seul point de fuite pour tout le mur, celui que le script tient au
   centre de l'écran. Donner à chaque carte sa propre perspective
   produirait soixante murs miniatures au lieu d'un seul grand. */
.ip-carte{
  transform-style:preserve-3d;
}
.ip-carte__lien{
  transform-style:preserve-3d;
}

/* LE REFLET SPÉCULAIRE — la lumière suit la main.
   Un voile radial posé sur l'image, dont le centre est piloté par
   `--gx` / `--gy` écrits par le script. À l'opacité nulle au repos :
   sans JavaScript, il n'existe tout simplement pas. */
.ip-carte__reflet{
  position:absolute;inset:0;z-index:2;pointer-events:none;
  border-radius:inherit;
  background:radial-gradient(circle at var(--gx,50%) var(--gy,50%),
    rgba(255,255,255,.34) 0%,
    rgba(255,255,255,.10) 34%,
    rgba(255,255,255,0) 62%);
  opacity:0;
}

/* L'OMBRE PREND LA COULEUR DE L'ŒUVRE.
   Une toile bleue posée sur du blanc jette un reflet bleuté ; c'est ce
   que fait la couleur dominante dans la vraie lumière. `--ac-c` est
   déjà écrit sur le filet par le gabarit — le cadre le reprend pour sa
   lueur. `color-mix` garde l'opacité sous contrôle ; le navigateur qui
   ne l'a pas garde simplement l'ombre d'origine. */
@supports (color:color-mix(in srgb, red 50%, blue)){
  .ip-carte__media{
    box-shadow:
      0 30px 60px -34px rgba(13,17,23,.42),
      0 26px 70px -38px color-mix(in srgb, var(--ac-c, #004aad) 34%, transparent);
    transition:box-shadow .5s ease;
  }
  .ip-carte.is-touche .ip-carte__media{
    box-shadow:
      0 40px 70px -30px rgba(13,17,23,.46),
      0 34px 90px -34px color-mix(in srgb, var(--ac-c, #004aad) 46%, transparent);
  }
}

/* LA RÉVÉLATION PREND DE LA PROFONDEUR.
   L'arrivée existante (`[data-defile]`) monte les cartes de 26 px ; ici
   on y ajoute le fond du cadre : la toile part légèrement plus petite et
   un peu plus loin en Z. Ces règles reprennent la spécificité des règles
   d'arrivée, plus la grille : un cran au-dessus, sans `!important`.

   L'IMAGE N'EST PAS ANIMÉE ICI : elle porte déjà le zoom de survol de
   `.ip-carte:hover`, et deux règles sur la même propriété se seraient
   disputées à chaque carte révélée. La profondeur vit sur l'encadrement,
   l'image reste exactement comme elle est — c'est la règle de la
   maison. */
html.ip-defile .ip .ip-grille [data-defile]:not(.est-la){
  transform:translate3d(0,30px,-46px) scale(.97);
}
html.ip-defile .ip .ip-grille [data-defile].est-la{
  transform:none;
}

/* MOUVEMENT REFUSÉ : le mur redevient un mur.
   Le script ne démarre pas ; ces règles garantissent qu'aucune règle
   de cette section ne survit — perspective exceptée, qui sans
   transformation ne produit rien. */
@media (prefers-reduced-motion:reduce){
  .ip-carte__lien{transform:none!important}
  .ip-carte__reflet{display:none}
  html.ip-defile .ip .ip-grille [data-defile]:not(.est-la),
  html.ip-defile .ip .ip-grille [data-defile]:not(.est-la) .ip-carte__media img{
    transform:none!important;
  }
}

/* Sous 640 px la courbure est discrète (réglée dans le script) et
   l'inclinaison n'existe pas — pas de souris. Le reflet n'a donc rien
   à éclairer : on le coupe, il ne coûtera même pas son dégradé. */
@media (max-width:640px){
  .ip-carte__reflet{display:none}
}
@media (max-width:1080px){.ip-grille{grid-template-columns:repeat(2,1fr)}}
/* ═══ À UNE COLONNE, LES RÉSERVATIONS DE HAUTEUR N'ONT PLUS D'OBJET ═══
   Les deux lignes réservées au titre et la ligne réservée à la technique
   servent à UNE chose : aligner les cartels d'une carte à l'autre SUR LA
   MÊME RANGÉE. Sur téléphone il n'y a plus de rangée — une œuvre, puis la
   suivante — et ces réservations ne font plus qu'un trou : un titre d'une
   seule ligne laissait une ligne et demie de vide avant « Aquarelle —
   30 × 21 cm », et autant avant l'œuvre d'après. On les rend au blanc de
   la page, et le cartel se resserre autour de son texte. */
@media (max-width:640px){
  .ip-grille{grid-template-columns:1fr;gap:clamp(26px,7vw,44px)}
  .ip-carte__pied{padding-top:12px;gap:4px}
  .ip-carte__pied > b{min-height:0}
  .ip-carte__pied > i:not(.ip-carte__filet){min-height:0}
  /* Le filet se calait au bas de la carte pour aligner les prix d'une
     rangée ; sans rangée, il n'a plus qu'à suivre la ligne du dessus. */
  .ip-carte__filet{margin-top:6px}
}

/* LES RESPIRATIONS ENTRE LES RANGÉES.
   Reprises de l'accueil, alternance comprise : un bord, puis l'autre. Centrées,
   elles s'empilaient sur l'axe de la grille et se lisaient comme des titres de
   section — le regard s'arrêtait à chacune. Rejetées dans la marge que la
   rangée du dessus laisse libre, elles redeviennent des notes, et le zigzag
   entraîne la lecture vers le bas. */
/* UNE SEULE IMAGE DANS LA GRILLE (galerie de l'atelier).
   Trois colonnes pour un élément laissent deux vides à droite : l'œil lit une
   grille inachevée, pas une photo unique. On sort donc de la grille dès qu'il
   n'y a qu'un élément — une image, centrée, à une largeur de lecture.
   Le cadre passe aussi de `contain` à `cover` : une vue d'atelier n'est pas une
   œuvre, la rogner d'un centimètre ne trahit rien, alors qu'une bande de fond
   autour d'elle la ferait ressembler à une toile mal cadrée. */
.ip-grille--une{
  grid-template-columns:1fr;
  justify-items:center;
}
.ip-grille--une .ip-carte{max-width:min(560px,100%)}
.ip-grille--une .ip-carte__media{aspect-ratio:1 / 1}
.ip-grille--une .ip-carte__media img{object-fit:cover}

.ip-grille__mot{
  grid-column:1 / -1;
  margin:clamp(26px,4vh,58px) 0 clamp(14px,2vh,28px);
  display:flex;
}
.ip-grille__mot p{
  position:relative;margin:0;max-width:30ch;
  padding-top:clamp(18px,2vw,28px);
  font-family:'Playfair Display',Georgia,serif;
  font-size:clamp(21px,2.2vw,34px);line-height:1.24;letter-spacing:-.012em;
  color:var(--ip-encre);
  /* Même réglage que sur l'accueil : à vingt signes, une phrase de cent
     tombait sur six lignes de trois mots et se lisait par saccades. */
  text-wrap:balance;hyphens:none;
}
.ip-grille__mot p::before{
  content:'';position:absolute;top:0;width:52px;height:1px;
  background:currentColor;opacity:.28;
}
.ip-grille__mot--g{justify-content:flex-start}
.ip-grille__mot--g p{text-align:left}
.ip-grille__mot--g p::before{left:0}
.ip-grille__mot--d{justify-content:flex-end}
.ip-grille__mot--d p{text-align:right}
.ip-grille__mot--d p::before{right:0}
@media (max-width:640px){
  .ip-grille__mot--g,.ip-grille__mot--d{justify-content:flex-start}
  .ip-grille__mot--g p,.ip-grille__mot--d p{text-align:left;max-width:none}
  .ip-grille__mot--d p::before{right:auto;left:0}
}

/* ---------------------------------------------------------------------------
   LES CHAMPS DE FORMULAIRE
   ---------------------------------------------------------------------------
   Contact et espace client partagent exactement ces règles : un formulaire qui
   change de dessin d'une page à l'autre donne l'impression d'avoir quitté le
   site. */
.ip-champ{display:flex;flex-direction:column;gap:8px;margin:0 0 clamp(18px,2vw,26px)}
.ip-champ label,.ip label.ip-etiq{
  font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--ip-encre-2);
}
.ip input[type=text],.ip input[type=email],.ip input[type=tel],
.ip input[type=password],.ip input[type=number],.ip textarea,.ip select{
  width:100%;box-sizing:border-box;
  padding:15px 18px;border:1px solid var(--ip-trait);border-radius:12px;
  background:rgba(255,255,255,.8);color:var(--ip-encre);
  font-family:'Archivo',system-ui,sans-serif;font-size:16px;line-height:1.5;
  transition:border-color .25s,box-shadow .25s;
}
.ip input:focus,.ip textarea:focus,.ip select:focus{
  outline:none;border-color:var(--ip-bleu);
  box-shadow:0 0 0 3px rgba(0,74,173,.14);
}
.ip textarea{resize:vertical;min-height:150px}
.ip-duo-champs{display:grid;grid-template-columns:1fr 1fr;gap:clamp(14px,1.8vw,24px)}
@media (max-width:640px){.ip-duo-champs{grid-template-columns:1fr}}

.ip-legende{padding:0;margin:0 0 clamp(14px,1.8vw,22px);display:flex;flex-direction:column;gap:4px}
.ip-legende b{font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(19px,1.7vw,26px);color:var(--ip-encre)}
.ip-legende i{font-style:normal;font-size:14.5px;line-height:1.55;color:var(--ip-encre-2)}
.ip-bloc{border:0;margin:0 0 clamp(30px,4vw,52px);padding:0;min-width:0}

/* Le choix par vignettes ou par cartouches, en boutons radio : aucune ligne de
   JavaScript, donc rien qui puisse ne pas se charger, et navigable au clavier. */
.ip-choix{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}
.ip-choix label{
  display:block;cursor:pointer;
  padding:18px 20px;border:1px solid var(--ip-trait);border-radius:14px;
  background:rgba(255,255,255,.7);transition:border-color .25s,background .25s;
}
.ip-choix input{position:absolute;opacity:0;width:0;height:0}
.ip-choix label > span{display:block}
.ip-choix b{display:block;font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:17.5px;color:var(--ip-encre);margin-bottom:5px}
.ip-choix i{font-style:normal;font-size:14.5px;line-height:1.55;color:var(--ip-encre-2)}
.ip-choix label:hover{border-color:rgba(0,74,173,.4)}
.ip-choix input:checked + span{color:var(--ip-encre)}
.ip-choix label:has(input:checked){border-color:var(--ip-bleu);background:rgba(0,74,173,.05)}
.ip-choix label:has(input:focus-visible){box-shadow:0 0 0 3px rgba(0,74,173,.16)}

.ip-mur{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:12px}
.ip-mur label{cursor:pointer;display:block;text-align:center}
.ip-mur input{position:absolute;opacity:0;width:0;height:0}
.ip-mur__cadre{
  display:flex;align-items:center;justify-content:center;
  aspect-ratio:1;border-radius:10px;overflow:hidden;
  border:1px solid var(--ip-trait);background:rgba(255,255,255,.75);
  transition:border-color .25s,box-shadow .25s;
}
.ip-mur__cadre img{width:100%;height:100%;object-fit:cover;display:block}
.ip-mur__cadre em{font-style:normal;font-size:12.5px;line-height:1.4;color:var(--ip-encre-2);padding:8px}
.ip-mur__nom{
  display:block;margin-top:8px;font-size:12px;line-height:1.35;color:var(--ip-encre-2);
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
}
.ip-mur label:has(input:checked) .ip-mur__cadre{border-color:var(--ip-bleu);box-shadow:0 0 0 2px rgba(0,74,173,.3)}
.ip-mur label:has(input:focus-visible) .ip-mur__cadre{box-shadow:0 0 0 3px rgba(0,74,173,.2)}

.ip-envoi{display:flex;flex-wrap:wrap;align-items:center;gap:16px 22px;margin-top:clamp(8px,1vw,14px)}
.ip-envoi small{font-size:13px;line-height:1.6;color:var(--ip-encre-2);max-width:44ch}
.ip-envoi button{
  border:0;cursor:pointer;font-family:'Archivo',system-ui,sans-serif;
}
.ip-ok{
  margin:0 0 clamp(20px,3vw,34px);padding:16px 20px;border-radius:12px;
  background:var(--ip-bleu);color:#fff;font-size:15px;
}

/* La suite en trois temps, sous le formulaire. */
.ip-suite3{
  list-style:none;margin:clamp(40px,5vw,70px) 0 0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:clamp(22px,3vw,48px);counter-reset:ip;
}
.ip-suite3 li{border-top:1px solid var(--ip-trait);padding-top:16px}
.ip-suite3 b{display:block;font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(17px,1.4vw,21px);color:var(--ip-encre);margin-bottom:6px}
.ip-suite3 span{font-size:15px;line-height:1.65;color:var(--ip-encre-2)}

/* ---------------------------------------------------------------------------
   LA BARRE DE FILTRES DU CATALOGUE
   --------------------------------------------------------------------------- */
/* ═══ LA BARRE DE FILTRES N'EST PLUS UN BANDEAU ═══
   Elle était un rectangle blanc pleine largeur, collé en haut de la page.
   Au-dessus d'un fond peint, ce rectangle est la deuxième grande surface
   opaque de l'écran après la barre de navigation, et il écrase la matière
   sur toute la largeur.

   Elle perd donc son fond, sa bordure et son flou. Ce qui reste sont les
   commandes elles-mêmes, qui étaient DÉJÀ des pilules — elles n'avaient
   qu'un contour, elles reçoivent maintenant un voile qui les rend
   lisibles par-dessus n'importe quelle zone du pigment. La barre devient
   une rangée de pastilles flottantes, et la peinture court derrière.

   Le flou disparaît pour la raison mesurée ailleurs dans ce fichier : un
   `backdrop-filter` sur un élément COLLANT au-dessus d'un canevas animé
   se recalcule à chaque image de défilement, sur toute sa largeur. */
.ip-filtres{
  position:sticky;top:0;z-index:20;
  padding:14px var(--ip-marge);
  background:transparent;
  border-bottom:0;
}
.ip-filtres__ligne{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px}
.ip-filtres__type{display:flex;flex-wrap:wrap;gap:8px;margin-right:auto}
.ip-pilule{
  display:inline-flex;align-items:center;min-height:40px;padding:0 18px;
  border-radius:999px;border:1px solid rgba(13,17,23,.10);
  background:rgba(255,255,255,.78);
  box-shadow:0 14px 30px -22px rgba(9,24,48,.45), inset 0 1px 0 rgba(255,255,255,.7);
  color:var(--ip-encre);text-decoration:none;font-size:13.5px;
  transition:background .25s cubic-bezier(.32,.72,0,1),color .25s,border-color .25s,transform .25s cubic-bezier(.32,.72,0,1);
}
.ip-pilule:hover{border-color:rgba(0,74,173,.35);background:rgba(255,255,255,.94)}
.ip-pilule:active{transform:scale(.97)}
.ip-pilule.is-on{background:var(--ip-bleu);border-color:var(--ip-bleu);color:#fff}
/* Le compteur et « tout effacer » ne sont pas des commandes de filtre :
   ils restent du texte, mais reçoivent le même voile en plus léger pour
   ne pas se perdre sur une zone dense du pigment. */
.ip-compte,.ip-reset{
  display:inline-flex;align-items:center;min-height:34px;padding:0 14px;
  /* .62 mesuré à 4,12:1 sur les zones denses du pigment, sous le seuil.
     À .80 la même encre passe à 5,1:1 — voir `essai/capsule.js`. */
  border-radius:999px;background:rgba(255,255,255,.8);
  font-size:13px;color:var(--ip-encre-2);
}
.ip-compte{font-variant-numeric:tabular-nums}
.ip-reset{text-decoration:none;border:1px solid transparent;transition:border-color .25s,background .25s}
.ip-reset:hover{border-color:rgba(13,17,23,.14);background:rgba(255,255,255,.9)}

.ip-menu{position:relative}
.ip-menu > summary{
  list-style:none;cursor:pointer;
  display:inline-flex;align-items:center;gap:.5em;min-height:40px;padding:0 16px;
  border-radius:999px;border:1px solid rgba(13,17,23,.10);
  background:rgba(255,255,255,.78);
  box-shadow:0 14px 30px -22px rgba(9,24,48,.45), inset 0 1px 0 rgba(255,255,255,.7);
  font-size:13.5px;color:var(--ip-encre);
  transition:background .25s cubic-bezier(.32,.72,0,1),border-color .25s,transform .25s cubic-bezier(.32,.72,0,1);
}
.ip-menu > summary:hover{background:rgba(255,255,255,.94)}
.ip-menu > summary:active{transform:scale(.97)}
.ip-menu > summary::-webkit-details-marker{display:none}
.ip-menu.is-on > summary{border-color:var(--ip-bleu);color:var(--ip-bleu)}
.ip-menu > summary i{font-style:normal;opacity:.6;font-size:.85em}
.ip-menu__pan{
  position:absolute;top:calc(100% + 8px);left:0;z-index:30;min-width:210px;
  display:flex;flex-direction:column;gap:2px;padding:10px;
  background:rgba(255,255,255,.97);border:1px solid rgba(13,17,23,.10);border-radius:20px;
  box-shadow:0 30px 60px -28px rgba(9,24,48,.5), inset 0 1px 0 rgba(255,255,255,.8);
}
.ip-menu__pan a{
  padding:9px 12px;border-radius:9px;color:var(--ip-encre);text-decoration:none;font-size:14px;
}
.ip-menu__pan a:hover{background:rgba(0,74,173,.07)}
.ip-menu__pan a[aria-current=true]{color:var(--ip-bleu);font-weight:600}
.ip-menu__pan--couleurs{
  display:grid;grid-template-columns:1fr 1fr;min-width:280px;
}
.ip-cchoix{display:inline-flex;align-items:center;gap:.55em}
.ip-cpuce{width:12px;height:12px;border-radius:50%;flex:none;box-shadow:inset 0 0 0 1px rgba(0,0,0,.12)}

/* ---------------------------------------------------------------------------
   MON COMPTE
   --------------------------------------------------------------------------- */
.ip-compte-grille{
  display:grid;grid-template-columns:minmax(200px,250px) minmax(0,1fr);
  gap:clamp(28px,3.6vw,64px);align-items:start;
}
@media (max-width:900px){.ip-compte-grille{grid-template-columns:1fr}}
.ip-nav-compte{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.ip-nav-compte a{
  display:block;padding:13px 16px;border-radius:11px;
  color:var(--ip-encre);text-decoration:none;font-size:15px;
  border:1px solid transparent;transition:background .25s,border-color .25s;
}
.ip-nav-compte a:hover{background:rgba(0,74,173,.06)}
.ip-nav-compte li.is-active > a,
.ip-nav-compte li.is-active a{
  background:rgba(0,74,173,.09);border-color:rgba(0,74,173,.28);
  color:var(--ip-bleu);font-weight:600;
}
.ip-compte-corps{min-width:0}

/* Les messages de WooCommerce : voir plus bas, section « LES MESSAGES ».
   L'ancienne règle tenait en cinq lignes et donnait un rectangle bleu pâle
   sans hiérarchie ; elle a été remplacée, pas complétée. */
.ip table{width:100%;border-collapse:collapse;font-size:15px}
.ip table th,.ip table td{
  text-align:left;padding:14px 12px;border-bottom:1px solid var(--ip-trait);
}
.ip table th{
  font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--ip-encre-2);
  font-weight:600;
}
.ip .button,.ip .woocommerce-Button{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:48px;padding:0 26px;border:0;border-radius:999px;cursor:pointer;
  background:var(--ip-bleu);color:#fff;text-decoration:none;
  font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
}
.ip .button:hover,.ip .woocommerce-Button:hover{background:#00306e;color:#fff}

/* ---------------------------------------------------------------------------
   MODE SOMBRE
   ---------------------------------------------------------------------------
   Le thème sombre du site est déclaré couleur par couleur dans site.css. Ici
   il suffit de retourner les cinq tokens : tout le reste en dérive. */
html.cda-dark .ip{
  /* Même encre bleutée que l'accueil et que site.css : un seul noir pour
     tout le site, celui qui ne découpe pas les toiles. */
  --ip-papier:#05070b;
  --ip-encre:#f2f2f2;
  --ip-encre-2:rgba(255,255,255,.62);
  --ip-trait:rgba(255,255,255,.14);
}
html.cda-dark .ip::before{
  background:
    radial-gradient(120% 80% at 12% 0%, rgba(0,74,173,.22), transparent 60%),
    radial-gradient(100% 70% at 100% 8%, rgba(61,127,214,.12), transparent 62%);
}
/* Le bleu de charte plafonne à 2,4:1 sur du noir : illisible en texte. Il reste
   la couleur des SURFACES, et le texte passe à la version éclaircie — même
   arbitrage que site.css, pour que les deux feuilles ne se contredisent pas. */
html.cda-dark .ip{--ip-bleu-txt:#5b9cf0}
html.cda-dark .ip-ouv__sur,
html.cda-dark .ip-ouv__titre em,
html.cda-dark .ip-ouv__reperes b,
html.cda-dark .ip-chap h2 em,
html.cda-dark .ip-menu.is-on > summary{color:var(--ip-bleu-txt)}
/* le prix suit l'encre du thème, pas le bleu — voir plus haut */
html.cda-dark .ip-carte__pied em{color:var(--ip-encre)}
html.cda-dark .ip-panneau{
  background:var(--cda-verre-lumiere),var(--cda-verre);
  border-color:var(--cda-verre-bord);
}
/* Les pastilles en mode nuit : même construction, valeurs inversées. */
html.cda-dark .ip-filtres{background:transparent}
html.cda-dark .ip-pilule,
html.cda-dark .ip-menu > summary{
  background:rgba(10,14,20,.72);
  border-color:rgba(255,255,255,.14);
  box-shadow:0 14px 30px -22px rgba(0,0,0,.7), inset 0 1px 0 rgba(255,255,255,.07);
}
html.cda-dark .ip-pilule:hover,
html.cda-dark .ip-menu > summary:hover{background:rgba(18,24,32,.9)}
/* L'état actif garde sa couleur pleine : la règle de nuit ci-dessus est
   plus spécifique que `.ip-pilule.is-on` et la lui volerait sans ceci. */
html.cda-dark .ip-pilule.is-on{background:var(--ip-bleu);border-color:var(--ip-bleu);color:#fff}
html.cda-dark .ip-compte,
html.cda-dark .ip-reset{background:rgba(10,14,20,.74)}
html.cda-dark .ip-reset:hover{background:rgba(18,24,32,.86);border-color:rgba(255,255,255,.16)}
html.cda-dark .ip-menu__pan{
  background:rgba(14,18,24,.97);border-color:rgba(255,255,255,.12);
  box-shadow:0 30px 60px -28px rgba(0,0,0,.8), inset 0 1px 0 rgba(255,255,255,.06);
}
html.cda-dark .ip input,html.cda-dark .ip textarea,html.cda-dark .ip select,
html.cda-dark .ip-choix label,html.cda-dark .ip-mur__cadre{
  background:rgba(27,27,27,.8);color:var(--ip-encre);
}
html.cda-dark .ip-btn{border-color:rgba(255,255,255,.24);color:var(--ip-encre)}
html.cda-dark .ip-btn--plein{background:var(--ip-bleu);border-color:var(--ip-bleu);color:#fff}
html.cda-dark .ip-carte__media{background:linear-gradient(160deg,#1b1b1b,#121212)}

/* ---------------------------------------------------------------------------
   COMPLÉMENTS DE L'ESPACE CLIENT
   ---------------------------------------------------------------------------
   Trois classes réclamées par les gabarits WooCommerce et par rien d'autre.
   Elles vivent ici plutôt que dans les fichiers de gabarit : un `style=` en dur
   dans une surcharge de plugin est la première chose qu'on oublie de mettre à
   jour quand la charte change. */

/* La note de bas de formulaire — « un lien vous sera envoyé par e-mail », la
   mention de confidentialité. Plus petite que le corps, jamais en gris trop
   pâle : c'est une information, pas une décharge de responsabilité. */
.ip-note{
  margin:clamp(10px,1.2vw,16px) 0 0;
  font-size:14px;line-height:1.6;color:var(--ip-encre-2);max-width:52ch;
}

/* Le mur de la collection : les toiles déjà acquises. Les vignettes sont plus
   petites que celles du catalogue — on ne revend pas ces œuvres, on les
   retrouve — d'où une grille plus dense que `.ip-grille` par défaut. */
.ip-col__mur{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}

/* L'état d'acheminement. La teinte arrive en ligne dans `--e`, calculée par le
   gabarit d'après le statut WooCommerce : c'est une donnée, elle n'a donc pas à
   être écrite ici. */
.ip-col__etat{
  display:inline-flex;align-items:center;align-self:flex-start;
  padding:5px 12px;border-radius:999px;
  background:color-mix(in srgb, var(--e,#5a636d) 14%, transparent);
  color:var(--e,#5a636d);
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
}
/* `color-mix()` n'est pas partout : sans lui la pastille garderait un fond
   transparent et le texte coloré resterait lisible — la dégradation est donc
   déjà acceptable. Ce repli ajoute quand même un fond neutre. */
@supports not (background: color-mix(in srgb, red 10%, transparent)){
  .ip-col__etat{background:rgba(13,17,23,.06)}
}

.ip-col__vide{text-align:center}
.ip-col__vide h2{
  margin:0 0 12px;font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(22px,2.4vw,34px);color:var(--ip-encre);
}
.ip-col__vide p{margin:0 auto;max-width:44ch;font-size:var(--ip-suite);
  line-height:1.7;color:var(--ip-encre-2)}

html.cda-dark .ip-col__etat{background:rgba(255,255,255,.08)}

/* La colonne de la collection, dans le tableau de bord. `.ip-col` ne porte que
   le rythme vertical entre ses blocs : la grille, l'état vide et la rangée
   d'actions sont déjà dessinés par leurs propres classes. */
.ip-col{display:flex;flex-direction:column;gap:clamp(30px,4vw,56px)}
/* La rangée d'actions du compte (« Éditer l'adresse », « Se déconnecter »).
   Elle reprend `.ip-liens` pour les pastilles et n'ajoute qu'un filet de
   séparation : à cet endroit de la page, on quitte la collection pour les
   réglages, et le changement de nature mérite d'être marqué. */
.ip-col__admin{border-top:1px solid var(--ip-trait);padding-top:clamp(20px,2.4vw,32px)}


/* ---------------------------------------------------------------------------
   LE MUR DES ŒUVRES, SUR LA PAGE CONTACT
   ---------------------------------------------------------------------------
   Il ne proposait que les dix-huit dernières pièces. Il les propose toutes,
   ce qui pose un problème de place et un seul : cent vignettes poussent le
   bouton d'envoi hors de l'écran. La réponse n'est pas de rogner le choix —
   c'était l'erreur d'avant — mais de borner la HAUTEUR et de laisser défiler
   à l'intérieur. Le formulaire garde alors sa taille quel que soit le nombre
   d'œuvres au catalogue.

   Les familles portent un intertitre collant. Au milieu d'un mur long, sans
   lui, on ne sait plus si l'on regarde des huiles ou des aquarelles ; collé
   en haut de la zone, il répond sans qu'on ait à remonter. */

.ip-mur-tete{
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:10px 18px;margin-bottom:14px;
}
/* « Aucune en particulier » quitte le mur pour la ligne de tête. Dans le mur,
   c'était une case sans image au milieu de vignettes : elle se lisait comme
   une œuvre manquante. En tête, c'est ce qu'elle est — l'option par défaut. */
.ip-mur-aucune{display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-size:15px}
.ip-mur-aucune input{position:absolute;opacity:0;width:0;height:0}
.ip-mur-aucune span{
  display:inline-flex;align-items:center;min-height:40px;padding:0 16px;
  border:1px solid var(--ip-trait);border-radius:999px;color:var(--ip-encre);
  transition:background .25s,border-color .25s,color .25s;
}
.ip-mur-aucune:has(input:checked) span{
  background:var(--ip-bleu);border-color:var(--ip-bleu);color:#fff;
}
.ip-mur-aucune:has(input:focus-visible) span{box-shadow:0 0 0 3px rgba(0,74,173,.2)}
/* Le nombre est annoncé : « 47 œuvres disponibles » dit d'emblée qu'il faut
   faire défiler, ce qu'une zone coupée net ne dit jamais assez clairement. */
.ip-mur-compte{
  font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ip-encre-2);font-variant-numeric:tabular-nums;
}

.ip-mur-zone{
  max-height:min(52vh,440px);overflow-y:auto;overscroll-behavior:contain;
  padding:4px 12px 4px 4px;
  border:1px solid var(--ip-trait);border-radius:14px;
  background:rgba(255,255,255,.5);
  /* Un dégradé en bas dit qu'il reste des œuvres sous la coupe. Une zone qui
     s'arrête net sur une rangée entière paraît finie. */
  -webkit-mask-image:linear-gradient(#000 calc(100% - 26px), transparent);
  mask-image:linear-gradient(#000 calc(100% - 26px), transparent);
}
.ip-mur-famille{
  position:sticky;top:0;z-index:2;margin:0;
  padding:10px 4px 8px;
  background:linear-gradient(#fff 72%, rgba(255,255,255,0));
  font-size:11.5px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ip-bleu);font-weight:600;
}
.ip-mur-famille i{
  font-style:normal;color:var(--ip-encre-2);letter-spacing:.06em;margin-left:.4em;
  font-variant-numeric:tabular-nums;
}
.ip-mur-zone .ip-mur{margin-bottom:18px}
.ip-mur-zone .ip-mur:last-child{margin-bottom:0}

/* Les vignettes gagnent en taille : à 104 px on reconnaissait mal une marine
   d'une autre. Le titre passe sous l'image sur deux lignes maximum — c'est lui
   qui partira dans l'e-mail, mieux vaut qu'il ait été lu. */
.ip-mur{grid-template-columns:repeat(auto-fill,minmax(118px,1fr));gap:14px}

@media (max-width:640px){
  .ip-mur-zone{max-height:min(48vh,380px)}
  .ip-mur{grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:12px}
}

html.cda-dark .ip-mur-zone{background:rgba(18,18,18,.5)}
html.cda-dark .ip-mur-famille{background:linear-gradient(#000 72%, rgba(0,0,0,0));color:var(--ip-bleu-txt)}
html.cda-dark .ip-mur-aucune span{color:var(--ip-encre)}

/* ---------------------------------------------------------------------------
   OUVERTURE AVEC PORTRAIT — la page du peintre
   ---------------------------------------------------------------------------
   Le portrait était plus bas, à côté de la section « La manière ». On lisait
   donc trois actes de biographie avant de voir de qui l'on parlait : le visage
   arrivait après la seule question à laquelle il répond. Sur la page d'un
   artiste, la photographie n'illustre pas le texte, elle EST la présentation.

   Le texte tient la colonne de gauche, le portrait celle de droite, alignés en
   haut. Sous 900 px la grille retombe sur une colonne et l'ordre du document
   reprend la main : le nom et les faits d'abord, le visage ensuite. Un portrait
   plein écran avant même le titre obligerait à défiler pour savoir où l'on est. */
.ip-ouv--portrait{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(240px,360px);
  gap:clamp(28px,4vw,72px);
  align-items:start;
}
.ip-ouv__texte{min-width:0}
/* Le portrait descend d'un cran : calé en haut, son bord supérieur tombait à
   hauteur de la sur-ligne en capitales, soit très au-dessus du titre — la page
   commençait alors par une image flottant seule dans le blanc. Aligné sur le
   titre, il fait partie de la même ligne d'entrée. */
.ip-ouv__portrait{margin-top:clamp(10px,2.4vh,34px)}
@media (max-width:900px){
  .ip-ouv--portrait{grid-template-columns:1fr}
  .ip-ouv__portrait{max-width:360px;margin-top:clamp(24px,4vw,36px)}
}


/* ---------------------------------------------------------------------------
   LES ŒUVRES ARRIVENT QUAND ON LES ATTEINT
   ---------------------------------------------------------------------------
   `[data-parait]` joue son animation AU CHARGEMENT. C'est ce qu'il faut pour
   un en-tête : il est visible, il arrive, on le voit arriver. Appliqué à la
   grille du catalogue, le même mécanisme produisait exactement l'inverse de
   son intention — trois cartes sont dans l'écran, cinquante-six ne le sont
   pas, et celles-là avaient fini de s'animer avant qu'on ait touché la
   molette. On faisait défiler une page entièrement figée.

   `[data-defile]` corrige la seule chose qui manquait : le MOMENT. La carte
   attend d'entrer dans l'écran, et c'est un IntersectionObserver, dans
   site.js, qui pose `.est-la` à cet instant. Une fois posée, elle n'est jamais
   retirée : une animation qui se rejoue en remontant transforme un catalogue
   en guirlande.

   POURQUOI L'ÉTAT MASQUÉ DÉPEND D'UNE CLASSE SUR <html>.
   `html.ip-defile` n'est ajoutée par le script qu'une fois l'observateur
   réellement construit. Tant qu'elle n'est pas là, aucune règle ne met
   d'opacité nulle : si le JavaScript ne s'exécute pas — erreur, extension,
   navigateur ancien —, le catalogue reste entièrement lisible au lieu de
   s'afficher blanc. On ne masque qu'après avoir prouvé qu'on saura révéler.

   Le mouvement est plus discret que celui des en-têtes : 26 px et un souffle
   d'échelle. Répété soixante fois en descendant, un geste ample fatigue.
   --------------------------------------------------------------------------- */
html.ip-defile .ip [data-defile]{
  opacity:0;
  transform:translate3d(0,26px,0) scale(.985);
  transition:opacity .75s ease, transform .85s cubic-bezier(.16,1,.3,1);
  transition-delay:calc(var(--r,0) * 70ms);
  will-change:opacity, transform;
}
html.ip-defile .ip [data-defile].est-la{
  opacity:1;
  transform:none;
  /* Le calque de composition est rendu après l'arrivée : le garder sur
     cinquante-neuf cartes coûterait de la mémoire vidéo pour rien. */
  will-change:auto;
}
@media (prefers-reduced-motion:reduce){
  html.ip-defile .ip [data-defile]{
    opacity:1 !important;transform:none !important;transition:none !important;
  }
}

/* L'ancrage devient doux : cliquer un filtre ou « revenir en haut » ne
   téléporte plus la page. C'est la seule partie du défilement qu'une feuille
   de style puisse animer — la molette, elle, appartient au système, et la
   détourner en JavaScript rend le geste étranger à la main qui l'exécute. */
@media (prefers-reduced-motion:no-preference){
  html{scroll-behavior:smooth}
}


/* ---------------------------------------------------------------------------
   MON COMPTE — LES CHAMPS NE FONT PLUS LA LARGEUR DE L'ÉCRAN
   ---------------------------------------------------------------------------
   `.ip input{width:100%}` est juste : un champ doit remplir la colonne qui lui
   est donnée. Le défaut n'était pas là — il était dans la colonne. Le contenu
   de l'espace client occupait tout ce qui restait après la navigation, soit
   plus de treize cents pixels sur un écran large. Un champ « Prénom » y
   mesurait donc 1,3 mètre de large pour huit lettres, et le formulaire se
   lisait comme un tableur.

   Deux bornes, et chacune répond à un cas distinct :

   1. LA PAGE. Un espace client n'a aucune raison de s'étaler sur toute la
      largeur d'un 27 pouces. 1180 px, c'est la mesure d'un document : la
      navigation reste à gauche, le contenu garde une colonne lisible, et le
      reste est du blanc — qui est une décision, pas un oubli.

   2. LES FORMULAIRES. Même dans une colonne de 900 px, un champ de saisie sur
      une ligne ne doit pas dépasser une soixantaine de signes : au-delà, l'œil
      perd le début de ce qu'il tape. On borne donc le FORMULAIRE et non le
      champ — ainsi les paires « Prénom / Nom », que WooCommerce pose côte à
      côte, se partagent correctement la largeur restante au lieu d'être
      rognées chacune de son côté.

   Les tableaux — commandes, téléchargements — ne sont pas dans un formulaire
   et gardent donc toute la colonne. C'est ce qu'il faut : une ligne de commande
   porte cinq colonnes, elle a besoin de la place qu'un champ n'a pas.
   --------------------------------------------------------------------------- */
.ip-compte-grille{
  max-width:1180px;
}
.ip-compte-corps form{
  max-width:640px;
}
/* Le formulaire d'adresse contient déjà ses propres paires : on lui laisse un
   peu plus d'air, sinon « Adresse » et « Complément » se serrent. */
.ip-compte-corps form.woocommerce-address-fields,
.ip-compte-corps .woocommerce-address-fields > form{
  max-width:720px;
}
/* WooCommerce écrit ses paires avec ces deux classes. Sans cette règle elles
   s'empilent l'une sous l'autre dans une colonne bornée, ce qui rallonge le
   formulaire pour rien. */
.ip-compte-corps .form-row-first,
.ip-compte-corps .form-row-last{width:calc(50% - 10px);display:inline-block;vertical-align:top}
.ip-compte-corps .form-row-first{margin-right:16px}
@media (max-width:560px){
  .ip-compte-corps .form-row-first,
  .ip-compte-corps .form-row-last{width:100%;margin-right:0;display:block}
}
/* Le mot de passe et ses explications : la mention d'aide sous le champ ne doit
   pas courir plus loin que le champ lui-même. */
.ip-compte-corps form em,
.ip-compte-corps form .description,
.ip-compte-corps form small{max-width:56ch;display:block}


/* ---------------------------------------------------------------------------
   LES LIEUX DU PARCOURS
   ---------------------------------------------------------------------------
   Un acte de biographie devient une grille à trois colonnes : le repère
   d'époque à gauche, le texte au milieu, le lieu à droite. Les trois colonnes
   ne se valent pas et la grille le dit — le texte prend tout ce qui reste, la
   carte a une largeur fixe. Une carte qui s'étirerait avec la fenêtre finirait
   par peser autant que le récit qu'elle illustre.

   Sous 1180 px la carte passe SOUS le texte plutôt que de l'étrangler : à deux
   cent quatre-vingts pixels de carte, une colonne de texte de 400 px donne des
   lignes de trente signes, et un paragraphe de biographie se lit alors comme
   une colonne de journal.

   `align-self:start` : sans lui, la carte s'étirerait sur toute la hauteur de
   l'acte — deux paragraphes, parfois une citation — et l'on obtiendrait un
   cadre Google de sept cents pixels de haut à côté de six lignes de texte.
   --------------------------------------------------------------------------- */
.ip-acte--lieu{
  grid-template-columns:minmax(140px,190px) minmax(0,1fr) minmax(240px,290px);
}
.ip-acte__lieux{
  align-self:start;
  display:flex;flex-direction:column;gap:clamp(14px,1.6vw,22px);
}
@media (max-width:1180px){
  .ip-acte--lieu{grid-template-columns:minmax(140px,190px) minmax(0,1fr)}
  .ip-acte__lieux{
    grid-column:2;
    /* Sous le texte, deux cartes tiennent côte à côte : l'acte italien en a
       deux, et empilées elles ajouteraient six cents pixels de défilement. */
    flex-direction:row;flex-wrap:wrap;
    margin-top:clamp(20px,2.4vw,30px);
  }
  .ip-acte__lieux > *{flex:1 1 240px;max-width:340px}
}
@media (max-width:860px){
  .ip-acte--lieu{grid-template-columns:1fr}
  .ip-acte__lieux{grid-column:1}
}

/* LA CARTE ELLE-MÊME.
   Le cadre reprend exactement le dessin d'une carte d'œuvre — même rayon, même
   filet, même ombre portée — pour que le lieu se lise comme une pièce de la
   page et non comme un composant collé depuis un autre site.

   La désaturation est le détail qui décide de tout. Une carte Google brute
   arrive avec ses verts, ses jaunes de route et son bleu d'autoroute : trois
   couleurs qui n'appartiennent pas à la charte, et qui, posées à côté d'une
   marine, tirent l'œil plus fort que la peinture. Réduite à 55 % de saturation
   elle devient un fond de plan ; au survol elle reprend ses couleurs, ce qui
   suffit à dire qu'elle est vivante et cliquable. */
.ip-lieu{margin:0}
.ip-lieu__cadre{
  display:block;position:relative;overflow:hidden;
  border-radius:14px;border:1px solid var(--ip-trait);
  aspect-ratio:4 / 3;
  background:linear-gradient(160deg,#eef0f2,#e4e8ec);
  box-shadow:0 24px 48px -32px rgba(13,17,23,.4);
}
.ip-lieu__cadre iframe{
  position:absolute;inset:0;width:100%;height:100%;border:0;display:block;
  filter:saturate(.55) contrast(1.04);
  transition:filter .5s ease;
}
.ip-lieu:hover .ip-lieu__cadre iframe,
.ip-lieu:focus-within .ip-lieu__cadre iframe{filter:saturate(1) contrast(1)}

.ip-lieu figcaption{
  display:flex;flex-direction:column;gap:2px;
  padding-top:11px;
}
.ip-lieu figcaption b{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(16px,1.3vw,19px);line-height:1.2;color:var(--ip-encre);
}
.ip-lieu figcaption i{
  font-style:normal;font-size:13px;line-height:1.5;color:var(--ip-encre-2);
}
.ip-lieu figcaption a{
  margin-top:5px;align-self:start;
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
  color:var(--ip-bleu);text-decoration:none;
  border-bottom:1px solid rgba(0,74,173,.28);padding-bottom:2px;
  transition:border-color .25s;
}
.ip-lieu figcaption a:hover{border-color:var(--ip-bleu)}

@media (prefers-reduced-motion:reduce){
  .ip-lieu__cadre iframe{transition:none}
}


/* ---------------------------------------------------------------------------
   WOOCOMMERCE FLOTTAIT LES DEUX COLONNES DE L'ESPACE CLIENT
   ---------------------------------------------------------------------------
   C'est la vraie raison pour laquelle cette page ne ressemblait à rien, et
   aucune retouche de largeur ne pouvait y changer quoi que ce soit.

   `woocommerce-layout.css` — chargé par l'extension, pas par le thème — écrit
   ceci depuis toujours :

       .woocommerce-account .woocommerce-MyAccount-navigation { float:left;  width:30% }
       .woocommerce-account .woocommerce-MyAccount-content    { float:right; width:68% }

   Le gabarit du thème, lui, pose une grille de 250 px + le reste. Les deux
   règles ne se contredisent pas : elles s'ajoutent. La grille donnait bien à
   la navigation une colonne de 250 px, et WooCommerce lui donnait ensuite une
   largeur de 30 % DE CETTE COLONNE — soit 75 px. Mesuré : navigation 75 px
   dans une piste de 250, contenu 353 px dans une piste de 519. D'où les
   intitulés coupés (« COMMA… », « TÉLÉCH… ») et le contenu tassé au milieu.

   Un flottement à l'intérieur d'une grille n'a par ailleurs aucun sens : un
   élément de grille est déjà placé, le flottement ne peut que le rétrécir.
   On annule donc les deux déclarations plutôt que de lutter contre elles à
   coups de largeurs.

   Le sélecteur passe par `.ip-compte-grille` : trois classes contre deux, il
   l'emporte quel que soit l'ordre de chargement des feuilles. Compter sur
   l'ordre aurait suffi aujourd'hui — et aurait cassé le jour où un plugin de
   cache décide de concaténer les styles dans un autre ordre.
   --------------------------------------------------------------------------- */
.ip .ip-compte-grille > .woocommerce-MyAccount-navigation,
.ip .ip-compte-grille > .woocommerce-MyAccount-content{
  float:none;
  width:auto;
  max-width:none;
  margin:0;
}

/* La navigation ne doit jamais couper un intitulé. « Moyens de paiement » est
   le plus long ; sous 200 px il se brise en trois lignes. La piste ne descend
   donc pas sous cette valeur, et le texte ne se coupe pas au milieu d'un mot. */
.ip-nav-compte a{overflow-wrap:break-word;hyphens:none}


/* ---------------------------------------------------------------------------
   « LAQUELLE VOUS ARRÊTE ? » — le mur des œuvres, redessiné
   ---------------------------------------------------------------------------
   Ce qu'il était : une rangée d'étiquettes de 104 px, sans état de sélection
   lisible — un liseré bleu de deux pixels —, surmontée d'une ligne à part
   portant une pastille « Aucune en particulier » et un compte. Trois éléments
   de formulaire pour une seule question, et rien qui ressemblait au reste du
   site.

   Ce qu'il est : une grille de vignettes au format des cartes d'œuvre, où
   « aucune » est la première case. Quatre décisions, chacune pour une raison
   précise.

   1. LA SÉLECTION SE VOIT DE LOIN. Un cadre azur, une pastille cochée en haut
      à droite, la vignette qui se soulève d'un pixel. On choisit ici parmi
      cinquante images : un liseré fin se perd, et l'on ne sait plus si l'on a
      cliqué.

   2. LE CADRE EST AU FORMAT DE L'ŒUVRE, pas au carré. `object-fit:contain`
      sur fond neutre : un panoramique reste un panoramique. Recadrer au carré
      dans un sélecteur d'œuvres revient à montrer autre chose que ce qu'on
      demande de reconnaître.

   3. LA ZONE DÉFILANTE S'ESTOMPE EN BAS. Un dégradé de masque signale qu'il
      reste des pièces sous la ligne de coupe. Une zone tranchée net se lit
      comme une fin de liste, et personne ne fait défiler ce qu'il croit fini.

   4. LES INTERTITRES DE FAMILLE RESTENT COLLÉS EN HAUT pendant qu'on parcourt
      leur groupe. Au milieu d'un mur long, on ne sait plus si l'on regarde des
      huiles ou des aquarelles.

   Toujours aucune ligne de JavaScript : ce sont des boutons radio, l'état
   sélectionné est dessiné par `:has(input:checked)`, et le clavier y circule
   dans l'ordre du document.
   --------------------------------------------------------------------------- */

/* Le compte, dans la légende. */
.ip-legende--compte b{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.ip-legende--compte b em{
  font-style:normal;font-family:'Archivo',system-ui,sans-serif;
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
  color:var(--ip-bleu);
  background:rgba(0,74,173,.08);border:1px solid rgba(0,74,173,.2);
  border-radius:999px;padding:5px 11px;
}

.ip-mur{
  display:grid;
  /* `min(124px, 46%)` garantit DEUX COLONNES quelle que soit la largeur du
     panneau. Avec `minmax(124px,1fr)` seul, une colonne étroite — panneau
     resserré sur téléphone — retombait à une seule vignette par rangée, large
     comme la moitié de l'écran : on ne comparait plus rien, on feuilletait. */
  grid-template-columns:repeat(auto-fill,minmax(min(124px,46%),1fr));
  gap:clamp(12px,1.4vw,18px);
}
.ip-mur label{cursor:pointer;display:block;position:relative}
.ip-mur input{position:absolute;opacity:0;width:0;height:0}

.ip-mur__cadre{
  display:block;position:relative;overflow:hidden;
  aspect-ratio:4 / 5;border-radius:12px;
  border:1px solid var(--ip-trait);
  background:linear-gradient(160deg,#f7f5f0,#eceef1);
  transition:border-color .22s, box-shadow .22s, transform .22s;
}
.ip-mur__cadre img{
  width:100%;height:100%;display:block;
  /* `contain` et non `cover` : on demande de RECONNAÎTRE une œuvre. */
  object-fit:contain;
}
.ip-mur label:hover .ip-mur__cadre{
  border-color:rgba(0,74,173,.42);
  transform:translateY(-2px);
  box-shadow:0 14px 26px -18px rgba(0,42,99,.6);
}
/* L'ÉTAT CHOISI. Trois signaux d'un coup : le cadre, l'ombre, la pastille. */
.ip-mur label:has(input:checked) .ip-mur__cadre{
  border-color:var(--ip-bleu);
  box-shadow:0 0 0 2px var(--ip-bleu), 0 16px 30px -18px rgba(0,42,99,.7);
  transform:translateY(-2px);
}
.ip-mur label:has(input:checked)::after{
  content:'';position:absolute;top:8px;right:8px;width:22px;height:22px;
  border-radius:50%;background:var(--ip-bleu);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");
  background-size:13px;background-position:center;background-repeat:no-repeat;
  box-shadow:0 2px 8px rgba(0,42,99,.45);
}
.ip-mur label:has(input:focus-visible) .ip-mur__cadre{
  box-shadow:0 0 0 3px rgba(0,74,173,.28);
}
.ip-mur__nom{
  display:block;margin-top:8px;
  font-size:12.5px;line-height:1.35;color:var(--ip-encre-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.ip-mur label:has(input:checked) .ip-mur__nom{color:var(--ip-bleu);font-weight:600}

/* « Aucune en particulier » : même case, dessinée en creux. */
.ip-mur__vide .ip-mur__cadre{
  border-style:dashed;background:none;
  display:flex;align-items:center;justify-content:center;
  color:var(--ip-encre-2);
}
.ip-mur__vide .ip-mur__cadre svg{width:30%;height:auto;opacity:.55}
.ip-mur__vide:has(input:checked) .ip-mur__cadre{border-style:solid;color:var(--ip-bleu)}

/* LA ZONE DÉFILANTE. */
.ip-mur-zone{
  max-height:min(56vh,470px);
  overflow-y:auto;overscroll-behavior:contain;
  padding:4px 14px 22px 4px;
  border-radius:14px;
  /* Le masque dit qu'il reste des pièces dessous. Les navigateurs qui
     l'ignorent affichent la zone entière : rien n'est perdu. */
  -webkit-mask-image:linear-gradient(#000 calc(100% - 46px), transparent);
          mask-image:linear-gradient(#000 calc(100% - 46px), transparent);
}
.ip-mur-zone::-webkit-scrollbar{width:8px}
.ip-mur-zone::-webkit-scrollbar-thumb{background:rgba(0,42,99,.22);border-radius:8px}
.ip-mur-zone::-webkit-scrollbar-track{background:transparent}

.ip-mur-famille{
  position:sticky;top:0;z-index:2;margin:22px 0 12px;
  display:flex;align-items:center;gap:10px;
  padding:8px 0 9px;
  font-size:11.5px;letter-spacing:.18em;text-transform:uppercase;font-weight:600;
  color:var(--ip-bleu);
  background:linear-gradient(var(--ip-papier) 74%, rgba(255,255,255,0));
}
.ip-mur-famille::after{
  content:'';flex:1;height:1px;background:var(--ip-trait);
}
.ip-mur-famille i{
  order:1;font-style:normal;font-size:11px;letter-spacing:.06em;
  color:var(--ip-encre-2);
}
.ip-mur-zone > .ip-mur:first-child{margin-bottom:4px}

@media (max-width:640px){
  .ip-mur{grid-template-columns:repeat(auto-fill,minmax(min(98px,46%),1fr))}
  .ip-mur-zone{max-height:min(52vh,400px)}
}

html.cda-dark .ip-mur-famille{background:linear-gradient(#0d1117 74%, rgba(13,17,23,0))}
html.cda-dark .ip-mur__cadre{background:linear-gradient(160deg,#1a1d22,#141619)}


/* ---------------------------------------------------------------------------
   LES CARTES NE SE CHARGENT QU'À LA DEMANDE
   ---------------------------------------------------------------------------
   L'aperçu est un dessin, pas une image de Google : un plan schématique en SVG
   de deux cents octets, qui dit « ici il y aura une carte » sans transmettre la
   moindre donnée. Le cadre garde exactement la forme et le dessin qu'il aura
   une fois chargé, pour que le clic ne provoque aucun saut de mise en page.
   --------------------------------------------------------------------------- */
.ip-lieu__cadre{
  display:flex;align-items:center;justify-content:center;
}
.ip-lieu__apercu{position:absolute;inset:0}
.ip-lieu__apercu svg{width:100%;height:100%;display:block}
.ip-lieu__bouton{
  position:relative;z-index:2;
  display:inline-flex;align-items:center;gap:8px;
  padding:11px 18px;border:0;border-radius:999px;cursor:pointer;
  background:rgba(13,17,23,.82);color:#fff;
  font-family:inherit;font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;font-weight:600;
  transition:background .25s, transform .25s;
}
.ip-lieu__bouton:hover{background:var(--ip-bleu);transform:translateY(-1px)}
.ip-lieu__bouton:focus-visible{outline:2px solid var(--ip-bleu);outline-offset:3px}
/* L'avertissement est SOUS le bouton et non dans une infobulle : le visiteur
   doit savoir ce qu'il déclenche AVANT de cliquer, pas après. */
.ip-lieu__avis{
  position:absolute;left:10px;right:10px;bottom:9px;z-index:2;
  font-size:10.5px;line-height:1.35;text-align:center;color:var(--ip-encre-2);
}
.ip-lieu__cadre.est-chargee .ip-lieu__apercu,
.ip-lieu__cadre.est-chargee .ip-lieu__bouton,
.ip-lieu__cadre.est-chargee .ip-lieu__avis{display:none}


/* ---------------------------------------------------------------------------
   LES PAGES LÉGALES
   ---------------------------------------------------------------------------
   Un texte juridique se lit mal par principe ; le rôle de la mise en page est
   d'en atténuer la peine, pas de l'aggraver. Trois règles :

   · une mesure courte — 68 signes — parce qu'on relit souvent la même phrase ;
   · des articles numérotés et détachés, pour qu'on puisse en citer un ;
   · les FAITS sortis du texte courant. Un SIRET, une adresse, un délai se
     cherchent du regard : perdus au milieu d'un paragraphe, il faut le lire en
     entier pour les trouver. `.ip-legal__faits` les pose en deux colonnes.
   --------------------------------------------------------------------------- */
.ip-legal{max-width:820px}
.ip-legal__art{padding:clamp(22px,2.6vw,32px) 0;border-top:1px solid var(--ip-trait)}
.ip-legal__art:first-child{border-top:0;padding-top:0}
.ip-legal__art h2{
  display:flex;gap:12px;align-items:baseline;
  margin:0 0 .7em;
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(19px,1.8vw,26px);line-height:1.2;color:var(--ip-encre);
}
.ip-legal__art h2 span{
  font-family:'Archivo',system-ui,sans-serif;font-size:13px;font-weight:600;
  color:var(--ip-bleu);letter-spacing:.04em;
}
.ip-legal__art p{
  margin:0 0 .9em;max-width:68ch;
  font-size:15.5px;line-height:1.75;color:var(--ip-encre-2);
}
.ip-legal__art p:last-child{margin-bottom:0}

/* Les faits, en deux colonnes. */
.ip-legal__faits{list-style:none;margin:0 0 1em;padding:0}
.ip-legal__faits li{
  display:grid;grid-template-columns:minmax(120px,190px) minmax(0,1fr);
  gap:6px 18px;align-items:baseline;
  padding:9px 0;border-bottom:1px solid var(--ip-trait);
}
.ip-legal__faits li:last-child{border-bottom:0}
.ip-legal__faits b{
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ip-encre-2);font-weight:600;
}
.ip-legal__faits span{font-size:15.5px;line-height:1.55;color:var(--ip-encre);white-space:pre-line}
@media (max-width:560px){
  .ip-legal__faits li{grid-template-columns:1fr;gap:2px}
}

/* Les tableaux — traitements de données, cookies. Ils débordent sur téléphone :
   ils défilent DANS leur cadre, jamais la page. */
.ip-legal__tab{overflow-x:auto;margin:0 0 1em;-webkit-overflow-scrolling:touch}
.ip-legal__tab table{width:100%;min-width:520px;border-collapse:collapse;font-size:14px}
.ip-legal__tab th{
  text-align:left;padding:10px 14px 10px 0;border-bottom:1px solid var(--ip-bleu);
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ip-bleu);font-weight:600;
}
.ip-legal__tab td{
  padding:12px 14px 12px 0;border-bottom:1px solid var(--ip-trait);
  line-height:1.55;color:var(--ip-encre-2);vertical-align:top;
}
.ip-legal__tab code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;
  color:var(--ip-encre);word-break:break-all;
}

/* Un point d'attention — une exception, une exclusion. Il est encadré parce
   qu'il coûte un droit au lecteur : ce sont les lignes qu'on lui reprochera de
   n'avoir pas lues, et elles doivent donc se voir. */
.ip-legal__att{
  margin:1.2em 0 !important;padding:16px 20px;
  border-left:3px solid var(--ip-bleu);border-radius:0 10px 10px 0;
  background:rgba(0,74,173,.05);
  color:var(--ip-encre) !important;
}
.ip-legal__note{
  margin:clamp(24px,3vw,36px) 0 0;padding-top:clamp(18px,2vw,24px);
  border-top:1px solid var(--ip-trait);
  font-size:13.5px;line-height:1.65;color:var(--ip-encre-2);max-width:68ch;
}

/* LE MARQUEUR DES CHAMPS NON REMPLIS.
   Il est voyant, et c'est le but : une mention légale incomplète doit se voir
   au premier coup d'œil, jamais se confondre avec une donnée réelle. */
.ip-acompleter{
  background:rgba(179,70,47,.12);color:#a03c26;
  border:1px dashed rgba(179,70,47,.5);border-radius:6px;
  padding:1px 8px;font-size:12.5px;letter-spacing:.06em;
  text-transform:uppercase;font-weight:600;
}
html.cda-dark .ip-acompleter{background:rgba(255,140,110,.16);color:#ffb4a0}

/* ===========================================================================
   LES REPÈRES DU CATALOGUE

   Ce bloc dit en toutes lettres ce que la grille montre en images. Il est
   volontairement discret : plus petit que le corps du texte des pages,
   sans fond, sans cadre — la grille reste le sujet. Un encadré aurait fait
   « bloc SEO », ce qu'il est, mais ce qu'il ne doit pas avoir l'air d'être.
   =========================================================================== */
.ip-reperes{
  max-width:760px;margin:0 auto;padding:clamp(28px,4vw,52px) 0 0;
  border-top:1px solid var(--ip-trait);
}
.ip-reperes__titre{
  font-family:var(--cda-display,'Oswald',system-ui,sans-serif);
  text-transform:uppercase;
  font-size:clamp(17px,1.5vw,20px);font-weight:500;letter-spacing:.01em;
  margin:0 0 .7em;color:var(--ip-encre);
}
.ip-reperes p{
  font-size:15px;line-height:1.75;color:var(--ip-encre-2,var(--ip-encre));
  margin:0 0 1em;text-wrap:pretty;
}
.ip-reperes p:last-child{margin-bottom:0}
.ip-reperes__familles{
  font-size:14.5px;
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 18px;
}
.ip-reperes__etiq{color:var(--ip-encre-2);font-size:13px}
.ip-reperes__familles a{
  color:var(--ip-encre);text-decoration:none;
  display:inline-flex;align-items:center;gap:5px;min-height:24px;
  border-bottom:1px solid var(--ip-trait);padding-bottom:1px;
  transition:border-color .25s ease;
}
.ip-reperes__familles a:hover{border-bottom-color:currentColor}
.ip-reperes__familles a span{
  font-size:12px;opacity:.55;
}

/* ===========================================================================
   LE CHAMP DE RECHERCHE DU CATALOGUE

   Il a exactement la hauteur et le rayon des pastilles voisines : c'est un
   filtre de plus, et il doit se lire comme tel. Il ne prend la parole qu'au
   focus, où le trait passe au bleu — le même bleu que la pastille active.
   =========================================================================== */
.ip-cherche{
  display:inline-flex;align-items:center;gap:8px;
  min-height:40px;padding:0 14px;border-radius:999px;
  border:1px solid var(--ip-trait);background:transparent;
  transition:border-color .25s ease,background .25s ease;
  max-width:min(260px,42vw);
}
.ip-cherche:focus-within{border-color:var(--ip-bleu);background:rgba(0,74,173,.04)}
.ip-cherche svg{width:15px;height:15px;flex:none;color:var(--ip-encre-2)}
.ip-cherche:focus-within svg{color:var(--ip-bleu)}
.ip-cherche input{
  border:0;background:none;outline:none;min-width:0;width:100%;
  font-family:inherit;font-size:13.5px;color:var(--ip-encre);padding:0;
}
.ip-cherche input::placeholder{color:var(--ip-encre-2);opacity:.85}
.ip-cherche input::-webkit-search-cancel-button{-webkit-appearance:none}

.ip-cherche__vide{
  margin:0 0 22px;font-size:15px;line-height:1.6;color:var(--ip-encre-2);
  text-align:center;
}
.ip-cherche__vide[hidden]{display:none}

@media (max-width:620px){
  .ip-cherche{max-width:100%;flex:1 1 100%;order:-1}
  .ip-cherche input{font-size:16px}   /* 16 px : en dessous, iOS zoome au focus */
}

/* `.ip-carte` porte `display:flex` : sans cette règle, l'attribut `hidden`
   posé par la recherche resterait sans effet — une propriété d'affichage
   déclarée l'emporte toujours sur le `display:none` de la feuille par
   défaut du navigateur. C'est la panne classique de tout filtre en
   JavaScript, et elle est silencieuse. */
.ip-grille .ip-carte[hidden]{display:none !important}

/* ===========================================================================
   LE BLOC « UNE QUESTION ? » SE DÉTACHE DU MENU DU COMPTE

   Il touchait la dernière entrée de la navigation : à deux pixels près, son
   titre se lisait comme un onglet de plus. L'écart et le filet disent ce que
   la structure disait déjà — ici, le menu est fini.
   =========================================================================== */
.ip-nav-compte__aide{
  margin-top:clamp(30px,4vh,52px);
  padding-top:clamp(20px,2.6vh,30px);
  border-top:1px solid var(--ip-trait);
}

/* ===========================================================================
   LES MESSAGES

   « Nous vous avons envoyé un lien par courriel » est la phrase la plus
   importante de la page au moment où elle s'affiche : c'est la seule qui
   dise à quelqu'un ce qu'il doit faire ensuite. Elle était rendue dans un
   rectangle bleu pâle de quatorze pixels de haut, sans titre, sans icône,
   du même gris que le reste — on la lisait après l'avoir cherchée.

   TROIS CHOSES LA RENDENT LISIBLE, ET AUCUNE N'EST DÉCORATIVE.

   · UNE ICÔNE, dessinée en masque pour prendre la couleur du message. Elle
     dit le GENRE de la nouvelle — réussi, à savoir, raté — avant que le
     texte soit lu. WooCommerce en pose une lui-même, tirée de sa police
     d'icônes ; on la neutralise plutôt que d'en afficher deux.

   · UNE BARRE DE COULEUR à gauche, et non un fond teinté sur toute la
     surface. Un aplat pâle derrière du texte le rend plus difficile à
     lire, pas plus visible ; la barre marque le bloc sans toucher au
     contraste de la phrase.

   · UNE ARRIVÉE. Le message apparaît après une action — un clic sur un
     bouton — et il apparaît souvent au-dessus de la ligne de flottaison,
     là où l'œil n'est pas. Un fondu montant de trois dixièmes suffit à
     accrocher le regard ; au-delà, on attend au lieu de lire.
   =========================================================================== */
.ip .woocommerce-message,
.ip .woocommerce-info,
.ip .woocommerce-error,
.ip .woocommerce-notices-wrapper > *{
  --msg:#004aad;                       /* la couleur du genre de message */
  /* BLOC, PAS FLEX, ET C'EST UNE CORRECTION MESURÉE.
     En `flex`, chaque <li> d'un message qui en contient plusieurs devient
     un élément de la ligne : une erreur en deux points s'affichait sur
     DEUX COLONNES côte à côte au lieu de deux lignes. Le retrait plus
     l'icône en position absolue traite de la même façon un message d'un
     seul texte, une liste de trois, ou un bouton ajouté par une
     extension. */
  position:relative;display:block;
  margin:0 0 22px;padding:18px 22px 18px 57px;
  border:1px solid var(--ip-trait);
  border-left:3px solid var(--msg);
  border-radius:4px 14px 14px 4px;
  background:var(--ip-papier);
  box-shadow:0 18px 40px -34px rgba(6,10,20,.55);
  font-size:15.5px;line-height:1.6;color:var(--ip-encre);
  list-style:none;
  animation:ip-msg .34s cubic-bezier(.16,1,.3,1) both;
}
@keyframes ip-msg{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .ip .woocommerce-message,.ip .woocommerce-info,.ip .woocommerce-error{animation:none}
}

/* L'icône. `mask` plutôt qu'un fond coloré : un seul dessin, trois couleurs,
   et il suit automatiquement le mode sombre. */
.ip .woocommerce-message::before,
.ip .woocommerce-info::before,
.ip .woocommerce-error::before{
  content:'';
  position:absolute;left:22px;top:19px;
  width:21px;height:21px;
  background:var(--msg);
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
  /* pastille + coche */
  -webkit-mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><path d='M8.4 12.3l2.5 2.5 4.7-5'/></svg>");
  mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><path d='M8.4 12.3l2.5 2.5 4.7-5'/></svg>");
  /* WooCommerce pose sa propre icône avec sa police : on la remplace, donc
     on efface ce qui vient d'elle. */
  font-size:0;line-height:0;
}
/* Information : un « i ». */
.ip .woocommerce-info::before{
  -webkit-mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='12' cy='12' r='9'/><path d='M12 11v5'/><path d='M12 7.6v.01'/></svg>");
  mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='12' cy='12' r='9'/><path d='M12 11v5'/><path d='M12 7.6v.01'/></svg>");
}
/* Erreur : un point d'exclamation. */
.ip .woocommerce-error{--msg:#b3462f}
.ip .woocommerce-error::before{
  -webkit-mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='12' cy='12' r='9'/><path d='M12 7.5v5.5'/><path d='M12 16.4v.01'/></svg>");
  mask-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='12' cy='12' r='9'/><path d='M12 7.5v5.5'/><path d='M12 16.4v.01'/></svg>");
}
.ip .woocommerce-message{--msg:#1d7a4c}

/* La première phrase porte la nouvelle ; WooCommerce n'ayant pas de titre,
   c'est elle qu'on met en avant. Les listes de messages multiples gardent
   leurs puces implicites, alignées sur le texte et non sur l'icône. */
.ip .woocommerce-error li,
.ip .woocommerce-message li,
.ip .woocommerce-info li{margin:0 0 6px;list-style:none}
.ip .woocommerce-error li:last-child,
.ip .woocommerce-message li:last-child,
.ip .woocommerce-info li:last-child{margin-bottom:0}
.ip .woocommerce-message strong,
.ip .woocommerce-info strong{font-weight:600}

/* Le bouton que WooCommerce glisse parfois dans un message — « Voir le
   panier » — ne doit pas pousser le texte : il passe à la ligne. */
.ip .woocommerce-message .button,
.ip .woocommerce-info .button{margin:10px 0 0;float:none;display:inline-flex}
.ip .woocommerce-notices-wrapper:empty{display:none}

html.cda-dark .ip .woocommerce-message,
html.cda-dark .ip .woocommerce-info,
html.cda-dark .ip .woocommerce-error,
html.cda-dark .ip .woocommerce-notices-wrapper > *{
  background:rgba(255,255,255,.04);
  border-color:rgba(255,255,255,.12);
  /* `border-color` repeint les quatre côtés : sans cette ligne, la barre
     d'accent disparaissait en mode sombre — mesuré, elle passait au gris
     de bordure. C'est elle qui porte tout le sens du bloc. */
  border-left-color:var(--msg);
  box-shadow:none;
}
html.cda-dark .ip .woocommerce-message{--msg:#4cc389}
html.cda-dark .ip .woocommerce-info{--msg:#6ba6f2}
html.cda-dark .ip .woocommerce-error{--msg:#e08a72}

/* ===========================================================================
   LE VERRE DÉPOLI S'ARRÊTE AUX PETITS ÉCRANS

   `.ip-panneau` porte un `backdrop-filter: blur(18px)` — c'est lui qui donne
   au panneau son fond dépoli, et c'est un élément de la charte : on le garde.

   Mais un flou d'arrière-plan sur un bloc qui DÉFILE oblige la carte
   graphique à refaire le flou à chaque image, sur toute la surface du bloc.
   Sur un ordinateur cela ne se voit pas ; sur un téléphone de milieu de
   gamme, c'est la première cause de défilement saccadé — et c'est là que
   l'effet se voit le moins, puisque le panneau occupe presque tout l'écran
   et qu'il n'y a quasiment plus d'arrière-plan à flouter.

   En dessous de 780 px, le flou cède donc la place à un fond opaque de même
   valeur. Personne ne verra la différence ; tout le monde sentira celle du
   défilement.
   =========================================================================== */
@media (max-width:780px){
  /* Le flou part, le verre reste : un peu plus dense qu'en grand écran,
     parce que le panneau occupe presque tout l'affichage et qu'il n'y a
     plus grand-chose derrière lui à laisser voir. */
  .ip-panneau{
    -webkit-backdrop-filter:none;backdrop-filter:none;
    background:var(--cda-verre-lumiere),rgba(255,255,255,.74);
  }
  html.cda-dark .ip-panneau{background:var(--cda-verre-lumiere),rgba(16,21,29,.72)}
}

/* ===========================================================================
   L'ERGONOMIE MOBILE — MESURÉE SUR LE SITE EN LIGNE, PAS SUPPOSÉE
   ===========================================================================
   Ce bloc répond à trois défauts relevés au doigt sur un téléphone de
   375 px, page par page. Chacun est chiffré : ce ne sont pas des
   préférences, ce sont des seuils que la page ne tenait pas.

   1. LE PANNEAU DES FILTRES SORTAIT DE L'ÉCRAN.
      `.ip-menu__pan` est un menu déroulant ancré sous son bouton, avec
      `min-width:210px` — et 280 px pour celui des couleurs. Le troisième
      bouton d'une rangée commence vers 200 px : le panneau s'ouvrait donc
      de 207 à 439 px sur un écran qui en fait 375. Mesuré, il dépassait de
      64 px, et c'est ce qui faisait « glisser » la page sur le côté.
      Sur mobile il cesse d'être un menu ancré pour devenir une feuille :
      calée sur la gouttière, jamais plus large que la fenêtre.

   2. LES CIBLES TACTILES ÉTAIENT SOUS 44 px.
      Relevé : liens du pied de page 24 px de haut, choix de couleur 33 px,
      entrées de menu 33 px, bouton du menu mobile 38×28, croix de
      fermeture 31×32, bascule de langue 19×14. La recommandation d'Apple
      et celle de Google se rejoignent à 44 px ; en dessous, on vise, on
      manque, et on ouvre le lien d'à côté. On agrandit la ZONE SENSIBLE
      sans grossir le dessin, par du remplissage et une hauteur minimale —
      rien ne change à l'œil.

   3. DU TEXTE DESCENDAIT À 10 px.
      Relevé : titres du pied de page 11 px, sur-titre d'ouverture 10 px,
      noms de couleurs 12,5 px sur soixante-deux étiquettes, mentions 11,3.
      À bout de bras, sur un écran tenu à quarante centimètres, 10 px est
      illisible pour une bonne partie des acheteurs de ce site — qui n'ont
      pas vingt ans. Plancher à 13 px pour tout ce qui se lit, la
      hiérarchie étant reportée sur la graisse et la couleur, qui ne
      coûtent rien en lisibilité.
   =========================================================================== */
@media (max-width:780px){

  /* 1. le menu des filtres devient une feuille, jamais plus large que l'écran */
  .ip-menu{position:static}
  .ip-menu__pan,
  .ip-menu__pan--couleurs{
    position:absolute;left:var(--ip-marge);right:var(--ip-marge);
    width:auto;min-width:0;max-width:none;
    box-sizing:border-box;
  }
  .ip-menu__pan--couleurs{grid-template-columns:1fr 1fr}

  /* 2. les cibles tactiles : 44 px de haut, partout où l'on appuie */
  .ip-menu__pan a,
  .ip-cchoix{min-height:44px;display:flex;align-items:center}
  .ip-pilule,
  .ip-menu > summary{min-height:44px}
  .ip-reset{display:inline-flex;align-items:center;min-height:44px}

  /* 3. le plancher de lisibilité */
  .ip-ouv__sur{font-size:13px}
  .ip-mur__nom{font-size:13px}
  .ip-mur-famille{font-size:13px}
  .ip-menu__pan a,
  .ip-cchoix{font-size:14.5px}
}

/* ===========================================================================
   ===========================================================================
   LA PAGE DU PEINTRE — `pt-*`
   ===========================================================================
   Un vocabulaire à part, et c'est délibéré. Le reste du site emploie `ip-*`,
   un jeu de composants pensé pour des pages qui se ressemblent : catalogue,
   contact, mentions légales. Une page d'artiste n'a pas à leur ressembler —
   c'est la seule page du site dont le sujet EST une composition. Elle a donc
   ses propres formes, et chacune ne sert qu'une fois : le seuil, la palette,
   la route, les quatre gestes, la voix, le mur, le vis-à-vis.

   Aucune de ces formes n'emploie de panneau. C'était le défaut de la version
   précédente : tout y était un rectangle blanc posé sur la page, et six
   rectangles identiques à la suite se lisent comme un formulaire. Ici, le
   fond de pigment reste visible d'un bout à l'autre — ce sont les filets,
   les échelles de texte et les alignements qui structurent, pas des boîtes.
   =========================================================================== */

.pt{--pt-filet:rgba(13,17,23,.16)}
html.cda-dark .pt{--pt-filet:rgba(255,255,255,.2)}

/* Les têtes de section, communes aux six blocs. */
.pt-tete{max-width:52ch;margin:0 0 clamp(38px,5vw,68px);padding:0 var(--ip-marge)}
.pt-tete h2{
  margin:0 0 .5em;font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(28px,3.4vw,52px);line-height:1.08;letter-spacing:-.01em;color:var(--ip-encre);
}
.pt-tete h2 em{font-style:italic;color:var(--ip-bleu)}
html.cda-dark .pt-tete h2 em{color:var(--ip-bleu-txt,#6ba6f2)}
.pt-tete p{margin:0;font-size:var(--ip-suite);line-height:1.7;color:var(--ip-encre-2)}
.pt-tete--centre{margin-left:auto;margin-right:auto;text-align:center;max-width:58ch}

/* ---------------------------------------------------------------------------
   1. LE SEUIL
   ---------------------------------------------------------------------------
   Deux colonnes qui se CHEVAUCHENT : le nom occupe les colonnes 1 à 2, le
   portrait les colonnes 2 à 3. La zone commune est la colonne 2, et c'est
   là que le nom passe devant le visage.

   Le chevauchement est retiré sous 900 px. Ce n'est pas une simplification
   par facilité : sur une colonne unique, un nom posé sur un portrait le
   couvre entièrement au lieu de le border, et l'effet se retourne. */
.pt-seuil{
  /* ═══ DEUX BLOCS, UNE LIGNE DE BASE ═══
     Le texte d'un côté, la photographie de l'autre, tous deux calés sur
     la MÊME ligne du bas. C'est le seul alignement de la composition, et
     il tient quelle que soit la hauteur de l'image.

     La version précédente plaçait le surtitre, le nom et la phrase dans
     trois cases distinctes. Une case de grille s'étire à la hauteur de sa
     rangée, et la rangée était celle du portrait : le surtitre se
     retrouvait donc au milieu de la page, le nom tout en bas, et quatre
     cents pixels de vide entre les deux. Un bloc unique ne peut plus se
     disloquer. */
  display:grid;
  grid-template-columns:minmax(0,.72fr) minmax(0,1fr);
  align-items:end;
  column-gap:clamp(10px,2vw,30px);
  padding:clamp(90px,12vh,140px) var(--ip-marge) clamp(50px,7vh,90px);
  max-width:1320px;margin-inline:auto;
  position:relative;isolation:isolate;overflow:clip;
}

/* CONSTELLATION CHROMATIQUE — la scène reste derrière le portrait et le texte.
   Sans la classe posée par le module, elle est invisible : aucun canevas blanc
   ne peut donc apparaître pendant le chargement ou sur une machine sans WebGL. */
.pt-scene{
  position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  opacity:0;transition:opacity 1.4s cubic-bezier(.16,1,.3,1);
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 13%,#000 82%,transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0,#000 13%,#000 82%,transparent 100%);
}
.pt-seuil--3d .pt-scene{opacity:.84}
.pt-scene canvas{display:block;width:100%;height:100%}
.pt-scene__legende{
  position:absolute;right:clamp(14px,2vw,28px);bottom:clamp(88px,11vh,132px);
  display:flex;flex-direction:column;align-items:flex-end;gap:5px;margin:0;
  color:var(--ip-encre-2);font-size:10px;line-height:1.2;letter-spacing:.22em;
  text-transform:uppercase;opacity:.72;
}
.pt-scene__legende::before{
  content:'';width:clamp(42px,5vw,72px);height:1px;margin-bottom:6px;
  background:linear-gradient(90deg,transparent,var(--pt-actif,var(--ip-bleu)));
  transition:background .35s ease;
}
.pt-scene__legende b{font-weight:500;color:var(--ip-encre);letter-spacing:.12em}
.pt-seuil__dit,.pt-portrait,.pt-frise{position:relative}

/* Une lueur basse lie la scène au papier sans ajouter de panneau au héros. */
.pt-seuil::after{
  content:'';position:absolute;z-index:0;left:18%;right:-10%;bottom:2%;height:42%;
  pointer-events:none;opacity:0;filter:blur(42px);
  background:radial-gradient(ellipse at 58% 80%,color-mix(in srgb,var(--pt-actif,var(--ip-bleu)) 22%,transparent),transparent 67%);
  transition:opacity 1.2s ease,background .45s ease;
}
.pt-seuil--3d::after{opacity:.58}
.pt-seuil__dit{grid-column:1;grid-row:1;align-self:end;position:relative;z-index:2;min-width:0}

.pt-sur{
  margin:0 0 clamp(10px,1.4vw,18px);
  font-size:13px;letter-spacing:.3em;text-transform:uppercase;color:var(--ip-encre-2);
}
.pt-nom{
  margin:0;
  font-family:'Playfair Display',Georgia,serif;font-weight:700;
  font-size:clamp(78px,26vw,360px);letter-spacing:-.04em;
  /* ═══ LA PANSE DES « J » DESCEND SOUS LA LIGNE, ET IL FAUT LUI FAIRE
     DE LA PLACE ═══
     `line-height:.86` serrait la boîte à moins d'un cadratin. En
     Playfair, le J capital plonge nettement sous la ligne de base : les
     jambages sortaient donc de la boîte et venaient barrer la phrase
     posée dessous — on le voit sur la capture, « Né en 1957 » traversé
     par les deux J.

     La garde est en `em` et non en pixels : elle suit la taille du nom,
     qui va de 78 à 360 px selon l'écran. Une valeur fixe aurait été trop
     grande en bas de plage et trop juste en haut — c'est-à-dire fausse
     partout sauf à une largeur. */
  line-height:1;
  /* La marge est de .18em et non de .06 : les marges verticales de deux
     frères ADJACENTES SE FUSIONNENT — seule la plus grande compte. Celle
     du nom et celle de la phrase ne s'additionnent donc pas, et une
     valeur calculée comme si elles s'ajoutaient laissait la garde à
     0,10 em au lieu des 0,16 nécessaires. Mesuré par `essai/peintre.js`. */
  margin-bottom:.18em;
  color:var(--ip-encre);white-space:nowrap;
  /* ═══ LE CHEVAUCHEMENT, OBTENU PAR DÉBORDEMENT ═══
     Le nom ne fait que trois signes : à cette taille, il est plus large
     que sa colonne. `width:max-content` le laisse prendre sa vraie
     largeur, et une case de grille ne rogne pas ce qui dépasse — il
     passe donc naturellement devant le portrait, sans marge négative à
     régler ni proportion à deviner. Le recouvrement suit la taille du
     nom, ce qui est exactement ce qu'on veut. */
  width:max-content;max-width:none;
  text-shadow:0 2px 34px rgba(255,255,255,.6);
}
html.cda-dark .pt-nom{text-shadow:0 2px 34px rgba(0,0,0,.8)}
.pt-phrase{
  margin:clamp(20px,2.6vw,34px) 0 0;max-width:34ch;
  font-size:var(--ip-gros-petit);line-height:1.5;color:var(--ip-encre);
}

.pt-portrait{
  grid-column:2;grid-row:1;align-self:end;
  margin:0;position:relative;z-index:1;
  /* La photographie se cale à GAUCHE de sa colonne, pas à droite.
     Bornée en hauteur, elle est souvent plus étroite que sa colonne :
     ferrée à droite, elle s'éloignait du nom et le recouvrement tombait
     à zéro sur grand écran — mesuré, 291 px d'écart. Contre le bord
     gauche de sa colonne, elle vient au contraire à la rencontre du nom,
     et l'air qui reste passe dans la marge de droite, où il se lit comme
     une marge et non comme un trou. */
  display:flex;flex-direction:column;align-items:flex-start;
}
/* ═══ LE PORTRAIT GARDE SES PROPORTIONS, ET TIENT DANS L'ÉCRAN ═══
   Il avait d'abord une hauteur imposée et un `object-fit:cover` : le
   cadre décidait, et la photographie était rognée pour y entrer. Sur la
   page d'un peintre, c'est le portrait qui doit décider — d'où
   `height:auto`.

   Mais `height:auto` seul confie la hauteur à la LARGEUR DE LA COLONNE :
   une photographie en portrait, servie sur cinq cents pixels de large,
   en fait sept cents de haut. Le seuil dépassait alors la hauteur de
   l'écran et le nom passait sous la ligne de flottaison.

   La contrainte juste n'est ni la largeur ni un recadrage : c'est la
   HAUTEUR DISPONIBLE. `max-height` en unités de fenêtre, `width:auto`
   pour que la largeur suive : la photographie garde son rapport exact,
   pas un pixel n'est perdu, et elle ne peut plus pousser le seuil hors
   de l'écran. Une photo panoramique, elle, reste bornée par la colonne —
   les deux limites cohabitent sans jamais déformer. */
.pt-portrait img{
  width:auto;height:auto;
  max-width:100%;max-height:min(70vh,640px);
  display:block;
  border-radius:clamp(14px,2vw,26px);
  box-shadow:0 60px 120px -70px rgba(9,24,48,.7);
}
.pt-portrait figcaption{
  margin-top:12px;font-size:13px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ip-encre-2);text-align:left;
}

/* La frise : trois faits sur une ligne, séparés par des filets. */
.pt-frise{
  grid-column:1 / 3;grid-row:2;
  list-style:none;margin:clamp(44px,6vh,78px) 0 0;padding:clamp(26px,3vw,36px) 0 0;
  border-top:1px solid var(--pt-filet);
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(18px,2.4vw,40px);
}
.pt-frise li{display:flex;flex-direction:column;gap:8px;min-width:0}
.pt-frise li + li{border-left:1px solid var(--pt-filet);padding-left:clamp(18px,2.4vw,40px)}
.pt-frise b{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(19px,2.1vw,32px);line-height:1.1;color:var(--ip-encre);
  overflow-wrap:anywhere;
}
.pt-frise span{font-size:13px;letter-spacing:.2em;text-transform:uppercase;color:var(--ip-encre-2)}

@media (max-width:900px){
  /* Le chevauchement est retiré, et ce n'est pas une facilité : sur une
     colonne unique, un nom posé sur un portrait le COUVRE au lieu de le
     border, et l'effet se retourne contre ce qu'il cherche. */
  .pt-seuil{grid-template-columns:minmax(0,1fr);padding-top:clamp(74px,10vh,110px)}
  .pt-seuil__dit,.pt-portrait,.pt-frise{grid-column:1;grid-row:auto}
  .pt-nom{width:auto;text-shadow:none;font-size:clamp(72px,21vw,150px)}
  .pt-portrait{margin:clamp(22px,4vw,32px) 0 0;align-items:stretch}
  .pt-portrait img{max-height:56vh;margin-inline:auto}
  .pt-portrait figcaption{text-align:left}
  .pt-frise{grid-template-columns:minmax(0,1fr);margin-top:clamp(34px,6vw,48px)}
  .pt-frise li + li{border-left:0;border-top:1px solid var(--pt-filet);padding-left:0;padding-top:18px}
  .pt-scene{inset:-4% -24% 18% -24%}
  .pt-seuil--3d .pt-scene{opacity:.62}
  .pt-scene__legende{display:none}
}

@media (prefers-reduced-motion:reduce){
  .pt-scene,.pt-seuil::after{display:none}
}

/* ---------------------------------------------------------------------------
   2. SA PALETTE
   ---------------------------------------------------------------------------
   Une lamelle par toile, rangée par teinte. La bande va d'un bord à l'autre
   de l'écran : c'est ce qui la fait lire comme une matière plutôt que comme
   un graphique.

   AU SURVOL, ON AGRANDIT PAR `transform`, JAMAIS PAR LA LARGEUR. Une
   transition de largeur sur soixante éléments recalculerait la mise en page
   de toute la bande à chaque image. `scaleY` depuis le bas ne coûte rien :
   c'est le compositeur qui le fait. */
.pt-couleurs{padding:var(--ip-section) 0}
.pt-nuancier{
  list-style:none;margin:0;padding:0;display:flex;width:100%;
  height:clamp(120px,20vh,210px);
  border-top:1px solid var(--pt-filet);border-bottom:1px solid var(--pt-filet);
}
.pt-nuancier li{flex:1 1 0;min-width:0;position:relative}
.pt-nuancier a{
  display:block;width:100%;height:100%;background:var(--c);
  transform-origin:50% 100%;
  transition:transform .5s cubic-bezier(.32,.72,0,1);
}
.pt-nuancier a:hover,
.pt-nuancier a:focus-visible{transform:scaleY(1.16);outline:none}
/* Le nom de l'œuvre ne s'affiche qu'à la demande : soixante étiquettes
   permanentes feraient une page illisible. */
.pt-nuancier__nom{
  position:absolute;left:50%;bottom:calc(100% + 12px);transform:translateX(-50%) translateY(6px);
  white-space:nowrap;pointer-events:none;opacity:0;
  font-size:13px;letter-spacing:.06em;color:var(--ip-encre);
  background:rgba(255,255,255,.94);border:1px solid var(--pt-filet);
  border-radius:999px;padding:7px 14px;
  transition:opacity .25s ease,transform .35s cubic-bezier(.32,.72,0,1);
  z-index:3;
}
html.cda-dark .pt-nuancier__nom{background:rgba(14,18,24,.96);color:#f2f2f2}
.pt-nuancier a:hover .pt-nuancier__nom,
.pt-nuancier a:focus-visible .pt-nuancier__nom{opacity:1;transform:translateX(-50%) translateY(0)}
/* Aux deux bouts, l'étiquette sortirait de l'écran : on la ramène. */
.pt-nuancier li:nth-child(-n+3) .pt-nuancier__nom{left:0;transform:translateX(0) translateY(6px)}
.pt-nuancier li:nth-child(-n+3) a:hover .pt-nuancier__nom{transform:translateX(0) translateY(0)}
.pt-nuancier li:nth-last-child(-n+3) .pt-nuancier__nom{left:auto;right:0;transform:translateX(0) translateY(6px)}
.pt-nuancier li:nth-last-child(-n+3) a:hover .pt-nuancier__nom{transform:translateX(0) translateY(0)}

@media (max-width:640px){
  /* Au doigt il n'y a pas de survol, et soixante lamelles de six pixels ne
     se visent pas : la bande devient un aplat qu'on regarde, sans lien. */
  .pt-nuancier{height:clamp(90px,14vh,140px)}
  .pt-nuancier a{pointer-events:none}
  .pt-nuancier__nom{display:none}
}

/* ---------------------------------------------------------------------------
   3. LA ROUTE
   ---------------------------------------------------------------------------
   Un trait vertical, trois escales accrochées de part et d'autre. */
.pt-route{padding:var(--ip-section) 0}

/* ---------------------------------------------------------------------------
   LA CARTE DU PARCOURS
   ---------------------------------------------------------------------------
   Elle est LARGE ET BASSE : une carte carrée au milieu d'une page ferait
   une illustration ; un bandeau se lit comme un en-tête de chapitre, ce
   qu'elle est. Le rapport est écrit en `aspect-ratio` et le dessin la
   remplit en `slice` — la carte est donc recadrée, jamais déformée.

   LE TRAIT SE DESSINE AU DÉFILEMENT, comme le filet des escales juste en
   dessous : même idiome, même horloge, aucun JavaScript. Là où
   `animation-timeline` n'existe pas, la route est simplement tracée en
   entier — on perd le geste, jamais la carte.
   --------------------------------------------------------------------------- */
.pt-carte{
  margin:0 auto clamp(30px,5vh,66px);
  max-width:1320px;
  padding:0 var(--ip-marge);
}
.pt-carte__svg{
  display:block;width:100%;
  aspect-ratio:900/560;
  border-radius:clamp(10px,1.1vw,18px);
  box-shadow:0 26px 60px -42px rgba(10,30,54,.55);
}


/* La route. Un trait bleu, arrondi aux deux bouts, posé sur un liseré
   clair qui le décolle du bleu de la mer — sans lui, il disparaît dès
   qu'il traverse un golfe. */
.pt-carte__route{
  fill:none;
  stroke:var(--ip-bleu);
  stroke-width:3.4;
  stroke-linecap:round;
}
.pt-carte__gaine{
  fill:none;
  stroke:rgba(255,253,246,.82);
  stroke-width:8;
  stroke-linecap:round;
}
html.cda-dark .pt-carte__gaine{stroke:rgba(8,14,20,.6)}
.pt-carte__point{fill:var(--ip-bleu);stroke:#fff;stroke-width:3}
.pt-carte__halo{fill:var(--ip-bleu);opacity:.16;transform-box:fill-box;transform-origin:50% 50%}
.pt-carte__nom{
  fill:var(--ip-encre);
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:24px;
  paint-order:stroke;stroke:#f4f1e8;stroke-width:5;stroke-linejoin:round;
}
html.cda-dark .pt-carte__point{stroke:#0d1117}
html.cda-dark .pt-carte__nom{fill:#eef3fa;stroke:#232e37}

@media (prefers-reduced-motion:no-preference){
  /* Les quatre haltes battent l'une après l'autre : le décalage dit
     l'ordre du parcours sans qu'on ait à numéroter les points. */
  .pt-carte__halo{animation:ip-lieu-bat 2.8s ease-in-out infinite;animation-delay:calc(var(--n,0) * 320ms)}
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion:no-preference){
    @keyframes pt-carte-trace{from{stroke-dashoffset:2600}to{stroke-dashoffset:0}}
    /* La gaine se trace AVEC le trait, sinon elle révèle d'avance tout
       le chemin qu'on est en train de découvrir. */
    .pt-carte__route,
    .pt-carte__gaine{
      stroke-dasharray:2600;
      animation:pt-carte-trace linear both;
      animation-timeline:view();
      animation-range:entry 12% cover 46%;
    }
  }
}

.pt-escales{
  list-style:none;margin:0;padding:0 var(--ip-marge);position:relative;
  max-width:1320px;margin-inline:auto;
}
/* le trait */
.pt-escales::before{
  content:'';position:absolute;left:50%;top:0;bottom:0;width:1px;
  background:var(--pt-filet);transform:translateX(-.5px);
}
.pt-escale{
  position:relative;display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  column-gap:clamp(40px,7vw,110px);
  align-items:center;
  padding:clamp(40px,6vh,80px) 0;
}
/* la puce sur le trait */
.pt-escale__puce{
  position:absolute;left:50%;top:clamp(46px,6.5vh,88px);
  width:11px;height:11px;border-radius:50%;
  background:var(--ip-bleu);transform:translateX(-5.5px);
  box-shadow:0 0 0 6px var(--ip-papier);
}
html.cda-fond-on .pt-escale__puce{box-shadow:0 0 0 6px rgba(255,255,255,.7)}
html.cda-dark.cda-fond-on .pt-escale__puce{box-shadow:0 0 0 6px rgba(10,14,20,.75)}
.pt-escale__quand{
  margin:0 0 .35em;font-size:13px;letter-spacing:.26em;text-transform:uppercase;
  color:var(--ip-bleu);
}
html.cda-dark .pt-escale__quand{color:var(--ip-bleu-txt,#6ba6f2)}
.pt-escale__ou{
  margin:0;font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(30px,4.4vw,64px);line-height:1;letter-spacing:-.015em;color:var(--ip-encre);
}
.pt-escale__quoi{
  margin:.55em 0 clamp(18px,2.4vw,30px);
  font-size:13px;letter-spacing:.16em;text-transform:uppercase;color:var(--ip-encre-2);
}
.pt-escale__gros{margin:0 0 1em;font-size:var(--ip-gros-petit);line-height:1.5;color:var(--ip-encre)}
.pt-escale__dit p:last-child{margin:0;font-size:var(--ip-suite);line-height:1.7;color:var(--ip-encre-2)}
.pt-escale__vu{display:flex;flex-direction:column;gap:clamp(14px,1.8vw,22px);min-width:0}
/* une escale sur deux passe de l'autre côté */
.pt-escale:nth-child(even) .pt-escale__dit{grid-column:2;text-align:right}
.pt-escale:nth-child(even) .pt-escale__vu{grid-column:1;grid-row:1}

@media (max-width:900px){
  /* Le trait passe à gauche et toutes les escales s'y accrochent du même
     côté : en colonne unique, une alternance gauche/droite n'alterne plus
     rien, elle ne fait que décaler du texte au hasard. */
  .pt-escales{padding-left:calc(var(--ip-marge) + 26px)}
  .pt-escales::before{left:var(--ip-marge)}
  .pt-escale{grid-template-columns:minmax(0,1fr);row-gap:clamp(20px,3vw,28px);padding:clamp(28px,4vh,44px) 0}
  .pt-escale__puce{left:calc(var(--ip-marge) - 26px);top:clamp(32px,4.4vh,50px)}
  .pt-escale:nth-child(even) .pt-escale__dit{grid-column:1;text-align:left}
  .pt-escale:nth-child(even) .pt-escale__vu{grid-column:1;grid-row:auto}
}

/* LE TRAIT SE DESSINE AU DÉFILEMENT, SANS JAVASCRIPT.
   `animation-timeline: view()` confie l'avancement au compositeur : aucune
   écoute de défilement, aucun calcul par image. Là où la propriété n'existe
   pas, rien ne s'exécute et le trait reste dessiné en entier — on perd
   l'effet, jamais la structure. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion:no-preference){
    @keyframes pt-trait{from{transform:translateX(-.5px) scaleY(0)}to{transform:translateX(-.5px) scaleY(1)}}
    .pt-escales::before{
      transform-origin:50% 0;
      animation:pt-trait linear both;
      animation-timeline:view();
      animation-range:entry 8% cover 42%;
    }
  }
}

/* ---------------------------------------------------------------------------
   4. QUATRE GESTES
   ---------------------------------------------------------------------------
   Quatre colonnes, un numéro en creux par colonne. Le numéro n'a pas de
   couleur pleine : il donne un repère sans concurrencer le texte. */
.pt-gestes{padding:var(--ip-section) 0}
.pt-quatre{
  list-style:none;margin:0;padding:0 var(--ip-marge);
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(24px,3vw,52px);
  max-width:1320px;margin-inline:auto;
}
.pt-quatre li{
  position:relative;padding-top:clamp(20px,2.4vw,30px);
  border-top:1px solid var(--pt-filet);min-width:0;
}
.pt-quatre__n{
  display:block;margin-bottom:.1em;
  font-family:'Oswald','Archivo',system-ui,sans-serif;font-weight:200;
  font-size:clamp(44px,5vw,86px);line-height:1;
  color:transparent;-webkit-text-stroke:1px var(--pt-filet);
}
.pt-quatre h3{
  margin:0 0 .5em;font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(19px,1.7vw,26px);line-height:1.15;color:var(--ip-encre);
}
.pt-quatre p{margin:0;font-size:var(--ip-suite);line-height:1.7;color:var(--ip-encre-2)}
@media (max-width:1080px){.pt-quatre{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.pt-quatre{grid-template-columns:minmax(0,1fr)}}

/* ---------------------------------------------------------------------------
   5. LA VOIX
   ---------------------------------------------------------------------------
   Sa phrase, seule. C'est la seule chose de la page qu'il dit lui-même. */
/* LA LARGEUR DE LA CITATION EST EN PIXELS, ET C'EST UNE LEÇON.
   Elle était en `24ch`. L'unité `ch` se calcule sur la police de
   L'ÉLÉMENT QUI PORTE LA RÈGLE — ici le `<figure>`, en corps de texte
   courant — et non sur les soixante pixels du `<p>` qu'il contient. La
   citation se retrouvait donc bornée à environ 260 px : deux mots par
   ligne, sur douze lignes. Une mesure typographique posée sur un
   conteneur ne mesure pas le texte de ses enfants. */
.pt-voix{
  margin:0;padding:clamp(70px,12vh,150px) var(--ip-marge);
  max-width:min(92vw,980px);margin-inline:auto;text-align:center;
}
.pt-voix blockquote{margin:0}
.pt-voix p{
  margin:0;font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;
  font-size:clamp(26px,4.6vw,62px);line-height:1.18;letter-spacing:-.015em;color:var(--ip-encre);
  text-wrap:balance;
}
.pt-voix p::before{content:'« '}
.pt-voix p::after{content:' »'}
.pt-voix figcaption{
  margin-top:clamp(22px,3vw,36px);
  font-size:13px;letter-spacing:.3em;text-transform:uppercase;color:var(--ip-encre-2);
}

/* ---------------------------------------------------------------------------
   6. L'ATELIER
   ---------------------------------------------------------------------------
   Composition asymétrique : la première photo tient deux colonnes et deux
   rangées, les autres se rangent autour. Une grille régulière donne un
   contact-planche ; celle-ci donne un mur. */
.pt-atelier{padding:var(--ip-section) 0}
/* ═══ LA BASE EST JUSTE POUR N'IMPORTE QUEL NOMBRE ═══
   Elle valait `repeat(4, 1fr)` avec des rangées de hauteur fixe, et toutes
   les compositions par nombre de photos étaient écrites en `:has()`. Là où
   `:has()` manque — Safari d'avant 15.4, les vues web anciennes — AUCUNE
   d'elles ne s'applique : la page retombait sur quatre colonnes rigides,
   c'est-à-dire exactement le bug d'« image décalée » que ces règles avaient
   été écrites pour corriger, et sans aucun signe dans la console.

   La base ne compte donc plus : `auto-fit` fait tenir ce qu'il y a, une
   photo remplit sa ligne, cinq se rangent. Les compositions restent, mais
   comme un RAFFINEMENT sous `@supports`. Le repli n'est pas la meilleure
   composition — c'est une composition qui ne peut pas être fausse. */
.pt-mur{
  list-style:none;margin:0;padding:0 var(--ip-marge);
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));
  grid-auto-rows:auto;
  gap:clamp(12px,1.6vw,22px);
  max-width:1320px;margin-inline:auto;
}
.pt-mur li{margin:0;min-width:0;overflow:hidden;aspect-ratio:4 / 3;border-radius:clamp(10px,1.2vw,16px)}

/* ═══ LA COMPOSITION DÉPEND DU NOMBRE DE PHOTOGRAPHIES ═══
   La règle était unique : la première photo occupait deux colonnes sur
   deux rangées, quoi qu'il arrive. Avec UNE seule photographie — le cas
   réel du site aujourd'hui — elle prenait donc la moitié gauche d'une
   grille de quatre colonnes et laissait l'autre moitié vide : d'où
   l'image « décalée » qu'on voit à l'écran. Ce n'était pas un défaut de
   centrage, c'était une composition faite pour cinq images appliquée à
   une seule.

   Chaque nombre a maintenant sa composition, et chacune remplit
   exactement sa grille — aucune case vide, donc rien qui paraisse
   décalé. `:has()` compte les éléments sans une ligne de JavaScript. */

@supports selector(:has(*)) {
/* La grille reprend ses rangées de hauteur fixe : les compositions
   ci-dessous jouent sur `grid-row: span 2`, qui ne veut rien dire contre
   des rangées automatiques. */
.pt-mur{grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:clamp(150px,20vh,230px)}
.pt-mur li{aspect-ratio:auto}

/* UNE SEULE PHOTOGRAPHIE : ELLE GARDE SES PROPORTIONS.
   Elle était contrainte en 16/10 et recadrée pour y entrer — donc rognée
   en haut et en bas si elle était verticale, sur les côtés si elle était
   panoramique. Quand il n'y en a qu'une, elle EST le sujet : c'est elle
   qui décide de sa forme. Comme pour le portrait du seuil, la seule
   contrainte est la hauteur disponible, et la largeur suit. */
.pt-mur:has(li:only-child){grid-template-columns:minmax(0,1fr);grid-auto-rows:auto;max-width:1000px}
.pt-mur:has(li:only-child) li{aspect-ratio:auto;display:flex;justify-content:center}
.pt-mur:has(li:only-child) img{
  width:auto;height:auto;max-width:100%;max-height:min(76vh,720px);object-fit:fill;
}

/* deux : côte à côte, à égalité */
.pt-mur:has(li:nth-child(2)):not(:has(li:nth-child(3))){grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:auto;max-width:1100px}
.pt-mur:has(li:nth-child(2)):not(:has(li:nth-child(3))) li{aspect-ratio:4 / 3}

/* trois : une grande à gauche, deux empilées à droite */
.pt-mur:has(li:nth-child(3)):not(:has(li:nth-child(4))){grid-template-columns:repeat(2,minmax(0,1fr))}
.pt-mur:has(li:nth-child(3)):not(:has(li:nth-child(4))) li:first-child{grid-row:span 2}

/* quatre : deux par deux */
.pt-mur:has(li:nth-child(4)):not(:has(li:nth-child(5))){grid-template-columns:repeat(2,minmax(0,1fr))}

/* cinq : la composition asymétrique, celle pour laquelle elle était faite */
.pt-mur:has(li:nth-child(5)){grid-template-columns:repeat(6,minmax(0,1fr))}
.pt-mur:has(li:nth-child(5)) li{grid-column:span 3}
.pt-mur:has(li:nth-child(5)) li:first-child{grid-column:span 6;grid-row:span 2}
}
.pt-mur img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 1.1s cubic-bezier(.16,1,.3,1);
}
.pt-mur li:hover img{transform:scale(1.05)}
@media (max-width:780px){
  /* Au téléphone, toute composition asymétrique se réduit à une colonne
     de vignettes minuscules : on empile, chacune à sa vraie place.

     LES DEUX RÈGLES SONT SÉPARÉES, ET IL LE FAUT. Une liste de sélecteurs
     séparés par des virgules est rejetée EN ENTIER dès qu'un seul de ses
     membres est incompris — le pardon des sélecteurs invalides n'existe
     que dans `:is()` et `:where()`. Un `:has()` mêlé au simple `.pt-mur`
     emportait donc l'empilement mobile avec lui sur les navigateurs qui
     ne connaissent pas `:has()` : la page tombait sur quatre colonnes de
     vignettes sur un écran de trois cent quatre-vingt-dix pixels. Le cas
     simple vit seul ; les compositions le raffinent sous `@supports`. */
  .pt-mur{grid-template-columns:minmax(0,1fr);grid-auto-rows:auto}
  .pt-mur li{grid-column:auto;grid-row:auto;aspect-ratio:4 / 3}
}
@supports selector(:has(*)) {
  @media (max-width:780px){
    .pt-mur:has(li:nth-child(5)),
    .pt-mur:has(li:nth-child(4)):not(:has(li:nth-child(5))),
    .pt-mur:has(li:nth-child(3)):not(:has(li:nth-child(4))),
    .pt-mur:has(li:nth-child(2)):not(:has(li:nth-child(3))){
      grid-template-columns:minmax(0,1fr);grid-auto-rows:auto;
    }
    .pt-mur:has(li:nth-child(5)) li,
    .pt-mur:has(li:nth-child(5)) li:first-child,
    .pt-mur:has(li:nth-child(3)):not(:has(li:nth-child(4))) li:first-child{
      grid-column:auto;grid-row:auto;aspect-ratio:4 / 3;
    }
    /* La photo unique garde ses proportions, y compris au téléphone. */
    .pt-mur:has(li:only-child) li{aspect-ratio:auto}
  }
}

/* ---------------------------------------------------------------------------
   7. LE VIS-À-VIS
   ---------------------------------------------------------------------------
   Deux rôles qui se font face, séparés par un filet, l'un ferré à gauche et
   l'autre à droite. La forme dit la chose avant qu'on ait lu une ligne. */
.pt-duo{padding:var(--ip-section) 0}
.pt-face{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(30px,5vw,90px);
  padding:0 var(--ip-marge);max-width:1100px;margin-inline:auto;
  position:relative;
}
.pt-face::before{
  content:'';position:absolute;left:50%;top:0;bottom:0;width:1px;
  background:var(--pt-filet);
}
.pt-face__part{min-width:0}
.pt-face__part--moi{text-align:right}
.pt-face b{
  display:block;margin-bottom:.6em;
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(24px,3vw,42px);line-height:1;color:var(--ip-bleu);
}
html.cda-dark .pt-face b{color:var(--ip-bleu-txt,#6ba6f2)}
.pt-face p{margin:0;font-size:var(--ip-suite);line-height:1.7;color:var(--ip-encre-2)}
@media (max-width:780px){
  .pt-face{grid-template-columns:minmax(0,1fr);gap:clamp(26px,6vw,38px)}
  .pt-face::before{left:0;top:0;bottom:0}
  .pt-face__part{padding-left:22px}
  .pt-face__part--moi{text-align:left}
}

/* ---------------------------------------------------------------------------
   LA CARTE DE SITUATION, TRACÉE PAR LE THÈME
   ---------------------------------------------------------------------------
   Elle remplace le rectangle beige qui servait d'aperçu et qui n'indiquait
   aucun lieu. Les couleurs sont celles de la maison : la mer dans le bleu
   pâle des panneaux, la terre dans un ivoire de carte marine, les
   frontières en filet. Rien n'est chargé : tout est du SVG inerte, tracé à
   partir des coordonnées réelles.
   --------------------------------------------------------------------------- */
.ip-lieu__carte{width:100%;height:100%;display:block}
/* ═══ L'ANNEAU DE CÔTE A LA MER POUR INTÉRIEUR, PAS LA TERRE ═══
   Le tracé est un seul anneau fermé qui suit la rive européenne puis la
   rive africaine : ce qu'il enferme est donc l'EAU. Rempli en ivoire, il
   dessinait une Méditerranée en terre au milieu d'un continent bleu — le
   négatif exact de la carte. Le rectangle de fond porte la terre, le
   tracé porte la mer, et les îles reviennent en terre par-dessus. */
/* ═══ LES DEUX COULEURS SONT REMISES À L'ENDROIT ═══
   L'ancien tracé était UN SEUL ANNEAU fermé suivant la rive européenne
   puis la rive africaine : ce qu'il enfermait était donc l'eau, et il
   fallait peindre le rectangle de fond en terre et l'anneau en mer — le
   négatif de ce que disent les noms de classes.
   Les tracés viennent maintenant des masses continentales réelles : le
   rectangle est la MER, les tracés sont la TERRE. Chaque classe porte
   enfin ce qu'elle nomme. */
/* ═══ LES DEUX APLATS DEVIENNENT DEUX MATIÈRES ═══
   La mer était un seul bleu pâle et la terre un seul ivoire : à distance,
   la carte se lisait « toute blanche ». Une carte n'a pas l'air vraie
   parce que ses côtes sont exactes — celles-ci l'étaient déjà — mais
   parce que l'eau a un fond et que la terre a une peau. La mer prend
   donc un dégradé du plateau vers le large, la terre un dégradé du vert
   du nord vers l'ocre du sud, et le relief vient par filtre (voir
   `inc/carte-mediterranee.php`). Les classes ne changent pas de nom :
   tout le balisage existant continue de fonctionner. */
.ip-lieu__mer{fill:url(#cda-carte-eau)}
.ip-lieu__plateau{opacity:.72}      /* la frange turquoise le long des côtes */
.ip-lieu__relief{opacity:.7;mix-blend-mode:multiply}
.ip-lieu__terre{fill:url(#cda-carte-sol);stroke:#8e7f5e;stroke-width:.9;stroke-linejoin:round}
/* Les frontières sont un pointillé SOMBRE : sur une terre devenue ocre,
   un pointillé clair disparaissait. */
.ip-lieu__bord{fill:none;stroke:#6c6047;stroke-width:1.2;stroke-dasharray:5 5;opacity:.5}
.ip-lieu__pays{
  fill:#5f5540;font-size:21px;letter-spacing:.2em;
  font-family:'Archivo',system-ui,sans-serif;font-weight:600;
  /* Le nom doit tenir sur l'ocre ET sur le vert : un liseré clair posé
     SOUS la lettre (`paint-order`) le rend lisible sur les deux. */
  paint-order:stroke;stroke:rgba(255,252,242,.55);stroke-width:4;stroke-linejoin:round;
}
/* Le halo bat doucement : c'est ce qui fait trouver le point en un
   dixième de seconde sur une carte qu'on découvre. Il n'anime que
   `transform` et `opacity`, donc il ne coûte rien. */
.ip-lieu__halo{fill:var(--ip-bleu);opacity:.18;transform-box:fill-box;transform-origin:50% 50%}
.ip-lieu__point{fill:var(--ip-bleu);stroke:#fff;stroke-width:3}
@media (prefers-reduced-motion:no-preference){
  @keyframes ip-lieu-bat{
    0%,100%{transform:scale(.72);opacity:.26}
    50%    {transform:scale(1.18);opacity:.10}
  }
  .ip-lieu__halo{animation:ip-lieu-bat 2.8s ease-in-out infinite}
}
/* EN MODE SOMBRE, LA CARTE REDEVIENT DEUX APLATS, ET C'EST VOULU.
   Un relief et un plateau continental sont des effets de LUMIÈRE : de
   nuit il n'y en a pas, et les servir quand même donnait une terre
   marbrée de gris qui ne ressemblait plus à rien. On garde la géographie
   et on rend la matière. */
html.cda-dark .ip-lieu__mer{fill:#0f1a22}
html.cda-dark .ip-lieu__plateau{opacity:.16}
html.cda-dark .ip-lieu__relief{display:none}
html.cda-dark .ip-lieu__terre{fill:#232e37;stroke:#3b4c58}
html.cda-dark .ip-lieu__bord{stroke:#5a6c78;opacity:.6}
html.cda-dark .ip-lieu__pays{fill:#7c8c97;stroke:rgba(10,16,22,.6)}
html.cda-dark .ip-lieu__point{stroke:#0d1117}

/* LE BOUTON QUITTE LE CENTRE DE LA CARTE.
   Il y était posé au milieu, où il masquait précisément ce qu'on venait
   chercher. Tant que l'aperçu ne montrait rien, cela n'avait pas
   d'importance ; maintenant que la carte est lisible, il doit s'effacer.
   Il descend donc dans un coin, en petit — il reste offert, il ne se met
   plus en travers. */
.ip-lieu__bouton{
  position:absolute !important;left:auto !important;top:auto !important;
  right:10px !important;bottom:10px !important;transform:none !important;
  background:rgba(255,255,255,.92) !important;color:var(--ip-encre) !important;
  border:1px solid var(--ip-trait) !important;
  font-size:11px !important;padding:8px 13px !important;
  box-shadow:0 10px 24px -14px rgba(9,24,48,.5);
}
.ip-lieu__bouton:hover{background:var(--ip-bleu) !important;color:#fff !important;border-color:var(--ip-bleu) !important}
html.cda-dark .ip-lieu__bouton{background:rgba(14,18,24,.92) !important;color:#f2f2f2 !important}

/* ===========================================================================
   LE CACHET — CE QUI FAIT QUE LA PAGE APPARTIENT À UN PEINTRE
   ===========================================================================
   Quatre ajouts, et chacun répond à une absence précise plutôt qu'à
   l'envie de décorer. Une page d'artiste se juge à ce qu'elle donne à
   voir, pas au nombre de ses ornements — on n'ajoute donc rien qui ne
   dise quelque chose de LUI.

     · LE RUBAN DES TITRES     ses mots, pas des formes abstraites.
     · LE TRAIT DE PINCEAU     les filets de section cessent d'être des
                               règles de tableur.
     · LA LETTRINE             chaque escale s'ouvre comme un chapitre.
     · LA TRAME DE TOILE       la citation se pose sur une toile, pas sur
                               du vide.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   LE RUBAN DES TITRES
   ---------------------------------------------------------------------------
   La liste est doublée dans le balisage et l'ensemble glisse d'exactement
   la moitié de sa largeur : au moment où le premier exemplaire sort du
   cadre, le second occupe sa place au pixel près, et la boucle se referme
   sans saut. C'est la seule façon d'obtenir un défilement continu sans
   mesurer quoi que ce soit en JavaScript.

   L'animation ne touche que `transform` : le compositeur s'en charge, la
   page ne recalcule rien. Et elle s'arrête sous `prefers-reduced-motion`,
   où le ruban devient une simple ligne de titres, lisible et immobile. */
.pt-ruban{
  overflow:hidden;padding:clamp(26px,3.6vh,48px) 0;
  border-top:1px solid var(--pt-filet);border-bottom:1px solid var(--pt-filet);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
}
.pt-ruban__file{display:flex;width:max-content}
.pt-ruban__lot{
  display:flex;align-items:center;gap:clamp(30px,4vw,64px);
  list-style:none;margin:0;padding:0 clamp(15px,2vw,32px) 0 0;
}
.pt-ruban__lot li{
  display:inline-flex;align-items:center;gap:.6em;white-space:nowrap;
  font-family:'Playfair Display',Georgia,serif;font-style:italic;font-weight:400;
  font-size:clamp(19px,2.2vw,34px);line-height:1;color:var(--ip-encre);
}
.pt-ruban__puce{
  width:.36em;height:.36em;border-radius:50%;background:var(--c,var(--ip-bleu));
  flex:none;box-shadow:0 0 0 1px rgba(13,17,23,.12);
}
@media (prefers-reduced-motion:no-preference){
  @keyframes pt-ruban{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}
  .pt-ruban__file{animation:pt-ruban 64s linear infinite;will-change:transform}
  .pt-ruban:hover .pt-ruban__file{animation-play-state:paused}
}

/* ---------------------------------------------------------------------------
   TROIS TOILES
   --------------------------------------------------------------------------- */
.pt-toiles{padding:var(--ip-section) 0}
.pt-toiles .ip-grille{padding:0 var(--ip-marge);max-width:1320px;margin-inline:auto}
.pt-toiles__vers{
  margin:clamp(34px,4.6vh,64px) 0 0;padding:0 var(--ip-marge);
  max-width:1320px;margin-inline:auto;text-align:center;
}

/* ---------------------------------------------------------------------------
   LE TRAIT DE PINCEAU
   ---------------------------------------------------------------------------
   Les titres de section étaient posés sur rien, et les séparations du
   site sont des filets d'un pixel — c'est-à-dire des règles de tableur.
   Chaque `h2` reçoit donc un trait sous lui, tracé comme un coup de
   brosse : épais au départ, aminci à la sortie, avec un bord irrégulier.

   Il est dessiné en `clip-path`, pas en image : rien à télécharger, il
   prend la couleur qu'on lui donne, et il se redessine net à toutes les
   densités d'écran. Sa largeur est en `em`, donc il grandit avec le
   titre qu'il souligne. */
.pt-tete h2{position:relative;display:inline-block}
.pt-tete h2::after{
  content:'';position:absolute;left:0;bottom:-.22em;
  width:min(3.4em,100%);height:.13em;
  background:var(--ip-bleu);opacity:.85;
  /* le galbe d'un coup de brosse : attaque pleine, sortie effilée */
  clip-path:polygon(0 18%, 6% 4%, 34% 0, 62% 10%, 88% 4%, 100% 26%,
                    97% 62%, 74% 84%, 42% 96%, 14% 88%, 3% 66%);
}
html.cda-dark .pt-tete h2::after{background:var(--ip-bleu-txt,#6ba6f2)}

/* ---------------------------------------------------------------------------
   LA LETTRINE
   ---------------------------------------------------------------------------
   Chaque escale s'ouvre sur une capitale de trois lignes. C'est la marque
   d'un récit qu'on lit plutôt que d'une fiche qu'on consulte, et cela ne
   coûte rien : `::first-letter` ne demande ni balisage ni script.

   Elle est retirée sur la colonne de droite, ferrée à droite : une
   lettrine ferrée à droite ouvre le paragraphe par sa fin, ce qui est un
   contresens typographique. */
.pt-escale__gros::first-letter{
  float:left;line-height:.78;padding:.06em .1em 0 0;
  font-family:'Playfair Display',Georgia,serif;font-weight:700;
  font-size:3.1em;color:var(--ip-bleu);
}
html.cda-dark .pt-escale__gros::first-letter{color:var(--ip-bleu-txt,#6ba6f2)}
.pt-escale:nth-child(even) .pt-escale__gros::first-letter{float:none;font-size:inherit;color:inherit;padding:0;line-height:inherit}
@media (max-width:900px){
  /* toutes les escales reviennent à gauche : la lettrine revient partout */
  .pt-escale:nth-child(even) .pt-escale__gros::first-letter{
    float:left;line-height:.78;padding:.06em .1em 0 0;
    font-size:3.1em;color:var(--ip-bleu);
  }
  html.cda-dark .pt-escale:nth-child(even) .pt-escale__gros::first-letter{color:var(--ip-bleu-txt,#6ba6f2)}
}

/* ---------------------------------------------------------------------------
   LA TRAME DE TOILE
   ---------------------------------------------------------------------------
   La citation flottait sur le fond, sans support. Elle se pose maintenant
   sur une trame — la texture d'une toile de lin, deux familles de fils
   croisés, dessinée en dégradés répétés. Aucune image n'est chargée : ce
   sont quatre `repeating-linear-gradient`, que le navigateur peint une
   fois et garde en cache.

   L'opacité est basse à dessein. Une trame qu'on remarque est un motif ;
   une trame qu'on ne remarque pas est une matière — et c'est une matière
   qu'on veut, sous les mots d'un peintre. */
.pt-voix{position:relative;isolation:isolate}
.pt-voix::before{
  content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  border-radius:clamp(16px,2vw,28px);
  background:
    repeating-linear-gradient(90deg, rgba(13,17,23,.05) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(13,17,23,.05) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.35) 0 2px, transparent 2px 8px),
    rgba(255,255,255,.4);
  -webkit-mask-image:radial-gradient(120% 100% at 50% 50%, #000 42%, transparent 78%);
          mask-image:radial-gradient(120% 100% at 50% 50%, #000 42%, transparent 78%);
}
html.cda-dark .pt-voix::before{
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.05) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(0deg,  rgba(255,255,255,.05) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(90deg, rgba(0,0,0,.3) 0 2px, transparent 2px 8px),
    rgba(10,14,20,.4);
}

/* =====================================================================
   DIRECTION 2026-09 — LE STYLE DE L'ACCUEIL PASSE AUX PAGES INTÉRIEURES
   ---------------------------------------------------------------------
   L'accueil a changé de voix : titres en Playfair bas de casse, accent en
   italique bleue, surtitre tenu par un filet, et surtout PLUS DE PLAQUES
   DE VERRE — la lisibilité vient d'un halo dont les bords se dissolvent
   dans le pigment. Le catalogue, le contact, la page du peintre et
   l'espace client parlaient encore la langue d'avant : capitales
   condensées et panneaux à bords arrondis.

   CE FICHIER NE TOUCHE À AUCUN GABARIT.
   Tout passe par les classes déjà en place (`ip-`, `pt-`, `cda-wc-`) :
   c'est ce qui permet de porter le style sur quatre pages sans rouvrir
   quatre fichiers PHP, et de le retirer en supprimant ce bloc si le
   résultat ne convenait pas.
   ===================================================================== */

/* ═══ 1. LA VOIX DES TITRES ═══
   Oswald en capitales annonçait ; Playfair en bas de casse raconte. C'est
   le même changement que sur l'accueil, et il ne coûte rien d'autre que
   trois déclarations — la structure des pages ne bouge pas d'un pixel. */
.ip-ouv__titre{
  font-family:'Playfair Display',Georgia,serif;
  font-weight:500;
  font-size:clamp(38px,6.4vw,106px);
  line-height:1.0;
  letter-spacing:-.018em;
  text-transform:none;
}
.ip-ouv__titre em{font-style:italic;color:var(--ip-bleu)}

.ip-tete h2,
.ip-fin h2,
.ip-reperes__titre{
  font-family:'Playfair Display',Georgia,serif;
  font-weight:500;
  text-transform:none;
  letter-spacing:-.012em;
  line-height:1.08;
}
.ip-tete h2{font-size:clamp(26px,3.3vw,52px)}
.ip-fin h2{font-size:clamp(24px,2.9vw,46px)}
.ip-tete h2 em,
.ip-fin h2 em,
.ip-reperes__titre em{font-style:italic;color:var(--ip-bleu)}
html.cda-dark .ip-ouv__titre em,
html.cda-dark .ip-tete h2 em,
html.cda-dark .ip-fin h2 em{color:var(--ip-bleu-txt,#6ba6f2)}

/* La tête de section perd son filet du dessous : sur l'accueil, le titre
   n'est plus souligné — c'est le surtitre qui ouvre le chapitre, et deux
   traits pour une seule tête en font un tableau. */
.ip-tete{border-bottom:0;padding-bottom:0;margin-bottom:clamp(28px,3.6vw,56px)}

/* ═══ 2. LE SURTITRE TIENT SON FILET ═══ */
.ip-ouv__sur{
  display:inline-flex;align-items:center;gap:clamp(12px,1.2vw,20px);
  font-weight:400;
  font-size:11px;letter-spacing:.3em;
}
.ip-ouv__sur::after{
  content:'';width:clamp(26px,4vw,74px);height:1px;
  background:linear-gradient(90deg,currentColor,transparent);
}

/* ═══ 3. L'OUVERTURE DE CHAPITRE, ÉCRITE PAR LA SECTION ELLE-MÊME ═══
   Chaque section porte déjà son nom dans `data-dot-section` — c'est ce
   que lit la pastille de navigation latérale. Le même mot sert ici de
   surtitre, sans qu'un seul gabarit soit modifié : `attr()` le prend là
   où il est. `:has()` limite la règle aux sections qui ont une vraie
   tête ; sur le catalogue, trois sections portent le même nom (« Les
   œuvres ») et il aurait été répété trois fois au-dessus de la même
   grille. */
.pt-couleurs[data-dot-section]::before,
.pt-toiles[data-dot-section]::before,
.pt-route[data-dot-section]::before,
.pt-gestes[data-dot-section]::before,
/* LA LISTE EST COUPÉE EN DEUX, POUR LA MÊME RAISON QUE LE MUR D'ATELIER :
   un `:has()` dans une liste séparée par des virgules fait tomber TOUS les
   sélecteurs de la liste là où il n'est pas compris. Les deux premiers
   n'ont aucun besoin de `:has()` et n'ont pas à dépendre de lui. */
.pt-atelier[data-dot-section]::before,
.pt-duo[data-dot-section]::before{
  content:attr(data-dot-section);
  display:flex;align-items:center;gap:clamp(12px,1.2vw,20px);
  width:fit-content;
  margin:0 0 clamp(14px,2vh,24px);
  padding:0 var(--ip-marge);
  font-family:'Archivo',system-ui,sans-serif;
  font-size:11px;letter-spacing:.3em;text-transform:uppercase;
  color:var(--ip-bleu);
}
.pt-couleurs[data-dot-section]::after,
.pt-toiles[data-dot-section]::after,
.pt-route[data-dot-section]::after,
.pt-gestes[data-dot-section]::after,
.pt-atelier[data-dot-section]::after,
.pt-duo[data-dot-section]::after{content:none}
/* La même étiquette, pour les sections génériques qui ont une vraie tête.
   Elle a besoin de `:has()`, elle — et elle seule. */
.ip-sect[data-dot-section]:has(> .ip-tete)::before{
  content:attr(data-dot-section);
  display:flex;align-items:center;gap:clamp(12px,1.2vw,20px);
  width:fit-content;
  margin:0 0 clamp(14px,2vh,24px);
  padding:0;
  font-family:'Archivo',system-ui,sans-serif;
  font-size:11px;letter-spacing:.3em;text-transform:uppercase;
  color:var(--ip-bleu);
}

/* ═══ 4. LE PANNEAU DEVIENT UN HALO ═══
   C'est le geste central de la nouvelle page d'accueil, et celui qui se
   voit le plus : un texte n'a pas besoin d'une plaque, il a besoin de
   lumière. Le rectangle, sa bordure et son angle arrondi disparaissent ;
   reste une clarté large, floutée, dont les bords se dissolvent dans le
   pigment. Le contraste de lecture est le même — c'est le même voile,
   simplement sans arête. */
.ip-panneau{
  position:relative;
  padding:clamp(24px,3.2vw,54px) 0 !important;
  border:0 !important;
  border-radius:0 !important;
  background:none !important;
  box-shadow:none !important;
  -webkit-backdrop-filter:none !important;
  backdrop-filter:none !important;
}
html.cda-fond-on .ip-panneau,
html.cda-dark.cda-fond-on .ip-panneau{background:none !important}
.ip-panneau::before{
  content:'';position:absolute;inset:-2.4vh -2.6vw;z-index:0;pointer-events:none;
  border-radius:clamp(60px,7vw,150px);
  background:rgba(255,255,255,.84);
  filter:blur(42px);
}
html.cda-dark .ip-panneau::before{background:rgba(8,13,20,.82)}
.ip-panneau > *{position:relative;z-index:1}
@media (max-width:640px){
  .ip-panneau{padding:clamp(20px,5vw,30px) 0 !important}
}

/* ═══ 5. L'ESPACE CLIENT ENTRE DANS LA MAISON ═══
   « Mon compte » était la seule page du site sans mise en page : un
   conteneur de mille pixels et les gabarits bruts de WooCommerce. Elle
   reçoit maintenant la même ouverture, le même halo et les mêmes filets
   que le catalogue — c'est aussi la page où l'on revient le plus souvent
   quand on a acheté, donc celle où l'écart se remarquait le plus. */
.cda-wc{--ip-marge:clamp(20px,5vw,110px)}
.cda-wc .cda-wc-wrap{
  position:relative;
  max-width:1120px;margin:0 auto;
  padding:clamp(26px,3.4vw,56px) 0 !important;
}
.cda-wc .cda-wc-wrap::before{
  content:'';position:absolute;inset:-2.6vh -3.4vw;z-index:0;pointer-events:none;
  border-radius:clamp(60px,7vw,150px);
  background:rgba(255,255,255,.84);
  filter:blur(42px);
}
html.cda-dark .cda-wc .cda-wc-wrap::before{background:rgba(8,13,20,.82)}
.cda-wc .cda-wc-wrap > *{position:relative;z-index:1}
.cda-wc .cda-wc-wrap h1,
.cda-wc .cda-wc-wrap h2,
.cda-wc .cda-wc-wrap h3{
  font-family:'Playfair Display',Georgia,serif;font-weight:500;
  letter-spacing:-.01em;color:var(--ip-encre);
}

/* Le menu du compte : une colonne de filets, plus une boîte blanche à
   bord arrondi. Même dessin que la chronologie du peintre — un trait, et
   la ligne active portée par un aplat bleu. */
.cda-wc .woocommerce-MyAccount-navigation ul{
  border:0 !important;border-radius:0 !important;background:none !important;
  border-top:1px solid var(--ip-trait) !important;
}
.cda-wc .woocommerce-MyAccount-navigation li{
  border-bottom:1px solid var(--ip-trait) !important;background:none !important;
}
.cda-wc .woocommerce-MyAccount-navigation li a{
  display:block;padding:14px 4px;
  font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ip-encre-2);text-decoration:none;
  transition:color .25s ease,padding-left .3s cubic-bezier(.16,1,.3,1);
}
.cda-wc .woocommerce-MyAccount-navigation li a:hover{background:none !important;color:var(--ip-bleu);padding-left:10px}
/* La ligne courante était un aplat bleu plein — un bouton dans une liste de
   filets. Elle garde son bleu, mais dans l'encre et dans un trait vertical :
   le même signe que la pastille de la chronologie du peintre. Sans le
   `background:none`, la règle du thème repeignait l'aplat et le texte bleu
   qu'on vient de poser dessus devenait illisible. */
.cda-wc .woocommerce-MyAccount-navigation li.is-active a{
  background:none !important;color:var(--ip-bleu) !important;font-weight:600;
  padding-left:14px;
}
.cda-wc .woocommerce-MyAccount-navigation li.is-active{
  box-shadow:inset 3px 0 0 var(--ip-bleu);
}

/* WooCommerce colle une pastille de coche en absolu dans ses messages. Elle
   était calée sur le cartouche qui n'existe plus, et tombait en travers du
   texte. Le filet de couleur dit déjà de quel message il s'agit. */
.cda-wc .woocommerce-message::before,
.cda-wc .woocommerce-info::before,
.cda-wc .woocommerce-error::before{display:none !important;content:none !important}
@media (min-width:901px){
  .cda-wc .woocommerce-account .woocommerce{
    display:grid;grid-template-columns:minmax(190px,240px) minmax(0,1fr);
    gap:clamp(30px,4vw,72px);align-items:start;
  }
}
.cda-wc .woocommerce-MyAccount-content{min-width:0}

/* Les tableaux de commandes : des filets, pas des cases. */
.cda-wc table.shop_table,
.cda-wc table.woocommerce-orders-table{
  border:0 !important;border-radius:0 !important;background:none !important;
}
.cda-wc table.shop_table th{border-bottom:1px solid var(--ip-trait) !important}
.cda-wc table.shop_table td{border-bottom:1px solid rgba(13,17,23,.07) !important}

/* Les messages de WooCommerce reprennent le filet de couleur du site
   plutôt qu'un cartouche gris à coins arrondis. */
.cda-wc .woocommerce-message,
.cda-wc .woocommerce-info,
.cda-wc .woocommerce-error{
  border-radius:0 !important;background:none !important;
  border:0 !important;border-left:2px solid var(--ip-bleu) !important;
  padding:4px 0 4px 18px !important;
}
.cda-wc .woocommerce-error{border-left-color:#b3462f !important}

/* =====================================================================
   LA LIGNÉE DU CADRE, APPLIQUÉE AUX PAGES INTÉRIEURES
   =====================================================================
   POURQUOI UNE COUCHE, ET NON QUATRE GABARITS RÉÉCRITS.
   Le catalogue, le contact et le compte partagent déjà leurs composants :
   `.ip-ouv` pour l'ouverture, `.ip-panneau` pour les blocs, `.ip-champ`
   pour les champs, `.ip-carte` pour les œuvres, `.ip-btn` pour les
   actions. Réécrire quatre fichiers PHP pour changer une apparence,
   c'est quatre occasions de casser du balisage qui fonctionne — dont
   celui de WooCommerce, qu'on ne maîtrise qu'à moitié. Cette couche ne
   touche donc à aucun gabarit : elle reprend les mêmes composants et
   leur applique le vocabulaire de l'accueil.

   CE QUI EST REPRIS DE L'ACCUEIL, ET RIEN D'AUTRE :
   · l'œil de section en pastille, avec son carré de moulure ;
   · le titre en Playfair, le mot souligné en azur italique ;
   · TOUT EST ACCROCHÉ — passe-partout, feuillure, ombre basse et large ;
   · le bouton à pastille, sa flèche dans son propre disque ;
   · une seule courbe de mouvement, et des arrivées qui ont une masse.

   Le verre dépoli des anciens panneaux disparaît : un `backdrop-filter`
   sur un bloc qui défile fait repeindre la zone à chaque image, et sur
   une page de catalogue il y en avait jusqu'à trois à l'écran.
   ===================================================================== */

.ip{
  --ip2-r:clamp(14px,1.3vw,22px);
  --ip2-mat:10px;
  --ip2-lent:cubic-bezier(.32,.72,0,1);
}

/* --- L'OUVERTURE ----------------------------------------------------
   Le fil d'Ariane devient la pastille : il situe le visiteur ET donne au
   titre son point de départ, ce qui était déjà son rôle. Le titre passe
   en Playfair — l'Oswald en capitales des pages intérieures disait une
   autre marque que l'accueil, à un clic d'écart. */
.ip-ouv__sur{
  display:inline-flex;align-items:center;gap:9px;
  padding:6px 14px 6px 11px;border-radius:999px;
  border:1px solid color-mix(in srgb,var(--ip-bleu) 22%,transparent);
  background:color-mix(in srgb,var(--ip-bleu) 5%,transparent);
  font-family:'Archivo',system-ui,sans-serif;
  font-size:10.5px;letter-spacing:.2em;
}
.ip-ouv__sur::before{
  content:'';width:7px;height:7px;border-radius:2px;
  background:var(--ip-bleu);opacity:.85;flex:0 0 auto;
}
/* LE FIL D'ARIANE EST UN VRAI CHEMIN DE RETOUR. Ses liens faisaient douze
   pixels de haut — la hauteur des lettres, rien de plus. Un peu de
   rembourrage vertical suffit à en faire une cible, sans toucher au
   dessin : la pastille qui les contient a déjà sa propre hauteur. */
.ip-ouv__sur a{
  color:inherit;text-decoration:none;
  display:inline-flex;align-items:center;
  min-height:32px;padding-inline:2px;
}
.ip-ouv__sur a:hover{text-decoration:underline}
@media (max-width:620px){
  .ip-ouv__sur a{min-height:40px;padding-inline:6px}
}
.ip-ouv__titre{
  font-family:'Playfair Display',Georgia,serif;
  font-weight:600;
  font-size:clamp(36px,5.6vw,92px);
  line-height:1.02;letter-spacing:-.028em;
  text-transform:none;
}
.ip-ouv__titre em{font-style:italic}
.ip-ouv{border-bottom:0}

/* --- LE TITRE SE LIT SUR DU PAPIER, PAS SUR LA MER ------------------
   Sur ces pages, le fond n'est pas blanc : c'est le pigment de l'accueil,
   un canevas fixe qui va de l'écume presque blanche à un bleu de mer
   soutenu. Selon l'endroit où la page s'ouvre, le titre tombait sur une
   zone dense — d'où le gris sale derrière lui.

   Le voile général ne pouvait pas le régler : il relève le plancher de
   luminosité de la page ENTIÈRE, et le monter assez pour sauver le titre
   aurait délavé le pigment partout. On pose donc une clarté LOCALE :
   opaque sous l'ouverture, dissoute en bas — le titre est sur du papier,
   et dix centimètres plus bas la matière est intacte. Aucun bord, donc
   aucun cartouche.

   Ce n'est pas un filtre : un filtre coûte une repeinte, un dégradé
   fixe ne coûte rien. */
.ip-ouv{position:relative;z-index:1}
html.cda-fond-on .ip-ouv::after{
  content:'';position:absolute;z-index:-1;pointer-events:none;
  /* ═══ POURQUOI CE N'EST PLUS UN DÉGRADÉ VERTICAL ═══
     Un dégradé linéaire s'arrête quelque part, et il s'arrête sur une
     LIGNE. Ici il s'arrêtait au bas de l'ouverture : la clarté tombait
     d'un coup, le pigment reprenait sa densité, et cette reprise dessinait
     une bande sombre en travers de la page, juste sous le titre. C'est ça
     qu'on voyait — pas un filtre posé sur le titre, mais la fin de ce qui
     l'éclairait.

     Un dégradé RADIAL n'a pas de ligne : il s'éteint dans toutes les
     directions à la fois, donc il n'a pas de bord à voir. On le centre sur
     le titre, on l'étend bien au-delà du bloc — d'où les débords généreux
     ci-dessous — et il n'y a plus rien à raccorder. */
  left:-18vw;right:-18vw;top:-30vh;bottom:-42vh;
  background:
    radial-gradient(118% 96% at 30% 34%,
      color-mix(in srgb,var(--ip-papier,#fff) 93%,transparent) 0%,
      color-mix(in srgb,var(--ip-papier,#fff) 78%,transparent) 38%,
      color-mix(in srgb,var(--ip-papier,#fff) 40%,transparent) 64%,
      transparent 84%);
}
html.cda-dark.cda-fond-on .ip-ouv::after{
  background:
    radial-gradient(118% 96% at 30% 34%,
      rgba(11,16,22,.96) 0%,
      rgba(11,16,22,.82) 38%,
      rgba(11,16,22,.42) 64%,
      transparent 84%);
}

/* --- LES ŒUVRES SONT ACCROCHÉES, PAS POSÉES -------------------------
   Le cadre d'image était un rectangle arrondi avec une ombre dessous.
   Il reçoit le passe-partout et la feuillure du seuil : sur une page qui
   vend des toiles encadrées, c'est la seule présentation qui ne demande
   pas au visiteur d'imaginer le résultat. Le rapport réel de l'œuvre
   (`--ar`) est conservé — on ne recadre jamais une toile. */
/* LE CADRE ENTOURE LA TOILE, PAS LA CARTE.
   Posé sur le lien, le passe-partout enveloppait aussi le cartel — et
   comme le cadre d'image est chassé vers le bas (`margin-top:auto`, pour
   que les toiles s'alignent par leur base comme sur une cimaise), tout
   l'espace libre de la carte se retrouvait DANS le passe-partout : une
   plage ivoire vide au-dessus de chaque œuvre. Le cadre revient donc
   là où il doit être, autour de l'image seule, et le cartel se lit
   dessous, sur le papier de la page. */
.ip-carte__media{
  /* AUCUN ANGLE ARRONDI. Un châssis est assemblé à quatre onglets à
     quarante-cinq degrés : ses angles sont vifs. Arrondir le cadre d'une
     toile, c'est la transformer en vignette d'application — et c'est
     exactement ce que le reste du site s'emploie à éviter. */
  border:var(--ip2-mat) solid transparent;
  border-radius:0;
  background:
    linear-gradient(160deg,#fbfaf6,#f1ede4) padding-box,
    linear-gradient(160deg,#f2eee4,#e6e0d2) border-box;
  box-shadow:
    inset 0 0 0 1px rgba(24,38,56,.1),
    inset 0 13px 20px -12px rgba(6,20,38,.62),
    inset 0 -7px 15px -11px rgba(6,20,38,.38),
    inset 11px 0 17px -13px rgba(6,20,38,.34),
    inset -11px 0 17px -13px rgba(6,20,38,.34),
    0 30px 58px -38px rgba(9,34,62,.55);
  transition:box-shadow .7s var(--ip2-lent);
}
/* ═══ ON NE TOUCHE PAS À `transform` SUR CET ÉLÉMENT ═══
   `catalogue-motion.js` écrit la courbure du mur EN LIGNE sur
   `.ip-carte__lien`, à chaque image. Une élévation au survol écrite ici
   serait écrasée sans jamais s'afficher — et le mur, lui, existe déjà et
   fait mieux le travail. Le survol ne change donc que ce que le module
   ne touche pas : le passe-partout, qui apparaît. */
.ip-carte__lien{border-radius:0}
/* ═══ LE PASSE-PARTOUT EST PEINT PAR L'ÉLÉMENT LUI-MÊME ═══
   Première tentative : un `::before` posé derrière, en `z-index:-1`. Il
   ne s'est jamais affiché, et c'était logique — un enfant en z-index
   négatif se peint APRÈS le fond de son parent, donc dessous n'est pas
   dessous : le fond blanc du parent le recouvrait, et `isolation` le
   fermait dans un contexte dont il ne pouvait plus sortir.

   La bonne méthode n'a pas besoin d'un second élément. Une bordure
   TRANSPARENTE réserve l'épaisseur du passe-partout, et deux fonds
   empilés remplissent chacun leur boîte : le papier s'arrête au bord
   intérieur (`padding-box`), le carton du passe-partout occupe tout
   (`border-box`). Une seule boîte, deux matières, aucun élément en plus
   dans le balisage. */
.ip-carte{position:relative}
@media (hover:hover){
  .ip-carte__lien:hover .ip-carte__media{
    box-shadow:
      inset 0 0 0 1px rgba(24,38,56,.1),
      inset 0 13px 20px -12px rgba(6,20,38,.62),
      inset 0 -7px 15px -11px rgba(6,20,38,.38),
      inset 11px 0 17px -13px rgba(6,20,38,.34),
      inset -11px 0 17px -13px rgba(6,20,38,.34),
      0 46px 78px -38px rgba(9,34,62,.62);
  }
}

/* --- CE QUI S'ALIGNE, C'EST LE CARTEL — PAS LA TOILE -----------------
   DEUX ERREURS SUCCESSIVES, ET LA SECONDE ÉTAIT LA MIENNE.

   1. J'avais décalé une colonne sur deux pour casser la trame. Sur une
      page de vente ce n'est pas une composition, c'est un catalogue qu'on
      ne peut plus comparer d'un coup d'œil — et c'est ce décalage, et lui
      seul, qui faisait démarrer les titres à trois hauteurs différentes.
      Il est retiré : il a sa place sur l'accueil, où l'on regarde ; pas
      ici, où l'on choisit.

   2. J'ai ensuite imposé une ouverture carrée à toutes les œuvres pour
      les « mettre au même niveau ». C'était répondre à côté : uniformiser
      les CADRES pour aligner les TITRES. Un carton entoilé 30 × 40 et une
      marine 55 × 46 n'ont pas la même forme, et c'est précisément ce
      qu'un catalogue de peintre doit montrer. Annulé.

   Le mécanisme d'origine du thème faisait déjà exactement ce qu'il faut,
   et il suffit de ne plus le contrarier : chaque toile garde son rapport
   réel, la carte est une colonne de hauteur pleine, et le cadre d'image
   est chassé vers le bas. Tout l'espace libre passe donc AU-DESSUS des
   œuvres — là où il ne se voit pas — et les toiles s'alignent par leur
   BASE, comme sur une cimaise. Les cartels, posés juste dessous,
   tombent alors sur la même ligne quelle que soit la forme au-dessus. */
.ip-grille{align-items:stretch}

/* --- LA BARRE DE FILTRES DEVIENT UN ÎLOT ----------------------------
   Elle était une bande collée à toute la largeur, séparée du reste par
   des filets : un bandeau de réglages. Elle devient un îlot flottant,
   détaché des bords, qui garde le contenu visible derrière lui. Le flou
   est ici légitime — l'élément est collant, donc composé une fois et
   non repeint à chaque image, ce qui est exactement la condition. */
/* PLEINE LARGEUR, ET PASTILLE.
   Elle a d'abord été un îlot resserré au milieu : il introduisait une
   troisième mesure — celle de la page, celle de la grille, et la
   sienne — et plus rien ne s'alignait. Elle a ensuite été un bandeau
   bord à bord : la pastille disparaissait avec lui.

   Les deux tiennent ensemble. Elle va d'une marge à l'autre, exactement
   comme la grille d'œuvres en dessous — donc elle s'aligne sur elle — et
   elle garde ses bouts ronds. Une barre est large ; une pastille a des
   extrémités. Ce sont deux propriétés différentes, elles n'ont jamais eu
   à se disputer. */
/* ═══ ELLE SE COLLE AU HAUT DE LA FENÊTRE, PAS SOUS LA BARRE ═══
   Elle était calée à `--nav-h + 8px`. C'est juste sur l'accueil, où la
   barre de navigation est en `position:fixed` et reste donc à l'écran.
   Sur les pages intérieures elle est en `position:relative` : elle s'en
   va au premier défilement, et la barre de filtres restait suspendue
   soixante-dix pixels plus bas que le bord — avec, au-dessus d'elle, une
   bande où les œuvres continuaient de défiler à l'air libre. C'est
   exactement ce qu'on voit sur la capture : la barre paraît trop basse
   parce qu'elle attend une barre qui n'est plus là.

   LE TOIT. Une pastille détachée du bord laisse forcément passer quelque
   chose au-dessus d'elle et dans l'arrondi de ses angles. Elle emporte
   donc son propre fond : un bandeau pleine largeur qui monte jusqu'au
   bord de la fenêtre et se dissout sous elle. On garde la pastille ET on
   ne voit plus rien défiler derrière. */
.ip-filtres{
  position:sticky;top:10px;z-index:20;
  /* LA LARGEUR N'EST PLUS CALCULÉE, ELLE EST DÉDUITE.
     Elle valait `calc(100% - marge * 2)`. Un pourcentage se résout contre
     le bloc conteneur, et celui-ci n'est pas toujours la fenêtre : sur
     téléphone, la barre ressortait trente pixels au-delà du bord droit et
     « Acrylique » était coupé. Un élément de bloc à qui l'on donne
     seulement ses marges prend tout seul ce qui reste — c'est juste dans
     tous les contextes, et il n'y a rien à recalculer. */
  margin-inline:var(--ip-marge);max-width:none;width:auto;
  border-radius:999px;
  padding:10px clamp(16px,1.6vw,26px);
  /* ═══ LE MÊME VERRE QUE LA CAPSULE DU MENU ═══
     La recette n'est pas inventée ici : c'est celle de `.cda-nav-liens`,
     au chiffre près — deux blancs en dégradé, un liseré clair, un flou
     d'arrière-plan saturé. Deux capsules de verre sur la même page qui ne
     seraient pas faites de la même matière se verraient immédiatement.

     Le repli sans `backdrop-filter` n'est pas facultatif : sans lui, un
     navigateur qui ne sait pas flouter afficherait des filtres à trente
     pour cent d'opacité au-dessus d'un mur d'œuvres. */
  background:linear-gradient(180deg,rgba(255,255,255,.52),rgba(255,255,255,.34));
  border:1px solid rgba(255,255,255,.62);
  -webkit-backdrop-filter:blur(22px) saturate(1.4);
          backdrop-filter:blur(22px) saturate(1.4);
  box-shadow:0 18px 44px -30px rgba(6,26,50,.7);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .ip-filtres{background:rgba(255,255,255,.86)}
}
html.cda-dark .ip-filtres{
  background:linear-gradient(180deg,rgba(10,15,23,.62),rgba(10,15,23,.42));
  border-color:rgba(255,255,255,.14);
}

/* ═══ ELLE GARDE SON FLOU AU-DESSUS DU PIGMENT ═══
   Une règle plus haut le coupait sur les pages à fond animé, et le
   raisonnement était bon : un flou d'arrière-plan sur un élément collant,
   au-dessus d'un canevas qui se redessine, se recalcule à chaque image.
   Mais la capsule du menu, elle, l'a gardé sur ces mêmes pages — le site
   paie déjà ce coût une fois. Le refuser à la barre de filtres ne
   sauvait rien de mesurable et cassait la parenté entre les deux : une
   capsule en verre et une capsule en papier sur le même écran. */
html.cda-fond-on .ip-filtres{
  -webkit-backdrop-filter:blur(22px) saturate(1.4);
          backdrop-filter:blur(22px) saturate(1.4);
}
/* ═══ LE TOIT OPAQUE EST RETIRÉ ═══
   Il couvrait la bande au-dessus de la pastille pour qu'on n'y voie rien
   défiler. Il faisait son travail, et il coûtait exactement ce qu'on
   voulait garder : posée sur une plaque blanche pleine largeur, la
   pastille ne flottait plus — c'était redevenu un bandeau avec une forme
   arrondie dedans.

   Il n'était nécessaire que tant que la barre se collait soixante-dix
   pixels trop bas. Elle est maintenant à DIX pixels du bord : ce qui
   passe au-dessus d'elle, c'est une bande de dix pixels — et à travers
   du verre, c'est précisément ce qu'on veut voir. */
/* ═══ LE TOIT PASSAIT DEVANT LES FILTRES ═══
   Un descendant en `z-index:-1` se peint APRÈS le fond de son parent,
   mais AVANT son contenu : le bandeau couvrait donc les pastilles, qui
   apparaissaient délavées, comme sous un calque blanc. C'est le même
   piège que le passe-partout des cartes du catalogue, et il se règle de
   la même façon — non pas en enfonçant le fond, mais en RELEVANT le
   contenu. La ligne de filtres prend sa propre couche. */
.ip-filtres > *{position:relative;z-index:1}
@media (max-width:900px){
  /* ═══ SUR TÉLÉPHONE, LA BARRE SE LIT EN RANGÉES CENTRÉES ═══
     Elle gardait sa disposition de bureau : les types de technique poussés
     à gauche par un `margin-right:auto`, et tout le reste chassé à droite.
     Sur une seule ligne c'est une barre ; repliée sur trois rangées, c'est
     un tas de pastilles ferrées de deux côtés différents, avec des trous
     au milieu.

     Les deux familles deviennent donc deux RANGÉES, chacune centrée : les
     techniques d'abord — c'est le filtre qu'on utilise en premier — puis
     les réglages et le compte. Chaque rangée occupe toute la largeur, ce
     qui suffit à les séparer sans aucun filet. */
  .ip-filtres{
    /* Un rayon de cinq cents pixels sur un bloc haut de trois rangées
       donne une gélule. Vingt-huit pixels gardent la parenté avec la
       capsule sans en prendre la forme. */
    border-radius:28px;padding:12px 12px;top:8px;
  }
  .ip-filtres__ligne{justify-content:center;gap:8px 10px}
  .ip-filtres__type{
    width:100%;margin-right:0;
    justify-content:center;
  }
  /* ELLES RAPETISSAIENT DU MAUVAIS CÔTÉ. Sur grand écran ces commandes
     font 40 px et 34 px ; ici, au doigt, elles descendaient à 36 et 30.
     C'est l'inverse de ce qu'il faut : un curseur vise au pixel, un doigt
     couvre un centimètre. « Effacer les filtres » est une vraie commande,
     et c'était la plus petite de la barre. Seuls le rembourrage et le
     corps de texte se resserrent maintenant ; la HAUTEUR DE PRISE reste
     celle du grand écran. */
  .ip-pilule{min-height:40px;padding:0 14px;font-size:13px}
  .ip-menu > summary{min-height:40px}
  .ip-compte,.ip-reset{min-height:38px;padding:0 14px}
  /* La recherche passe en pleine largeur sous les réglages : un champ de
     saisie coincé entre deux pastilles rondes ne se voit pas comme un
     champ. */
  .ip-cherche{width:100%;order:9}
}

/* --- LES PANNEAUX : ON N'Y TOUCHE PAS, ET C'EST UNE DÉCISION ---------
   J'avais écrit ici le passe-partout et la feuillure des cartes. Rien ne
   s'affichait, et la cause n'était pas un bug : une règle antérieure de
   cette feuille neutralise `.ip-panneau` en `!important` — fond, bordure,
   rayon, ombre — et le remplace par un halo flouté. Le choix est écrit
   noir sur blanc dans son commentaire : « un texte n'a pas besoin d'une
   plaque, il a besoin de lumière ».

   C'est le même raisonnement que celui qui a fait tomber les boîtes de la
   section du peintre sur l'accueil, et il tient toujours. Encadrer un
   paragraphe reviendrait à traiter du texte comme une œuvre : sur ce
   site, le cadre veut dire « ceci est une toile ». Le lui faire dire
   d'autre chose l'affaiblirait partout ailleurs.

   Les panneaux restent donc des halos. Le cadre est réservé à ce qui est
   peint. */

/* --- LES BOUTONS ----------------------------------------------------
   Pastille pleine, et la flèche — quand il y en a une — dans son propre
   disque. Au survol le bouton s'enfonce d'un cheveu : la tension est
   interne, il ne quitte pas sa place dans la page. */
.ip-btn{
  border-radius:999px;
  padding:12px 26px;
  transition:transform .55s var(--ip2-lent), background-color .55s var(--ip2-lent),
             color .55s var(--ip2-lent), box-shadow .55s var(--ip2-lent);
}
.ip-btn::before{display:none}
.ip-btn:active{transform:scale(.985)}
.ip-btn--plein{box-shadow:0 20px 40px -26px rgba(0,74,173,.75)}
@media (hover:hover){
  .ip-btn--plein:hover{background:var(--ip-bleu-profond,#00306e);box-shadow:0 28px 52px -26px rgba(0,74,173,.8)}
  .ip-btn:not(.ip-btn--plein):hover{background:var(--ip-bleu);color:#fff}
}

/* --- LES CHAMPS -----------------------------------------------------
   Un champ est une petite fenêtre : même feuillure que les cadres, en
   plus discrète. C'est ce qui l'ancre dans la page au lieu d'y flotter,
   et ça remplace la bordure grise d'un pixel — la seule chose qu'un
   formulaire soigné ne doit jamais montrer. */
.ip-champ input,.ip-champ textarea,.ip-champ select,
.ip .input-text,.ip input[type=text],.ip input[type=email],
.ip input[type=password],.ip input[type=tel],.ip textarea{
  border-radius:12px;
  border:1px solid color-mix(in srgb,var(--ip-encre) 10%,transparent);
  background:#fdfcf9;
  box-shadow:inset 0 6px 12px -10px rgba(9,28,52,.45);
  transition:border-color .4s var(--ip2-lent), box-shadow .4s var(--ip2-lent);
}
.ip-champ input:focus,.ip-champ textarea:focus,.ip-champ select:focus,
.ip .input-text:focus,.ip input:focus,.ip textarea:focus{
  outline:0;
  border-color:color-mix(in srgb,var(--ip-bleu) 55%,transparent);
  box-shadow:
    inset 0 6px 12px -10px rgba(9,28,52,.3),
    0 0 0 3px color-mix(in srgb,var(--ip-bleu) 14%,transparent);
}

/* --- LA LONGUEUR D'UNE LIGNE DE SAISIE -------------------------------
   Depuis que le panneau est un halo sans retrait, un champ occupe toute
   la largeur du texte — près de treize cents pixels sur un grand écran.
   Un champ n'est pas un paragraphe : sa largeur annonce ce qu'on attend
   dedans, et une ligne de treize cents pixels pour un nom de famille
   promet un roman. Les champs sont donc bornés à la mesure d'une colonne
   de lecture, comme le reste du texte de la page. Le message, lui, garde
   sa largeur : on y écrit vraiment plusieurs lignes. */
/* CE CAP A ÉTÉ RETIRÉ.
   J'avais borné les blocs à 760 pixels pour qu'un champ ne fasse pas
   treize cents pixels de long. Le raisonnement était juste et le résultat
   faux : le formulaire s'est tassé à gauche et la moitié droite de la
   page est restée vide — ce qui est pire qu'un champ trop large. Borner
   une colonne sans rien mettre à côté, c'est creuser un trou.

   Les blocs reprennent donc la pleine largeur. Seuls les champs d'une
   ligne sont bornés, et ils le sont DANS leur bloc : un nom, un courriel,
   un téléphone n'ont pas besoin de plus, et le bloc, lui, continue de
   tenir la page. */
.ip-champ input:not([type=checkbox]):not([type=radio]),
.ip-champ select{max-width:min(100%,620px)}

/* --- L'ARRIVÉE, AVEC SA MASSE ---------------------------------------
   Même geste que sur l'accueil : l'objet vient de la profondeur de champ
   au lieu de devenir opaque sur place. Le flou ne vit que pendant le
   trajet — un filtre permanent sur une grille qui défile ferait
   repeindre la page entière à chaque image. */
@media (prefers-reduced-motion:no-preference){
  /* `data-parait` est une ANIMATION, pas une transition : lui ajouter une
     `transition` n'aurait eu aucun effet. On redéclare donc l'image-clé,
     avec la course allongée et la netteté qui se fait. */
  @keyframes ip2-parait{
    from{opacity:0;transform:translate3d(0,42px,0);filter:blur(9px)}
    to  {opacity:1;transform:none;filter:blur(0)}
  }
  .ip [data-parait]{
    animation:ip2-parait 1s var(--ip2-lent) both;
    animation-delay:calc(var(--r,0) * 105ms);
  }

  /* `data-defile`, lui, est bien une transition — mais la classe posée
     par le script s'appelle `est-la`, pas `is-la`. Le flou ne vit que
     tant qu'elle n'est pas là. */
  html.ip-defile .ip .ip-grille [data-defile]:not(.est-la){filter:blur(7px)}
  html.ip-defile .ip .ip-grille [data-defile]{
    transition:transform .9s var(--ip2-lent), opacity .7s var(--ip2-lent),
               filter .7s var(--ip2-lent);
  }
  html.ip-defile .ip .ip-grille [data-defile].est-la{filter:blur(0)}
}

/* =====================================================================
   LE VERRE SUR LES PAGES INTÉRIEURES
   =====================================================================
   Même règle que dans `site.css` : le verre est pour CE QUI FLOTTE, et
   pour rien d'autre. Sur ces pages, trois familles seulement le méritent.
   ===================================================================== */

/* 1. LES PANNEAUX DÉROULANTS de la barre de filtres. Ils s'ouvrent par
      dessus la grille d'œuvres — c'est la définition même de ce qui
      flotte, et ils étaient en blanc plein au-dessus d'un mur de
      tableaux. */
.ip-menu__pan{
  background:linear-gradient(180deg,rgba(255,255,255,.72),rgba(255,255,255,.56));
  border:1px solid rgba(255,255,255,.66);
  -webkit-backdrop-filter:blur(26px) saturate(1.35);
          backdrop-filter:blur(26px) saturate(1.35);
  box-shadow:0 26px 56px -34px rgba(6,26,50,.6);
}
html.cda-dark .ip-menu__pan{
  background:linear-gradient(180deg,rgba(12,17,25,.74),rgba(12,17,25,.58));
  border-color:rgba(255,255,255,.13);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .ip-menu__pan{background:rgba(255,255,255,.95)}
}

/* 2. LA PAGE CONTACT — LES DEUX SURFACES QU'ON MANIPULE.
      ------------------------------------------------------------------
      Le formulaire lui-même reste du papier : un champ de saisie est une
      fenêtre creusée dans la page, pas une plaque posée dessus, et le
      texte d'un formulaire doit être le plus lisible de tout le site.

      Mais deux choses y FLOTTENT réellement, et elles portent tout le
      geste de la page : le choix de l'objet du message, et le mur
      d'œuvres où l'on désigne une toile. Ce sont les seules zones où
      l'on clique en regardant autre chose que du texte — et elles sont
      posées sur le pigment animé. C'est là que le verre a un sens.

      Le mur d'œuvres, en plus, DÉFILE sous le doigt : un fond opaque en
      faisait une boîte dans la boîte ; en verre, on voit que la matière
      continue derrière, et la zone se lit comme une fenêtre ouverte sur
      le fonds plutôt que comme un cadre supplémentaire. */
.ip-choix label{
  background:linear-gradient(180deg,rgba(255,255,255,.56),rgba(255,255,255,.38));
  border:1px solid rgba(255,255,255,.62);
  -webkit-backdrop-filter:blur(18px) saturate(1.3);
          backdrop-filter:blur(18px) saturate(1.3);
  box-shadow:0 16px 38px -30px rgba(6,26,50,.6);
  transition:background .3s cubic-bezier(.32,.72,0,1), border-color .3s ease, transform .3s cubic-bezier(.32,.72,0,1);
}
.ip-choix label:active{transform:scale(.99)}
/* La case retenue n'est pas « du verre plus clair » : elle prend l'azur,
   comme la pastille active du menu. Une sélection doit se voir de loin,
   et une matière ne se compare pas à elle-même. */
/* LA TEINTE VA SUR L'ÉTIQUETTE, PAS SUR SON TEXTE.
   Écrite `input:checked + span`, elle peignait le bloc de texte à
   l'intérieur de la case : un rectangle bleu posé dans un cadre de verre,
   avec une marge blanche autour. C'est la CASE qu'on choisit. */
.ip-choix label:has(input:checked){
  border-color:rgba(0,74,173,.55);
  background:linear-gradient(180deg,rgba(0,74,173,.14),rgba(0,74,173,.06));
}
html.cda-dark .ip-choix label{
  background:linear-gradient(180deg,rgba(12,17,25,.62),rgba(12,17,25,.44));
  border-color:rgba(255,255,255,.13);
}

.ip-mur-zone{
  background:linear-gradient(180deg,rgba(255,255,255,.44),rgba(255,255,255,.28));
  border:1px solid rgba(255,255,255,.55);
  border-radius:clamp(14px,1.3vw,22px);
  -webkit-backdrop-filter:blur(20px) saturate(1.3);
          backdrop-filter:blur(20px) saturate(1.3);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7), 0 20px 46px -34px rgba(6,26,50,.55);
}
html.cda-dark .ip-mur-zone{
  background:linear-gradient(180deg,rgba(12,17,25,.56),rgba(12,17,25,.38));
  border-color:rgba(255,255,255,.12);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .ip-choix label{background:rgba(255,255,255,.92)}
  .ip-mur-zone{background:rgba(255,255,255,.88)}
}

/* 3. LE MESSAGE DE CONFIRMATION. Il apparaît par-dessus le formulaire
      qu'on vient d'envoyer : il flotte, donc il est en verre — et il
      garde son vert, qui est l'information. */
.ip-ok{
  -webkit-backdrop-filter:blur(18px) saturate(1.25);
          backdrop-filter:blur(18px) saturate(1.25);
}

/* =========================================================================
   LES LIEUX, LA VEILLE, ET LA PAGE INTROUVABLE
   -------------------------------------------------------------------------
   Trois composants nouveaux, écrits dans le vocabulaire déjà posé : les
   jetons `--ip-*`, le passe-partout et la feuillure des cartes, le verre
   pour ce qui flotte. Rien d'inventé — on ne fait ici que décliner.
   ========================================================================= */

/* --- LA CARTE DES LIEUX ---------------------------------------------- */
.lx-carte{
  margin:0 auto clamp(30px,5vh,66px);
  max-width:1320px;
  padding:0 var(--ip-marge);
}
.lx-carte__svg{
  display:block;width:100%;
  aspect-ratio:900/560;
  border-radius:clamp(10px,1.1vw,18px);
  box-shadow:0 26px 60px -42px rgba(10,30,54,.55);
}
/* LE POINT EST UN LIEN, DONC IL A UN ÉTAT DE MISE AU POINT VISIBLE.
   Un `outline` sur un `<a>` dans du SVG ne se dessine pas de la même
   façon selon les navigateurs ; on épaissit donc le halo, ce qui se voit
   partout et se voit bien. */
.lx-point{cursor:pointer}
.lx-point__pastille{
  /* `stroke-width` est écrit dans le balisage, à l'échelle de la fenêtre.
     Le déclarer ici aussi le figerait. */
  fill:var(--ip-bleu);stroke:#fff;
  transition:r .25s cubic-bezier(.16,1,.3,1);
}
.lx-point__halo{
  fill:var(--ip-bleu);opacity:.16;
  transform-box:fill-box;transform-origin:50% 50%;
  transition:opacity .25s ease;
}
.lx-point__nom{
  fill:var(--ip-encre);
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  /* La taille vient du SVG, où elle est déduite de la fenêtre : un
     nombre fixe ici redonnerait des noms énormes quand la carte se
     resserre. Le liseré suit la même règle. */
  font-size:var(--lx-corps,18px);
  paint-order:stroke;stroke:rgba(255,253,246,.92);
  stroke-width:calc(var(--lx-corps,18px) * .28);stroke-linejoin:round;
}
.lx-point:hover .lx-point__halo,
.lx-point:focus-visible .lx-point__halo,
.lx-point.est-actif .lx-point__halo{opacity:.38}
/* `r` est animable en CSS depuis Chrome 104 et Safari 16 ; ailleurs le
   halo suffit à signaler le survol. On l'exprime en part du rayon posé
   dans le balisage plutôt qu'en nombre absolu. */
.lx-point:hover .lx-point__pastille,
.lx-point:focus-visible .lx-point__pastille{r:calc(var(--lx-corps,18px) * .58)}
.lx-point.est-actif .lx-point__pastille{fill:#b3462f}
html.cda-dark .lx-point__pastille{stroke:#0d1117}
html.cda-dark .lx-point__nom{fill:#eef3fa;stroke:rgba(10,16,22,.78)}

@media (prefers-reduced-motion:no-preference){
  /* Les halos battent l'un après l'autre : le décalage dit qu'il y a
     plusieurs endroits, ce qu'un point immobile ne dit pas. */
  .lx-point__halo{animation:ip-lieu-bat 3.2s ease-in-out infinite;animation-delay:calc(var(--n,0) * 280ms)}
}
@media (prefers-reduced-motion:reduce){
  .lx-point__pastille,.lx-point__halo{transition:none}
}
/* Au téléphone, les noms écrits à côté des points se chevauchent dès
   qu'il y en a plus de trois dans le même golfe. La carte reste la
   carte — on la lit — et les noms sont juste en dessous, dans la liste,
   qui elle est faite pour être parcourue. */
/* Au téléphone, la carte est deux fois plus petite qu'à l'écran : les
   noms que le calage laisse passer s'y touchent quand même. On les
   retire, on garde les points — la liste juste en dessous porte les noms,
   et elle est faite pour être lue. */
@media (max-width:700px){
  .lx-point__nom{display:none}
  .lx-carte__svg{aspect-ratio:900/620}
}

/* --- LA LISTE DES LIEUX ---------------------------------------------- */
.lx-liste-sect{padding-top:0}
.lx-liste{
  list-style:none;margin:0;padding:0 var(--ip-marge);
  max-width:1320px;margin-inline:auto;
  display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,210px),1fr));
  gap:clamp(10px,1.2vw,16px);
}
.lx-liste__item a{
  display:flex;flex-direction:column;gap:4px;
  min-height:76px;justify-content:center;
  padding:14px 18px;
  border:1px solid var(--ip-trait);border-radius:4px;
  text-decoration:none;color:inherit;
  background:color-mix(in srgb,var(--ip-papier) 72%,transparent);
  transition:border-color .25s ease,transform .3s cubic-bezier(.16,1,.3,1);
}
.lx-liste__item a:hover,
.lx-liste__item a:focus-visible{border-color:var(--ip-bleu);transform:translateY(-2px)}
.lx-liste__item b{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:18px;line-height:1.2;letter-spacing:-.01em;
}
.lx-liste__item i{
  font-style:normal;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ip-bleu);font-variant-numeric:tabular-nums;
}
@media (prefers-reduced-motion:reduce){ .lx-liste__item a{transition:none} }

.lx-vide{max-width:64ch}
.lx-vide h2{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(22px,2.6vw,32px);margin:0 0 14px;text-wrap:balance;
}
.lx-vide p{margin:0 0 12px;line-height:1.72;color:var(--ip-encre-2)}

/* --- LA VEILLE -------------------------------------------------------- */
/* ELLE VIT DANS DEUX MONDES, ET ELLE EMPORTE DONC LES SIENS.
   La boîte de veille apparaît sur les pages intérieures — où les jetons
   `--ip-*` existent, parce qu'ils sont déclarés sur `.ip` — ET sur la
   fiche d'œuvre, qui n'est pas une `.ip` du tout. Écrite avec
   `var(--ip-bleu)` sans repli, elle y perdait sa couleur, ses marges et
   son trait : un formulaire noir et blanc au milieu d'une fiche.

   `var(--ip-x, valeur)` règle les deux cas d'un coup : le jeton hérité
   gagne quand il existe, la valeur écrite ici sert sinon. On ne
   redéclare surtout PAS `--ip-bleu` sur `.vl` — ça écraserait le jeton
   de la page au lieu de le suivre. */
.vl{
  --vl-marge:var(--ip-marge, clamp(20px,5vw,110px));
  --vl-bleu:var(--ip-bleu, #004aad);
  --vl-papier:var(--ip-papier, #fff);
  --vl-encre:var(--ip-encre, #0d1117);
  --vl-encre-2:var(--ip-encre-2, #333d48);
  --vl-trait:var(--ip-trait, rgba(13,17,23,.14));
  padding:clamp(40px,6vh,80px) 0;
}
.vl__in{
  max-width:min(1320px, 78ch);margin-inline:auto;padding:0 var(--vl-marge);
}
.vl__sur{
  display:inline-block;margin:0 0 12px;
  padding:5px 13px;border-radius:999px;
  border:1px solid color-mix(in srgb,var(--vl-bleu) 24%,transparent);
  background:color-mix(in srgb,var(--vl-bleu) 6%,transparent);
  font-size:10.5px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;
  color:var(--vl-bleu);
}
.vl__titre{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:clamp(24px,3.1vw,40px);line-height:1.15;letter-spacing:-.018em;
  margin:0 0 12px;text-wrap:balance;color:var(--vl-encre);
}
.vl__dit{margin:0 0 22px;max-width:56ch;line-height:1.7;color:var(--vl-encre-2)}

.vl__mot{
  margin:0 0 16px;padding:12px 16px;border-radius:4px;
  font-size:14.5px;line-height:1.55;
}
.vl__mot--bon{background:rgba(47,127,107,.1);color:#1f6552;border:1px solid rgba(47,127,107,.28)}
.vl__mot--mal{background:rgba(179,70,47,.08);color:#9a3c28;border:1px solid rgba(179,70,47,.3)}
html.cda-dark .vl__mot--bon{background:rgba(108,196,169,.12);color:#8fdcc2;border-color:rgba(108,196,169,.32)}
html.cda-dark .vl__mot--mal{background:rgba(224,138,112,.12);color:#f0a98f;border-color:rgba(224,138,112,.34)}

/* LE CHAMP ET LE BOUTON SONT SUR UNE SEULE LIGNE, ET ILS SE SÉPARENT.
   `flex-wrap` plutôt qu'une bascule en grille à un point de rupture : la
   boîte de veille apparaît en pleine largeur sur une page de lieu et dans
   une colonne sur une fiche d'œuvre, donc sa largeur ne se déduit pas de
   celle de l'écran. C'est le contenu qui décide. */
/* `align-content:start` — sans lui, dès que le bouton passe à la ligne,
   le conteneur répartit sa hauteur libre entre les rangées et le champ
   de saisie s'étire à quatre-vingts pixels de haut. C'est le piège d'un
   conteneur flexible qui passe à la ligne : `align-items` gouverne une
   rangée, `align-content` gouverne l'espace ENTRE les rangées, et sa
   valeur par défaut est d'étirer. Constaté au banc d'essai, à 390 px. */
.vl__ligne{display:flex;flex-wrap:wrap;gap:10px;align-items:stretch;align-content:start}
.vl__etiq{
  flex:0 0 100%;
  font-size:11px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--vl-encre-2);margin-bottom:2px;
}
/* `box-sizing` EXPLICITE. Le thème ne pose pas de remise à zéro globale :
   un champ de saisie reste donc en `content-box`, où `min-height` borne
   la HAUTEUR DU TEXTE et non celle de la boîte. Les cinquante-deux pixels
   demandés en devenaient quatre-vingt-deux une fois ajoutés les
   rembourrages — un champ deux fois trop haut à côté de son bouton.
   Mesuré au banc d'essai. */
.vl__champ{
  box-sizing:border-box;
  flex:1 1 240px;min-width:0;
  /* 16 px : en dessous, iOS zoome la page à la mise au point. */
  font:inherit;font-size:16px;
  padding:14px 16px;min-height:52px;
  border:1px solid var(--vl-trait);border-radius:4px;
  background:var(--vl-papier);color:var(--vl-encre);
}
.vl__champ:focus-visible{outline:2px solid var(--vl-bleu);outline-offset:1px;border-color:var(--vl-bleu)}
.vl__btn{
  box-sizing:border-box;
  flex:0 0 auto;min-height:52px;
  padding:0 26px;border:0;border-radius:999px;cursor:pointer;
  background:var(--vl-bleu);color:#fff;
  font-family:inherit;font-size:12.5px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;
  transition:background .25s ease,transform .25s cubic-bezier(.16,1,.3,1);
}
.vl__btn:hover{background:#00306e}
.vl__btn:active{transform:scale(.98)}
@media (prefers-reduced-motion:reduce){ .vl__btn{transition:none} }

.vl__accord{
  display:flex;gap:10px;align-items:flex-start;
  margin-top:14px;max-width:60ch;
  font-size:13px;line-height:1.55;color:var(--vl-encre-2);cursor:pointer;
}
/* LA CASE FAIT VINGT PIXELS ET SA PRISE QUARANTE-QUATRE.
   Le carré natif fait treize pixels de côté : impossible à viser au
   pouce. On l'agrandit, et le `<label>` entier reste cliquable — c'est
   lui la vraie cible. */
/* 24 px : le minimum que les règles d'accessibilité fixent pour une
   cible, et le carré natif en fait treize. Le `<label>` entier reste
   cliquable — c'est lui la vraie prise, et il fait 44 px de haut — mais
   la case doit être visable pour elle-même. */
.vl__accord input{
  flex:none;width:24px;height:24px;margin-top:0;
  accent-color:var(--vl-bleu);cursor:pointer;
}
.vl__accord span{padding-block:11px}

/* LE PIÈGE À ROBOTS SORT DE L'ÉCRAN — il n'est pas masqué.
   `display:none` et `visibility:hidden` sont reconnus par les automates
   récents, qui laissent alors le champ vide : le piège n'attrape plus
   rien. Hors cadre, il est rempli comme les autres. */
.vl__piege{
  position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;
  /* Seize pixels, alors que personne ne le verra jamais : c'est un champ
     de saisie, et tout contrôle automatique qui vérifie le zoom d'iOS le
     signalerait à chaque passage. Une alerte permanente qu'on apprend à
     ignorer est pire qu'une règle inutile. */
  font-size:16px;
}

/* --- LA FICHE D'ŒUVRE : LE LIEU, LE CERTIFICAT, LA COMMANDE ----------- */
.cda-prod-lieu{
  display:flex;align-items:center;gap:8px;
  margin:0 0 16px;font-size:14px;color:#4a5764;
}
.cda-prod-lieu svg{flex:none;color:var(--ip-bleu,#004aad)}
.cda-prod-lieu a{color:var(--ip-bleu,#004aad);text-decoration:none;border-bottom:1px solid rgba(0,74,173,.3)}
.cda-prod-lieu a:hover{border-bottom-color:var(--ip-bleu,#004aad)}
html.cda-dark .cda-prod-lieu{color:#a2b1bf}

.cda-prod-commande{
  display:block;text-align:center;margin-bottom:12px;
  background:var(--ip-bleu,#004aad);color:#fff;text-decoration:none;
  padding:16px;border-radius:999px;
  font-size:13px;letter-spacing:.14em;text-transform:uppercase;
}
.cda-prod-commande:hover{background:#00306e}

/* LE CERTIFICAT : UNE VIGNETTE, PAS UNE PIÈCE JOINTE.
   Elle est petite et posée sous la ligne qui l'annonce ; on l'ouvre en
   grand par la visionneuse déjà utilisée pour les œuvres. */
.cda-cert-voir{
  display:flex;align-items:center;gap:10px;
  margin-top:8px;padding:6px 10px 6px 6px;
  border:1px solid rgba(0,42,99,.16);border-radius:6px;
  background:none;cursor:zoom-in;
  font-family:inherit;font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--ip-bleu,#004aad);
}
.cda-cert-voir img{
  width:58px;height:44px;object-fit:cover;border-radius:3px;display:block;
}
.cda-cert-voir:hover{border-color:var(--ip-bleu,#004aad)}
html.cda-dark .cda-cert-voir{border-color:rgba(255,255,255,.16)}

/* --- LA PAGE INTROUVABLE --------------------------------------------- */
.e404-sorties{
  max-width:1320px;margin-inline:auto;padding:0 var(--ip-marge);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));
  gap:clamp(12px,1.4vw,18px);
}
.e404-sortie{
  display:flex;flex-direction:column;gap:7px;
  padding:22px 24px 24px;
  border:1px solid var(--ip-trait);border-top:3px solid var(--ip-bleu);
  border-radius:4px;text-decoration:none;color:inherit;
  background:color-mix(in srgb,var(--ip-papier) 72%,transparent);
  transition:transform .3s cubic-bezier(.16,1,.3,1),border-color .25s ease;
}
.e404-sortie:hover,
.e404-sortie:focus-visible{transform:translateY(-3px);border-color:var(--ip-bleu)}
.e404-sortie b{
  font-family:'Playfair Display',Georgia,serif;font-weight:600;
  font-size:20px;line-height:1.25;letter-spacing:-.012em;
}
.e404-sortie span{font-size:14px;line-height:1.6;color:var(--ip-encre-2)}
@media (prefers-reduced-motion:reduce){ .e404-sortie{transition:none} }


/* =========================================================================
   LES RÉVÉLATIONS AU DÉFILEMENT, ET LA LUMIÈRE SUR LE VERNIS
   =========================================================================
   Deux ajouts issus du même relevé du 16 septembre 2026. Sur dix-huit sites
   primés, la révélation par `clip-path` est la technique la PLUS répandue :
   quatre-vingt-quatre éléments chez Decathlon, cinquante-cinq chez The Last
   Tango, vingt et un chez Obys. Ce thème en comptait UN.
   ========================================================================= */

/* ═══ 1. LA TOILE SE DÉVOILE, ELLE N'APPARAÎT PAS ═══
   Un fondu dit « voici une image ». Un bord qui balaie dit « voici ce qu'on
   découvre » — c'est le drap qu'on retire d'un tableau, et sur un site de
   galerie la différence de sens est entière.

   AUCUN JAVASCRIPT, ET C'EST LE POINT. `animation-timeline: view()` lie
   l'animation à la traversée de l'élément dans la fenêtre, côté navigateur.
   Elle tourne donc hors du fil principal : `moteur.js` n'a rien à ordonnancer,
   rien à mesurer, et le défilement ne peut pas accrocher à cause d'elle. Le
   banc d'essai mesure zéro lecture de position supplémentaire.

   L'ÉTAT AU REPOS EST VISIBLE. Toute la règle vit dans `@supports` : là où
   la fonctionnalité manque, il n'y a pas de `clip-path` du tout, donc pas
   d'image en attente d'un événement qui ne viendra jamais. C'est l'erreur
   classique des apparitions au défilement, et le thème se l'interdit déjà
   ailleurs pour la même raison. */
@keyframes cda-devoile {
  from { clip-path: inset(0 0 100% 0) }
  to   { clip-path: inset(0 0 0 0) }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* ═══ LA CHRONOLOGIE EST NOMMÉE, ET C'EST OBLIGATOIRE ICI ═══
       `animation-timeline: view()` posé sur l'image ne marchait PAS, et sans
       la moindre erreur : mesuré au banc, l'animation était bien attachée à
       une `ViewTimeline`, la plage bien lue — mais son état restait
       `finished` et sa progression à 1, à toute position de défilement.

       La raison est que `view()` prend pour fenêtre de référence le plus
       proche CONTENEUR DE DÉFILEMENT, et que `.ip-carte__media` en est un :
       il porte `overflow:hidden` pour son arrondi. L'image remplit
       exactement ce cadre, donc elle y est toujours entièrement visible, donc
       la phase d'entrée est toujours terminée. La révélation ne se serait
       jamais jouée, et rien n'aurait signalé qu'elle dormait.

       On désigne donc explicitement la CARTE comme sujet : elle, son
       conteneur de défilement est la page. L'animation reste sur l'image —
       de sorte que l'ombre portée du cadre n'est pas rognée pendant le
       dévoilement, ce qui la ferait grandir avec lui. */
    /* ═══ LE SUJET EST LE CADRE, PAS L'IMAGE ═══
       La règle a d'abord été posée sur `.ip-carte__media img`. C'était faux,
       et d'une façon qui ne se voit pas : `view()` prend pour source le plus
       proche CONTENEUR DE DÉFILEMENT de son sujet, et `.ip-carte__media` en
       est un — il porte `overflow:hidden` pour son arrondi. La chronologie de
       l'image aurait donc eu pour source un cadre qui ne défile jamais.
       Mesuré au banc avec le cadre pour sujet : `source` vaut bien `html`.

       CETTE RÈGLE N'A PAS PU ÊTRE VUE À L'ŒUVRE. Le navigateur d'essai de cet
       atelier ne fait pas avancer les chronologies de défilement — vérifié
       sur une page témoin de vingt lignes sans aucune feuille du thème, dont
       la chronologie reste inactive elle aussi. Sa forme est donc calquée sur
       `.pt-carte__route`, plus bas dans ce fichier, qui emploie le même
       mécanisme et tourne en production. À vérifier à l'œil au premier
       chargement du catalogue.

       Conséquence assumée du choix du cadre : `clip-path` rogne aussi son
       ombre portée, qui grandit donc avec le dévoilement. Sur une toile qu'on
       descend à sa place, c'est le bon sens de lecture. */
    .ip-carte__media {
      animation: cda-devoile linear both;
      animation-timeline: view();
      /* Le dévoilement s'achève bien avant que la carte soit au centre : une
         œuvre qu'on lit encore à moitié cachée au milieu de l'écran serait une
         coéterie, pas une mise en scène. Les cartes déjà visibles au
         chargement sont au-delà de la plage, donc entières dès la première
         image. */
      animation-range: entry 10% cover 42%;
    }
  }
}

/* ═══ 2. LE REFLET DEVIENT UNE LUMIÈRE ═══
   `.ip-carte__reflet` pose un halo blanc au survol. En opacité simple, ce
   blanc DÉLAVE l'œuvre : il ajoute du blanc partout, y compris dans les
   ombres, et une marine y perd ses noirs.

   `soft-light` ne rajoute pas de blanc, il éclaircit CE QUI EST DÉJÀ CLAIR et
   laisse les valeurs sombres tranquilles — exactement ce que fait la lumière
   sur un vernis. Le halo devient un reflet au lieu d'être un voile.

   C'est le seul endroit du thème où un mode de fusion est posé, et c'est
   délibéré : l'élément ne contient aucun texte et ne reçoit aucun clic
   (`pointer-events:none`), donc aucun réglage de contraste ne peut se
   retourner contre la lisibilité. Sur un titre, la même propriété serait un
   pari ; ici, non. */
.ip-carte__reflet { mix-blend-mode: soft-light }
