/* ==========================================================================
   Jolihuit, refonte 2026
   --------------------------------------------------------------------------
   Feuille autonome : elle ne dépend pas de tokens.css, base.css ni
   components.css, et ne les modifie pas. Les 21 autres pages du site
   continuent de tourner sur l'ancienne direction tant que celle-ci n'est
   pas validée.

   Trois principes, et tout le reste en découle.

   1. LA SUITE.
      Cinq couleurs, toujours dans le même ordre : violet, menthe, corail,
      jaune, rose. Elles ne sont pas déduites du logo, elles sont relevées
      dans le CSS de jolihuit.com, où elles sont déjà numérotées de 0 à 4
      et employées dans l'ordre en descendant la page. Le système existait
      avant nous ; on le reprend, index compris.
      Mécanique : la classe .seq distribue la suite sur les enfants d'un
      conteneur, en boucle de cinq. Elle est posée sur <main>, donc chaque
      section porte son rang, et tout ce qu'elle contient en hérite. On ne
      pose jamais une couleur à la main.

   2. LA RETENUE.
      Encre noire, boutons noirs, angles à zéro, blanc à peine chaud,
      beaucoup de vide. Ces cinq couleurs sont franches, pas pastel : un
      corail à 100 % sur un aplat crierait. Elles n'apparaissent donc que
      diluées (lavis à 10 %), assombries (encres), en filet fin, ou au
      feutre à 60 %. Jamais un aplat saturé plein écran.

   3. LE FEUTRE.
      L'emphase de la maison, reprise au caractère près de jolihuit.com :
      un dégradé transparent jusqu'à 60 % de la hauteur de ligne, puis la
      couleur à 60 % d'opacité. Le trait ne couvre que le bas des lettres,
      comme un vrai surligneur. C'est ce geste, et pas l'italique, qui
      remplace le gras et la couleur dans les titres.

   Nommage : préfixe r- pour tout ce qui appartient à la refonte, afin que
   rien n'entre en collision avec l'ancienne feuille si les deux cohabitent
   un jour sur une même page.
   ========================================================================== */

/* ==========================================================================
   1. Jetons
   ========================================================================== */

:root {
  /* --- Fond et encre ---------------------------------------------------- */
  /* Blanc à peine chaud. Le crème de l'ancienne direction éteignait les
     pastels et nous rangeait dans le rayon « artisanal français ». */
  --r-bg:        #FCFBFA;
  --r-bg-pure:   #FFFFFF;   /* bandes alternées */
  --r-ink:       #141312;   /* noir chaud, celui du wordmark */
  --r-ink-soft:  #4A4644;
  --r-ink-mute:  #7A746E; /* durci le 25/09 : #8B8580 tombait a ~3.6:1 sur blanc, sous le seuil AA 4.5:1 */
  --r-rule:      rgba(20, 19, 18, .14);
  --r-rule-soft: rgba(20, 19, 18, .07);
  --r-on-dark:   #FCFBFA;

  /* --- La suite ---------------------------------------------------------
     Ces cinq valeurs ne sont pas déduites du logo : elles sont relevées
     dans le CSS de jolihuit.com, où elles portent les classes
     .rtex-highlighter-0 à -4 et servent de surlignage au feutre. Elles y
     sont numérotées et employées dans l'ordre, une fois chacune, en
     descendant la page. C'est un système déjà en place, pas une palette
     à inventer : on le reprend tel quel, index compris.

       0  rgba(97,40,255,.6)    violet
       1  rgba(88,232,191,.6)   menthe
       2  rgba(255,95,69,.6)    corail
       3  rgba(255,198,21,.6)   jaune
       4  rgba(255,192,212,.6)  rose

     Les trois premières sont aussi les trois points du wordmark. La
     palette de la marque et celle du logo sont la même chose. */
  --arc-1: #6128FF;   /* violet */
  --arc-2: #58E8BF;   /* menthe */
  --arc-3: #FF5F45;   /* corail */
  --arc-4: #FFC615;   /* jaune  */
  --arc-5: #FFC0D4;   /* rose   */

  /* La sixième, le rouge, ajoutée le 25 septembre 2026 à la demande
     d'Andréa pour que les six catégories du journal aient chacune leur
     couleur (Grandir partageait le violet de DIY). Pas de rouge caché dans
     le site d'origine : aucun .rtex-highlighter au-delà de 4, et le point
     « rouge » du wordmark est le corail (#FF5F45, relevé dans le PNG).
     C'est donc ce corail poussé vers un rouge franc, teinte 348° contre
     8° : assez loin de lui pour ne pas le doubler (écart Lab 22), loin du
     rose (écart 69). Hors de .seq, qui reste en boucle de cinq : la
     sixième ne sert qu'aux catégories du journal (data-rang="6"). */
  --arc-6: #E5173F;   /* rouge  */

  /* Lavis : les mêmes à 10 %, calculés sur --r-bg. Fonds de panneau,
     tuiles du menu, survols. Ce sont des couleurs franches : diluées à ce
     point elles posent une teinte sans jamais crier. */
  --lavis-1: #ECE6FA;
  --lavis-2: #ECF9F4;
  --lavis-3: #FCEBE8;
  --lavis-4: #FCF6E3;
  --lavis-5: #FCF5F6;
  --lavis-6: #FAE4E7;

  /* Encres : les mêmes, poussées jusqu'à passer 4,5:1 sur le fond. Le
     violet tient déjà tout seul (6,24:1) ; les quatre autres non, une
     menthe à 1,48:1 sur du blanc n'est pas un texte, c'est un souvenir.
     Réservées aux chiffres, aux titres courts et aux pictogrammes. */
  --encre-1: #6128FF;   /* 6,24:1, la valeur d'origine convient */
  --encre-2: #0A7A5D;   /* 5,14:1 */
  --encre-3: #D63A22;   /* 4,53:1 */
  --encre-4: #8A6708;   /* 5,05:1 */
  --encre-5: #B0396A;   /* 5,58:1 */
  --encre-6: #E4173F;   /* 4,52:1, le rouge d'origine est à 4,49:1 */

  /* --- Rôles fonctionnels ----------------------------------------------
     Ils ne sont plus une famille à part : ils pointent dans la suite.

     Ce sont eux, et non la suite, qui habillent tout ce qui porte une
     information d'état : disponibilité, offre commerciale, note. La suite
     structure la page, les rôles renseignent le visiteur. Confondre les
     deux revenait à repeindre un « en stock » en rose parce qu'il tombait
     dans la cinquième section. */
  --vif-violet: var(--arc-1);    /* focus clavier, liens actifs */
  --vif-vert:   var(--encre-2);  /* en stock */
  --vif-corail: var(--encre-3);  /* promotion, stock bas */

  /* L'or des avis. Une étoile de notation est dorée partout, depuis
     toujours : c'est une convention de lecture, pas une préférence, et
     une étoile menthe cesse d'être lue comme une note.

     Ce n'est pas le jaune de la marque (--arc-4) : à 1,7:1 sur le fond,
     il ne se voit pas. Celui-ci est le même jaune assombri jusqu'à passer
     3:1, le seuil des éléments non textuels porteurs de sens. Mesuré sur
     --r-bg : 3,14:1. */
  --or-avis: #B98600;

  /* Le feutre : la couleur du rang courant, posée à 60 % comme sur
     jolihuit.com. Chaque section redéfinit --arc, donc --feutre suit. */
  --feutre-1: rgba(97, 40, 255, .6);
  --feutre-2: rgba(88, 232, 191, .6);
  --feutre-3: rgba(255, 95, 69, .6);
  --feutre-4: rgba(255, 198, 21, .6);
  --feutre-5: rgba(255, 192, 212, .6);
  --feutre-6: rgba(229, 23, 63, .6);
  --feutre:   var(--feutre-1);

  /* Hauteur à laquelle le trait démarre. Elle se règle par piste : la
     boîte d'un élément en ligne suit les métriques de la fonte, pas la
     hauteur de ligne, donc 60 % ne tombe pas au même endroit sous
     Poppins et sous Fraunces. Valeur de référence chez elle : 60 %. */
  --feutre-stop: 68%;

  /* --- Typographie ------------------------------------------------------ */
  /* Le texte courant ne change jamais : Poppins, la police que la marque
     utilise déjà en production. Seuls les titres varient d'une piste à
     l'autre, via les variables --rf-* redéfinies plus bas. */
  --r-body: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --rf-display: 'Fraunces', Georgia, serif;
  --rf-weight:  400;
  --rf-track:   -.015em;
  --rf-leading: 1.06;
  --rf-settings: 'opsz' 96, 'SOFT' 40, 'WONK' 1;

  /* Corps de texte à 16 px, pas 14. Atelier Camille descend à 14 px et
     centre ses paragraphes : c'est la seule chose qu'on ne leur reprend
     pas, ça se lit mal. */
  --fs-micro: .75rem;    /* 12 px, suréligne et méta */
  --fs-sm:    .875rem;   /* 14 px */
  --fs-base:  1rem;      /* 16 px */
  --fs-lg:    1.125rem;  /* 18 px */
  --fs-h3:    clamp(1.25rem, 2.2vw, 1.6rem);
  --fs-h2:    clamp(2rem, 4.6vw, 3.4rem);
  --fs-h1:    clamp(2.6rem, 6.4vw, 5rem);

  /* --- Rythme et formes ------------------------------------------------- */
  /* Angle droit partout. La rondeur reste la propriété du wordmark. */
  --r-radius: 0;

  --sp-section: clamp(3.5rem, 7vw, 6rem);
  --sp-gutter:  clamp(1.25rem, 4vw, 2.5rem);
  --w-max:  100rem;   /* 1600 px */
  --w-text: 46rem;
  --h-header: 4.5rem;

  --ease: cubic-bezier(.22, .61, .36, 1);

  /* Deux temps, parce qu'ils ne répondent pas à la même chose.
       --dur         la réponse à un geste : survol, ouverture, bascule
       --dur-reveal  l'entrée en scène d'un bloc qui arrive au défilement
       --stagger     le décalage d'un enfant au suivant dans un groupe

     Le décalage ne s'applique qu'aux groupes de huit éléments ou moins :
     au-delà, les derniers arrivent si tard qu'ils paraissent en retard
     plutôt qu'en cascade. Les quatre cartes produit, les quatre avis et
     les quatre engagements tiennent tous dans cette limite. */
  --dur: .45s;
  --dur-reveal: .5s;
  --stagger: 80ms;
}

/* ==========================================================================
   1 bis. Les icônes
   --------------------------------------------------------------------------
   Le sprite attribue à chaque icône une couleur FIXE, liée à son sujet :
   le tapis est menthe, le matelas lavande, l'oreiller rose. La nouvelle
   direction dit l'inverse : la couleur vient du rang dans la suite, hérité
   de la section. Deux règles de couleur sur la même surface, qui se
   contredisent. Repeindre les icônes ne réglerait rien, ça saturerait la
   contradiction : il faut en supprimer une.

   On garde le rang. Les icônes deviennent donc monochromes et héritent de
   leur contexte, ce qui les rend au passage posables sur n'importe quel
   fond, y compris le bloc sombre et une photo, ce qui était impossible.

   Aucun dessin n'est retouché et le sprite n'est pas régénéré : ses
   couleurs sont déjà des variables à repli, il suffit de les définir.
   Les 21 autres pages, qui ne chargent pas cette feuille, gardent leurs
   icônes bicolores tant que la direction n'est pas tranchée.
   ========================================================================== */

:root {
  /* Les encres d'accent, celles qui portaient la nervure ou la fermeture,
     passent à la couleur courante. */
  --jh-encre-menthe:  currentColor;
  --jh-encre-lavande: currentColor;
  --jh-encre-rose:    currentColor;
  --jh-encre-jaune:   currentColor;
  --jh-encre-corail:  currentColor;

  /* Les lavis, qui remplissaient le corps du dessin, deviennent un voile
     de la couleur courante. Assez pour que l'icône garde un corps, trop
     peu pour qu'elle redevienne une pastille de catalogue. */
  --jh-lavis-menthe:  color-mix(in srgb, currentColor 9%, transparent);
  --jh-lavis-lavande: var(--jh-lavis-menthe);
  --jh-lavis-rose:    var(--jh-lavis-menthe);
  --jh-lavis-jaune:   var(--jh-lavis-menthe);
  --jh-lavis-corail:  var(--jh-lavis-menthe);

  /* Une seule exception : l'arc-en-ciel. Ce n'est pas un pictogramme,
     c'est la marque elle-même, au même titre que le wordmark. Il garde
     donc ses quatre bandes, mais dans les vraies valeurs. */
  --jh-lavande: var(--arc-1);
  --jh-menthe:  var(--arc-2);
  --jh-rose:    var(--arc-3);
  --jh-jaune:   var(--arc-4);
}

/* Par défaut une icône ne fixe AUCUNE couleur : elle prend celle de son
   contexte par currentColor. Une règle .icon { color: ... } ici casserait
   le blanc du header posé sur la photo, qui vient de l'inverse : le
   header déclare sa couleur, les icônes suivent. */

/* Partout où la suite s'applique, l'icône prend l'encre de son rang. */
/* Les pictogrammes aussi prennent la couleur vraie. L'encre assombrie
   était faite pour du texte ; appliquée au jaune elle donnait un olive
   qui n'est dans aucune palette de la maison. Un pictogramme accompagné
   de son libellé en noir est un ornement, pas une information : il n'a
   pas à passer le contraste d'un texte, il a à être de la bonne
   couleur. */
.r-trust__icon,
.r-reseaux .icon,
/* Six pictogrammes de six couleurs alignés en fin de page faisaient une
   planche d'autocollants. Ce sont des engagements de service, pas six
   sujets différents : une seule encre, et le regard les lit comme un
   ensemble. */
.r-socle__points .icon { color: var(--r-ink-soft); }

/* ==========================================================================
   2. Socle
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

body {
  margin: 0;
  background: var(--r-bg);
  color: var(--r-ink);
  font-family: var(--r-body);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.7;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, picture, video, svg { display: block; max-width: 100%; }
img, video { height: auto; }

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  letter-spacing: var(--rf-track);
  line-height: var(--rf-leading);
  /* Casse normale. Aucune capitale forcée sur un titre : c'est le premier
     signe qui nous rangeait dans le template du moment. */
  text-transform: none;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

p { margin: 0 0 1.15em; font-size: .95rem; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

ul, ol { margin: 0; padding: 0; list-style: none; }

button, input { font: inherit; color: inherit; }
/* Repli oublié en portant la feuille depuis base.css : sans lui, un bouton
   qui ne fixe pas lui-même son fond montre le chrome natif du navigateur,
   un rectangle blanc bordé. C'est ce qui faisait le carré blanc du bouton
   de fermeture en plein écran : il n'avait jamais eu besoin de le
   redéfinir, base.css le faisait pour lui, partout. */
button { background: none; border: 0; cursor: pointer; padding: 0; }

/* Anneau de focus : le violet du point du j, un des trois vifs. */
:focus-visible {
  outline: 2px solid var(--vif-violet);
  outline-offset: 3px;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: .75rem 1.25rem;
  background: var(--r-ink); color: var(--r-on-dark);
  font-size: var(--fs-sm);
}
.skip-link:focus { left: 0; }

/* ==========================================================================
   3. Gabarit
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--w-max);
  margin-inline: auto;
  padding-inline: var(--sp-gutter);
}

.wrap--text { max-width: var(--w-text); }

.r-section { padding-block: var(--sp-section); }
.r-section--tight { padding-block: clamp(3rem, 6vw, 5rem); }
.r-section--pure { background: var(--r-bg-pure); }

/* ==========================================================================
   4. La suite de l'arc-en-ciel
   --------------------------------------------------------------------------
   Le cœur du système. .seq distribue violet, menthe, corail, jaune, rose
   sur les enfants directs, en boucle de cinq. Chaque enfant reçoit quatre
   variables : --arc (la couleur pleine), --lavis (sa dilution à 10 %),
   --encre (sa version lisible en texte) et --feutre (sa version
   surligneur, à 60 %). Aucun composant ne code une couleur en dur, il lit
   la variable.
   ========================================================================== */

.seq > *:nth-child(5n + 1) { --arc: var(--arc-1); --lavis: var(--lavis-1); --encre: var(--encre-1); --feutre: var(--feutre-1); }
.seq > *:nth-child(5n + 2) { --arc: var(--arc-2); --lavis: var(--lavis-2); --encre: var(--encre-2); --feutre: var(--feutre-2); }
.seq > *:nth-child(5n + 3) { --arc: var(--arc-3); --lavis: var(--lavis-3); --encre: var(--encre-3); --feutre: var(--feutre-3); }
.seq > *:nth-child(5n + 4) { --arc: var(--arc-4); --lavis: var(--lavis-4); --encre: var(--encre-4); --feutre: var(--feutre-4); }
.seq > *:nth-child(5n + 5) { --arc: var(--arc-5); --lavis: var(--lavis-5); --encre: var(--encre-5); --feutre: var(--feutre-5); }

/* Le filet à cinq bandes. Sert de bord haut de page, de séparateur de
   section et de soulignement. Il remplace le « × × × » d'Atelier Camille
   et l'ornement en losange de l'ancienne direction. */
.arcrule {
  display: flex;
  height: 3px;
  width: 100%;
}
.arcrule > span { flex: 1; }
.arcrule > span:nth-child(1) { background: var(--arc-1); }
.arcrule > span:nth-child(2) { background: var(--arc-2); }
.arcrule > span:nth-child(3) { background: var(--arc-3); }
.arcrule > span:nth-child(4) { background: var(--arc-4); }
.arcrule > span:nth-child(5) { background: var(--arc-5); }

/* Bord haut du document, et rien de plus.

   Il était collant, donc les cinq couleurs de la maison restaient à
   l'écran du premier au dernier pixel de la page, soit neuf mille pixels
   de haut. Un signe qu'on voit en permanence cesse d'être un signe et
   devient un décor de fenêtre.

   Il reste donc là où il a un sens : tout en haut, premier trait qu'on
   voit en arrivant, avant même le wordmark, puis il s'en va avec le reste
   de la page. Le filet complet se retrouve en bas du bouton du héros, en
   séparateur entre deux sections, et dans le logo du pied de page. */
.arcrule--top { position: relative; z-index: 60; }

/* Séparateur de section, centré et court. */
.arcrule--sep {
  max-width: 7.5rem;
  margin: 0 auto;
  height: 2px;
}

/* ==========================================================================
   5. Composants de texte
   ========================================================================== */

/* Suréligne. Elle existe encore mais devient rare : deux ou trois sur toute
   la page, jamais une par section, et l'interlettrage passe de .25em à
   .08em. C'est l'accumulation qui faisait template, pas l'objet. */
.eyebrow {
  display: block;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--r-ink);
  margin-bottom: 1rem;
}

.lead {
  font-size: var(--fs-lg);
  line-height: 1.65;
  color: var(--r-ink-soft);
}

/* L'italique du serif est le seul outil d'emphase dans les titres. Pas de
   gras, pas de couleur.

   Mais le geste, lui, n'est pas celui d'Atelier Camille : c'est le sien.
   jolihuit.com surligne déjà ses titres au feutre, et la mécanique est
   reprise au caractère près, y compris l'astuce qui fait tout : un
   dégradé qui reste transparent jusqu'à 60 % de la hauteur de ligne, puis
   pose la couleur à 60 % d'opacité. Le trait ne couvre que le bas des
   lettres, comme un vrai surligneur passé un peu vite, et le texte reste
   noir dessous.

   L'italique d'Atelier Camille aurait été plus sage. Le feutre est à
   elle : entre les deux, il n'y avait pas à hésiter. Il vaut donc pour
   les trois pistes, qui ne diffèrent ainsi plus que par leur police,
   ce qui est précisément ce qu'on cherche à comparer. */
h1 em, h2 em, h3 em, .r-manifeste__phrase em {
  font-style: normal;
  font-synthesis: none;
  text-decoration: none;
  background: linear-gradient(transparent var(--feutre-stop), var(--feutre) var(--feutre-stop));
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

/* Pas de feutre dans le héros. Le surligneur est un geste de papier : il
   suppose une encre noire sur un fond clair. Posé derrière du blanc sur
   une photo, il ne surligne plus rien, il tache. Le titre du héros garde
   donc son emphase muette. */
.r-hero em { background: none; }

.link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--arc-1);
  text-decoration-thickness: 1.5px;
  text-underline-offset: .28em;
  transition: text-decoration-color var(--dur) var(--ease);
}
.link:hover { text-decoration-color: var(--vif-violet); }

/* ==========================================================================
   6. Boutons
   ========================================================================== */

.r-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 2rem;
  border: 1px solid var(--r-ink);
  border-radius: var(--r-radius);
  background: var(--r-ink);
  color: var(--r-on-dark);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.r-btn:hover { background: transparent; color: var(--r-ink); }

.r-btn--ghost {
  background: transparent;
  border-color: currentColor;
  color: var(--r-on-dark);
}
.r-btn--ghost:hover { background: var(--r-on-dark); color: var(--r-ink); }

/* Le bouton du héros. Le rectangle filaire blanc en capitales espacées
   posé sur une photo est LE bouton de héros de tout le web depuis dix
   ans : c'est exactement le genre de signe qui nous rangeait dans le
   gabarit du moment. Il devient donc un aplat de son violet, celui du
   point du j et du premier surligneur de sa page d'accueil.

   Deux effets. Il se voit sur n'importe quelle photo, ce qu'un filet
   blanc ne garantit jamais. Et il est à elle : le violet plein est ce
   que son WordPress emploie déjà pour tous ses appels à l'action.

   La suite passe dessous, en filet de cinq bandes. C'est le seul endroit
   de la page où elle apparaît entière et à pleine taille, et c'est
   justifié : c'est le premier bouton que le visiteur voit. */
.r-hero .r-btn--ghost {
  position: relative;
  background: var(--arc-1);
  border-color: var(--arc-1);
  color: #FFF;
  padding-bottom: 4px;
  overflow: hidden;
}
.r-hero .r-btn--ghost::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  /* Tricolore, et non la suite. Quatre pastels sous un aplat violet
     faisaient une bande décorative de plus, sans rien dire. Le bleu blanc
     rouge, lui, énonce l'argument le plus fort de la maison, celui que
     personne ne peut copier : Origine France Garantie, certification
     AFNOR 104432. Un signe qui parle vaut mieux qu'un ornement.

     Le bleu n'est pas le #000091 de la charte de l'État : posé sur un
     aplat violet, un bleu marine est son propre voisin et disparaît. Il
     est monté à #0F62D9, qui se lit franchement bleu contre le violet
     comme contre le blanc. Le rouge reste celui du drapeau. */
  background: linear-gradient(to right,
    #0F62D9 0 33.33%, #FFF 33.33% 66.66%, #E1000F 66.66% 100%);
}
.r-hero .r-btn--ghost:hover {
  background: var(--r-ink);
  border-color: var(--r-ink);
  color: #FFF;
}

.r-btn--full { width: 100%; }

/* ==========================================================================
   7. Barre d'annonce et en-tête
   ========================================================================== */

.r-topbar {
  background: var(--r-bg-pure);
  border-bottom: 1px solid var(--r-rule-soft);
  font-size: var(--fs-micro);
  letter-spacing: .02em;
}
.r-topbar__inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  min-height: 2.5rem;
  text-align: center;
}
.r-topbar p { margin: 0; }
.r-topbar__side { display: none; color: var(--r-ink-mute); }

@media (min-width: 60rem) {
  .r-topbar__inner { justify-content: space-between; }
  .r-topbar__side { display: block; }
}

/* En-tête transparent posé sur le héros, qui devient opaque au défilement.
   C'est ce qui donne à la photo tout le premier écran. */
.r-header {
  position: sticky;
  /* 0 et non 3px : le filet arc-en-ciel ne suit plus le défilement, donc
     il n'y a plus de bande à lui réserver. À 3px, l'en-tête laissait voir
     un liseré de page qui défile au-dessus de lui. */
  top: 0;
  /* Le panneau Boutique se cale sur toute la largeur de l'en-tête, pas
     sur le mot qui l'ouvre : c'est ce qui lui permet de tenir trois
     colonnes sans déborder de la grille de la page. */
  isolation: isolate;
  z-index: 50;
  background: transparent;
  color: var(--r-on-dark);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.r-header.is-solid {
  background: var(--r-bg);
  color: var(--r-ink);
  box-shadow: 0 1px 0 var(--r-rule-soft);
}

.r-header__inner {
  position: relative;   /* repère du panneau Boutique */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
  min-height: var(--h-header);
}

.r-nav {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.r-nav a, .r-nav button {
  color: inherit;
  text-decoration: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  position: relative;
}
/* Le survol de navigation pose la première bande de la suite. */
.r-nav a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 2px;
  background: var(--arc-1);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur) var(--ease);
}
.r-nav a:hover::after { transform: scaleX(1); }

/* --------------------------------------------------------------------------
   Le panneau Boutique, sur ordinateur
   --------------------------------------------------------------------------
   Le menu de bureau listait quatre rubriques et aucun produit : ni les
   quatre pièces, ni les neuf accessoires n'étaient atteignables depuis
   l'en-tête. Sur un site qui vend treize références, c'était le défaut le
   plus coûteux de la maquette, et il ne se voyait pas parce que le tiroir
   mobile, lui, faisait le travail.

   Le panneau reprend donc le rangement du tiroir, à l'identique : les
   quatre pièces en vitrine photo, les accessoires groupés par produit.
   Une seule façon de ranger la maison, quel que soit l'écran.

   Il est piloté par le même mécanisme que le repli du tiroir, celui de
   main.js : aria-expanded sur le déclencheur, hidden sur le panneau,
   fermeture à l'échappement et au clic extérieur. Pas de second système
   pour le même geste.
   -------------------------------------------------------------------------- */
.r-nav__group { position: static; }

.r-panneau {
  position: absolute;
  top: 100%;
  left: 0; right: 0;
  z-index: 60;
  background: var(--r-bg);
  border-top: 1px solid var(--r-rule-soft);
  box-shadow: 0 1.5rem 3rem rgba(20, 19, 18, .10);
  color: var(--r-ink);
}
.r-panneau[hidden] { display: none; }

/* Le filet de la suite ferme le panneau par le bas, comme il ouvre la
   page par le haut. */
.r-panneau::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: linear-gradient(to right,
    var(--arc-1) 0 20%, var(--arc-2) 20% 40%, var(--arc-3) 40% 60%,
    var(--arc-4) 60% 80%, var(--arc-5) 80% 100%);
}

.r-panneau__inner {
  display: grid;
  grid-template-columns: 1.15fr 1.25fr .8fr;
  gap: clamp(2rem, 4vw, 4rem);
  max-width: var(--w-max);
  margin-inline: auto;
  padding: 2.5rem var(--sp-gutter) 3rem;
  text-align: left;
}

.r-panneau__titre {
  margin: 0 0 1.25rem;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--r-ink-mute);
}

/* Le nom du produit est en casse normale et dans la police de titres :
   on lit un nom, pas une rubrique. Même règle que dans le tiroir. */
.r-panneau__nom {
  display: block;
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.05rem;
  line-height: 1.2;
  letter-spacing: var(--rf-track);
  text-transform: none;
}
.r-panneau__prix {
  display: block;
  margin-top: .2rem;
  font-size: var(--fs-sm);
  letter-spacing: 0;
  text-transform: none;
  color: var(--r-ink-mute);
}

/* --- La vitrine ---------------------------------------------------------- */
.r-panneau__vitrine { display: grid; gap: .4rem; }
.r-panneau__vitrine > *:nth-child(4n + 1) { --arc: var(--arc-1); --lavis: var(--lavis-1); }
.r-panneau__vitrine > *:nth-child(4n + 2) { --arc: var(--arc-2); --lavis: var(--lavis-2); }
.r-panneau__vitrine > *:nth-child(4n + 3) { --arc: var(--arc-3); --lavis: var(--lavis-3); }
.r-panneau__vitrine > *:nth-child(4n + 4) { --arc: var(--arc-4); --lavis: var(--lavis-4); }

.r-panneau__vitrine a {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  align-items: center;
  gap: .9rem;
  padding-right: .75rem;
  background: var(--lavis);
  border-left: 3px solid var(--arc);
  color: var(--r-ink);
  text-decoration: none;
  transition: background var(--dur) var(--ease);
}
.r-panneau__vitrine a:hover { background: color-mix(in srgb, var(--arc) 20%, var(--r-bg)); }
.r-panneau__vitrine a::after { content: none; }
.r-panneau__vitrine img { width: 3.5rem; height: 3.5rem; object-fit: cover; display: block; }

/* --- Les familles d'accessoires ------------------------------------------ */
.r-panneau__familles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 2rem;
}
.r-panneau__familles > *:nth-child(4n + 1) { --arc: var(--arc-1); }
.r-panneau__familles > *:nth-child(4n + 2) { --arc: var(--arc-2); }
.r-panneau__familles > *:nth-child(4n + 3) { --arc: var(--arc-3); }
.r-panneau__familles > *:nth-child(4n + 4) { --arc: var(--arc-4); }

.r-panneau__famille {
  display: grid;
  gap: .3rem;
  padding-left: .85rem;
  border-left: 2px solid var(--arc);
}
.r-panneau__famtitre {
  margin: 0 0 .35rem;
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: var(--fs-sm);
  font-style: italic;
  font-synthesis: none;
  letter-spacing: 0;
  text-transform: none;
  color: var(--r-ink-mute);
}
.r-panneau__famille a {
  font-size: var(--fs-sm);
  letter-spacing: 0;
  text-transform: none;
  color: var(--r-ink-soft);
  text-decoration: none;
}
.r-panneau__famille a::after { content: none; }
.r-panneau__famille a:hover { color: var(--r-ink); text-decoration: underline; text-underline-offset: .2em; }

/* --- La troisième colonne ------------------------------------------------
   Un menu qui ne sert qu'à ranger est un sommaire. Celui-ci met en avant
   ce que la marque a de plus singulier et qu'aucune liste de liens ne
   peut montrer : ses imprimés.
   ------------------------------------------------------------------------ */
.r-panneau__col--pousse { display: grid; align-content: start; }
.r-panneau__pousse {
  display: grid;
  justify-items: start;
  gap: .1rem;
  color: var(--r-ink);
  text-decoration: none;
}
.r-panneau__pousse::after { content: none; }
.r-panneau__pousse img {
  width: 100%;
  max-width: 11rem;
  height: auto;
  border-radius: 50%;
  margin-bottom: .9rem;
  transition: transform var(--dur) var(--ease);
}
.r-panneau__pousse:hover img { transform: scale(1.03); }

/* --- Le panneau en liste (La maison, Journal, 25 septembre 2026) ---------
   Même composant que Boutique : même bouton .nav__trigger, même mécanique
   de main.js, même panneau pleine largeur fermé par le filet. Seul le
   contenu change : une liste de rubriques en tuiles de lavis, trois par
   rangée, sans photo, chacune avec son pictogramme dans l'encre de son
   rang. Couleur par rang dans la suite ; une catégorie du journal garde sa
   couleur à elle (data-rang, section 31) et le pictogramme de sa colonne
   (.r-picto). Une entrée .r-panneau__tout (« Tout le journal ») ouvre la
   liste sur toute la largeur. */
.r-panneau--liste .r-panneau__inner { display: block; }
.r-panneau__liste {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.r-panneau__liste > li:not([data-rang]):nth-child(5n + 1) { --arc: var(--arc-1); --lavis: var(--lavis-1); --encre: var(--encre-1); }
.r-panneau__liste > li:not([data-rang]):nth-child(5n + 2) { --arc: var(--arc-2); --lavis: var(--lavis-2); --encre: var(--encre-2); }
.r-panneau__liste > li:not([data-rang]):nth-child(5n + 3) { --arc: var(--arc-3); --lavis: var(--lavis-3); --encre: var(--encre-3); }
.r-panneau__liste > li:not([data-rang]):nth-child(5n + 4) { --arc: var(--arc-4); --lavis: var(--lavis-4); --encre: var(--encre-4); }
.r-panneau__liste > li:not([data-rang]):nth-child(5n + 5) { --arc: var(--arc-5); --lavis: var(--lavis-5); --encre: var(--encre-5); }
.r-panneau__liste a {
  display: flex;
  align-items: center;
  gap: .85rem;
  min-height: 3.5rem;
  padding: .75rem 1.1rem;
  background: var(--lavis);
  border-left: 3px solid var(--arc);
  color: var(--r-ink);
  text-decoration: none;
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.05rem;
  line-height: 1.2;
  letter-spacing: var(--rf-track);
  text-transform: none;
}
.r-panneau__liste a::after { content: none; }
.r-panneau__liste a:hover,
.r-panneau__liste a[aria-current] { background: color-mix(in srgb, var(--arc) 20%, var(--r-bg)); }
.r-panneau__liste a > span:not(.nav__chevron) { flex: 1; min-width: 0; }
/* Le pictogramme : le trait fin de la maison, dans l'encre du rang (les
   symboles du sprite sont monochromes, section 1 bis ; .r-picto est celui
   de la colonne du journal). Il se redresse au survol comme sur journal/. */
.r-panneau__liste a > svg {
  flex: none;
  width: 1.75rem; height: 1.75rem;
  color: var(--encre, var(--r-ink));
  transition: transform var(--dur) var(--ease);
}
.r-panneau__liste a > .r-picto { width: 1.5rem; height: 1.5rem; stroke-width: 1.4; }
.r-panneau__liste a:hover > svg { transform: translateY(-2px) rotate(-6deg); }
.r-panneau__liste .nav__chevron {
  flex: none;
  color: var(--r-ink-mute);
  transform: rotate(-45deg);
  transition: transform var(--dur) var(--ease);
}
.r-panneau__liste a:hover .nav__chevron { transform: translateX(.25rem) rotate(-45deg); }

/* « Tout le journal » : une tuile comme les autres, en tête et sur toute la
   rangée. Pas de couleur de rang (ce n'est pas une rubrique) : un lavis
   neutre, un filet gauche aux six couleurs des catégories et l'arc-en-ciel,
   comme la tuile « Tous les articles » de journal/ (section 31). Plus
   haute, une ligne d'explication, le chevron en encre. */
.r-panneau__tout { grid-column: 1 / -1; margin-bottom: .6rem; }
.r-panneau__liste .r-panneau__tout a {
  --fond: color-mix(in srgb, var(--r-ink) 4%, var(--r-bg));
  min-height: 4.5rem;
  padding-block: .9rem;
  border-left: 0;
  background:
    linear-gradient(to bottom, var(--arc-1) 0 16.66%, var(--arc-2) 0 33.33%, var(--arc-3) 0 50%,
      var(--arc-4) 0 66.66%, var(--arc-5) 0 83.33%, var(--arc-6) 0) left / 3px 100% no-repeat,
    var(--fond);
  font-size: 1.4rem;
}
.r-panneau__liste .r-panneau__tout a:hover,
.r-panneau__liste .r-panneau__tout a[aria-current] { --fond: color-mix(in srgb, var(--r-ink) 9%, var(--r-bg)); }
.r-panneau__liste .r-panneau__tout a > svg { width: 2.75rem; height: 2.75rem; }
.r-panneau__liste .r-panneau__tout .nav__chevron { color: var(--r-ink); }
.r-panneau__sous {
  display: block;
  margin-top: .2rem;
  font-family: var(--r-body);
  font-variation-settings: normal;
  font-size: var(--fs-sm);
  letter-spacing: 0;
  color: var(--r-ink-soft);
}

/* En dessous du bureau, le panneau n'existe pas : c'est le tiroir qui
   prend le relais, et son contenu est le même. */
@media (max-width: 59.99rem) {
  .r-nav__group { display: none; }
}

/* Trois déroulants et deux liens ne tiennent pas dans le premier tiers de
   l'en-tête sous 80 rem : les rubriques passaient sur deux lignes et
   touchaient le logo (mesuré le 25 septembre 2026). La navigation mesure
   environ 450 px, le tiers disponible 366 px à 960 px : un logo centré sur
   la page y est impossible sans rogner les rubriques. Centré dans l'espace
   restant, il tombait à 150 px du milieu et se lisait comme une erreur.
   Entre 60 et 80 rem, le logo passe donc à gauche, la navigation le suit,
   Compte et panier restent à droite : un alignement franc, le rangement
   des boutiques en largeur moyenne. Au-delà de 80 rem, retour au centre. */
.r-nav--desk > a, .r-nav__group > .nav__trigger { white-space: nowrap; }
@media (min-width: 60rem) and (max-width: 79.99rem) {
  .r-header__inner { grid-template-columns: auto 1fr auto; column-gap: clamp(1.75rem, 3vw, 2.5rem); }
  .r-header__inner > .r-brand { order: -1; justify-self: start; }
  .r-nav--desk { gap: 1.25rem; }
}

.r-nav--end { justify-content: flex-end; }

.r-brand { justify-self: center; }
.r-brand img { width: 120px; height: auto; }
/* Le wordmark est noir : sur la photo du héros, il lui faut une version
   blanche. brightness(0) aplatit tout en noir avant d'inverser, ce qui
   donne un blanc franc. Un invert(1) seul retournerait aussi les trois
   points colorés et sortirait des couleurs qui ne sont pas celles de la
   maison. À remplacer par un vrai fichier blanc quand il existera. */
.r-header:not(.is-solid) .r-brand img { filter: brightness(0) invert(1); }

.r-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44 px, et non 36 : sur mobile, le burger et le panier sont les deux
     seules commandes de navigation de la page. */
  width: 2.75rem; height: 2.75rem;
  background: none; border: 0; cursor: pointer;
  color: inherit;
  position: relative;
}
.r-iconbtn .icon { width: 24px; height: 24px; }

.icon { width: 24px; height: 24px; fill: none; stroke: currentColor; }

.r-cartcount {
  position: absolute; top: 0; right: 0;
  min-width: 1.1rem; height: 1.1rem;
  padding: 0 .25rem;
  border-radius: 999px;
  background: var(--vif-violet);
  color: #fff;
  font-size: .625rem;
  font-weight: 600;
  line-height: 1.1rem;
  text-align: center;
}

.r-nav--mobile { display: flex; }
.r-nav--desk { display: none; }

@media (min-width: 60rem) {
  .r-nav--mobile { display: none; }
  .r-nav--desk { display: flex; }
}

/* ==========================================================================
   8. Héros
   --------------------------------------------------------------------------
   Diptyque bord à bord, sans marge, sans carte, sans coin arrondi. Le titre
   n'est pas centré au milieu de l'écran : il est calé en bas à gauche, sur
   la ligne de la gouttière. C'est ce décalage qui casse la recette
   « suréligne centrée, titre serif centré, bouton centré » qu'on retrouve
   partout, y compris sur le site qui avait alerté la maison.
   ========================================================================== */

.r-hero {
  position: relative;
  margin-top: calc(-1 * var(--h-header) - 3px);

  /* Fond sombre sous la photo. Pendant la seconde que dure le balayage,
     la partie non encore dévoilée laisserait voir le fond de page, clair,
     sur lequel le wordmark et les icônes du header, blancs, disparaissent.
     Le noir tient ce demi-écran le temps que la photo arrive. */
  background: var(--r-ink);
}

.r-hero__media {
  display: grid;
  grid-template-columns: 1fr;

  /* svh, pas vh. Sur mobile, la barre d'adresse se replie au défilement
     et l'unité vh est recalculée : le conteneur grandit, et comme la
     photo est en object-fit cover, elle se remet à l'échelle sous les
     yeux. C'est le « la photo grandit » constaté au scroll, pas une
     animation. svh se mesure sur le viewport barre déployée, donc la
     hauteur ne bouge plus jamais.
     La ligne en vh reste au-dessus comme repli pour les navigateurs qui
     ne connaissent pas svh, qui seront de toute façon les mêmes que ceux
     où le bug existait déjà. */
  height: clamp(34rem, 92vh, 56rem);
  height: clamp(34rem, 92svh, 56rem);
}
.r-hero__media > picture,
.r-hero__media > img { height: 100%; }
.r-hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* Le second volet du diptyque n'apparaît qu'à partir du grand écran :
   sur mobile, une seule image plein cadre vaut mieux que deux moitiés. */
.r-hero__second { display: none; }

@media (min-width: 60rem) {
  .r-hero__media { grid-template-columns: 1fr 1fr; }
  .r-hero__second { display: block; }
}

/* Deux voiles, pas un. Celui du bas porte le titre, celui du haut rend la
   navigation lisible quelle que soit la photo qu'on mettra derrière : la
   direction photo va changer, le gabarit doit tenir sans elle. */
.r-hero__voile {
  position: absolute; inset: 0;
  pointer-events: none;
  /* Le voile du haut ne décore pas : il garantit le contraste du header,
     qui est posé sur la photo sans fond à lui. Il doit donc tenir même
     sur le pire cas, un mur rose pâle en plein cadre. */
  background:
    linear-gradient(to bottom, rgba(20,19,18,.55) 0%, rgba(20,19,18,.34) 7%, rgba(20,19,18,.12) 15%, rgba(20,19,18,0) 26%),
    linear-gradient(to top,    rgba(20,19,18,.78) 0%, rgba(20,19,18,.45) 26%, rgba(20,19,18,.10) 52%, rgba(20,19,18,0) 72%);
}

/* Sur grand écran, un troisième voile, horizontal cette fois.
   Le diptyque avait un défaut de composition : le texte occupait le volet
   gauche, le volet droit ne portait rien, et le voile du bas assombrissait
   les deux de la même façon. Résultat, la moitié droite avait l'air d'une
   photo qu'on aurait oublié de remplir.

   Le voile horizontal règle ça en assumant la répartition : le volet
   gauche devient un cartouche, c'est là qu'on parle ; le volet droit
   redevient une photo nette, c'est là qu'on montre. L'asymétrie cesse
   d'être un manque pour devenir la structure.

   Atelier Camille résout le même problème en centrant son titre à cheval
   sur la couture. On ne le copie pas : leur titre fait trois mots, le
   nôtre porte une phrase entière et un paragraphe. */
@media (min-width: 60rem) {
  .r-hero__voile {
    background:
      linear-gradient(to right,  rgba(20,19,18,.62) 0%, rgba(20,19,18,.42) 30%, rgba(20,19,18,.12) 46%, rgba(20,19,18,0) 56%),
      /* Celui-ci court sur toute la largeur, volet clair compris : le
         compte et le panier sont à droite, et ils doivent rester lisibles
         même quand la photo de droite est un imprimé turquoise en plein
         soleil. */
      linear-gradient(to bottom, rgba(20,19,18,.60) 0%, rgba(20,19,18,.36) 8%, rgba(20,19,18,.14) 15%, rgba(20,19,18,0) 24%),
      linear-gradient(to top,    rgba(20,19,18,.55) 0%, rgba(20,19,18,.22) 30%, rgba(20,19,18,0) 58%);
  }
}

.r-hero__content {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
  color: var(--r-on-dark);
}
/* Le titre reste dans le volet gauche du diptyque : à cheval sur la
   couture, il aurait l'air d'un accident de gabarit. */
.r-hero__inner { max-width: 38rem; }

.r-hero h1 { margin-bottom: 1.25rem; }

.r-hero__note {
  font-size: var(--fs-lg);
  line-height: 1.6;
  max-width: 34rem;
  margin-bottom: 2rem;
  color: rgba(252, 251, 250, .92);
}

.r-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
}

/* Sur mobile, le bouton s'arrêtait aux deux tiers de l'écran et laissait
   un vide à droite qui le faisait paraître mal posé. Il prend toute la
   largeur : c'est franc, c'est plus facile à viser au pouce, et ça évite
   d'avoir à centrer un bloc dont tout le reste est aligné à gauche. */
@media (max-width: 47.9375rem) {
  .r-hero__actions { display: grid; gap: 1rem; }
  .r-hero__actions .r-btn { width: 100%; }
}

.r-hero__preuve {
  margin: 0;
  font-size: var(--fs-micro);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: rgba(252, 251, 250, .8);
}

/* ==========================================================================
   9. Réassurance
   --------------------------------------------------------------------------
   Libellé en display, sous-ligne en italique. La suite de l'arc-en-ciel
   apparaît ici pour la première fois en entier, en quatre filets courts.
   ========================================================================== */

.r-trust { background: var(--r-bg-pure); border-block: 1px solid var(--r-rule-soft); }

.r-trust__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(2rem, 5vw, 3.5rem) 1.5rem;
  padding-block: clamp(2.5rem, 5vw, 4rem);
}
@media (min-width: 60rem) {
  .r-trust__grid { grid-template-columns: repeat(4, 1fr); }
}

.r-trust__item { text-align: center; }

.r-trust__bar {
  width: 2.25rem; height: 3px;
  margin: 0 auto 1.25rem;
  background: var(--arc);
}

.r-trust__icon {
  width: 40px; height: 40px;
  margin: 0 auto .75rem;
}

.r-trust__label {
  display: block;
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.05rem;
  line-height: 1.3;
}

.r-trust__desc {
  display: block;
  margin-top: .35rem;
  font-size: var(--fs-sm);
  font-style: italic;
  color: var(--r-ink-mute);
}

/* ==========================================================================
   10. Titres de section
   ========================================================================== */

.r-head { margin-bottom: clamp(2.5rem, 5vw, 4rem); max-width: 42rem; }
.r-head p { margin-top: 1rem; }

/* Variante calée à droite, utilisée une fois par page pour rompre
   l'alignement systématique à gauche. */
.r-head--end { margin-left: auto; text-align: right; }

/* ==========================================================================
   11. Collection
   --------------------------------------------------------------------------
   Grandes images, légende nue. Pas de carte, pas de bordure, pas de bouton
   permanent : le nom et le prix sur une ligne, comme sur une planche de
   catalogue. Le bouton d'ajout n'apparaît qu'au survol, et reste toujours
   accessible au clavier.
   ========================================================================== */

.r-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2.5rem, 5vw, 4rem) clamp(1.25rem, 2.5vw, 2rem);
}
@media (min-width: 40rem)  { .r-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem)  { .r-grid { grid-template-columns: repeat(4, 1fr); } }

.r-card__media {
  position: relative;
  overflow: hidden;
  background: var(--lavis);
}
.r-card__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: transform 1.2s var(--ease), opacity .5s var(--ease);
}
.r-card:hover .r-card__media img { transform: scale(1.035); }

/* --- La seconde photo -----------------------------------------------------
   Au survol, la carte montre l'autre face du produit : un autre imprimé et
   un autre angle, jamais la même photo recadrée. C'est ce qui rend une
   grille de quatre images vivante sans y ajouter le moindre ornement.

   Elle est empilée par-dessus la première plutôt que substituée : pas de
   requête au moment du survol, donc pas de blanc le temps du chargement.
   Elle reste hors du flux d'accessibilité une fois masquée, mais garde son
   alt : elle décrit un vrai contenu, pas une décoration.
   ------------------------------------------------------------------------ */
.r-card__dos {
  position: absolute;
  inset: 0;
  height: 100%;
  opacity: 0;
}
.r-card:hover .r-card__dos,
.r-card:focus-within .r-card__dos { opacity: 1; }

/* Sans survol (tactile), la seconde photo ne servirait à rien et
   doublerait le poids de la grille : on ne la charge pas. */
@media (hover: none) {
  .r-card__dos { display: none; }
}

/* La pastille produit prend la couleur de rang du produit dans la suite.
   Le tapis est premier : lavande. Le matelas deuxième : menthe. */
/* La pastille prenait la couleur du rang, donc trois pastilles voisines
   sortaient en violet, vert et jaune dans le même écran. Elles criaient
   plus fort que les photos, pour dire « nouveauté » et « en stock ».

   Elles suivent maintenant ce qu'elles annoncent, et non l'endroit où
   elles tombent dans la page :
     par défaut  une mention éditoriale (incontournable, nouveauté), encre
     --stock     une disponibilité, le vert des rôles fonctionnels
     --offre     une remise ou un prix lié, le corail des promotions */
.r-card__tag {
  position: absolute;
  top: 0; left: 0;
  z-index: 2;
  padding: .4rem .75rem;
  background: var(--r-ink);
  color: var(--r-on-dark);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.r-card__tag--stock { background: var(--vif-vert); }
.r-card__tag--offre { background: var(--vif-corail); }

.r-card__quick {
  /* Un lien vers la fiche depuis le 25 septembre 2026 : les quatre produits
     de la collection demandent un imprimé, qu'on choisit sur la fiche. */
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  position: absolute;
  left: 0; right: 0; bottom: 0;
  min-height: 46px;
  border: 0;
  background: var(--r-ink);
  color: var(--r-on-dark);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
  transform: translateY(100%);
  transition: transform var(--dur) var(--ease);
}
.r-card:hover .r-card__quick,
.r-card__quick:focus-visible { transform: translateY(0); }

.r-card__line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem .75rem;
  margin-top: 1rem;
}
.r-card__name {
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.15rem;
  line-height: 1.25;
}
.r-card__name a { text-decoration: none; }
.r-card__price { font-size: var(--fs-sm); color: var(--r-ink-soft); }
.r-card__desc {
  margin: .35rem 0 0;
  font-size: var(--fs-sm);
  font-style: italic;
  color: var(--r-ink-mute);
}

/* Le nuancier d'imprimés devient un objet de plein droit, pas une rangée
   de miettes sous la carte : douze motifs dessinés par des artistes
   françaises, c'est ce que personne d'autre n'a. */
.r-prints {
  display: flex;
  flex-wrap: wrap;
  /* 8 px, et non 6 : c'est cet écart qui permet à la zone tactile de
     chaque pastille de déborder de 4 px de chaque côté sans mordre sur
     sa voisine. Le pas devient 36 + 8 = 44 px, la cible aussi. */
  gap: .5rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--r-rule-soft);
}
.r-prints__label {
  width: 100%;
  margin: 0 0 .6rem;
  font-size: .6875rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--r-ink-mute);
}
/* Les fichiers -mini sont des pastilles rondes, avec leurs coins blancs.
   Enfermées dans un carré, leur cercle se retrouvait tranché en haut et
   en bas par le filet du cadre. Le cadre devient donc rond lui aussi :
   c'est la seule autre rondeur du site avec les pastilles de la lettre,
   et elle est justifiée par la source, pas par le goût. */
/* Choisir son motif est le premier geste qu'on demande au visiteur, et
   c'était la cible la plus difficile à viser du site : 30 px séparés de
   6 px, quarante fois sur la page, au pouce.

   Le disque passe à 36 px et reçoit une zone tactile de 44 px, portée par
   un pseudo-élément qui déborde dans l'écart. Rien ne bouge à l'écran que
   les 6 px de disque : c'est la surface sensible qui grandit, pas le
   dessin. Les zones voisines se touchent sans se recouvrir, donc aucune
   pastille ne vole le clic de sa voisine. */
.r-print {
  position: relative;
  display: block;
  width: 36px; height: 36px;
  /* Pas d'overflow:hidden ici : il rognerait la zone tactile qui doit
     justement déborder. L'image porte déjà son propre arrondi. */
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--r-rule-soft);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.r-print::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 44px; height: 44px;
  transform: translate(-50%, -50%);
}
.r-print img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.r-print:hover { box-shadow: inset 0 0 0 2px var(--r-ink); transform: translateY(-2px); }

/* ==========================================================================
   12. Bloc décalé
   --------------------------------------------------------------------------
   Le geste emprunté à Atelier Camille : un panneau plein qui déborde
   derrière la photo, alterné à gauche puis à droite. Chez eux le panneau
   est beige. Chez nous il prend le lavis de la suite, ce qui transforme un
   emprunt en élément de la maison.
   ========================================================================== */

.r-offset {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
@media (min-width: 60rem) {
  .r-offset { grid-template-columns: 1.05fr .95fr; }
  .r-offset--flip .r-offset__media { order: 2; }
}

.r-offset h2 { margin-bottom: 1rem; }
.r-offset .eyebrow { margin-bottom: .75rem; }

.r-offset__media { position: relative; }
/* Le panneau : décalé de 2 rem vers le haut et vers l'extérieur. */
.r-offset__media::before {
  content: '';
  position: absolute;
  z-index: 0;
  top: -2rem; bottom: 2rem;
  left: -2rem; right: 4rem;
  background: var(--lavis, var(--lavis-1));
}
.r-offset--flip .r-offset__media::before { left: 4rem; right: -2rem; }
.r-offset__media img { position: relative; z-index: 1; width: 100%; }

@media (max-width: 59.99rem) {
  .r-offset__media::before { left: -1rem; right: 2rem; top: -1rem; bottom: 1rem; }
  .r-offset--flip .r-offset__media::before { left: 2rem; right: -1rem; }
}

/* ==========================================================================
   13. Manifeste
   --------------------------------------------------------------------------
   Le texte passe à la première personne et l'objet le plus singulier de la
   marque revient : le polaroid à légende manuscrite du site en production.
   ========================================================================== */

.r-manifeste__phrase {
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  line-height: 1.22;
  letter-spacing: var(--rf-track);
  margin: 0 0 1.75rem;
}

.r-signature {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--r-rule-soft);
}
.r-signature img {
  width: 56px; height: 56px;
  border-radius: 999px;   /* le rond est réservé au portrait et aux pastilles */
  object-fit: cover;
}
.r-signature__name { font-weight: 600; }
.r-signature__role { font-size: var(--fs-sm); font-style: italic; color: var(--r-ink-mute); }

.r-polaroid {
  margin: 0;
  padding: .75rem .75rem 0;
  background: var(--r-bg-pure);
  box-shadow: 0 1px 2px rgba(20,19,18,.08), 0 12px 28px rgba(20,19,18,.10);
  transform: rotate(-2.4deg);

  /* 20 rem laissaient 290 px de panneau vide à droite de la photo sur
     grand écran : le décalage n'était plus un débord, c'était un trou.
     Le polaroid remplit maintenant sa colonne et le panneau redevient ce
     qu'il doit être, une marge de couleur derrière la photo. */
  max-width: 26rem;
  margin-inline: auto;
}
.r-polaroid img { width: 100%; }
.r-polaroid figcaption {
  padding: .9rem .25rem 1.1rem;
  font-family: 'Reenie Beanie', cursive;
  font-size: 1.35rem;
  line-height: 1;
  text-align: center;
  color: var(--r-ink-soft);
}

/* ==========================================================================
   14. Piliers numérotés
   --------------------------------------------------------------------------
   Trois arguments, trois rangs de la suite. Le numéro est en display, la
   couleur vient de --arc.
   ========================================================================== */

.r-pillars {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 60rem) { .r-pillars { grid-template-columns: repeat(3, 1fr); } }

/* Plus de chiffre 01/02/03 : ce repère ordinal est le premier signe
   qui trahit un gabarit générique. Le filet de couleur au-dessus du
   titre suffit à marquer chaque bloc sans compter dessus. */
.r-pillar { padding-top: 1.5rem; border-top: 3px solid var(--arc); }
.r-pillar h3 {
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.25rem;
  margin-bottom: .6rem;
}
.r-pillar p { color: var(--r-ink-soft); font-size: var(--fs-sm); }

/* --- Points clés en pleine section ----------------------------------------
   Même dessin que .r-buy__points (icône, titre, ligne), mais posé en
   section plutôt que confiné à la colonne d'achat : utile sur les fiches
   accessoire, plus courtes, où les points clés méritent un peu plus de
   place que trois piliers numérotés. */
.r-keypoints {
  display: grid;
  gap: 2.75rem 3rem;
}
@media (min-width: 48rem) { .r-keypoints { grid-template-columns: repeat(2, 1fr); } }
.r-keypoints > *:nth-child(5n + 1) { --arc: var(--arc-1); }
.r-keypoints > *:nth-child(5n + 2) { --arc: var(--arc-2); }
.r-keypoints > *:nth-child(5n + 3) { --arc: var(--arc-3); }
.r-keypoints > *:nth-child(5n + 4) { --arc: var(--arc-4); }
.r-keypoints > *:nth-child(5n + 5) { --arc: var(--arc-5); }
.r-keypoints li {
  display: grid;
  grid-template-columns: 3.75rem 1fr;
  gap: 1.25rem;
  align-items: start;
  padding-top: 1.25rem;
  border-top: 3px solid var(--arc);
}
.r-keypoints .icon { width: 3.25rem; height: 3.25rem; color: var(--arc); }
.r-keypoints h3 { font-family: var(--rf-display); font-weight: var(--rf-weight); font-variation-settings: var(--rf-settings); font-size: 1.15rem; margin-bottom: .35rem; }
.r-keypoints p { color: var(--r-ink-soft); font-size: var(--fs-sm); }

/* --- Encart, un fait mis en avant -------------------------------------
   Angles droits comme le reste de la maison : la mise en avant vient de
   la teinte et du filet, jamais d'un coin arrondi. */
.r-callout {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1.25rem;
  align-items: start;
  padding: clamp(1.5rem, 4vw, 2.5rem);
  background: var(--lavis, var(--lavis-1));
  border-left: 3px solid var(--arc, var(--arc-1));
}
.r-callout__icon { width: 2.75rem; height: 2.75rem; color: var(--arc, var(--arc-1)); flex: none; }
.r-callout h2, .r-callout h3 { margin-bottom: .5rem; }
.r-callout p { margin: 0; color: var(--r-ink-soft); }
.r-callout p + p { margin-top: .75rem; }

/* --- Trois raisons, en cartes -------------------------------------------
   Une carte par idée : icône, titre, phrase, lien. Bordée plutôt que
   simplement filetée, pour la distinguer de .r-pillars quand les deux
   se suivent sur une même page. */
.r-offers {
  display: grid;
  gap: 1.5rem;
}
@media (min-width: 48rem) { .r-offers { grid-template-columns: repeat(3, 1fr); } }
.r-offers > *:nth-child(5n + 1) { --arc: var(--arc-1); }
.r-offers > *:nth-child(5n + 2) { --arc: var(--arc-2); }
.r-offers > *:nth-child(5n + 3) { --arc: var(--arc-3); }
.r-offers > *:nth-child(5n + 4) { --arc: var(--arc-4); }
.r-offers > *:nth-child(5n + 5) { --arc: var(--arc-5); }
.r-offer {
  padding: clamp(1.5rem, 3vw, 2rem);
  border: 1px solid var(--r-rule);
}
.r-offer .icon { width: 2.5rem; height: 2.5rem; color: var(--arc); margin-bottom: 1.25rem; }
.r-offer h3 {
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.2rem;
  margin-bottom: .6rem;
}
.r-offer p { color: var(--r-ink-soft); font-size: var(--fs-sm); margin-bottom: 1.25rem; }
.r-offer .link {
  display: inline-block;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration-color: var(--arc);
}

/* --- Page des imprimés ----------------------------------------------------
   Un index en haut, une pastille par imprimé, pour sauter directement à
   sa fiche. Une fiche par imprimé en dessous, avec ses photos et ses
   liens d'achat : la structure que la cliente avait déjà dessinée. */
.r-motifs-index {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem 1rem;
  text-align: center;
}
@media (min-width: 40rem)  { .r-motifs-index { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 60rem)  { .r-motifs-index { grid-template-columns: repeat(6, 1fr); } }
.r-motifs-index > *:nth-child(5n + 1) { --arc: var(--arc-1); }
.r-motifs-index > *:nth-child(5n + 2) { --arc: var(--arc-2); }
.r-motifs-index > *:nth-child(5n + 3) { --arc: var(--arc-3); }
.r-motifs-index > *:nth-child(5n + 4) { --arc: var(--arc-4); }
.r-motifs-index > *:nth-child(5n + 5) { --arc: var(--arc-5); }
.r-motifs-index a { display: block; color: inherit; }
.r-motifs-index img {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: .85rem;
  box-shadow: inset 0 0 0 1px var(--r-rule);
  transition: box-shadow var(--dur) var(--ease);
}
.r-motifs-index a:hover img,
.r-motifs-index a:focus-visible img { box-shadow: inset 0 0 0 3px var(--arc); }
.r-motifs-index span { font-size: var(--fs-sm); font-weight: 600; }

.r-motif {
  display: grid;
  gap: 1.5rem;
  align-items: start;
}
@media (min-width: 56rem) { .r-motif { grid-template-columns: 1.1fr .9fr; gap: 3rem; } }
.r-motif__vues {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .6rem;
}
.r-motif__vues img { aspect-ratio: 1 / 1; object-fit: cover; }
.r-motif__vues--une { grid-template-columns: minmax(0, 14rem); }
/* Quatre vues (le tapis plus trois pièces) : jamais une orpheline sur une deuxième ligne.
   Carré de deux sur mobile, une rangée de quatre dès que la fiche passe en deux colonnes. */
.r-motif__vues:has(> :nth-child(4)) { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 56rem) { .r-motif__vues:has(> :nth-child(4)) { grid-template-columns: repeat(4, 1fr); } }
.r-motif h2 { margin-bottom: .5rem; }
.r-motif__note { color: var(--r-ink-soft); margin-bottom: 1.5rem; }
.r-motif__cta { display: flex; flex-wrap: wrap; gap: .75rem; }
.r-motif__cta a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 1.25rem;
  border: 1px solid var(--r-ink);
  color: var(--r-ink);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.r-motif__cta a:hover { background: var(--arc); border-color: var(--arc); color: #FFF; }

/* ==========================================================================
   15. Cautions, presse, avis
   ========================================================================== */

.r-proof {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
  align-items: center;
}
@media (min-width: 60rem) { .r-proof { grid-template-columns: repeat(3, 1fr); } }

.r-proof__item { display: flex; align-items: center; gap: 1.25rem; }
.r-proof__mark { width: 68px; height: auto; flex: none; }
.r-proof__mark--wide { width: 104px; }
.r-proof__title { margin: 0 0 .25rem; font-weight: 600; font-size: var(--fs-sm); }
.r-proof__desc { margin: 0; font-size: var(--fs-sm); color: var(--r-ink-mute); }

.r-medias { text-align: center; }
.r-medias__liste {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem 2.5rem;
  margin-top: 2rem;
}
.r-medias__liste a {
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: 1.15rem;
  text-decoration: none;
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
  transition: border-color var(--dur) var(--ease);
}
.r-medias__liste li:nth-child(5n+1) a:hover { border-color: var(--arc-1); }
.r-medias__liste li:nth-child(5n+2) a:hover { border-color: var(--arc-2); }
.r-medias__liste li:nth-child(5n+3) a:hover { border-color: var(--arc-3); }
.r-medias__liste li:nth-child(5n+4) a:hover { border-color: var(--arc-4); }
.r-medias__liste li:nth-child(5n+5) a:hover { border-color: var(--arc-5); }

.r-reviews {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
@media (min-width: 48rem) { .r-reviews { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem) { .r-reviews { grid-template-columns: repeat(3, 1fr); } }

.r-review { padding-top: 1.25rem; border-top: 3px solid var(--arc); }
.r-review blockquote { margin: 0 0 1rem; }
.r-review blockquote p {
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: 1.05rem;
  line-height: 1.45;
}
/* Les étoiles suivaient le rang de la section : le premier avis les avait
   violettes, le deuxième vertes, le troisième corail. Une note qui change
   de couleur d'un témoignage à l'autre n'est plus lue comme une note. Or
   pour toutes, et rien d'autre. */
.r-review__stars { display: flex; gap: .15rem; margin-bottom: .75rem; color: var(--or-avis); }
.r-review__stars .icon { width: 15px; height: 15px; }
.r-review__meta { margin: 0; font-size: var(--fs-micro); color: var(--r-ink-mute); }
.r-review__auteur { font-weight: 600; color: var(--r-ink); }

/* La mention d'achat vérifié est ce qui sépare un avis d'un commentaire.
   Elle prend le vert des rôles fonctionnels, celui de « en stock » : la
   même famille, parce qu'elle dit la même chose, un fait contrôlé. */
.r-review__verifie { color: var(--vif-vert); font-weight: 600; }

.r-score { font-size: var(--fs-sm); color: var(--r-ink-mute); }
.r-score strong {
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-weight: var(--rf-weight);
  font-size: 2rem;
  color: var(--r-ink);
  margin-right: .4rem;
  /* Chiffres à chasse fixe et largeur réservée pour trois caractères : le
     compteur part de 0 et monte à 647, et sans cela « avis certifiés »
     reculerait de quelques pixels à chaque changement de chiffre. */
  font-variant-numeric: tabular-nums;
  display: inline-block;
  min-width: 3ch;
}

/* ==========================================================================
   16. Questions fréquentes
   --------------------------------------------------------------------------
   Reconstruite : la première version posait des <details> natifs, qu'aucune
   règle ci-dessous ne visait. Ce qui s'affichait était donc le triangle et
   la taille de texte par défaut du navigateur, pas un choix de design.

   Le mécanisme reste celui de main.js, .faq__q / .faq__a, déjà câblé pour
   faq.html : aucune ligne de JavaScript n'a été ajoutée pour cette
   refonte, seul l'habillage est neuf.

   Les questions ne sont plus numérotées : le rang n'apprenait rien au
   lecteur, et un moteur qui cite une réponse n'a que faire du chiffre
   qui la précède. Le filet coloré en haut de chaque question suffit à
   relier la FAQ au reste du système.
   ========================================================================== */

.faq { border-bottom: 1px solid var(--r-rule-soft); }
.faq__item { border-top: 3px solid var(--arc, var(--r-rule)); padding-block: .25rem; }

.faq__q {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 1.1rem;
  width: 100%;
  padding: 1.6rem 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
}
.faq__label {
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.3rem;
  line-height: 1.35;
  letter-spacing: var(--rf-track);
  color: var(--r-ink);
}

/* Le signe : une croix qui s'aplatit en tiret à l'ouverture, dans la
   couleur du rang plutôt qu'en noir. C'était un détail qu'on pouvait se
   permettre d'oublier sur un accordéon générique ; ça ne l'est plus une
   fois que la question porte un numéro et une couleur. */
.faq__sign { position: relative; width: 18px; height: 18px; flex: none; align-self: center; }
.faq__sign::before,
.faq__sign::after {
  content: '';
  position: absolute;
  left: 0; top: 50%;
  width: 18px; height: 2px;
  background: var(--arc, var(--r-ink));
  transition: transform var(--dur) var(--ease);
}
.faq__sign::after { transform: rotate(90deg); }
.faq__q[aria-expanded="true"] .faq__sign::after { transform: rotate(0deg); }

/* La réponse s'aligne sous la question, pas sous le chiffre : le chiffre
   est un repère, pas le début d'un paragraphe.

   Ouverture (correction du 25 septembre 2026, valable pour toutes les
   .faq du site). La rangée passe de 0fr à 1fr d'un coup, sans transition :
   c'est un changement de mise en page, pas une animation, la hauteur
   n'étant jamais animée (section 3 du DESIGN.md). Seul le contenu entre
   en fondu, sur opacity et transform.

   Fermé, le contenu est en visibility: hidden, sans délai : ses liens
   sortent de l'ordre de tabulation et de la lecture d'écran dès la
   fermeture. La transition n'est posée que sur l'état ouvert, donc la
   fermeture est instantanée et l'ouverture en fondu. */
.faq__a {
  display: grid;
  grid-template-rows: 0fr;
}
.faq__a[data-open="true"] { grid-template-rows: 1fr; }
.faq__a > div {
  overflow: hidden;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-.5rem);
}
.faq__a[data-open="true"] > div {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .faq__a[data-open="true"] > div { transition: none; }
}
.faq__a p {
  max-width: 46ch;
  margin: 0;
  padding: 0 2.5rem 1.75rem 0;
  color: var(--r-ink-soft);
  font-size: var(--fs-base);
  line-height: 1.65;
}
@media (max-width: 30rem) {
  .faq__label { font-size: 1.1rem; }
}

/* --------------------------------------------------------------------------
   FAQ en 2 colonnes : ancrage a gauche (surtitre, titre, une phrase
   d'accroche), liste des questions a droite. C'est la meme mecanique
   visuelle que le bloc newsletter juste au-dessus (panneau a gauche,
   media a droite), pour que les deux sections riment.

   L'entete est sticky : sur les longues FAQ, le titre suit le lecteur
   plutot que de partir tres haut hors ecran des la premiere question
   ouverte. Sur mobile, on empile et on desactive le sticky.
   -------------------------------------------------------------------------- */
.r-faq-split {
  display: grid;
  /* Liste a gauche (col 1, la plus large), titre a droite (col 2).
     Zigzag avec la section newsletter au-dessus (panneau a gauche,
     media a droite) : les deux blocs alternent, la page respire. */
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.r-faq-split__list {
  grid-column: 1;
  grid-row: 1;
  min-width: 0;
}
.r-faq-split__head {
  grid-column: 2;
  grid-row: 1;
  position: sticky;
  top: clamp(5rem, 8vh, 7rem);
  align-self: start;
}
.r-faq-split__head .eyebrow { margin-bottom: .75rem; }
.r-faq-split__head h2 { margin: 0; }
.r-faq-split__head p {
  margin: 1.25rem 0 0;
  max-width: 32ch;
  color: var(--r-ink-soft);
}
@media (max-width: 60rem) {
  .r-faq-split {
    grid-template-columns: 1fr;
    gap: clamp(1.5rem, 4vw, 2.5rem);
  }
  .r-faq-split__head { position: static; }
  .r-faq-split__head p { max-width: none; }
  .r-faq-split__head,
  .r-faq-split__list { grid-column: 1; grid-row: auto; }
}


/* ==========================================================================
   17. Lettre d'information
   ========================================================================== */

/* --------------------------------------------------------------------------
   Le courrier de l'atelier
   --------------------------------------------------------------------------
   Le bloc était un aplat noir. Il tenait la page, mais il ne disait rien
   de la marque, et un aplat noir est le fond le plus interchangeable qui
   soit.

   À la place, l'imprimé. Pas un dessin de commande, pas un motif dessiné
   par nous : le vrai, Éclaboussures, découpé dans la photo du tapis qui
   sert déjà de héros à la page. Le fichier motif-eclaboussures.webp est
   une zone de 640 par 340 prise dans le tapis, sans bébé et sans bord.
   17 Ko.

   La lettre annonce « les nouveaux imprimés » : elle le dit maintenant en
   le montrant.

   Le texte ne se pose pas dessus, il se pose sur un panneau crème posé
   par-dessus. Un imprimé peint aussi dense ne supporte aucun texte, même
   voilé, et le voiler assez pour qu'il en supporte reviendrait à le
   détruire. Le panneau garde donc l'imprimé à pleine force d'un côté et
   une lisibilité parfaite de l'autre. C'est la même mécanique que les
   panneaux décalés du reste de la page.
   -------------------------------------------------------------------------- */
.r-news {
  position: relative;
  padding: 0;
  background: var(--r-bg-pure) url("../img/motif-eclaboussures.webp") center / cover no-repeat;
}

/* Un voile très léger. Il ne sert pas à lire par-dessus, seulement à
   asseoir le panneau. Tenu bas exprès : c'est le panneau qui porte la
   lisibilité, donc voiler davantage ne gagnerait rien et abîmerait
   l'imprimé, qui est ici le sujet. */
.r-news::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(105deg, rgba(252,251,250,.30) 0%, rgba(252,251,250,.06) 55%, rgba(252,251,250,0) 100%);
  pointer-events: none;
}

.r-news .wrap {
  position: relative;
  display: grid;
  padding-block: clamp(3rem, 7vw, 6rem);
}

.r-news__panneau {
  min-width: 0;
  background: var(--r-bg);
  padding: clamp(2rem, 4.5vw, 3.5rem);
  max-width: 42rem;
  box-shadow: 0 1.5rem 4rem rgba(20, 19, 18, .18);
}

/* Le titre est plus court que ceux des autres sections et il vit dans un
   panneau, pas dans la pleine largeur : à la taille commune il cassait en
   trois lignes et le coup de feutre se retrouvait coupé en deux. */
.r-news h2 {
  margin-bottom: 1rem;
  font-size: clamp(1.75rem, 3.2vw, 2.6rem);
  text-wrap: balance;
}
.r-news p { color: var(--r-ink-soft); }

.r-news__form {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin: 2rem 0 1rem;
}
.r-news__form input {
  flex: 1 1 15rem;
  min-width: 0;          /* sans quoi la largeur intrinsèque de l'input
                            pousse le panneau hors de l'écran en 390 px */
  min-height: 52px;
  padding: 0 1rem;
  border: 1px solid var(--r-rule);
  border-radius: var(--r-radius);
  background: var(--r-bg-pure);
  color: var(--r-ink);
  font: inherit;
}
.r-news__form input::placeholder { color: var(--r-ink-mute); }
.r-news__form input:focus-visible { outline: 2px solid var(--vif-violet); outline-offset: 2px; }
.r-news__legal { font-size: var(--fs-micro); color: var(--r-ink-mute); }

/* ==========================================================================
   18. Socle et pied de page
   ========================================================================== */

.r-socle { background: var(--r-bg-pure); border-block: 1px solid var(--r-rule-soft); }
.r-socle__points {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
  padding-top: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 48rem) { .r-socle__points { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 72rem) { .r-socle__points { grid-template-columns: repeat(6, 1fr); } }

.r-socle__points li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .6rem;
  text-align: center;
  font-size: var(--fs-micro);
  letter-spacing: .02em;
}
.r-socle__points .icon { width: 40px; height: 40px; }

/* --- Les cautions -----------------------------------------------------
   Ce que des tiers garantissent, sous ce que la boutique se promet à
   elle-même : on montre d'abord ce qui ne dépend pas de soi. C'était
   déjà la règle dans l'ancienne direction ; elle ne changeait pas de
   sens en changeant de robe, seulement les jetons portés.

   Trois marques très inégales en proportions (un tampon rond, un texte
   large, un sigle carré) : les caler à la même hauteur en aurait écrasé
   une. Elles sont calées à surface égale à la place, sur le socle de la
   grille, en rem plutôt qu'en pourcentage puisque la rangée se
   dimensionne sur son propre contenu. */
.r-socle__cautions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: start;
  margin-top: clamp(2rem, 4vw, 2.75rem);
  padding-block: clamp(1.75rem, 3.5vw, 2.25rem) clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--r-rule-soft);
  text-align: center;
}
.r-socle__cautions li { display: flex; flex-direction: column; align-items: center; gap: .9rem; }

.r-socle__marque { min-height: clamp(3.5rem, 8vw, 7rem); display: grid; place-items: end center; }
.r-socle__marque a { display: block; }
.r-socle__marque img { width: auto; max-width: 100%; }
.r-socle__mark--ofg { max-height: clamp(3.5rem, 8vw, 7rem); }
.r-socle__mark--tv  { max-height: clamp(2.1rem, 4.8vw, 4.15rem); }
.r-socle__mark--ce  { max-height: clamp(2.9rem, 6.6vw, 5.75rem); }

.r-socle__legende { font-size: var(--fs-micro); color: var(--r-ink-mute); line-height: 1.45; max-width: 20ch; }

@media (max-width: 40rem) {
  .r-socle__cautions { gap: .75rem; }
  .r-socle__points { gap: 1.6rem .5rem; }
  .r-socle__points .icon { width: 34px; height: 34px; }
}

.r-footer { padding-block: clamp(3rem, 6vw, 5rem) 2rem; }
.r-footer__grid {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
}
@media (min-width: 48rem) { .r-footer__grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; } }

.r-footer__logo { width: 130px; margin-bottom: 1.25rem; }
.r-footer__about { font-size: var(--fs-sm); color: var(--r-ink-soft); max-width: 26rem; }

.r-footer h3 {
  font-size: var(--fs-micro);
  font-family: var(--r-body);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  margin-bottom: 1rem;
}
.r-footer nav li { margin-bottom: .5rem; }
.r-footer nav a { font-size: var(--fs-sm); color: var(--r-ink-soft); text-decoration: none; }
.r-footer nav a:hover { color: var(--r-ink); text-decoration: underline; text-underline-offset: .2em; }

.r-reseaux { display: flex; gap: 1.25rem; margin-top: 1.5rem; }
.r-reseaux a {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: var(--fs-sm); text-decoration: none;
}
.r-reseaux .icon { width: 24px; height: 24px; }
.r-footer.r-footer--photo .r-reseaux a,
.r-footer.r-footer--photo .r-reseaux .icon { color: var(--arc-1); }

/* Deux marques seulement, donc on choisit leurs rangs au lieu de dérouler
   la suite. Violet pour Instagram, corail pour Pinterest : le corail est
   ce que la palette a de plus proche du rouge Pinterest, et une pastille
   Pinterest en menthe sonnerait faux. La suite reste la règle ; ici elle
   sert deux logos qui ont déjà leur couleur dans la tête des gens. */
.r-reseaux > *:nth-child(1) { --arc: var(--arc-1); }
.r-reseaux > *:nth-child(2) { --arc: var(--arc-3); }

.r-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .75rem;
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--r-rule-soft);
  font-size: var(--fs-micro);
  color: var(--r-ink-mute);
}
.r-footer__bottom p { margin: 0; }

/* ==========================================================================
   19. Tiroirs, panier, notification
   ========================================================================== */

.drawer { position: fixed; inset: 0; z-index: 80; visibility: hidden; }
.drawer[aria-hidden="false"] { visibility: visible; }
/* Le tiroir fermé déborde à droite (translateX 100 %) et créait un défilement horizontal sur mobile. */
html, body { overflow-x: hidden; overflow-x: clip; }
.drawer__backdrop {
  position: absolute; inset: 0;
  background: rgba(20,19,18,.45);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.drawer[aria-hidden="false"] .drawer__backdrop { opacity: 1; }
.drawer__panel {
  position: absolute;
  top: 0; bottom: 0; right: 0;
  width: min(26rem, 92vw);
  display: flex;
  flex-direction: column;
  background: var(--r-bg);
  transform: translateX(100%);
  transition: transform var(--dur) var(--ease);
}
.drawer--left .drawer__panel { right: auto; left: 0; transform: translateX(-100%); }
.drawer[aria-hidden="false"] .drawer__panel { transform: translateX(0); }

.drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.25rem var(--sp-gutter);
  border-bottom: 1px solid var(--r-rule-soft);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.drawer__body { flex: 1; overflow-y: auto; padding: 1.5rem var(--sp-gutter); }
.drawer__foot { padding: 1.5rem var(--sp-gutter); border-top: 1px solid var(--r-rule-soft); }

/* --------------------------------------------------------------------------
   Le contenu du tiroir se pose en cascade
   --------------------------------------------------------------------------
   Le panneau glissait proprement, mais tout ce qu'il contient apparaissait
   d'un bloc : sur mobile, le menu, c'est quatre vignettes produit, quatre
   familles d'accessoires et six liens, une masse d'un coup.

   Chaque enfant direct part 12 px plus bas et arrive à son tour. L'amorce
   de 200 ms laisse le panneau finir sa course avant que son contenu ne
   bouge : deux mouvements qui se chevauchent se lisent comme du désordre.

   Le rang est plafonné au huitième. Au-delà, le dernier élément entrerait
   près d'une seconde après le premier, et une cascade trop longue ne se
   lit plus comme une cascade mais comme une page qui rame.
   -------------------------------------------------------------------------- */
.js-anim .drawer__body > * {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dur-reveal) var(--ease), transform var(--dur-reveal) var(--ease);
  transition-delay: calc(200ms + var(--i, 0) * 70ms);
}
.js-anim .drawer[aria-hidden="false"] .drawer__body > * { opacity: 1; transform: none; }

.drawer__body > *:nth-child(2) { --i: 1; }
.drawer__body > *:nth-child(3) { --i: 2; }
.drawer__body > *:nth-child(4) { --i: 3; }
.drawer__body > *:nth-child(5) { --i: 4; }
.drawer__body > *:nth-child(6) { --i: 5; }
.drawer__body > *:nth-child(7) { --i: 6; }
.drawer__body > *:nth-child(n + 8) { --i: 7; }

@media (prefers-reduced-motion: reduce) {
  .js-anim .drawer__body > * {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }
}

.cart-row { display: flex; justify-content: space-between; gap: 1rem; font-size: var(--fs-sm); }
.cart-row--total { font-weight: 600; font-size: var(--fs-base); }
.cart-empty { font-size: var(--fs-sm); color: var(--r-ink-mute); }
.cart-reassurance { margin-top: 1.25rem; font-size: var(--fs-micro); color: var(--r-ink-mute); }
.cart-reassurance li { margin-bottom: .35rem; }

/* La jauge de livraison offerte : elle prend la menthe, deuxième rang de
   la suite, comme partout où quelque chose progresse vers un acquis. */
[data-freeship] { margin-bottom: 1.75rem; font-size: var(--fs-sm); }
[data-freeship] p { margin: 0 0 .5rem; }
.freeship__bar { height: 3px; background: var(--r-rule-soft); }
.freeship__fill {
  height: 100%;
  background: var(--arc-2);
  /* Échelle et non largeur : la maison n'anime jamais width (section 3 du
     DESIGN.md). main.js écrit scaleX(0 à 1). */
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur) var(--ease);
}

/* Lignes du panier. Le balisage vient de main.js, partagé avec l'ancienne
   direction : on habille ses classes plutôt que de dupliquer sa logique. */
.cart-line {
  display: grid;
  grid-template-columns: 68px 1fr;
  gap: 1rem;
  padding-bottom: 1.25rem;
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--r-rule-soft);
}
.cart-line img { width: 68px; aspect-ratio: 4 / 5; object-fit: cover; }
.cart-line__name { margin: 0 0 .2rem; font-weight: 600; font-size: var(--fs-sm); }
.cart-line__variant { margin: 0 0 .6rem; font-size: var(--fs-sm); color: var(--r-ink-mute); }
.cart-line__name a { color: inherit; text-decoration: none; }
.cart-line__name a:hover { text-decoration: underline; }
.cart-line__prix { margin: 0 0 .6rem; font-size: var(--fs-sm); }
.cart-line__actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; }
.cart-line__retirer {
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-sm);
  text-decoration: underline;
  text-underline-offset: .2em;
  cursor: pointer;
}

.qty { display: flex; align-items: center; gap: .25rem; }
.qty button {
  /* 44 px, la cible tactile de la maison (DESIGN.md, section 7). */
  width: 44px; height: 44px;
  border: 1px solid var(--r-rule);
  background: none;
  cursor: pointer;
  line-height: 1;
}
.qty button:hover { border-color: var(--r-ink); }
.qty button:disabled { opacity: .4; cursor: not-allowed; }
.qty span { min-width: 2rem; text-align: center; font-size: var(--fs-sm); }

.toast {
  position: fixed;
  left: 50%; bottom: 1.5rem;
  /* Hors champ de toute sa hauteur plus sa marge basse : à 150 %, une
     notification vide (ou courte) dépassait encore de quelques pixels. */
  transform: translate(-50%, calc(100% + 2rem));
  z-index: 90;
  padding: .85rem 1.5rem;
  background: var(--r-ink);
  color: var(--r-on-dark);
  font-size: var(--fs-sm);
  transition: transform var(--dur) var(--ease);
}
.toast.is-visible { transform: translate(-50%, 0); }

/* ==========================================================================
   19 bis. Menu mobile
   --------------------------------------------------------------------------
   Ce menu est une pièce de la maison, pas un gabarit : la vitrine en photos
   des quatre pièces principales, le repli des accessoires rangés par
   produit, les pictogrammes sur les liens simples. On ne le refait pas, on
   le rhabille. Le balisage est celui d'index.html, à la virgule près, pour
   qu'une correction faite ici reste transposable là-bas.

   Ce qui change, et rien d'autre :
     l'interlettrage des rubriques passe de .25em à .08em ;
     les angles passent à zéro ;
     le beige des tuiles laisse la place à la suite de l'arc-en-ciel ;
     les noms de produits prennent la nouvelle police de titres.
   ========================================================================== */

.drawer__nav { display: flex; flex-direction: column; gap: 1.75rem; }

/* Titre de rubrique. Capitales, mais serrées : c'est l'interlettrage à
   .25em qui donnait au site son air de gabarit. */
.drawer__titre {
  margin: 0 0 .85rem;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--r-ink-mute);
}
.drawer__nav .drawer__titre + * { margin-top: 0; }

/* Les liens simples du bas, chacun avec son repère. */
.drawer__nav > a {
  display: flex;
  align-items: center;
  gap: .85rem;
  text-decoration: none;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.drawer__nav > a .icon { width: 1.75rem; height: 1.75rem; flex: none; color: var(--encre, var(--r-ink)); }

/* Les liens simples du bas égrènent la suite, eux aussi. On ne peut pas
   poser .seq sur .drawer__nav : ses enfants sont un mélange de titres de
   rubrique, de la vitrine et du repli accessoires, et nth-child les
   compterait tous. nth-of-type ne voit que les <a>, ce qui est
   exactement le rang qu'on veut.

   L'arc-en-ciel est en tête et ne suit pas : il garde ses quatre bandes,
   comme partout ailleurs. */
.drawer__nav > a:nth-of-type(5n + 1) { --encre: var(--encre-1); }
.drawer__nav > a:nth-of-type(5n + 2) { --encre: var(--encre-2); }
.drawer__nav > a:nth-of-type(5n + 3) { --encre: var(--encre-3); }
.drawer__nav > a:nth-of-type(5n + 4) { --encre: var(--encre-4); }
.drawer__nav > a:nth-of-type(5n + 5) { --encre: var(--encre-5); }


/* --- La vitrine ----------------------------------------------------------
   Une liste de mots ne dit pas ce qu'on vend. Les quatre pièces ouvrent
   donc le menu avec leur photo. Le fond beige uniforme d'avant devient la
   suite : lavande, menthe, rose, jaune, dans le même ordre que la grille
   collection de la page. Le menu et la page racontent le même rangement.
   ------------------------------------------------------------------------ */
.drawer__vitrine { display: grid; gap: .5rem; }
.drawer__vitrine > *:nth-child(5n + 1) { --arc: var(--arc-1); --lavis: var(--lavis-1); }
.drawer__vitrine > *:nth-child(5n + 2) { --arc: var(--arc-2); --lavis: var(--lavis-2); }
.drawer__vitrine > *:nth-child(5n + 3) { --arc: var(--arc-3); --lavis: var(--lavis-3); }
.drawer__vitrine > *:nth-child(5n + 4) { --arc: var(--arc-4); --lavis: var(--lavis-4); }
.drawer__vitrine > *:nth-child(5n + 5) { --arc: var(--arc-5); --lavis: var(--lavis-5); }

.drawer__vitrine a {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto;
  align-items: center;
  gap: 1rem;
  background: var(--lavis);
  border-left: 3px solid var(--arc);
  border-radius: var(--r-radius);
  overflow: hidden;
  color: var(--r-ink);
  text-decoration: none;
  transition: background var(--dur) var(--ease);
}
/* Au survol on renforce le lavis, on ne bascule pas sur la couleur pure :
   un aplat de violet saturé rend le nom du produit illisible. */
.drawer__vitrine a:hover { background: color-mix(in srgb, var(--arc) 20%, var(--r-bg)); }
.drawer__vitrine img { width: 4.5rem; height: 4.5rem; object-fit: cover; }

/* Ici on lit un nom de produit, pas une rubrique : casse normale et police
   de titres, comme sur les cartes de la collection. */
.drawer__vitrine span {
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.1rem;
  line-height: 1.2;
  letter-spacing: var(--rf-track);
  text-transform: none;
}
.drawer__vitrine .nav__chevron { margin-right: 1.1rem; transform: rotate(-45deg); color: var(--r-ink-mute); }

/* --- Le repli des accessoires -------------------------------------------
   Même principe, en plus petit et rangé par famille. Chaque famille porte
   son rang dans la suite, en filet vertical : quatre familles, quatre
   couleurs, et l'œil retrouve son groupe sans lire les titres.
   ------------------------------------------------------------------------ */
.nav__group--stacked .submenu {
  position: static;
  min-width: 0;
  padding: 1rem 0 0;
  border: 0;
  background: none;
  box-shadow: none;
}

.accessoires-groupes { display: flex; flex-direction: column; gap: 1.35rem; }
.accessoires-groupes[hidden] { display: none; }

/* La suite, distribuée ici en CSS plutôt qu'avec une classe .seq dans le
   balisage : le HTML du menu doit rester identique à celui d'index.html. */
.accessoires-groupes > *:nth-child(5n + 1) { --arc: var(--arc-1); --lavis: var(--lavis-1); --encre: var(--encre-1); }
.accessoires-groupes > *:nth-child(5n + 2) { --arc: var(--arc-2); --lavis: var(--lavis-2); --encre: var(--encre-2); }
.accessoires-groupes > *:nth-child(5n + 3) { --arc: var(--arc-3); --lavis: var(--lavis-3); --encre: var(--encre-3); }
.accessoires-groupes > *:nth-child(5n + 4) { --arc: var(--arc-4); --lavis: var(--lavis-4); --encre: var(--encre-4); }
.accessoires-groupes > *:nth-child(5n + 5) { --arc: var(--arc-5); --lavis: var(--lavis-5); --encre: var(--encre-5); }

.accessoires-groupe {
  display: grid;
  gap: .35rem;
  padding-left: .9rem;
  border-left: 2px solid var(--arc);
}
.accessoires-groupe__titre {
  margin: 0 0 .55rem;
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: var(--fs-sm);
  font-style: italic;
  font-synthesis: none;
  letter-spacing: 0;
  text-transform: none;
  color: var(--r-ink-mute);
}
/* La piste C n'a pas d'italique : ses titres de famille prennent le filet
   arc-en-ciel, comme toutes ses autres emphases. */

.accessoires-groupe a {
  display: grid;
  grid-template-columns: 2.75rem 1fr auto;
  align-items: center;
  gap: .85rem;
  padding: .3rem .4rem .3rem 0;
  color: var(--r-ink);
  text-decoration: none;
  transition: background var(--dur) var(--ease);
}
.accessoires-groupe a:hover { background: var(--lavis); }
.accessoires-groupe__vignette {
  width: 2.75rem; height: 2.75rem;
  overflow: hidden;
  flex: none;
  border-radius: var(--r-radius);
}
.accessoires-groupe__vignette img { width: 100%; height: 100%; object-fit: cover; }
/* Les fiches encore sans photo prennent un pictogramme sur un lavis plutôt
   qu'un carré vide, en attendant leurs visuels. */
.accessoires-groupe__vignette--icone { display: grid; place-content: center; background: var(--lavis); }
.accessoires-groupe__vignette--icone .icon { width: 1.7rem; height: 1.7rem; color: var(--encre); }
.accessoires-groupe span { font-size: var(--fs-sm); line-height: 1.25; letter-spacing: 0; text-transform: none; }
.accessoires-groupe .nav__chevron { width: .35rem; height: .35rem; transform: rotate(-45deg); color: var(--r-ink-mute); }

/* Le déclencheur du repli. */
.nav__group--stacked { position: relative; }
.nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: 0 0 .2rem;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--r-ink);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.nav__chevron {
  width: .4rem; height: .4rem;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-.12rem) rotate(45deg);
  transition: transform var(--dur) var(--ease);
}
.nav__trigger[aria-expanded="true"] .nav__chevron { transform: translateY(.06rem) rotate(-135deg); }

/* --- Les replis La maison et Journal (25 septembre 2026) -----------------
   Même repli que les accessoires, mais le déclencheur a l'allure d'un lien
   simple du bas (pictogramme, graisse 500), puisqu'il en prend la place.
   Leur rang dans la suite est posé par data-rang (3 et 4), les trois liens
   simples qui suivent sont recalés pour garder la suite dans l'ordre de
   lecture : nth-of-type ne compte que les <a>, pas ces deux replis. */
.drawer__repli > .nav__trigger { gap: .85rem; font-weight: 500; }
.drawer__repli > .nav__trigger .icon { width: 1.75rem; height: 1.75rem; flex: none; color: var(--encre, var(--r-ink)); }
.drawer__nav > a:nth-of-type(3) { --encre: var(--encre-5); }
.drawer__nav > a:nth-of-type(4) { --encre: var(--encre-1); }
.drawer__nav > a:nth-of-type(5) { --encre: var(--encre-2); }

.drawer__liste {
  display: grid;
  gap: .1rem;
  margin: .75rem 0 0 .85rem;
  padding-left: .9rem;
  border-left: 2px solid var(--arc);
}
.drawer__liste[hidden] { display: none; }
.drawer__liste a {
  display: flex;
  align-items: center;
  gap: .7rem;
  min-height: 2.75rem;
  padding-right: .4rem;
  color: var(--r-ink);
  text-decoration: none;
  font-size: var(--fs-sm);
  letter-spacing: 0;
  text-transform: none;
}
.drawer__liste a:hover,
.drawer__liste a[aria-current] { background: var(--lavis); }
.drawer__liste a[aria-current] { font-weight: 600; }
.drawer__liste .nav__chevron { width: .35rem; height: .35rem; margin-left: auto; transform: rotate(-45deg); color: var(--r-ink-mute); }
/* Une catégorie du journal porte sa pastille, de la couleur de sa rubrique. */
.drawer__liste a[data-rang]::before {
  content: "";
  width: .55rem; height: .55rem;
  flex: none;
  border-radius: 50%;
  background: var(--arc);
}
.drawer__tout { font-weight: 600; }

/* ==========================================================================
   19 ter. L'ouverture du héros
   --------------------------------------------------------------------------
   Chez Atelier Camille, ce qu'on prend pour un balayage de page est en
   fait deux choses cumulées : leur diaporama qui enchaîne sa première
   transition horizontale tout de suite, et leurs éléments qui montent un
   par un. Il n'y a pas de rideau plein écran, et c'est heureux : un
   rideau retarde l'affichage du contenu et se paie sur la vitesse
   perçue, ce qui est cher pour un effet qu'on ne voit qu'une fois.

   On garde donc le geste et pas le procédé. La photo se dévoile de la
   droite vers la gauche par un clip-path, en descendant très légèrement
   d'une échelle 1,04 vers 1. Le titre, le paragraphe et le bouton
   montent ensuite l'un après l'autre.

   Tout en CSS, sans JavaScript : l'animation ne peut donc pas rester
   bloquée si un script échoue, et le contenu est dans le HTML dès la
   première image. Le texte n'est jamais masqué à l'accessibilité, il est
   seulement transparent le temps de monter.
   ========================================================================== */

@keyframes r-devoile {
  from { clip-path: inset(0 0 0 100%); transform: scale(1.03); }
  to   { clip-path: inset(0 0 0 0);    transform: scale(1); }
}

@keyframes r-monte {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

.r-hero__media {
  animation: r-devoile .62s cubic-bezier(.16, .84, .44, 1) both;
}

.r-hero h1,
.r-hero__note,
.r-hero__actions {
  animation: r-monte .45s cubic-bezier(.16, .84, .44, 1) both;
}
/* Les décalages chevauchent la fin du balayage au lieu de l'attendre.
   Tout est en place à 0,79 s au lieu de 1,65 s : à peine plus d'une
   demi-seconde de gagnée sur le papier, mais c'est la différence entre
   un site qui s'ouvre et un site qui se fait attendre. */
.r-hero h1        { animation-delay: .30s; }
.r-hero__note     { animation-delay: .38s; }
.r-hero__actions  { animation-delay: .46s; }

/* Le voile ne s'anime pas avec la photo : découpé en même temps, son
   dégradé du haut laisserait passer un header illisible pendant une
   seconde. Il est là dès le départ. */

@media (prefers-reduced-motion: reduce) {
  .r-hero__media,
  .r-hero h1,
  .r-hero__note,
  .r-hero__actions { animation: none; }
}

/* ==========================================================================
   19 bis. La matière
   --------------------------------------------------------------------------
   Ce bloc vivait dans une balise <style> au fond du <head> de l'accueil,
   posée après coup. Il est rentré ici : une page ne porte pas sa propre
   feuille de style, sinon la même règle finit par exister à deux endroits
   et diverger.

   Les durées ont été ramenées dans la fourchette de l'entrée au
   défilement, 400 à 600 ms. Elles montaient jusqu'à une seconde pour le
   volet sur la photo, et ça se voyait : le volet traînait derrière le
   regard au lieu de l'accompagner.

   Les bulles d'air sont la seule animation en boucle du site. Elle est
   gardée parce qu'elle dit quelque chose : ce sont les trous du latex qui
   laissent passer l'air, c'est-à-dire l'argument de la section. Une
   boucle qui illustre le propos n'est pas un ornement.
   ========================================================================== */

.mat { display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.mat__media { position: relative; }
.mat__frame { position: absolute; inset: -1.4rem -1.4rem auto auto; width: 82%; height: 82%; background: var(--lavis-2); z-index: 0; }
.mat__photo { position: relative; z-index: 1; overflow: hidden; }
.mat__photo img { width: 100%; height: auto; display: block; }
.mat__air { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.mat__air b {
  position: absolute;
  width: 9px; height: 9px;
  border-radius: 999px;
  background: radial-gradient(circle, rgba(88, 232, 191, .85), rgba(88, 232, 191, 0) 70%);
  opacity: 0;
}
.mat__txt .lead { font-size: var(--fs-lg); }
.mat__hl {
  background-image: linear-gradient(transparent 62%, var(--feutre-2) 0);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  padding: 0 .06em;
}

.mat-pillars {
  list-style: none;
  margin: clamp(2.5rem, 5vw, 4rem) 0 0;
  padding: clamp(2rem, 4vw, 3rem) 0 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  border-top: 1px solid var(--r-rule-soft);
}
.mat-pillar__rule { display: block; height: 2px; width: 100%; transform-origin: left center; }
.mat-pillar:nth-child(1) .mat-pillar__rule { background: var(--arc-1); }
.mat-pillar:nth-child(2) .mat-pillar__rule { background: var(--arc-2); }
.mat-pillar:nth-child(3) .mat-pillar__rule { background: var(--arc-3); }
.mat-pillar h3 { margin: 1rem 0 .4rem; }
.mat-pillar p { margin: 0; }

/* États de départ, seulement si le visiteur accepte le mouvement. */
.js-anim .mat__frame { transform: translate(18px, -18px); opacity: 0; transition: transform .55s var(--ease), opacity .55s var(--ease); }
.js-anim .mat__photo { clip-path: inset(0 100% 0 0); transition: clip-path .6s var(--ease) .1s; }
.js-anim .mat__hl { background-size: 0% 100%; transition: background-size .55s var(--ease) .2s; }
.js-anim .mat-pillar__rule { transform: scaleX(0); transition: transform .5s var(--ease); }
.js-anim .mat-pillar:nth-child(2) .mat-pillar__rule { transition-delay: var(--stagger); }
.js-anim .mat-pillar:nth-child(3) .mat-pillar__rule { transition-delay: calc(2 * var(--stagger)); }
.js-anim .mat-pillar h3,
.js-anim .mat-pillar p { opacity: 0; transform: translateY(12px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
.js-anim .mat-pillar h3 { transition-delay: .12s; }
.js-anim .mat-pillar p { transition-delay: .18s; }

/* États d'arrivée, posés par l'observateur de main.js. */
.mat.is-in .mat__frame { transform: none; opacity: 1; }
.mat.is-in .mat__photo { clip-path: inset(0 0 0 0); }
.mat.is-in .mat__hl { background-size: 100% 100%; }
.mat-pillar.is-in .mat-pillar__rule { transform: scaleX(1); }
.mat-pillar.is-in h3,
.mat-pillar.is-in p { opacity: 1; transform: none; }

.js-anim .mat__air b { animation: mat-air 2.4s ease-in-out infinite; }
.mat__air b:nth-child(2) { animation-delay: .5s; }
.mat__air b:nth-child(3) { animation-delay: .9s; }
.mat__air b:nth-child(4) { animation-delay: 1.3s; }
.mat__air b:nth-child(5) { animation-delay: 1.7s; }
@keyframes mat-air {
  0%   { opacity: 0;   transform: translateY(6px); }
  45%  { opacity: .85; }
  100% { opacity: 0;   transform: translateY(-16px); }
}

@media (max-width: 56rem) {
  .mat { grid-template-columns: 1fr; gap: 2rem; }
  .mat-pillars { grid-template-columns: 1fr; gap: 1.6rem; }
}

@media (prefers-reduced-motion: reduce) {
  .mat__air { display: none; }
  .js-anim .mat__frame,
  .js-anim .mat__photo,
  .js-anim .mat__hl,
  .js-anim .mat-pillar__rule,
  .js-anim .mat-pillar h3,
  .js-anim .mat-pillar p {
    transition: none;
    transform: none;
    opacity: 1;
    clip-path: none;
    background-size: 100% 100%;
  }
}

/* ==========================================================================
   20. Apparition au défilement
   ========================================================================== */

/* Apparition au défilement.

   0,5 s et non 0,7 : au-delà de 600 ms, une entrée liée au défilement
   cesse d'accompagner le regard et se met à le faire attendre. Le
   visiteur est déjà en train de lire quand le texte finit d'arriver.

   --dur-reveal existe séparément de --dur parce que les deux ne servent
   pas la même chose : --dur est le temps d'une réponse à un geste, un
   survol, une ouverture ; celui-ci est le temps d'une entrée en scène. */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-reveal) var(--ease), transform var(--dur-reveal) var(--ease);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}

/* Le décalage.

   Les quatre avis sont empilés : ils entrent dans le champ presque
   ensemble, et sans décalage ils apparaissaient d'un bloc. Un rang posé
   sur chacun suffit à les faire arriver l'un après l'autre. Le rang est
   posé en CSS et non en JavaScript, l'observateur existant n'a pas à le
   savoir. */
.r-reviews > .reveal:nth-child(2) { --i: 1; }
.r-reviews > .reveal:nth-child(3) { --i: 2; }
.r-reviews > .reveal:nth-child(4) { --i: 3; }
.reveal.is-visible { opacity: 1; transform: none; }
.no-js .reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  /* Le délai est neutralisé avec le reste : sans cela, un visiteur qui
     demande moins d'animations verrait quand même le quatrième avis
     arriver 240 ms après le premier, sans comprendre pourquoi. */
  .reveal { opacity: 1; transform: none; transition: none; transition-delay: 0s; }
}

/* ==========================================================================
   22. La fiche produit
   --------------------------------------------------------------------------
   Galerie à gauche, colonne d'achat collante à droite : la mise en page
   d'Atelier Camille, la seule chose qu'on leur reprend ici.

   Chez eux la galerie est une mosaïque de toutes les photos. Vérification
   faite au navigateur, produit.js empile déjà toutes les vues de
   l'imprimé actif : la mosaïque est là, elle n'avait qu'un habillage de
   visionneuse.

   Reste une limite qui n'est pas de mise en page : sur douze imprimés,
   un seul a une série complète de six vues. Les onze autres n'ont qu'une
   photo, et la colonne de gauche s'y réduit à une image. C'est le
   shooting qui débloquera cette page, pas le code.

   La mécanique est celle de produit.js, reprise sans y toucher : elle
   s'accroche à des attributs data-, pas à des classes.
   ========================================================================== */

/* --- Fil d'Ariane --------------------------------------------------------- */
.r-fil {
  padding-block: 1.25rem;
  font-size: var(--fs-sm);
  color: var(--r-ink-mute);
}
.r-fil a { color: inherit; text-decoration: none; }
.r-fil a:hover { color: var(--r-ink); text-decoration: underline; text-underline-offset: .2em; }
.r-fil span { margin-inline: .5rem; }
.r-fil [aria-current] { color: var(--r-ink); margin-inline: 0; }

/* --- La grille ------------------------------------------------------------ */
.r-pdp { padding-bottom: var(--sp-section); }
.r-pdp__grid { display: grid; gap: clamp(2rem, 4vw, 4rem); }

@media (min-width: 60rem) {
  .r-pdp__grid { grid-template-columns: minmax(0, 1.25fr) minmax(0, .75fr); align-items: start; }
  /* La colonne d'achat suit le défilement de la galerie. Le décalage tient
     compte de l'en-tête collant et du filet qui le surmonte. */
  .r-pdp__buy { position: sticky; top: calc(var(--h-header) + 2rem); }
}

/* --- La galerie -----------------------------------------------------------
   Reprise de produit.js et de sa mécanique de défilement, portée depuis
   produit.css sans changer une ligne de comportement. Je l'avais oubliée
   en construisant la fiche : je n'avais porté que l'habillage de la
   colonne d'achat, pas le viewport ni le plein écran. Résultat, les vues
   s'empilaient en bloc au lieu de défiler, et le zoom n'avait aucun style
   pour s'afficher. Corrigé ici, au complet. */
.gallery__viewport {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  background: var(--lavis-2);
}
.gallery__viewport::-webkit-scrollbar { display: none; }
.gallery__viewport.is-dragging { cursor: grabbing; scroll-snap-type: none; }
@media (pointer: fine) { .gallery__viewport { cursor: grab; } }

.gallery__slide {
  flex: 0 0 100%;
  scroll-snap-align: center;
  aspect-ratio: 1 / 1;
}
/* Sous la colonne collante, la photo carrée à pleine largeur repousse tout
   le reste de la fiche hors de l'écran : le nuancier d'imprimé s'y trouvait
   à plus d'un écran et demi de défilement. Un cadre un peu moins haut sur
   téléphone rend au nuancier une place proche du prix. */
@media (max-width: 59.99rem) { .gallery__slide { aspect-ratio: 4 / 3; } }
.gallery__slide[hidden] { display: none; }
.gallery__slide img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  -webkit-user-drag: none;
  user-select: none;
}

/* La photo annonce qu'elle s'ouvre, mais seulement là où le curseur existe. */
@media (pointer: fine) {
  .gallery__viewport.zoomable .gallery__slide img { cursor: zoom-in; }
  .gallery__viewport.zoomable.is-dragging .gallery__slide img { cursor: grabbing; }
}

.gallery__thumb-vide {
  display: block; width: 100%; aspect-ratio: 1 / 1;
  background: var(--lavis-2);
  border: 1px dashed var(--r-rule);
}
/* Fiche sans aucune photo (alèse zippée du tapis, 26/09/2026) : la case de
   la grande photo dit qu'elle attend, plutôt qu'un visuel d'un autre
   produit. Même fond et même filet que la vignette vide. Encre adoucie et
   non muette : la muette tombe sous 4,5:1 sur le lavis. */
.gallery__attente {
  display: grid; place-items: center;
  width: 100%; height: 100%; margin: 0; padding: 1.5rem;
  background: var(--lavis-2);
  border: 1px dashed var(--r-rule);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  text-align: center;
  color: var(--r-ink-soft);
}

/* --- Le repère de position --------------------------------------------
   Une photo à la fois qui glisse vers la suivante peut désorienter :
   rien à l'écran ne dit combien il y en a ni laquelle on regarde. Deux
   choses y répondent, ensemble plutôt que l'une sans l'autre :
     un compteur en chiffres, sans ambiguïté possible ;
     des points qui portent chacun la couleur de LEUR rang, pas
     seulement celle de la vue active, pour qu'un coup d'œil à la rangée
     donne déjà une texture différente à chaque position.
   Le mécanisme vient toujours de produit.js, inchangé ; seul un
   compteur optionnel y a été branché en plus, sans rien retirer. */
.r-gallery__repere {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .85rem;
  margin-top: 1rem;
}
.r-gallery__repere[hidden] { display: none; }

.r-gallery__dots { display: flex; gap: .5rem; }
.gallery__dot {
  width: 7px; height: 7px;
  padding: 0;
  border: 1px solid var(--arc, var(--r-ink-mute));
  border-radius: 50%;
  background: var(--lavis, transparent);
  cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.gallery__dot[aria-current="true"] { background: var(--arc, var(--r-ink)); transform: scale(1.3); }
.r-gallery__dots > *:nth-child(5n + 1) { --arc: var(--arc-1); --lavis: var(--lavis-1); }
.r-gallery__dots > *:nth-child(5n + 2) { --arc: var(--arc-2); --lavis: var(--lavis-2); }
.r-gallery__dots > *:nth-child(5n + 3) { --arc: var(--arc-3); --lavis: var(--lavis-3); }
.r-gallery__dots > *:nth-child(5n + 4) { --arc: var(--arc-4); --lavis: var(--lavis-4); }
.r-gallery__dots > *:nth-child(5n + 5) { --arc: var(--arc-5); --lavis: var(--lavis-5); }

.r-gallery__compteur {
  margin: 0;
  font-size: var(--fs-micro);
  color: var(--r-ink-mute);
  font-variant-numeric: tabular-nums;
}

/* Vignettes : réservées au bureau, où il y a la place de les lire. Une
   bande, pas une grille : le nombre de vues varie d'un imprimé à l'autre,
   et une grille à quatre colonnes laissait une seconde rangée bancale dès
   la cinquième vue. Chaque vignette porte, elle aussi, le rang de sa
   position en filet bas : à l'œil, la bande entière se lit comme une
   suite de repères plutôt que comme des photos interchangeables. */
.r-gallery__thumbs { display: none; }
.r-gallery__thumbs[hidden] { display: none; }
.r-gallery__thumbs > *:nth-child(5n + 1) { --arc: var(--arc-1); }
.r-gallery__thumbs > *:nth-child(5n + 2) { --arc: var(--arc-2); }
.r-gallery__thumbs > *:nth-child(5n + 3) { --arc: var(--arc-3); }
.r-gallery__thumbs > *:nth-child(5n + 4) { --arc: var(--arc-4); }
.r-gallery__thumbs > *:nth-child(5n + 5) { --arc: var(--arc-5); }
@media (min-width: 60rem) {
  .r-gallery__repere { display: none; }
  /* Depuis le 25 septembre 2026 le Tapis Magique a dix vues par
     imprimé : la bande passe à la ligne au lieu de défiler, sinon les
     dernières vignettes restaient cachées hors de la colonne, sans
     barre de défilement pour le dire. Les fiches à six vues ou moins
     tiennent toujours sur une seule ligne. */
  .r-gallery__thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    margin-top: .6rem;
    /* La bande est vide au premier rendu : produit.js n'y met les
       vignettes qu'une fois le script exécuté. Sans hauteur réservée,
       la photo du dessus tient toute la place une fraction de seconde,
       puis la page s'allonge d'un coup quand la bande apparaît. Réserver
       sa hauteur dès le départ supprime ce sursaut. */
    min-height: 4.25rem;
  }
  /* Largeur fixe, jamais étirée : avec un seul imprimé riche en vues
     (le tapis en a six) le rang tenait sa taille par le nombre de
     vignettes, mais un imprimé qui n'en a qu'une ou deux (le matelas,
     l'oreiller) les voyait grandir pour remplir toute la largeur de la
     colonne, jusqu'à des carrés de 400 px : la « photo qui s'allonge »
     signalée sur la fiche du matelas, en version ordinateur. */
  .gallery__thumb {
    flex: 0 0 4.25rem;
    aspect-ratio: 1 / 1;
    padding: 0;
    border-bottom: 3px solid var(--arc, transparent);
    background: var(--lavis-2);
    overflow: hidden;
    cursor: pointer;
    opacity: .62;
    transition: opacity var(--dur) var(--ease);
  }
  .gallery__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .gallery__thumb:hover { opacity: .85; }
  .gallery__thumb[aria-current="true"] {
    opacity: 1;
    box-shadow: inset 0 0 0 2px var(--r-ink);
  }
}

/* --- Agrandissement plein écran --------------------------------------------
   Un <dialog> ouvert en mode modal : le navigateur enferme le focus, ferme
   sur Échap et neutralise la page derrière. Sans <dialog> le zoom ne
   s'active pas du tout, la galerie continuant de fonctionner comme avant.
   Le défilement au doigt est natif, comme dans la galerie. */
.zoom {
  width: 100%; max-width: 100%;
  height: 100%; max-height: 100%;
  border: 0; padding: 0; margin: 0;
  background: var(--r-ink);
  color: var(--r-on-dark);
  overflow: hidden;
}
/* Un <dialog> ouvert en modal se dimensionne sur le viewport initial, pas
   sur le viewport réellement visible : sur mobile, la barre d'adresse qui
   se replie au premier défilement laisse la boîte plus haute que l'écran,
   et la photo suivante se met à déborder sous celle qu'on regarde. Même
   défaut que celui trouvé sur la hauteur du héros, même correction : dvh
   se mesure sur ce qui est visible à l'instant, et se recalcule si la
   barre bouge pendant que le zoom est ouvert. */
@supports (height: 100dvh) {
  .zoom { height: 100dvh; max-height: 100dvh; }
}
.zoom::backdrop { background: rgba(20,19,18, .92); }
.zoom[open] { display: grid; grid-template-rows: 1fr auto; }

.zoom__piste {
  grid-row: 1;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  align-items: center;
  min-height: 0;
}
.zoom__piste::-webkit-scrollbar { display: none; }
.zoom__piste.is-dragging { cursor: grabbing; scroll-snap-type: none; }
@media (pointer: fine) { .zoom__piste { cursor: grab; } }

.zoom__vue {
  flex: 0 0 100%;
  scroll-snap-align: center;
  position: relative;
  margin: 0;
  height: 100%;
}
.zoom__vue img {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%;
  padding: clamp(.5rem, 3vw, 3rem);
  max-width: none; max-height: none;
  object-fit: contain;
  -webkit-user-drag: none; user-select: none;
}

.zoom__barre {
  grid-row: 2;
  display: flex; align-items: center; justify-content: center; gap: 1.25rem;
  padding: 1rem 1.25rem calc(1rem + env(safe-area-inset-bottom));
  font-size: var(--fs-micro); letter-spacing: .08em;
  color: rgba(252, 251, 250, .72);
}
.zoom__compteur { margin: 0; font-variant-numeric: tabular-nums; }

.zoom__fermer {
  position: absolute; top: 0; right: 0; z-index: 2;
  padding: clamp(.75rem, 2vw, 1.25rem);
  color: var(--r-on-dark);
}
.zoom__fermer .icon { width: 1.5rem; height: 1.5rem; }

.zoom__fleche {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 3rem; height: 3rem;
  display: none; place-items: center;
  border-radius: 50%;
  background: rgba(252, 251, 250, .12);
  color: var(--r-on-dark);
  transition: background var(--dur) var(--ease);
}
.zoom__fleche:hover { background: rgba(252, 251, 250, .24); }
.zoom__fleche[disabled] { opacity: .25; }
.zoom__fleche--prec { left: clamp(.5rem, 2vw, 1.5rem); }
.zoom__fleche--suiv { right: clamp(.5rem, 2vw, 1.5rem); }
@media (pointer: fine) and (min-width: 48rem) { .zoom__fleche { display: grid; } }

/* --- La colonne d'achat --------------------------------------------------- */
.r-pdp__buy h1 { font-size: clamp(2rem, 3.6vw, 2.9rem); margin: .35rem 0 .75rem; }

/* Sur téléphone, le nuancier d'imprimé (et la taille, quand il y en a une)
   remonte juste sous le prix, avant le paragraphe de description et les
   quatre points clés : c'est lui qu'on vient chercher en premier, pas le
   texte qui l'entoure. À partir de l'écran où la colonne d'achat se colle
   à la galerie, l'ordre naturel du HTML reprend la main. */
@media (max-width: 59.99rem) {
  .r-pdp__buy { display: flex; flex-direction: column; }
  .r-pdp__buy .eyebrow { order: 1; }
  .r-pdp__buy h1 { order: 2; }
  .r-buy__note-avis { order: 3; }
  .r-buy__prix { order: 4; }
  .r-opt { order: 5; }
  .r-buy__desc { order: 6; margin-top: .25rem; }
  .r-buy__stock { order: 7; }
  .r-btn--achat { order: 8; }
  .r-buy__mentions { order: 9; }
  .r-buy__points { order: 10; }
  .r-pdp__buy .r-note { order: 11; }
}

.r-buy__note-avis {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 0 0 1.25rem;
  font-size: var(--fs-sm);
  color: var(--r-ink-mute);
}
.r-buy__note-avis a { color: inherit; }
/* Les etoiles d'avis sont un role fonctionnel, pas un element de la
   suite : elles prennent l'or des avis, comme sur l'accueil. La suite
   structure la page, les roles fonctionnels renseignent le visiteur, et
   les deux ne se melangent jamais. */
.r-stars { display: inline-flex; gap: 1px; color: var(--or-avis); }
.r-stars .icon { width: 15px; height: 15px; }

.r-buy__prix {
  margin: 0 0 1rem;
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: 1.75rem;
  letter-spacing: var(--rf-track);
}
.r-buy__desc { margin: 0 0 2rem; color: var(--r-ink-soft); }

.r-opt { margin-bottom: 1.75rem; }
.r-opt__head {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  margin-bottom: .75rem;
}
.r-opt__label {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--r-ink-mute);
}
.r-opt__value { font-size: var(--fs-sm); }
.r-opt__aide { margin: .75rem 0 0; font-size: var(--fs-sm); }

/* Les tailles : deux pavés, pas deux pastilles. Le prix est dans le choix,
   c'est la première question qu'on se pose. */
.r-sizes { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
.r-sizes .size {
  display: grid;
  gap: .15rem;
  padding: .85rem 1rem;
  background: none;
  border: 1px solid var(--r-rule);
  border-radius: var(--r-radius);
  cursor: pointer;
  text-align: left;
  color: inherit;
  font: inherit;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.r-sizes .size:hover { border-color: var(--r-ink); }
.r-sizes .size[aria-pressed="true"] {
  border-color: var(--arc-1);
  box-shadow: inset 0 0 0 1px var(--arc-1);
  background: var(--lavis-1);
}
.size__dim { font-size: var(--fs-base); }
.size__prix { font-size: var(--fs-sm); color: var(--r-ink-mute); }

/* Le nuancier. Les pastilles sont rondes à la source, leur cadre l'est
   aussi : même règle que sur les cartes de l'accueil. */
.prints { display: flex; flex-wrap: wrap; gap: .5rem; }
.prints .print {
  width: 44px; height: 44px;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 50%;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 0 0 1px var(--r-rule-soft);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.prints .print img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
.prints .print:hover { transform: translateY(-2px); }
.prints .print[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--r-bg), 0 0 0 4px var(--arc-1); }

/* Imprimé en rupture : barre oblique fine, liserée de clair pour rester
   lisible sur tous les motifs, pastille un peu éteinte. Le motif reste
   cliquable. Un seul interrupteur, data-rupture="true|false" sur le
   bouton : il pilote aussi le texte « en rupture » lu par les lecteurs
   d'écran (.print__rupture), pour ne pas reposer sur le visuel seul. */
.prints .print[data-rupture="true"] { position: relative; }
.prints .print[data-rupture="true"] img { opacity: .6; }
.prints .print[data-rupture="true"]::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: 50%;
  background: linear-gradient(to top right,
    transparent calc(50% - 2.5px), var(--r-bg) calc(50% - 2.5px),
    var(--r-bg) calc(50% - 1px), var(--r-ink) calc(50% - 1px),
    var(--r-ink) calc(50% + 1px), var(--r-bg) calc(50% + 1px),
    var(--r-bg) calc(50% + 2.5px), transparent calc(50% + 2.5px));
  pointer-events: none;
}
.print:not([data-rupture="true"]) .print__rupture { display: none; }

/* Le point de couleur venait de .stock::before dans components.css, jamais
   porté ici : la ligne s'est retrouvée sans son repère visuel. */
.r-buy__stock {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 1rem;
  font-size: var(--fs-sm);
  color: var(--vif-vert);
}
.r-buy__stock::before {
  content: '';
  width: .5rem; height: .5rem;
  flex: none;
  border-radius: 50%;
  background: var(--vif-vert);
}
/* Rupture proche : le même point passe au corail, sans changer de forme. */
.r-buy__stock--bas { color: var(--vif-corail); }
.r-buy__stock--bas::before { background: var(--vif-corail); }
.r-buy__mentions { margin: .75rem 0 0; font-size: var(--fs-sm); color: var(--r-ink-mute); }

/* Rupture de la variante choisie : le point et le texte passent au corail.
   L'état est aussi porté par le texte lu (aria-live sur .r-buy__stock), pas
   seulement par la couleur. */
.r-buy__stock--rupture { color: var(--vif-corail); }
.r-buy__stock--rupture::before { background: var(--vif-corail); }

/* Bouton d'achat désactivé : atténué, sans être confondu avec un bouton
   actif. Le curseur dit qu'il n'est pas cliquable. */
.r-btn--achat[disabled],
.r-btn--achat[aria-disabled="true"] {
  opacity: .5;
  cursor: not-allowed;
  filter: grayscale(0.4);
}

/* Taille en rupture pour l'imprimé courant : atténuée, barrée, mais le clic
   reste permis pour révéler le formulaire d'alerte. La mention lecteur
   d'écran (.size__rupture) est ajoutée par dispo.js. */
.r-sizes .size[data-rupture="true"] { opacity: .55; }
.r-sizes .size[data-rupture="true"] .size__dim { text-decoration: line-through; }

/* Rupture au niveau catalogue : cartes de l'e-shop et vignettes d'imprimés
   (index et fiches). Même teinte corail que la fiche et que .r-card__tag--offre,
   visuel atténué. L'état est posé par dispo-catalogue.js et toujours porté par
   un texte, jamais par la seule couleur. */
.r-card__tag--rupture { background: var(--vif-corail); }
.r-card__tag--offre + .r-card__tag--rupture { top: auto; bottom: 0; }
.r-card[data-rupture="true"] .r-card__media img { opacity: .6; }

.r-motifs-index a[data-rupture="true"] img,
.r-motif[data-rupture="true"] .r-motif__vues img { opacity: .6; }
.r-rupture-pill {
  display: inline-block;
  margin-top: .5rem;
  padding: .3rem .7rem;
  border-radius: 999px;
  background: var(--vif-corail);
  color: var(--r-on-dark);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.r-motif .r-rupture-pill { margin-top: .75rem; }

/* Formulaire « Prévenez-moi du retour en stock », discret, sous le bouton
   d'achat désactivé. */
.r-dispo { margin: 1rem 0 0; }
.r-dispo__intro {
  margin: 0 0 .6rem;
  font-size: var(--fs-sm);
  color: var(--r-ink-soft);
}
.r-dispo__ligne {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
}
.r-dispo__email {
  flex: 1 1 12rem;
  min-height: 52px;
  padding: 0 1rem;
  border: 1px solid var(--r-ink);
  border-radius: var(--r-radius);
  background: var(--r-bg-pure);
  color: var(--r-ink);
  font: inherit;
}
.r-dispo__email[aria-invalid="true"] { border-color: var(--vif-corail); }
/* Bouton d'envoi : contour encre lisible sur fond clair (le --ghost de base
   vise les fonds sombres). */
.r-dispo .r-dispo__envoi {
  flex: 0 0 auto;
  background: transparent;
  border-color: var(--r-ink);
  color: var(--r-ink);
}
.r-dispo .r-dispo__envoi:hover { background: var(--r-ink); color: var(--r-on-dark); }
.r-dispo .r-dispo__envoi[disabled] { opacity: .5; cursor: progress; }
.r-dispo__retour {
  margin: .6rem 0 0;
  font-size: var(--fs-sm);
  color: var(--r-ink-soft);
}

/* Le bouton d'achat reprend le violet et le tricolore du héros : c'est le
   même geste, au même rang d'importance. */
.r-btn--achat {
  position: relative;
  background: var(--arc-1);
  border-color: var(--arc-1);
  color: #FFF;
  padding-bottom: 4px;
  overflow: hidden;
}
.r-btn--achat::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
  background: linear-gradient(to right,
    #0F62D9 0 33.33%, #FFF 33.33% 66.66%, #E1000F 66.66% 100%);
}
.r-btn--achat:hover { background: var(--r-ink); border-color: var(--r-ink); color: #FFF; }

.r-buy__points {
  display: grid;
  gap: .85rem;
  margin: 2rem 0 0;
  padding: 1.5rem 0 0;
  border-top: 1px solid var(--r-rule-soft);
  list-style: none;
  font-size: var(--fs-sm);
}
.r-buy__points > *:nth-child(5n + 1) { --arc: var(--arc-1); }
.r-buy__points > *:nth-child(5n + 2) { --arc: var(--arc-2); }
.r-buy__points > *:nth-child(5n + 3) { --arc: var(--arc-3); }
.r-buy__points > *:nth-child(5n + 4) { --arc: var(--arc-4); }
.r-buy__points > *:nth-child(5n + 5) { --arc: var(--arc-5); }
.r-buy__points li { display: grid; grid-template-columns: 2rem 1fr; gap: .85rem; align-items: start; }
.r-buy__points .icon { width: 2rem; height: 2rem; color: var(--arc); }
.r-buy__points strong { font-weight: 600; }

/* --- Les deux tailles, en pleine page ------------------------------------- */
.r-tailles { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); }
@media (min-width: 48rem) { .r-tailles { grid-template-columns: 1fr 1fr; } }
.r-taille { padding-top: 1.5rem; border-top: 3px solid var(--arc, var(--arc-1)); }
.r-tailles > *:nth-child(1) { --arc: var(--arc-1); }
.r-tailles > *:nth-child(2) { --arc: var(--arc-2); }
.r-taille__dim {
  margin: 0;
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  letter-spacing: var(--rf-track);
}
.r-taille__prix { margin: .2rem 0 1rem; color: var(--r-ink-mute); }

/* --- La grille d'accessoires, à quatre ------------------------------------ */
@media (min-width: 48rem)  { .r-grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem)  { .r-grid--4 { grid-template-columns: repeat(4, 1fr); } }

.r-note { font-size: var(--fs-sm); color: var(--r-ink-mute); }
/* Dans le bloc d'achat, la note suit la ligne de mentions : un peu d'air
   pour qu'elles ne se lisent pas comme un seul paragraphe. */
.r-pdp__buy .r-note { margin-top: .75rem; }

/* --- La planche ------------------------------------------------------------
   Trois preuves en image, une seule section. Sur le rang de la suite,
   chaque carte porte un filet fin qui rappelle celui des piliers du
   latex juste au-dessus : deux triptyques du même mécanisme, l'un en
   texte, l'un en photo.

   Les images ne sont pas recadrées à un ratio commun : elles sont
   carrées à la source, 750 × 750, il n'y avait rien à corriger. */
.r-planche {
  display: grid;
  gap: 1.25rem;
  list-style: none;
}
@media (min-width: 48rem) { .r-planche { grid-template-columns: repeat(3, 1fr); gap: 1.5rem; } }

/* La couleur du rang vient de .seq, posé sur <ul> : violet, menthe,
   corail, le même mécanisme que partout ailleurs sur la page. */
.r-planche__card img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
}
.r-planche__titre {
  margin: .85rem 0 0;
  padding-top: .85rem;
  border-top: 3px solid var(--arc, var(--arc-1));
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.15rem;
  letter-spacing: var(--rf-track);
}

/* --- La ligne de chiffres --------------------------------------------------
   Les mêmes trois faits que les piliers du latex, sous une seconde forme :
   scannable d'un regard plutôt qu'à lire en phrase. Pas une nouvelle
   preuve, la même, redite en gros caractères. */
.r-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: clamp(2.5rem, 5vw, 4rem);
  border-top: 1px solid var(--r-rule-soft);
  list-style: none;
  text-align: center;
}
.r-stats__val {
  display: block;
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  letter-spacing: var(--rf-track);
  color: var(--arc, var(--r-ink));
}
.r-stats__label {
  display: block;
  margin-top: .35rem;
  font-size: var(--fs-sm);
  color: var(--r-ink-mute);
}

/* --- Les quatre âges -------------------------------------------------------
   Reprend le principe des piliers du latex : une grille, un rang de la
   suite par carte. L'icône est le seul dessin, monochrome, héritant de
   son rang comme partout ailleurs sur la page. */
.r-ages {
  display: grid;
  gap: 2rem;
  list-style: none;
}
@media (min-width: 48rem) { .r-ages { grid-template-columns: repeat(2, 1fr); gap: 2.5rem 3rem; } }
@media (min-width: 72rem) { .r-ages { grid-template-columns: repeat(4, 1fr); } }

/* Ce sont les seules images de ce bloc : pas de photo à côté pour porter
   le regard. À 2 rem elles se faisaient discrètes à côté du titre en
   Fraunces ; portées à 3,5 rem elles tiennent leur rang de quatre
   situations, pas de quatre puces. */
.r-ages .icon { width: 3.5rem; height: 3.5rem; color: var(--arc, var(--r-ink)); margin-bottom: 1.25rem; }
.r-ages__periode {
  margin: 0 0 .35rem;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--r-ink-mute);
}
.r-ages__titre {
  margin: 0 0 .5rem;
  font-family: var(--rf-display);
  font-weight: var(--rf-weight);
  font-variation-settings: var(--rf-settings);
  font-size: 1.3rem;
  letter-spacing: var(--rf-track);
}
.r-ages p:last-child { margin: 0; color: var(--r-ink-soft); font-size: var(--fs-sm); }

/* ===================================================================
   22. La barre d'achat mobile

   En dessous de 960 px, la colonne d'achat cesse d'etre collante. Sur
   une fiche longue, l'acheteur qui vient de finir sa lecture n'a plus
   rien a cliquer. Cette barre le lui rend, et disparait des que la
   colonne reprend son role.

   Elle ne s'affiche jamais au premier ecran : c'est le bloc d'achat
   lui-meme qui la declenche en sortant du champ.
   =================================================================== */
.r-achat-mobile {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .75rem clamp(1rem, 4vw, 1.5rem);
  padding-bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
  background: var(--r-bg);
  border-top: 1px solid var(--r-rule);
  box-shadow: 0 -6px 24px rgb(0 0 0 / .07);
}
.r-achat-mobile__texte { flex: 1 1 auto; min-width: 0; }
.r-achat-mobile__nom {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--r-ink-mute);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.r-achat-mobile__prix { margin: 0; font-weight: 600; }
.r-achat-mobile .r-btn { flex: none; white-space: nowrap; }
.r-achat-mobile__cta-prix { display: none; }

/* Sous 380 px, le prix de gauche suffit : on rend le bouton a son seul
   verbe plutot que de laisser la ligne se casser en deux. */
@media (max-width: 23.75rem) {
  .r-achat-mobile__texte { flex: 0 1 auto; }
}

/* Au-dessus, la colonne collante fait le travail : la barre n'a plus
   de raison d'etre. */
@media (min-width: 60rem) {
  .r-achat-mobile { display: none; }
}

/* Elle recouvre le bas du document : on rend la hauteur au contenu pour
   que le pied de page reste entierement lisible. */
@media (max-width: 59.99rem) {
  body:has(.r-achat-mobile) { padding-bottom: 5.5rem; }
}

/* L'etat de repos est hors champ, et il ne depend pas de .js-anim :
   cette classe n'est pas posee quand le visiteur a demande moins
   d'animation, et la barre resterait alors affichee des le premier
   ecran, exactement ce qu'elle doit eviter. Seul le glissement est
   conditionne, pas la position. */
.r-achat-mobile {
  transform: translateY(100%);
  transition: transform var(--dur) var(--ease);
}
.r-achat-mobile.is-visible { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .r-achat-mobile { transition: none; }
}

/* ===================================================================
   23. La tracabilite, pays par pays

   Une liste de definition deguisee : a gauche le lieu, a droite ce qui
   s'y fait. Pas de drapeau, pas d'icone : les emoji drapeaux de
   l'ancien site ne se lisent pas de la meme facon d'un systeme a
   l'autre, et un lecteur d'ecran les annonce mal.
   =================================================================== */
.r-origines {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0;
}
.r-origines li {
  display: grid;
  gap: .25rem .5rem;
  padding: 1.1rem 0;
  border-top: 1px solid var(--r-rule-soft);
}
.r-origines li:last-child { border-bottom: 1px solid var(--r-rule-soft); }
.r-origines__lieu {
  font-weight: 600;
  color: var(--r-ink);
}
.r-origines__quoi { color: var(--r-ink-soft); }

@media (min-width: 40rem) {
  .r-origines li {
    grid-template-columns: minmax(0, 11rem) minmax(0, 1fr);
    align-items: baseline;
    gap: 2rem;
  }
}

/* ===================================================================
   24. Le feutre qui se trace

   Le surlignage etait pose d'un bloc, deja seche quand le titre
   apparaissait. Il se trace maintenant de gauche a droite, une fois le
   titre en place : c'est le geste de la main qui passe le surligneur,
   pas un fond de couleur.

   Seuls les feutres portes par un bloc en .reveal s'animent. Partout
   ailleurs, dans une carte, dans un pied de page, le trait reste pose
   comme avant : un surlignage qui se redessine a chaque coin de l'oeil
   deviendrait un tic, et c'est exactement le marqueur qu'on evite.

   Sans .js-anim, donc pour qui a demande moins d'animation, rien de
   tout ceci ne s'applique et le trait est la des le chargement.
   =================================================================== */
.js-anim .reveal h1 em,
.js-anim .reveal h2 em,
.js-anim .reveal h3 em,
.js-anim .reveal.r-manifeste__phrase em {
  background-size: 0% 100%;
  transition: background-size .7s cubic-bezier(.25, .8, .35, 1) 220ms;
}
.js-anim .reveal.is-visible h1 em,
.js-anim .reveal.is-visible h2 em,
.js-anim .reveal.is-visible h3 em,
.js-anim .reveal.is-visible.r-manifeste__phrase em {
  background-size: 100% 100%;
}

/* ===================================================================
   25. La section de vente croisee

   Elle arrive apres dix ecrans de lecture. Sans marque propre, elle se
   lit comme une onzieme section editoriale alors que c'est le dernier
   moment ou on propose quelque chose. Un lavis de la couleur du rang
   courant suffit a la detacher, sans la crier.
   =================================================================== */
.r-section--offre {
  background: var(--lavis);
  border-block: 1px solid var(--r-rule-soft);
}
.r-section--offre .r-card__media { background: var(--r-bg-pure); }

/* Les cartes se soulevent d'un cheveu au survol, comme les vignettes de
   la collection sur l'accueil. */
.r-card { transition: transform var(--dur) var(--ease); }
.r-card:hover { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  .r-card { transition: none; }
  .r-card:hover { transform: none; }
}

/* ===================================================================
   26. Les pages légales (gabarit E)

   Mentions légales, CGV, confidentialité : du texte long, lu pour
   trouver un article précis. Colonne de lecture étroite (.wrap--text),
   titres d'article ramenés à la taille d'un h3 pour que quinze
   articles ne fassent pas quinze affiches. Le petit filet au-dessus de
   chaque titre prend la couleur du rang : c'est la suite qui structure,
   comme ailleurs.
   =================================================================== */
.r-legal { padding-bottom: var(--sp-section); }
.r-legal__art { scroll-margin-top: calc(var(--h-header) + 1rem); }
.r-legal__art + .r-legal__art { margin-top: clamp(2.5rem, 5vw, 3.5rem); }
.r-legal h2 { font-size: var(--fs-h3); margin-bottom: 1rem; }
.r-legal h2::before {
  content: "";
  display: block;
  width: 2.5rem;
  height: 2px;
  margin-bottom: 1rem;
  background: var(--arc, var(--arc-1));
}
.r-legal h3 { font-size: var(--fs-lg); margin: 1.75rem 0 .75rem; }
.r-legal ul { margin: 0 0 1.15em; padding-left: 1.25rem; list-style: disc; }
.r-legal li { font-size: .95rem; margin-bottom: .4rem; }
.r-legal li::marker { color: var(--r-ink-soft); }

/* L'encadré obligatoire de la garantie légale de conformité. Même
   geste que .r-callout (lavis et filet du rang), sans la colonne
   d'icône. */
.r-legal__encadre {
  margin-top: 2rem;
  padding: clamp(1.25rem, 4vw, 2rem);
  background: var(--lavis, var(--lavis-1));
  border-left: 3px solid var(--arc, var(--arc-1));
}
.r-legal__encadre p { font-size: var(--fs-sm); }

/* Le tableau des traitements. Aucun autre tableau dans la maison : ce
   style ne vit que dans .r-legal. Sous 48 rem il s'empile en fiches,
   chaque cellule annonçant sa colonne par son data-label, plutôt que
   de forcer un défilement horizontal sur quatre colonnes. */
.r-legal table {
  width: 100%;
  margin: 0 0 1.5rem;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
.r-legal th,
.r-legal td {
  padding: .75rem .75rem .75rem 0;
  text-align: left;
  vertical-align: top;
  border-top: 1px solid var(--r-rule-soft);
}
.r-legal thead th { font-weight: 600; border-top: 0; border-bottom: 1px solid var(--r-rule); }
@media (max-width: 47.99rem) {
  .r-legal thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
  .r-legal table, .r-legal tbody, .r-legal tr, .r-legal td { display: block; }
  .r-legal tr { padding: 1rem 0; border-top: 1px solid var(--r-rule); }
  .r-legal td { padding: .25rem 0; border: 0; }
  .r-legal td::before {
    content: attr(data-label);
    display: block;
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--r-ink-soft);
  }
}

/* Un blanc à remplir avant publication : [À COMPLÉTER : ...] ou
   [À CONFIRMER : ...]. Il doit se voir au premier coup d'oeil et ne
   jamais passer pour une information : fond jaune pâle, bordure
   pointillée. C'est un état, pas un rang de la suite, d'où une couleur
   propre. Encre #141312 sur #FFF3B8 : 16,6:1. Bordure --encre-4 sur ce
   jaune : 4,66:1. Cette classe disparaît de la page avec le dernier
   blanc, et le noindex avec elle. */
.r-provisoire {
  padding: 0 .3em;
  color: var(--r-ink);
  background: #FFF3B8;
  border: 1px dashed var(--encre-4);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* ==========================================================================
   27. La page d'attente (bientot-disponible)

   Un titre, une phrase, un bouton, centrés dans au moins une demi-hauteur
   d'écran : la page n'a rien d'autre à dire et le pied de page ne doit pas
   remonter sous l'en-tête. Le filet arc-en-ciel sépare la phrase du
   bouton, comme sous le bouton du héros.

   Les quatre enfants entrent l'un après l'autre avec .reveal, le rang est
   posé ici par nth-child. Le mouvement réduit neutralise délai compris
   (section 20).
   ========================================================================== */
.r-attente {
  display: grid;
  place-items: center;
  min-height: clamp(22rem, 60svh, 40rem);
  text-align: center;
}
.r-attente__bloc { max-width: 40rem; }
.r-attente .lead { margin-top: 1rem; }
.r-attente .arcrule--sep { margin-block: 2rem; }
.r-attente__bloc > .reveal:nth-child(2) { --i: 1; }
.r-attente__bloc > .reveal:nth-child(3) { --i: 2; }
.r-attente__bloc > .reveal:nth-child(4) { --i: 3; }

/* ===================================================================
   27. Le cadre d'un service tiers (avis-clients/)
   Le widget de la Société des Avis Garantis est une page entière servie
   dans un iframe. Sa hauteur de contenu va de 6 800 px (1 000 px de
   large) à 12 200 px (320 px), mesurée le 25 septembre 2026, et un
   iframe d'une autre origine ne peut pas s'ajuster à son contenu sans
   un script de leur côté. Le cadre est donc borné à la fenêtre et le
   widget défile dedans, comme sur l'ancien site, mais en largeur
   fluide : plus de 1 000 x 2 700 px en dur. La hauteur est posée dès
   le premier rendu, donc aucun décalage quand le cadre se charge.
   Filet --r-rule : il cadre sans porter d'information, pas de 3:1.
   =================================================================== */
.r-widget {
  border: 1px solid var(--r-rule);
  background: var(--r-bg-pure);
}
.r-widget iframe {
  display: block;
  width: 100%;
  height: clamp(32rem, 80vh, 60rem);
  height: clamp(32rem, 80svh, 60rem);
  border: 0;
}

/* ===================================================================
   28. La page panier (panier/)
   -------------------------------------------------------------------
   Les lignes sont celles du tiroir (.cart-line, section 19), dessinées
   par le même code de main.js. Seule la mise en page est ici : la liste
   à gauche, le récapitulatif à droite, collant sur grand écran ; les
   deux s'empilent sous 60 rem, le récapitulatif après la liste.
   =================================================================== */
.r-panier {
  display: grid;
  gap: 2.5rem;
  align-items: start;
}
@media (min-width: 60rem) {
  .r-panier { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 4rem; }
  .r-panier__recap { position: sticky; top: clamp(5rem, 8vh, 7rem); }
}
.r-panier__lignes { margin: 0; padding: 0; list-style: none; }
.r-panier .cart-line { grid-template-columns: 96px 1fr; }
.r-panier .cart-line img { width: 96px; }
.r-panier__recap {
  padding: 1.5rem;
  border: 1px solid var(--r-rule-soft);
}
.r-panier__recap h2 { margin: 0 0 1.25rem; font-size: var(--fs-h3); }
.r-panier__recap .cart-row { margin: 0 0 .5rem; }
.r-panier__recap .r-btn { margin-top: 1.25rem; }
.r-panier__vide .r-btn { margin-top: 1.5rem; }

/* ===================================================================
   29. Les formulaires de compte et le suivi de commande
       (mon-compte/, suivi-commande/, créés le 25 septembre 2026)

   Premiers vrais formulaires à plusieurs champs de la maison : jusqu'ici
   il n'y avait que la ligne unique de .r-news__form. Même dessin
   (angle droit, 52 px de haut, fond blanc), mais en colonne, avec un
   libellé visible au-dessus de chaque champ et un message d'erreur
   dessous.

   Contrastes, mesurés sur #FFFFFF :
     bord de champ --r-ink-mute #7A746E  4,6:1 (3:1 exigé, WCAG 1.4.11).
       Le --r-rule de .r-news__form, à 14 % d'opacité, ne passe pas :
       il n'est pas repris ici.
     erreur --vif-corail #D63A22         4,53:1, texte
     étape faite --vif-vert #0A7A5D      5,14:1, filet et texte
   La couleur ne porte jamais l'état seule : chaque erreur est écrite,
   chaque étape dit son état en toutes lettres.
   =================================================================== */

/* Les deux panneaux, connexion et inscription, côte à côte au-dessus de
   60 rem, l'un sous l'autre en dessous. */
.r-compte {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
}
@media (min-width: 60rem) { .r-compte { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Le panneau d'un formulaire : le filet de .r-offer, sans ses liens en
   capitales ni ses marges de carte, qui sont faites pour un appel à
   l'action, pas pour un lien dans une phrase. */
.r-cadre-form { padding: clamp(1.25rem, 4vw, 2.5rem); border: 1px solid var(--r-rule); background: var(--r-bg-pure); }
.r-cadre-form > .r-note { margin-top: 1.25rem; }
.r-cadre-form h2,
.r-espace h2 { font-size: var(--fs-h3); margin-bottom: .75rem; }
.r-espace h3 { font-size: var(--fs-lg); margin: 2.5rem 0 1rem; }

.r-form { display: grid; gap: 1.25rem; margin-top: 1.5rem; }
.r-champ label { display: block; margin-bottom: .4rem; font-size: var(--fs-sm); font-weight: 500; }
.r-champ input {
  width: 100%;
  min-height: 52px;
  padding: 0 1rem;
  border: 1px solid var(--r-ink-mute);
  border-radius: var(--r-radius);
  background: var(--r-bg-pure);
}
.r-champ input:focus-visible { outline: 2px solid var(--vif-violet); outline-offset: 2px; }
/* Le bord double en corail signale l'erreur ; le message écrit dessous
   la dit. */
.r-champ input[aria-invalid="true"] { border-color: var(--vif-corail); box-shadow: inset 0 0 0 1px var(--vif-corail); }
.r-champ__aide,
.r-champ__erreur { margin: .4rem 0 0; font-size: var(--fs-sm); }
.r-champ__aide { color: var(--r-ink-soft); }
.r-champ__erreur { color: var(--vif-corail); }
.r-champ__erreur:empty { display: none; }

/* Le lien « Mot de passe oublié » est un bouton : il n'emmène nulle
   part, il déclenche une action. */
.r-form .link { justify-self: start; font-size: var(--fs-sm); }

/* Une commande dans l'historique : numéro, date, total et statut sur
   une ligne qui passe à la ligne sur mobile, les articles dessous. */
.r-commandes { display: grid; gap: 1rem; }
.r-commande { padding: clamp(1.25rem, 3vw, 1.75rem); border: 1px solid var(--r-rule); background: var(--r-bg-pure); }
.r-commande__tete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem 1.5rem;
  margin-bottom: .75rem;
}
.r-commande__tete p { margin: 0; font-size: var(--fs-sm); color: var(--r-ink-soft); }
.r-commande__tete strong { color: var(--r-ink); font-weight: 600; }
.r-commande ul { font-size: var(--fs-sm); color: var(--r-ink-soft); }

/* Le statut est une information d'état : rôle fonctionnel, jamais la
   suite (DESIGN.md, section 4). Seule la livraison prend le vert, les
   autres états restent à l'encre. */
.r-statut {
  display: inline-block;
  padding: .15rem .6rem;
  border: 1px solid currentColor;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--r-ink);
}
.r-statut--livree { color: var(--vif-vert); }

/* Les trois étapes d'une commande. Faite : filet vert. En cours :
   aria-current="step", en gras. À venir : filet gris, texte atténué.
   Les colonnes passent à la ligne d'elles-mêmes sous 20 rem. */
.r-etapes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  gap: .75rem;
  margin: 1.5rem 0;
}
.r-etapes li {
  padding-top: .75rem;
  border-top: 3px solid var(--r-rule);
  font-size: var(--fs-sm);
  color: var(--r-ink-mute);
}
.r-etapes li.is-fait { border-top-color: var(--vif-vert); color: var(--r-ink); }
.r-etapes li[aria-current="step"] { font-weight: 600; }

/* L'aperçu de l'espace client : de l'air entre l'encart et le salut,
   la liste d'informations collée à son titre, le bouton de sortie à
   distance du dernier bloc. */
.r-espace .r-callout + h2 { margin-top: 2.5rem; }
.r-espace .r-origines { margin-top: 0; }
.r-espace__fin { margin-top: 2.5rem; }
.r-commande .r-note { margin-top: .75rem; }

/* --- L'espace connecté, rubriques (29 septembre 2026) ------------------
   Structure de l'ancien espace WooCommerce : menu à gauche au-dessus de
   60 rem (collant, comme la colonne du journal), bandeau qui défile
   au-dessus des rubriques en dessous (comme les rubriques de journal/).
   Les liens reprennent le dessin de .r-journal__cats : 44 px de haut,
   lavis au survol, gras et lavis pour la rubrique ouverte. */
.r-espace-grille { display: grid; gap: clamp(1.5rem, 4vw, 3rem); align-items: start; }
/* Sans min-width: 0, le bandeau du menu élargit la colonne au lieu de
   défiler. */
.r-espace-grille > * { min-width: 0; }
.r-espace-nav ul {
  display: flex;
  gap: .25rem;
  overflow-x: auto;
  padding-bottom: .25rem;
  border-bottom: 1px solid var(--r-rule);
}
.r-espace-nav a,
.r-espace-nav__sortie {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: .35rem .75rem;
  font-size: var(--fs-sm);
  color: var(--r-ink);
  white-space: nowrap;
  text-decoration: none;
}
.r-espace-nav a:hover,
.r-espace-nav a[aria-current],
.r-espace-nav__sortie:hover { background: var(--lavis, var(--lavis-1)); }
.r-espace-nav a[aria-current] { font-weight: 600; }
.r-espace-nav a:focus-visible,
.r-espace-nav__sortie:focus-visible { outline: 2px solid var(--vif-violet); outline-offset: -2px; }
.r-espace-nav__sortie { width: 100%; border: 0; background: none; font: inherit; font-size: var(--fs-sm); cursor: pointer; }
@media (min-width: 60rem) {
  .r-espace-grille { grid-template-columns: 15rem minmax(0, 1fr); }
  .r-espace-nav { position: sticky; top: calc(var(--h-header) + 2rem); }
  .r-espace-nav ul { display: block; padding-bottom: 0; border-bottom: 0; border-top: 1px solid var(--r-rule); }
  .r-espace-nav li { border-bottom: 1px solid var(--r-rule); }
  .r-espace-nav a,
  .r-espace-nav__sortie { white-space: normal; }
}
/* La rubrique garde la mesure de lecture de l'ancien .wrap--text. */
.r-espace { max-width: 46rem; }
.r-espace [data-panneau] > h2 { margin-bottom: 1rem; }
.r-espace [data-panneau] > .r-note { margin-top: 1rem; }
.r-espace .r-commandes + .r-note { margin-top: 1rem; }
.r-espace .r-form { margin-top: 0; }
.r-espace .r-form + h3 { margin-top: 3rem; }

/* Un message vide ne doit pas creuser un espace dans la grille du
   formulaire. */
.r-form > .r-note:empty { display: none; }
.r-champ__facultatif { font-weight: 400; color: var(--r-ink-soft); }
.r-champ__libelle { margin: 0 0 .4rem; font-size: var(--fs-sm); font-weight: 500; }
.r-champ__libelle + p { margin: 0; }
/* La récupération du mot de passe est seule sur la ligne. */
.r-compte__seul { grid-column: 1 / -1; max-width: 36rem; }

/* Les alertes de réassort : une ligne par article, filet entre deux. */
.r-alertes li { padding: 1rem 0; border-top: 1px solid var(--r-rule); }
.r-alertes li:last-child { border-bottom: 1px solid var(--r-rule); }
.r-alerte__quoi { margin: 0; }
.r-alerte .r-note { margin: .25rem 0 .5rem; }
.r-alerte__retrait { font-size: var(--fs-sm); min-height: 24px; }
.r-alertes__etat { margin-top: 1rem; }

/* Le résultat du suivi : détaché du formulaire, et la liste du colis
   prolonge celle de la commande sans doubler le filet. Les blocs
   masqués par hidden sont des div nues : une classe qui pose display
   annulerait l'attribut. */
.r-suivi__retour { margin-top: 2rem; }
.r-suivi__colis { margin-top: 0; }
.r-suivi__colis li:first-child { border-top: 0; }

/* ===================================================================
   30. Le journal (gabarit G, créé le 25 septembre 2026, mis en page
       le même jour sur le modèle des articles d'origine)
   -------------------------------------------------------------------
   Les articles sont rendus depuis un JSON de blocs par
   outils/journal-rendu.py : ce qui suit habille ces blocs, rien de plus.

   La mise en page est celle des articles d'Aude sur jolihuit.com
   (référence : meilleur-tapis-eveil-montessori) : image de une, titre,
   puis des rangées texte à gauche, image à droite ; chaque h2 en pleine
   largeur, surligné ; l'appel à l'action de fin centré ; une colonne à
   droite avec les catégories et d'autres articles. Ce qui change, c'est
   l'habillage de la maison : angles droits, feutre tracé, suite de
   couleurs par partie (.seq sur les <section> d'article), panneau de
   lavis décalé derrière les photos (.r-offset__media), zigzag des
   images d'une rangée à l'autre.

   Composants repris et non recréés : .eyebrow, le feutre des h2 (section
   5, tracé en section 24), .reveal, .r-offset__media, .r-legal__encadre,
   .faq, .r-btn, .r-provisoire, .seq.
   Contrastes : --r-ink-soft #4A4644 sur le fond, 8,9:1 ; liens en
   --encre-1 #6128FF, 6,24:1 ; titres de la colonne en --encre-1 aussi.
   =================================================================== */

/* --- La page : l'article et sa colonne ----------------------------------
   Sous 72 rem la colonne passe sous l'article, là où était « À lire
   ensuite ». Au-dessus, elle suit la lecture (collante). */
.r-journal { padding-block: clamp(.5rem, 2vw, 1.5rem) var(--sp-section); }
.r-journal__aside { margin-top: var(--sp-section); display: grid; gap: 2.5rem; }
@media (min-width: 72rem) {
  .r-journal {
    max-width: 84rem;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17rem;
    gap: clamp(3rem, 5vw, 5rem);
    align-items: start;
  }
  .r-journal__aside { position: sticky; top: calc(var(--h-header) + 2rem); margin-top: 0; }
}

/* --- La barre de lecture -------------------------------------------------
   Pilotée par le défilement lui-même (animation-timeline), sans écouteur
   ni JavaScript : elle avance du haut de l'article à sa fin. Un navigateur
   qui ne connaît pas encore la propriété (Firefox en 2026) n'a pas de
   barre, et rien d'autre ne change. Un seul trait violet, pas la suite :
   le filet arc-en-ciel n'est jamais collant (DESIGN.md, section 4). */
@supports (animation-timeline: view()) {
  .r-article { view-timeline-name: --r-lecture; }
  .r-article::before {
    content: "";
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 70;
    height: 3px;
    background: var(--vif-violet);
    transform-origin: 0 50%;
    animation: r-lecture linear both;
    animation-timeline: --r-lecture;
    animation-range: contain 0% contain 100%;
  }
  @keyframes r-lecture { from { transform: scaleX(0); } to { transform: scaleX(1); } }
}
@media (prefers-reduced-motion: reduce) {
  .r-article::before { display: none; }
}

/* --- L'image de une ------------------------------------------------------
   Recadrée en 16/9 comme la une d'origine l'était (1140 x 445), posée sur
   un panneau de lavis qui glisse en place au chargement. L'image elle-même
   ne s'anime pas : c'est le plus grand élément de la page (LCP). Une petite
   image (un logo de 350 px) n'est jamais agrandie : elle est centrée sur
   le lavis. */
.r-article__une { position: relative; margin: 0 0 clamp(2rem, 4vw, 3rem); isolation: isolate; }
.r-article__une::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--lavis, var(--lavis-1));
  transform: translate(clamp(.6rem, 1.5vw, 1.25rem), clamp(.6rem, 1.5vw, 1.25rem));
}
.r-article__une img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.r-article__une--petite { padding: clamp(2rem, 6vw, 4rem); background: var(--lavis, var(--lavis-1)); }
.r-article__une--petite::before { content: none; }
.r-article__une--petite img { width: auto; aspect-ratio: auto; margin-inline: auto; }
.js-anim .r-article__une::before { animation: r-une-panneau .8s var(--ease) .15s both; }
@keyframes r-une-panneau { from { transform: translate(0, 0); } }

/* --- L'en-tête -------------------------------------------------------------
   La catégorie (seule suréligne de la page) prend un court filet de la
   suite, qui se déroule quand l'en-tête arrive. */
.r-article__tete { max-width: 50rem; margin-bottom: clamp(2.5rem, 5vw, 3.5rem); }
.r-article__tete .eyebrow { display: flex; align-items: center; gap: .75rem; }
.r-article__tete .eyebrow::before {
  content: "";
  flex: none;
  width: 2.5rem;
  height: 3px;
  background: linear-gradient(to right, var(--arc-1) 0 20%, var(--arc-2) 0 40%,
    var(--arc-3) 0 60%, var(--arc-4) 0 80%, var(--arc-5) 0);
  transform-origin: 0 50%;
}
.js-anim .r-article__tete .eyebrow::before { transform: scaleX(0); transition: transform .6s var(--ease) .2s; }
.js-anim .r-article__tete.is-visible .eyebrow::before { transform: none; }
.r-article__tete h1 { font-size: clamp(2rem, 4.4vw, 3.4rem); line-height: 1.1; text-wrap: balance; }
.r-article__meta {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem 0;
  margin-top: 1.25rem;
  font-size: var(--fs-sm);
  color: var(--r-ink-soft);
}
.r-article__meta span + span::before { content: "·"; margin-inline: .6rem; color: var(--r-ink-mute); }

/* --- Le texte ------------------------------------------------------------
   16 px et non les .95rem du paragraphe de base : on lit ici. Le gras
   porte un surlignage jaune léger, comme sur l'ancien site : bas de
   ligne seulement, le texte reste noir dessus (contraste inchangé). */
.r-article__corps p,
.r-article__corps li { font-size: var(--fs-base); }
.r-article__corps strong {
  font-weight: 600;
  background: linear-gradient(transparent 66%, color-mix(in srgb, var(--arc-4) 30%, transparent) 0);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.r-article__corps .link { color: var(--encre-1); }
.r-article__texte { max-width: 42rem; }
/* .r-t3 et .r-t4 : un intertitre dont la balise a été remontée d'un
   niveau par journal-rendu.py (pas de saut h2 puis h4 dans le plan de la
   page) garde l'aspect de son niveau d'origine. */
.r-article__texte > h3:not(.r-t4),
.r-article__texte > .r-t3 {
  margin: 0 0 .9rem;
  font-size: clamp(1.2rem, 2vw, 1.4rem);
  line-height: 1.25;
  scroll-margin-top: calc(var(--h-header) + 1.5rem);
}
.r-article__texte > h3:not(.r-t4)::before,
.r-article__texte > .r-t3::before {
  content: "";
  display: block;
  width: 2rem;
  height: 2px;
  margin-bottom: .9rem;
  background: var(--arc, var(--arc-1));
}
.r-article__texte > h4,
.r-article__texte > .r-t4 { margin: 1.5rem 0 .5rem; font-size: var(--fs-base); }

/* Puces carrées de la couleur de la partie : angle droit, comme le reste. */
.r-article__texte > ul,
.r-article__texte > ol { margin: 0 0 1.15em; }
.r-article__texte > ul > li { position: relative; padding-left: 1.4rem; margin-bottom: .6rem; }
.r-article__texte > ul > li::before {
  content: "";
  position: absolute;
  left: .15rem; top: .7em;
  width: .45rem; height: .45rem;
  background: var(--arc, var(--arc-1));
}
.r-article__texte > ol { padding-left: 1.4rem; list-style: decimal; }
.r-article__texte > ol > li { margin-bottom: .6rem; padding-left: .25rem; }
.r-article__texte > ol > li::marker { color: var(--encre, var(--encre-1)); font-weight: 600; }

/* L'introduction : le premier paragraphe en chapô. */
.r-article__intro { margin-bottom: clamp(3rem, 6vw, 4.5rem); }
.r-article__intro .r-article__texte > p:first-child { font-size: var(--fs-lg); line-height: 1.7; }

/* --- Les parties et leurs titres -----------------------------------------
   Une <section> par h2, dans un .seq : chaque partie prend son rang de la
   suite, dans l'ordre, comme les surligneurs de l'ancien site. Le h2 est
   en pleine largeur et porte le feutre, qui se trace à l'arrivée. */
.r-article__partie + .r-article__partie { margin-top: clamp(3.5rem, 7vw, 5.5rem); }
.r-article__titre { max-width: 44rem; margin-bottom: clamp(1.75rem, 3.5vw, 2.5rem); }
.r-article__titre h2 {
  font-size: clamp(1.6rem, 3vw, 2.25rem);
  line-height: 1.2;
  text-wrap: balance;
  scroll-margin-top: calc(var(--h-header) + 1.5rem);
}

/* --- Les rangées ------------------------------------------------------------
   Texte 60 %, image 40 %, l'image occupe toute la hauteur de la rangée
   (recadrée si le texte est plus long, jamais déformée). Une rangée sur
   deux passe l'image à gauche : placement dans la grille, l'ordre du DOM
   reste texte puis image, donc en mobile l'image est toujours sous son
   texte. Le panneau de lavis (.r-offset__media) déborde côté texte. */
.r-article__rangee + .r-article__rangee,
.r-article__rangee + .r-article__cta,
.r-article__cta + .r-article__rangee { margin-top: clamp(2.5rem, 5vw, 3.5rem); }
.r-article__rangee--image { display: grid; gap: 2.5rem; }
@media (min-width: 48rem) {
  .r-article__rangee--image {
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: clamp(2.5rem, 5vw, 4.5rem);
    align-items: stretch;
  }
  .r-article__rangee--gauche { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
  .r-article__rangee--gauche > .r-article__texte { grid-column: 2; grid-row: 1; }
  .r-article__rangee--gauche > .r-article__media { grid-column: 1; grid-row: 1; }
  .r-article__rangee--image > .r-article__texte { align-self: center; }
}

.r-article__media { display: flex; flex-direction: column; gap: 1.5rem; }
.r-article__rangee--seule > .r-article__media { max-width: 30rem; margin-inline: auto; }
@media (max-width: 47.99rem) {
  /* Une photo en hauteur prendrait plus d'un écran en pleine largeur. */
  .r-article__media--portrait { max-width: 22rem; margin-inline: auto; width: 100%; }
}
.r-article__figure {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  margin: 0;
  overflow: hidden;
  background: var(--r-bg-pure);
}
.r-article__figure > a { display: block; flex: 1 1 auto; min-height: 0; }
.r-article__figure > img { flex: 1 1 auto; min-height: 0; }
.r-article__figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease);
}
@media (hover: hover) {
  .r-article__figure:hover img { transform: scale(1.04); }
}
.r-article__figure figcaption {
  padding: .75rem 1rem;
  font-size: var(--fs-sm);
  color: var(--r-ink-soft);
}

/* L'image se découvre de haut en bas quand sa rangée arrive, en plus du
   fondu de .reveal. Sans .js-anim (mouvement réduit), rien ne se cache. */
.js-anim .r-article__media .r-article__figure { clip-path: inset(0 0 100% 0); transition: clip-path .7s var(--ease) .12s; }
.js-anim .r-article__media.is-visible .r-article__figure { clip-path: inset(0); }

/* --- Citation, encadré, questions --------------------------------------- */
.r-article__citation {
  margin: 2rem 0;
  padding: .25rem 0 .25rem 1.5rem;
  border-left: 3px solid var(--arc, var(--arc-1));
}
.r-article__citation p {
  font-family: var(--rf-display);
  font-variation-settings: var(--rf-settings);
  font-size: clamp(1.15rem, 2vw, 1.35rem);
  line-height: 1.5;
}
.r-article__citation footer { margin-top: .5rem; font-size: var(--fs-sm); color: var(--r-ink-soft); }
.r-article__texte > .r-legal__encadre,
.r-article__texte > .faq { margin: 2rem 0; }
.r-article__texte > :last-child { margin-bottom: 0; }
.r-article__corps .r-legal__encadre p { font-size: var(--fs-base); }

/* --- L'appel à l'action de fin (bouton, téléchargement) --------------------
   Une rangée à part, centrée, comme sur l'ancien site. Filet du rang en
   haut plutôt qu'à gauche, bouton dans le violet de ses appels à
   l'action (blanc sur #6128FF : 6,24:1), flèche qui avance au survol. */
.r-article__cta {
  padding: clamp(1.75rem, 5vw, 3rem);
  border-left: 0;
  border-top: 3px solid var(--arc, var(--arc-1));
  text-align: center;
}
.r-article__cta p { max-width: 36rem; margin-inline: auto; }
.r-article__cta .r-btn {
  gap: .9rem;
  height: auto;
  margin-top: .75rem;
  padding-block: .9rem;
  line-height: 1.5;
  background: var(--vif-violet);
  border-color: var(--vif-violet);
  color: #FFF;
}
.r-article__cta .r-btn::after {
  content: "";
  flex: none;
  width: .5rem;
  height: .5rem;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur) var(--ease);
}
.r-article__cta .r-btn:hover { background: var(--r-ink); border-color: var(--r-ink); color: var(--r-on-dark); }
.r-article__cta .r-btn:hover::after { transform: translateX(4px) rotate(45deg); }

/* --- Le sommaire ------------------------------------------------------------
   Posé seulement sur un article long (MODELE-ARTICLE.md). */
.r-sommaire {
  margin: 2rem 0 0;
  padding: 1.25rem 1.5rem;
  background: var(--r-bg-pure);
  border: 1px solid var(--r-rule);
  border-top: 3px solid var(--arc, var(--arc-1));
}
.r-sommaire__titre {
  margin: 0 0 .75rem;
  font-family: var(--r-body);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.r-sommaire ol { list-style: decimal; padding-left: 1.25rem; }
.r-sommaire li { margin-bottom: .35rem; font-size: var(--fs-sm); }
.r-sommaire li::marker { color: var(--r-ink-soft); }

/* --- La colonne : catégories, autres articles ------------------------------
   Titres en capitales sans empattement, comme les widgets de l'ancien
   site. Pictogrammes des catégories dans l'encre de leur catégorie (data-rang,
   section 31, une couleur par catégorie depuis le 25 septembre 2026). */
.r-journal__bloc h2 {
  margin-bottom: .5rem;
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--r-rule);
  font-family: var(--r-body);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.r-journal__cats a {
  display: flex;
  align-items: center;
  gap: .8rem;
  min-height: 44px;
  padding: .35rem .6rem;
  font-size: var(--fs-sm);
  text-decoration: none;
}
.r-journal__cats a:hover,
.r-journal__cats a[aria-current] { background: var(--lavis, var(--lavis-1)); }
.r-journal__cats a[aria-current] { font-weight: 600; }
.r-picto,
.r-journal__chevron {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.r-picto { width: 1.4rem; height: 1.4rem; color: var(--encre, var(--encre-1)); }
.r-journal__chevron {
  width: 1rem;
  height: 1rem;
  margin-left: auto;
  color: var(--r-ink-mute);
  transition: transform var(--dur) var(--ease);
}
.r-journal__cats a:hover .r-journal__chevron { transform: translateX(3px); }

.r-journal__autres li + li { border-top: 1px dotted var(--r-ink-mute); }
.r-journal__autre {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: 1rem;
  align-items: center;
  padding-block: 1rem;
  text-decoration: none;
}
.r-journal__vignette { display: block; overflow: hidden; background: var(--lavis, var(--lavis-1)); }
.r-journal__vignette img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  transition: transform .8s var(--ease);
}
.r-journal__vignette--entier img { object-fit: contain; padding: .35rem; }
.r-journal__titre { color: var(--encre-1); font-size: var(--fs-sm); line-height: 1.45; }
.r-journal__autre:hover .r-journal__titre { text-decoration: underline; text-underline-offset: .2em; }
@media (hover: hover) {
  .r-journal__autre:hover img { transform: scale(1.06); }
}

/* ===================================================================
   31. La liste du journal et les pages de catégorie (gabarit G,
       direction « la revue de la maison », 25 septembre 2026)
   -------------------------------------------------------------------
   journal/ et category/<slug>/, rendues par outils/journal-listing.py.
   Une couverture (la une), des rubriques en tuiles, les deux suivants,
   puis les archives rangées par année. Préfixe .r-jl-.

   Repris sans copie : .r-grid et .r-card (section 11), .r-picto
   (section 30), @keyframes r-une-panneau (la une d'article), .reveal.
   Aucun reveal carte par carte. Seul JavaScript : la recherche de
   journal/ (bloc « Recherche du journal » de refonte.js).

   La couleur vient de la catégorie (data-rang, posé par le script),
   jamais de la position : .seq n'est plus sur la grille. Six couleurs,
   une par catégorie : DIY 1 violet, Entreprises 2 menthe, La marque 3
   corail, Montessori 4 jaune, Préparer 5 rose, Grandir 6 rouge.
   Aussi employé par la colonne des articles (section 30).
   =================================================================== */

[data-rang="1"] { --arc: var(--arc-1); --lavis: var(--lavis-1); --encre: var(--encre-1); --feutre: var(--feutre-1); }
[data-rang="2"] { --arc: var(--arc-2); --lavis: var(--lavis-2); --encre: var(--encre-2); --feutre: var(--feutre-2); }
[data-rang="3"] { --arc: var(--arc-3); --lavis: var(--lavis-3); --encre: var(--encre-3); --feutre: var(--feutre-3); }
[data-rang="4"] { --arc: var(--arc-4); --lavis: var(--lavis-4); --encre: var(--encre-4); --feutre: var(--feutre-4); }
[data-rang="5"] { --arc: var(--arc-5); --lavis: var(--lavis-5); --encre: var(--encre-5); --feutre: var(--feutre-5); }
[data-rang="6"] { --arc: var(--arc-6); --lavis: var(--lavis-6); --encre: var(--encre-6); --feutre: var(--feutre-6); }

.r-jl { padding-bottom: var(--sp-section); }

/* --- Le titre de la revue ---------------------------------------------- */
.r-jl-tete { padding-block: clamp(1.5rem, 4vw, 3rem) clamp(1.75rem, 3.5vw, 2.75rem); }
.r-jl-tete h1 { font-size: var(--fs-h1); line-height: 1; }
.r-jl-tete__ligne {
  display: flex; align-items: center; gap: 1rem;
  margin-top: clamp(1rem, 2vw, 1.5rem);
  font-size: var(--fs-sm); color: var(--r-ink-soft);
}
.r-jl-tete__ligne::after { content: ""; flex: 1; height: 1px; background: var(--r-rule); }
.r-journal-liste__h1 { display: flex; align-items: center; gap: .45em; }

/* --- La recherche (journal/ seulement) --------------------------------
   Le champ est un .r-champ (section 29) avec une loupe posée dedans.
   refonte.js masque les cartes par l'attribut hidden : la règle
   ci-dessous l'emporte sur les display des blocs (.r-jl-une en grille,
   .r-jl-seconds...). Une carte qui revient se fond à l'écran, rien
   n'anime sa disparition (elle quitte le flux aussitôt). */
.r-jl [hidden] { display: none; }
.r-jl-recherche { max-width: 32rem; margin-top: clamp(1.5rem, 3vw, 2rem); }
.r-jl-recherche__champ { position: relative; }
.r-jl-recherche__champ .r-picto {
  position: absolute; left: 1rem; top: 50%; transform: translateY(-50%);
  width: 1.25rem; height: 1.25rem; color: var(--r-ink-soft); pointer-events: none;
}
.r-jl-recherche .r-champ input { padding-left: 3rem; font-size: 1rem; }
.r-jl-recherche__etat:not(:empty) { margin-top: 1rem; font-size: var(--fs-sm); font-weight: 500; }
@keyframes r-jl-trouve { from { opacity: 0; transform: translateY(.5rem); } }
.js-anim .r-jl .is-trouve { animation: r-jl-trouve .4s var(--ease) both; }
.r-journal-liste__h1 .r-picto { width: .85em; height: .85em; stroke-width: 1.3; }

/* --- Les rubriques ------------------------------------------------------
   Sous 72 rem, le bandeau défile en lui-même (jamais la page) : deux
   tuiles et demie visibles à 320 px, un fondu à droite dit la suite. */
.r-jl-rubriques { margin-bottom: clamp(2.5rem, 5vw, 4rem); border-block: 1px solid var(--r-rule); }
.r-jl-rubriques ul {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(9.5rem, 1fr);
  overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.r-jl-rubriques ul::-webkit-scrollbar { display: none; }
@media (max-width: 71.99rem) {
  .r-jl-rubriques ul { mask-image: linear-gradient(to right, #000 82%, transparent); }
}
.r-jl-rubriques li { scroll-snap-align: start; }
.r-jl-rubriques li + li { border-left: 1px solid var(--r-rule-soft); }
.r-jl-rubrique {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; gap: .7rem;
  height: 100%; min-height: 7.75rem; padding: 1.15rem 1rem 1rem;
  text-decoration: none;
}
.r-jl-rubrique::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--lavis);
  clip-path: inset(100% 0 0 0);
  transition: clip-path var(--dur) var(--ease);
}
.r-jl-rubrique::after {
  content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 3px;
  background: var(--arc);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform var(--dur) var(--ease);
}
.r-jl-rubrique:hover::before, .r-jl-rubrique:focus-visible::before, .r-jl-rubrique[aria-current]::before { clip-path: inset(0); }
.r-jl-rubrique:hover::after, .r-jl-rubrique:focus-visible::after, .r-jl-rubrique[aria-current]::after { transform: none; }
.r-jl-rubrique .r-picto { width: 1.75rem; height: 1.75rem; stroke-width: 1.4; transition: transform var(--dur) var(--ease); }
.r-jl-rubrique:hover .r-picto { transform: translateY(-2px) rotate(-6deg); }
.r-jl-rubrique__nom {
  font-family: var(--rf-display); font-variation-settings: var(--rf-settings);
  font-size: 1.05rem; line-height: 1.2; text-wrap: balance;
}
.r-jl-rubrique[aria-current] .r-jl-rubrique__nom { font-weight: 600; }
.r-jl-rubrique__compte { margin-top: auto; font-size: var(--fs-micro); color: var(--r-ink-soft); font-variant-numeric: tabular-nums; }
/* « Tous les articles » : le filet est la suite des six couleurs. */
.r-jl-rubrique--tout {
  --lavis: var(--r-bg-pure);
  --arc: linear-gradient(to right, var(--arc-1) 0 16.66%, var(--arc-2) 0 33.33%, var(--arc-3) 0 50%,
         var(--arc-4) 0 66.66%, var(--arc-5) 0 83.33%, var(--arc-6) 0);
}
.r-jl-rubrique--tout .icon-arc { width: 1.75rem; height: 1.75rem; }

/* --- Ligne de catégorie et méta, communes aux trois niveaux ------------ */
.r-jl-cat { display: inline-flex; align-items: center; gap: .5rem; font-size: var(--fs-sm); font-weight: 500; color: var(--encre); }
.r-jl-cat .r-picto { width: 1.15rem; height: 1.15rem; color: inherit; }
.r-jl-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 0; font-size: var(--fs-sm); color: var(--r-ink-soft); }
/* Séparateur : une puce carrée de la couleur, comme dans l'article. */
.r-jl-meta > span + span::before {
  content: ""; display: inline-block; width: .3rem; height: .3rem;
  margin: 0 .65rem .15em; background: var(--arc);
}

/* --- La une --------------------------------------------------------------- */
.r-jl-une { display: grid; gap: clamp(2rem, 4vw, 2.5rem); margin-bottom: clamp(3rem, 6vw, 4.5rem); }
@media (min-width: 60rem) {
  .r-jl-une { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(3rem, 5vw, 5.5rem); align-items: center; }
}
.r-jl-une__media { position: relative; isolation: isolate; margin: 0 clamp(.75rem, 1.5vw, 1.25rem) clamp(.75rem, 1.5vw, 1.25rem) 0; }
.r-jl-une__media::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--lavis);
  transform: translate(clamp(.75rem, 1.5vw, 1.25rem), clamp(.75rem, 1.5vw, 1.25rem));
}
.js-anim .r-jl-une__media::before { animation: r-une-panneau .8s var(--ease) .15s both; }
.r-jl-une__media a { display: block; overflow: hidden; }
.r-jl-une__media img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform 1.2s var(--ease); }
.r-jl-une h2 { margin-top: 1rem; font-size: clamp(1.9rem, 3.6vw, 3rem); line-height: 1.1; text-wrap: balance; }
.r-jl-une h2 a { text-decoration: none; }
.r-jl-une__desc { margin-top: 1.25rem; max-width: 34rem; font-size: var(--fs-lg); line-height: 1.65; color: var(--r-ink-soft); }
.r-jl-une .r-jl-meta { margin-top: 1.25rem; }
.r-jl-lire {
  display: inline-flex; align-items: center; gap: .8rem; min-height: 44px; margin-top: 1.25rem;
  font-weight: 500; text-decoration: underline; text-decoration-color: var(--arc);
  text-decoration-thickness: 2px; text-underline-offset: .35em;
}
.r-jl-lire::after {
  content: ""; width: .5rem; height: .5rem;
  border-top: 2px solid currentColor; border-right: 2px solid currentColor;
  transform: rotate(45deg); transition: transform var(--dur) var(--ease);
}
.r-jl-une:hover .r-jl-lire::after { transform: translateX(4px) rotate(45deg); }
@media (hover: hover) { .r-jl-une:hover .r-jl-une__media img { transform: scale(1.03); } }

/* --- Les deux suivants ----------------------------------------------------- */
.r-jl-seconds {
  display: grid; gap: 2rem;
  padding-top: clamp(2rem, 4vw, 3rem); border-top: 1px solid var(--r-rule);
}
@media (min-width: 48rem) { .r-jl-seconds { grid-template-columns: 1fr 1fr; gap: clamp(2rem, 4vw, 4rem); } }
.r-jl-second article { display: grid; grid-template-columns: 7rem minmax(0, 1fr); gap: 1.25rem; align-items: center; }
@media (min-width: 60rem) { .r-jl-second article { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 1.75rem; } }
.r-jl-second h2 { margin-top: .5rem; font-size: clamp(1.15rem, 1.8vw, 1.45rem); line-height: 1.25; text-wrap: balance; overflow-wrap: anywhere; }
.r-jl-second h2 a { text-decoration: none; }
.r-jl-second .r-jl-meta { margin-top: .6rem; }

/* --- Les cartes d'archive ------------------------------------------------ */
@media (min-width: 60rem) { .r-grid--3 { grid-template-columns: repeat(3, 1fr); } }
.r-card--article .r-card__media img { aspect-ratio: 3 / 2; }
.r-jl-second .r-card__media img { aspect-ratio: 1; }
.r-card--entier .r-card__media img { object-fit: contain; padding: 1rem; }
.r-card--article .r-card__name { overflow-wrap: anywhere; }

/* --- La vignette : panneau de lavis qui glisse au survol --------------- */
.r-jl-vignette { position: relative; isolation: isolate; }
.r-jl-vignette::before {
  content: ""; position: absolute; inset: 0; z-index: -1; background: var(--lavis);
  transition: transform var(--dur) var(--ease);
}
.r-jl-vignette .r-card__media { background: var(--lavis); }
@media (hover: hover) {
  .r-card--article:hover .r-jl-vignette::before { transform: translate(.6rem, .6rem); }
}
.r-card--article:focus-within .r-jl-vignette::before { transform: translate(.6rem, .6rem); }
/* Le panneau suffit : pas de soulèvement de la carte (section 11). */
.r-card--article:hover { transform: none; }
.r-card--article:hover .r-card__name a,
.r-jl-second:hover h2 a,
.r-jl-une:hover h2 a {
  text-decoration: underline; text-decoration-color: var(--arc);
  text-decoration-thickness: 2px; text-underline-offset: .2em;
}

/* --- Les archives, par année --------------------------------------------- */
.r-jl-annee { margin-top: var(--sp-section); }
.r-jl-annee__tete { display: flex; align-items: baseline; gap: 1.25rem; margin-bottom: clamp(1.75rem, 3.5vw, 2.75rem); }
.r-jl-annee__tete h2 { font-size: clamp(2.75rem, 7vw, 5.5rem); line-height: .9; font-variant-numeric: lining-nums; }
.r-jl-annee__tete::after { content: ""; flex: 1; height: 1px; background: var(--r-rule); transform-origin: 0 50%; }
.js-anim .r-jl-annee__tete.reveal::after { transform: scaleX(0); transition: transform .9s var(--ease) .15s; }
.js-anim .r-jl-annee__tete.is-visible::after { transform: none; }

.r-jl .r-card--article .r-card__line { margin-top: .6rem; }
.r-jl .r-card--article .r-card__name { font-size: 1.2rem; }
.r-jl .r-card--article .r-jl-cat { margin-top: 1.1rem; }
.r-jl .r-card--article .r-jl-meta { margin-top: .5rem; }

/* Gardés : la liste des catégories en grille, avant le 25 septembre
   2026. Plus employée par journal-listing.py. */
.r-journal__nav { margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.r-journal__cats--grille { display: grid; gap: .25rem 1.5rem; }
@media (min-width: 40rem) { .r-journal__cats--grille { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 60rem) { .r-journal__cats--grille { grid-template-columns: repeat(3, 1fr); } }
.r-journal__compte { color: var(--r-ink-soft); font-weight: 400; }

@media (prefers-reduced-motion: reduce) {
  .r-jl-rubrique::before, .r-jl-rubrique::after, .r-jl-rubrique .r-picto,
  .r-jl-vignette::before, .r-jl-lire::after, .r-jl-une__media img { transition: none; }
  .r-jl-rubrique:hover .r-picto { transform: none; }
  .r-jl-une__media::before { animation: none; }
}

/* ===================================================================
   32. Le dépliant (a-propos/nos-engagements/, 25 septembre 2026)
   -------------------------------------------------------------------
   La .faq de la section 16, même balisage, même bouton, même
   JavaScript (main.js), même ouverture. Seule différence : un titre
   plus petit, parce que le dépliant vit dans la colonne de texte d'un
   .r-offset et non en pleine largeur. L'ouverture en fondu et le
   visibility: hidden du panneau fermé, d'abord écrits ici, sont
   remontés dans la .faq de base (section 16) le 25 septembre 2026.
   =================================================================== */

.faq--depli { margin-top: 1.75rem; }
.faq--depli .faq__q { padding-block: 1.1rem; }
.faq--depli .faq__label { font-size: 1.15rem; }
.faq--depli .faq__a p { max-width: none; padding-bottom: 1rem; }
.faq--depli .faq__a p:last-child { padding-bottom: 1.5rem; }
.faq--depli .faq__a a { overflow-wrap: anywhere; }
.faq--depli + p { margin-top: 2rem; }

/* ===================================================================
   33. Aller plus loin, les articles liés (25 septembre 2026)
   -------------------------------------------------------------------
   Dernière section de <main> des fiches produit et des pages de la
   maison, posée et actualisée par outils/journal-liens-produits.py
   (entre deux marqueurs, jamais à la main). Maillage interne : chaque
   page renvoie aux articles du journal qui parlent d'elle.

   Suréligne suivie d'un filet de la couleur du rang, titre et phrase
   dans un .r-head, puis une liste de lignes séparées par un filet
   pointillé : catégorie en capitales à gauche, titre exact de l'article
   à droite. Trois colonnes au-dessus de 72 rem, une en dessous ; sous
   30 rem la catégorie passe au-dessus du titre.

   La couleur de la catégorie vient de data-rang (section 31), comme
   partout dans le journal. Au survol, pas de lavis derrière le texte :
   l'encre du rouge (Grandir) est à 4,52:1 sur le fond et tomberait sous
   le seuil sur un lavis. Un trait de la couleur se déploie à gauche
   (transform), le titre se souligne. Aucun JavaScript.
   =================================================================== */

.r-liens .r-head { margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }

.r-liens__eyebrow {
  display: flex;
  align-items: center;
  gap: .75rem;
}
.r-liens__eyebrow::after {
  content: "";
  width: 2.5rem;
  height: 2px;
  background: var(--arc, var(--arc-1));
  transform-origin: left;
}
/* Le filet se trace avec l'entrée du bloc, comme le feutre du titre. */
.js-anim .reveal .r-liens__eyebrow::after {
  transform: scaleX(0);
  transition: transform .7s var(--ease) .22s;
}
.js-anim .reveal.is-visible .r-liens__eyebrow::after { transform: none; }

.r-liens__liste {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: clamp(1.5rem, 3vw, 2.5rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.r-liens__liste li { border-bottom: 1px dotted color-mix(in srgb, var(--r-ink) 35%, transparent); }

.r-liens__liste a {
  position: relative;
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: 1rem;
  align-items: baseline;
  min-height: 44px;
  padding: 1rem .5rem 1rem .9rem;
  color: var(--r-ink);
  text-decoration: none;
}
.r-liens__liste a::before {
  content: "";
  position: absolute;
  left: 0;
  top: .85rem;
  bottom: .85rem;
  width: 2px;
  background: var(--arc);
  transform: scaleY(0);
  transition: transform var(--dur) var(--ease);
}
.r-liens__liste a:hover::before,
.r-liens__liste a:focus-visible::before { transform: none; }

.r-liens__cat {
  font-size: var(--fs-micro);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--encre);
}
.r-liens__titre {
  font-size: var(--fs-base);
  line-height: 1.45;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1.5px;
  text-underline-offset: .25em;
  transition: text-decoration-color var(--dur) var(--ease);
}
.r-liens__liste a:hover .r-liens__titre,
.r-liens__liste a:focus-visible .r-liens__titre { text-decoration-color: currentColor; }

.r-liens__tout { margin-top: clamp(1.5rem, 3vw, 2.5rem); }
.r-liens__btn {
  gap: .75rem;
  padding-block: .75rem;
  text-align: center;
}
.r-liens__fleche {
  font-size: 1rem;
  letter-spacing: 0;
  transition: transform var(--dur) var(--ease);
}
.r-liens__btn:hover .r-liens__fleche { transform: translateX(4px); }

@media (max-width: 29.99rem) {
  .r-liens__liste a { grid-template-columns: minmax(0, 1fr); gap: .25rem; }
}
/* Une seule colonne mais assez de largeur : la catégorie tient sur une
   ou deux lignes au lieu de trois. */
@media (min-width: 30rem) and (max-width: 71.99rem) {
  .r-liens__liste a { grid-template-columns: 13rem minmax(0, 1fr); }
}
@media (min-width: 72rem) {
  .r-liens__liste { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
  .r-liens__liste a::before,
  .r-liens__titre,
  .r-liens__fleche { transition: none; }
}

/* ===================================================================
   34. Le journal sur l'accueil (25 septembre 2026)
   -------------------------------------------------------------------
   Section « Journal » de index.html, dernière de <main> après les
   questions, avant le socle, posée et actualisée par outils/journal-accueil.py
   (entre deux marqueurs, jamais à la main) : les trois derniers
   articles publiés et un bouton vers journal/.

   Repris sans copie : les cartes .r-card--article de journal/
   (section 31, couleur par data-rang), .r-grid--3, .r-head, le bouton
   de la section 33 (.r-liens__btn, flèche). Ne sont ajoutés ici que
   les espacements de carte que la section 31 réserve à .r-jl, et le
   défilement latéral sous 60 rem (trois cartes en deux colonnes
   laisseraient la troisième seule sur sa ligne). Aucun JavaScript.
   =================================================================== */

.r-accueil-journal .r-card--article .r-card__line { margin-top: .6rem; }
.r-accueil-journal .r-card--article .r-card__name { font-size: 1.2rem; }
.r-accueil-journal .r-card--article .r-jl-cat { margin-top: 1.1rem; }
.r-accueil-journal .r-card--article .r-jl-meta { margin-top: .5rem; }
.r-accueil-journal__tout { margin-top: clamp(2rem, 4vw, 3rem); }

/* Sous 60 rem, une rangée qui défile en elle-même (jamais la page),
   comme les rubriques de journal/ : toujours un bord de la carte
   suivante visible, un fondu à droite dit la suite. Le retrait bas et droit
   laisse la place au panneau de lavis qui glisse au survol. */
@media (max-width: 59.99rem) {
  .r-accueil-journal .r-accueil-journal__grille {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: min(82%, 17rem);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    padding: 0 .75rem .75rem 0;
    mask-image: linear-gradient(to right, #000 92%, transparent);
  }
  .r-accueil-journal__grille::-webkit-scrollbar { display: none; }
  .r-accueil-journal__grille > li { scroll-snap-align: start; }
}

/* --- Avis Certifies : ligne bandeau + sceau de section (genere) --- */
.r-topbar__avis{display:inline-flex;align-items:center;gap:.4rem}
.r-topbar__stars{color:#e6b34a;letter-spacing:.06em;font-size:.9em}
.r-avis-sceau{display:flex;flex-direction:column;align-items:center;gap:.75rem;margin-top:2.5rem}
.r-avis-sceau__widget{border:0;max-width:100%;width:160px;height:290px}
/* Avis : sceau officiel a gauche sur toute la hauteur, a droite le titre
   puis les trois avis. Empile sous 72rem. */
.r-avis-grid{display:grid;gap:1.5rem}
.r-avis-grid .r-avis-sceau{margin-top:0}
.r-avis-main .r-head{margin-bottom:clamp(1.5rem,3vw,2.5rem)}
@media (min-width:72rem){
  .r-avis-grid{grid-template-columns:1fr auto;align-items:start;gap:clamp(2.5rem,5vw,4.5rem)}
  .r-avis-grid .r-avis-main{order:1}
  .r-avis-grid .r-avis-sceau{order:2;align-items:flex-start;text-align:left}
}

/* Espace entre un bloc de points (cross-sell converti) et la grille de
   produits qui suit : sinon le dernier point colle aux cartes produit. */
.r-keypoints + .r-grid{margin-top:clamp(2.5rem,5vw,4rem)}

/* ==========================================================================
   Couleurs des pictogrammes du site, par symbole (et non par position) :
   un même pictogramme garde la même couleur partout. Contours dans la
   version foncée de la palette de la cliente (lisible sur blanc), aplats
   dans sa couleur vive, en transparence. Les pictogrammes du socle gardent
   l'encre unique voulue plus haut (.r-socle__points).
   ========================================================================== */
svg:has(> use[href="#jh-sans-plastique"]) { color: #6128FF; --jh-encre-lavande: #6128FF; --jh-lavis-lavande: rgba(97, 40, 255, .22); }
svg:has(> use[href="#jh-coton-bio"]) { color: #D63A22; --jh-encre-corail: #D63A22; --jh-lavis-corail: rgba(255, 95, 69, .35); }
svg:has(> use[href="#jh-latex"]) { color: #8A6708; --jh-encre-jaune: #8A6708; --jh-lavis-jaune: rgba(255, 198, 21, .45); }
.r-socle__points svg:has(> use) { color: var(--r-ink-soft); }
