/*
 * LES BLOCS.
 *
 * Une classe par intention, en francais. Rien n'est scope sur un identifiant
 * de generateur : un bloc se deplace d'une page a l'autre sans emporter de
 * feuille avec lui.
 *
 * LES CARTES ONT DISPARU
 *
 * La version precedente rangeait tout en cartes blanches a coins arrondis :
 * les prestations, les ateliers, les avis, les articles. Trois grilles de
 * cartes sur une page, c'est une seule idee de mise en page repetee, et c'est
 * ce qui donnait au site son air de gabarit. Ici chaque famille de contenu a
 * sa forme : des plaques pleine largeur pour les prestations, une liste a
 * grandes dates pour les ateliers, une citation seule pour les avis.
 */

/* ------------------------------------------------------------- ossature */

.enveloppe {
  width: 100%;
  max-width: 82rem;
  margin-inline: auto;
  padding-inline: var(--e-6);
}
@media (min-width: 62rem) { .enveloppe { padding-inline: var(--e-12); } }

.enveloppe--etroite { max-width: 52rem; }

.section { padding-block: var(--section); }

/* DEUX SECTIONS SUR LE MEME FOND N'EMPILENT PAS DEUX FOIS L'ESPACEMENT
 *
 * `padding-block` s'applique en haut ET en bas : entre deux sections, l'air
 * se double -- 288 px sur un grand ecran, plus d'un tiers d'ecran de vide.
 *
 * La ou le fond change, ce n'est pas un vide : les deux espacements sont a
 * l'interieur de deux bandes de couleurs differentes, la frontiere est une
 * ligne, et ils restent tels quels. La ou le fond ne change pas, l'air ne
 * separe plus rien : c'est un trou. La seconde section perd alors son
 * espacement du haut, et il reste un espacement de section entre les deux.
 *
 * Trois regles parce que CSS ne sait pas comparer deux fonds : il faut
 * nommer les trois cas de fond identique. */
.section:not(.section--haut):not(.section--jour) + .section:not(.section--haut):not(.section--jour),
.section--haut + .section.section--haut,
.section--jour + .section.section--jour {
  padding-top: 0;
}

/* LE REVERS CLAIR
 *
 * Il REDEFINIT les jetons, il ne corrige pas les classes une par une.
 *
 * C'est la seule facon qui tienne. Mesure faite : sur ce fond, l'encre du
 * monde sombre donne 1,05:1, sa version douce 1,03:1, son filet 1,00:1. Autant
 * dire rien. Chaque classe rattrapee a la main marchait, et toutes les autres
 * -- l'intitule d'une bande d'appuis, un filet de separation -- disparaissaient
 * en silence. Redefinir le jeton repare tout ce qui en descend, y compris ce
 * qui n'existe pas encore.
 *
 * L'accent change de valeur mais pas de teinte : #0A6155 est le meme
 * vert-sarcelle, assez fonce pour tenir sur du clair (6,45:1). La marque reste
 * reconnaissable, ce qui est la regle -- on ne desature pas une marque pour
 * l'adapter a un fond. */
.section--jour {
  --os:        var(--encre);
  --os-doux:   rgba(7, 26, 24, .70);
  --os-tenu:   rgba(7, 26, 24, .54);
  --voile:     rgba(7, 26, 24, .14);
  --vif:       #0A6155;
  --vif-sourd: #07463D;
  --nuit-haut: #E3E9E5;

  background: var(--jour);
  color: var(--encre);
}

/* Le bouton s'inverse : sur un fond clair, un aplat sombre porte mieux qu'un
   aplat de couleur, qui se disputerait avec le fond. */
.section--jour .bouton { background: var(--nuit); border-color: var(--nuit); color: var(--jour); }
.section--jour .bouton:hover { background: var(--vif); border-color: var(--vif); color: var(--jour); }
.section--jour .bouton__disque { background: rgba(237, 241, 238, .18); }

.section--haut { background: var(--nuit-haut); }

/* --------------------------------------------------------- typographie */

.titre-page    { font-size: var(--t-3xl); }
.titre-section { font-size: var(--t-2xl); }
.titre-bloc    { font-size: var(--t-xl); }
.titre-carte   { font-size: var(--t-l); letter-spacing: -0.02em; }

/* Le sur-titre est rationne : un pour trois sections au plus. Pose au-dessus
   de chaque titre, il donne a toutes les sections le meme rythme, et ce
   rythme-la est celui de tous les sites generes. */
.surtitre {
  display: block;
  margin-bottom: var(--e-4);
  color: var(--vif);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.chapo {
  max-width: var(--mesure);
  margin-top: var(--e-6);
  color: var(--os-doux);
  font-size: var(--t-l);
  line-height: 1.5;
}

.texte-mesure { max-width: var(--mesure); }
.texte-doux   { color: var(--os-doux); }
.centre       { text-align: center; }

.entete-section { max-width: 34ch; margin-bottom: var(--e-16); }

/* Un titre de section pose sur la grille editoriale garde la meme respiration
   qu'un titre ordinaire. Il l'avait perdue en changeant de conteneur, et
   l'image de la premiere plaque venait toucher le titre. */
.entete-grille { margin-bottom: var(--e-16); }

/* ------------------------------------------------------------- boutons */

.bouton {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-3) var(--e-8);
  border: 1px solid var(--vif);
  border-radius: var(--r-pilule);
  background: var(--vif);
  color: var(--nuit);
  font-family: var(--texte);
  font-size: var(--t-s);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  /* On nomme ce qui bouge. « all » ferait surveiller au navigateur des
     proprietes qu'on n'a pas voulu animer. */
  transition: background-color var(--v-court) var(--glisse),
              border-color var(--v-court) var(--glisse),
              color var(--v-court) var(--glisse),
              transform var(--v-court) var(--sortie);
}
.bouton:hover  { background: var(--vif-sourd); border-color: var(--vif-sourd); color: var(--nuit); }
/* Sans cet etat, le clic ne se sent pas, surtout au doigt. */
.bouton:active { transform: scale(0.97); }

/* LA FLECHE DANS SON CERCLE
   Une fleche posee nue a cote d'un mot est le reglage par defaut. Dans son
   propre disque, elle devient une piece de l'objet -- et au survol, c'est
   ELLE qui bouge, a l'interieur du bouton, plutot que le bouton entier qui
   se deforme. Le mouvement se passe dans la matiere. */
/* La marge droite se resserre SEULEMENT quand il y a un disque a loger. La
   version precedente la reduisait d'office et comptait sur une classe pour la
   rattraper : le bouton des evenements, qui ne passe pas par le gabarit, ne
   l'avait pas et se retrouvait de travers. Une regle qui depend de ce que
   l'element contient ne peut pas etre oubliee. */
.bouton:has(.bouton__disque) { padding-right: var(--e-2); }

.bouton__disque {
  display: grid;
  place-items: center;
  width: 1.75rem; height: 1.75rem;
  border-radius: var(--r-pilule);
  background: rgba(7, 26, 24, .14);
  transition: transform var(--v-court) var(--sortie), background-color var(--v-court) var(--glisse);
}
.bouton__disque svg { width: .7rem; height: .7rem; fill: none; stroke: currentColor; stroke-width: 1.75; }

@media (hover: hover) and (pointer: fine) {
  .bouton:hover .bouton__disque { transform: translate(2px, -2px); background: rgba(7, 26, 24, .22); }
}

.bouton--fantome { background: transparent; border-color: var(--voile); color: var(--os); }
.bouton--fantome:hover { background: transparent; border-color: var(--vif); color: var(--vif); }

.lien-fleche {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  color: var(--vif);
  font-size: var(--t-s);
  font-weight: 600;
  text-decoration: none;
}
.lien-fleche::after { content: "\2192"; transition: transform var(--v-court) var(--sortie); }
@media (hover: hover) and (pointer: fine) {
  .lien-fleche:hover::after { transform: translateX(0.3rem); }
}

/* ================================================== LES PLAQUES
   Une prestation par bande pleine largeur : l'image occupe une moitie et
   deborde jusqu'au bord de l'ecran, le texte tient l'autre. C'est la forme
   qui remplace les trois cartes alignees.

   L'alternance est bornee a deux : au troisieme « image a gauche, texte a
   droite », le procede se voit et la page devient un accordeon. La troisieme
   plaque passe donc en pleine largeur avec le texte pose dessus. */

/* Pas d'align-items ici : la valeur par defaut, « stretch », est ce qui fait
   que l'image occupe toute la hauteur de la bande. Centrer les deux colonnes
   laissait l'image a la hauteur de son contenu, et seul le min-height la
   sauvait -- elle ne rejoignait jamais le bas du texte. Le texte, lui, se
   centre tout seul plus bas. */
.plaque {
  display: grid;
  border-top: 1px solid var(--voile);
}

@media (min-width: 56rem) {
  .plaque { grid-template-columns: 1fr 1fr; gap: var(--e-16); }

  /* grid-row: 1 sur les deux, et ce n'est pas une precaution.
     Sans lui, le placement automatique suffit tant que l'ordre des colonnes
     suit l'ordre du document. Sur la plaque inversee il ne le suit plus :
     l'image est posee en colonne 2, le curseur a donc depasse la colonne 1 de
     la premiere ligne, et le texte est renvoye a la ligne suivante. L'image se
     retrouve en haut a droite et le texte dessous a gauche. */
  .plaque__visuel { grid-column: 1; grid-row: 1; }
  .plaque__texte  { grid-column: 2; grid-row: 1; align-self: center; padding-block: var(--e-24); padding-right: var(--e-12); }

  .plaque--inverse .plaque__visuel { grid-column: 2; }
  .plaque--inverse .plaque__texte  { grid-column: 1; padding-left: var(--e-12); padding-right: 0; }
}

/* Le min-height passe sur le conteneur, pas sur l'image : c'est lui qui doit
   porter la hauteur, l'image le remplit. */
.plaque__visuel { position: relative; overflow: hidden; min-height: 22rem; background: var(--nuit-haut); }
.plaque__visuel img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

/* Il y avait ici un zoom de 2 % au survol, sur 600 ms. Supprime : une image
   de cette taille est survolee des dizaines de fois par visite, l'effet ne se
   voyait pas, et 600 ms est le double du budget d'une interface. Quand une
   animation n'a pas d'autre raison que « c'est joli », on l'enleve avant de
   la reduire. */

.plaque__texte { padding-block: var(--e-12); }
.plaque__numero {
  display: block;
  margin-bottom: var(--e-4);
  color: var(--os-tenu);
  font-family: var(--titre);
  font-size: var(--t-s);
  letter-spacing: 0.1em;
}

/* La troisieme plaque : image pleine largeur, texte pose dedans. Elle casse
   l'alternance avant qu'elle ne devienne un tic. */
.plaque--pleine { display: block; position: relative; border-top: 0; }

/* Trois bandes pleine largeur qui se suivent se toucheraient sans rien pour
   les separer : le filet revient entre deux, jamais au-dessus de la
   premiere -- la, il doublerait celui du titre de section. */
.plaque--pleine + .plaque--pleine { border-top: 1px solid var(--voile); }
.plaque--pleine .plaque__visuel { min-height: 30rem; }
.plaque--pleine .plaque__visuel::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to right, rgba(7, 26, 24, .92) 0%, rgba(7, 26, 24, .72) 45%, rgba(7, 26, 24, .25) 100%);
}
.plaque--pleine .plaque__texte {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  max-width: 34rem;
  padding: var(--e-12) var(--e-6);
}
@media (min-width: 62rem) {
  .plaque--pleine .plaque__texte { padding-left: var(--e-24); }
}

/* ================================================== LA LISTE DES DATES
   Les ateliers ne sont pas des cartes : ce sont des rendez-vous. Une liste,
   avec la date en grand a gauche, comme un calendrier. */

.rendezvous { border-top: 1px solid var(--voile); }

.rendezvous__ligne {
  display: grid;
  gap: var(--e-3) var(--e-8);
  padding-block: var(--e-8);
  border-bottom: 1px solid var(--voile);
}
@media (min-width: 48rem) {
  .rendezvous__ligne { grid-template-columns: 14rem 1fr auto; align-items: baseline; }
}

.rendezvous__date {
  font-family: var(--titre);
  font-size: var(--t-l);
  letter-spacing: -0.02em;
}
.rendezvous__titre { font-size: var(--t-m); font-weight: 600; }
.rendezvous__texte { color: var(--os-doux); font-size: var(--t-s); max-width: 52ch; }

/* ================================================== LES AVIS
   Pas une grille de cartes. Une bande qui defile a la main, ou chaque avis
   occupe une largeur confortable. Sur un ecran etroit elle se fait glisser
   au doigt, ce que fait deja tout le monde. */

.avis-bande {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(85vw, 26rem);
  gap: var(--e-6);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--e-4);
  /* Le fil de defilement est masque : on est sur une bande de citations, pas
     sur un tableau de bord. */
  scrollbar-width: none;
}
.avis-bande::-webkit-scrollbar { display: none; }

/* LE DOUBLE LISERE
   Une carte posee a plat sur le fond avec un filet gris est le reglage par
   defaut. Ici, une coque tres legere contient un coeur d'une autre couleur,
   avec un rayon calcule pour que les deux courbes soient concentriques --
   sinon l'oeil voit deux arrondis qui se disputent. Un lisere clair en haut
   du coeur simule l'arete biseautee d'une plaque posee dans un cadre. */
.avis {
  scroll-snap-align: start;
  padding: 0.375rem;
  border: 1px solid rgba(232, 236, 233, .07);
  border-radius: 1.375rem;
  background: rgba(232, 236, 233, .03);
}

.avis__coeur {
  display: flex;
  flex-direction: column;
  gap: var(--e-6);
  height: 100%;
  padding: var(--e-8);
  /* 1.375rem de coque moins 0.375rem de marge : les courbes se suivent. */
  border-radius: 1rem;
  background: var(--nuit-haut);
  box-shadow: inset 0 1px 0 rgba(232, 236, 233, .10);
}
.avis__texte { margin: 0; font-size: var(--t-l); line-height: 1.45; letter-spacing: -0.01em; }
.avis__signature { margin-top: auto; color: var(--os-tenu); font-size: var(--t-s); }
.avis__portrait { width: 2.5rem; height: 2.5rem; border-radius: var(--r-pilule); object-fit: cover; }

/* ================================================== LES ARTICLES
   Une liste, pas une grille : trois cartes d'article de plus auraient fait
   la troisieme grille de cartes de la page. */

.journal { border-top: 1px solid var(--voile); }

.journal__entree {
  display: grid;
  gap: var(--e-4) var(--e-8);
  padding-block: var(--e-8);
  border-bottom: 1px solid var(--voile);
  text-decoration: none;
  color: inherit;
}
@media (min-width: 48rem) {
  .journal__entree { grid-template-columns: 8rem 1fr 14rem; align-items: start; }
}
.journal__date  { color: var(--os-tenu); font-size: var(--t-xs); letter-spacing: 0.08em; text-transform: uppercase; }
.journal__titre { font-size: var(--t-xl); }
.journal__resume{ color: var(--os-doux); font-size: var(--t-s); margin-top: var(--e-3); }
.journal__vignette { border-radius: var(--r-m); overflow: hidden; }
.journal__vignette img { aspect-ratio: 3 / 2; width: 100%; object-fit: cover; }

@media (hover: hover) and (pointer: fine) {
  .journal__entree { transition: background-color var(--v-court) var(--glisse); }
  .journal__entree:hover { background: var(--nuit-haut); }
}

/* ================================================== LA GRILLE TARIFAIRE
   Le nom a gauche, le prix a droite, alignes sur une colonne. Un seul filet
   entre deux lignes : dix lignes soulignees dix fois est le degrade le plus
   paresseux qui soit. */

/* Comme la fiche : l'enveloppe ne pose rien, la rubrique porte le rythme.
   Pas de filet ici -- la liste en a deja un, et un second trait 64 px plus
   haut aurait fait double barre sur la colonne de droite. */
.section-rubrique { padding-block: 0; }
.rubrique { padding-top: var(--e-16); padding-bottom: var(--e-12); }

.tarifs { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--voile); }

.tarif {
  display: grid;
  gap: var(--e-1) var(--e-8);
  grid-template-columns: 1fr auto;
  align-items: baseline;
  padding-block: var(--e-6);
  border-bottom: 1px solid var(--voile);
}
.tarif__nom    { margin: 0; font-size: var(--t-l); font-weight: 500; letter-spacing: -0.01em; }
.tarif__detail { grid-column: 1; margin: 0; color: var(--os-doux); font-size: var(--t-s); max-width: 60ch; }
/* Chiffres a chasse fixe : sur quatorze lignes, des chiffres proportionnels
   font onduler la colonne des prix, et l'oeil ne peut plus la balayer. */
.tarif__prix   { grid-column: 2; grid-row: 1; margin: 0; font-family: var(--titre); font-size: var(--t-l); white-space: nowrap; font-variant-numeric: tabular-nums; }
.tarif__lien   { grid-column: 2; margin: 0; }

/* ================================================== LA FICHE A ONGLETS */

/* L'enveloppe d'une fiche ne pose aucun espacement : deux fiches qui se
   suivent sont deux entrees d'une liste, pas deux sections. C'est la fiche
   qui porte le rythme, ci-dessous. */
.section-fiche { padding-block: 0; }

/* Le filet appartient a ce qui le suit : moins d'air au-dessus qu'en dessous,
   pour qu'il se lise comme le debut d'une fiche et non comme la fin de la
   precedente. */
.fiche { border-top: 1px solid var(--voile); padding-top: var(--e-16); padding-bottom: var(--e-12); }

/* La premiere fiche d'une rubrique suit le bandeau de la rubrique : le
   changement de fond separe deja, le filet ne ferait que doubler le trait. */
.section--haut + .section-fiche .fiche { border-top-color: transparent; }

.fiche__entete { display: grid; gap: var(--e-8); margin-bottom: var(--e-8); }
@media (min-width: 56rem) {
  .fiche__entete { grid-template-columns: 20rem 1fr; gap: var(--e-12); align-items: start; }
}
.fiche__visuel { border-radius: var(--r-m); overflow: hidden; }
.fiche__visuel img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.fiche__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--e-2) var(--e-6); margin-top: var(--e-4); color: var(--os-doux); font-size: var(--t-s); }
.fiche__prix { font-family: var(--titre); font-size: var(--t-l); color: var(--os); }

.fiche__onglets { display: flex; flex-wrap: wrap; gap: var(--e-6); border-bottom: 1px solid var(--voile); }
.fiche__onglet {
  padding: 0 0 var(--e-3);
  border: 0; border-bottom: 1px solid transparent;
  background: none;
  color: var(--os-tenu);
  font-family: var(--texte);
  font-size: var(--t-s);
  font-weight: 500;
  cursor: pointer;
  transition: color var(--v-court) var(--glisse), border-color var(--v-court) var(--glisse);
}
.fiche__onglet:hover { color: var(--os); }
.fiche__onglet[aria-selected="true"] { color: var(--vif); border-bottom-color: var(--vif); }

.fiche__panneau { padding-top: var(--e-8); max-width: var(--mesure); }
.fiche__panneau > h4 { margin-bottom: var(--e-3); font-family: var(--texte); font-size: var(--t-xs); font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--os-tenu); }

.fiche--interactive .fiche__panneau[hidden] { display: none; }
.fiche--interactive .fiche__panneau > h4 { display: none; }

/* ================================================== raccourcis, formulaire */

.raccourcis { display: flex; flex-wrap: wrap; gap: var(--e-2); }

.raccourci {
  padding: var(--e-2) var(--e-4);
  border: 1px solid var(--voile);
  border-radius: var(--r-pilule);
  color: var(--os-doux);
  font-size: var(--t-s);
  text-decoration: none;
  transition: border-color var(--v-court) var(--glisse), color var(--v-court) var(--glisse);
}
.raccourci:hover { border-color: var(--vif); color: var(--vif); }

.champ { display: flex; flex-direction: column; gap: var(--e-2); margin-bottom: var(--e-6); }
.champ__intitule { font-size: var(--t-s); color: var(--os-doux); }

.champ input, .champ textarea {
  width: 100%;
  padding: var(--e-3) 0;
  border: 0; border-bottom: 1px solid var(--voile);
  background: transparent;
  color: var(--os);
  font-family: var(--texte);
  font-size: var(--t-m);
  transition: border-color var(--v-court) var(--glisse);
}
.champ input:focus, .champ textarea:focus { outline: none; border-bottom-color: var(--vif); }
.champ textarea { resize: vertical; min-height: 6rem; }

/* ================================================== texte long */

.prose { max-width: var(--mesure); }
.prose h2 { margin-top: var(--e-16); margin-bottom: var(--e-4); font-size: var(--t-xl); }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin-top: var(--e-8); margin-bottom: var(--e-3); font-size: var(--t-l); }
.prose ul, .prose ol { margin: 0 0 var(--e-4); padding-left: var(--e-6); }
.prose li { margin-bottom: var(--e-2); }
.prose img { border-radius: var(--r-m); margin-block: var(--e-8); }

.article__voisins {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--e-4);
  margin-top: var(--e-16); padding-top: var(--e-8);
  border-top: 1px solid var(--voile);
}

/* ================================================== apparitions
   Un bloc qui entre par un fondu et deux pixels de montee. Une seule fois,
   au premier passage : une animation qui se rejoue a chaque defilement
   devient un tic nerveux. */

/* 500 ms, soit au-dela du budget de 300 ms d'une interface. C'est assume :
   ce n'est pas une interaction, c'est l'entree d'un contenu, vue une fois.
   La regle des 300 ms vise ce qu'on declenche et dont on attend la reponse. */
/* Le bloc arrive de loin : un flou de depart, en plus de la montee. C'est ce
   qui distingue une entree d'un simple changement d'opacite -- l'oeil lit une
   mise au point, pas un fondu.

   Le flou est reserve aux blocs de texte. Les plaques et les sections
   illustrees portent une image pleine largeur : la filtrer a chaque image
   d'animation ferait tomber la fluidite sur un telephone. Elles gardent la
   montee et le fondu, qui eux ne coutent rien. */
[data-revele] {
  opacity: 0;
  transform: translateY(1rem);
  filter: blur(5px);
  transition: opacity 700ms var(--glisse),
              transform 700ms var(--glisse),
              filter 700ms var(--glisse);
}
[data-revele].est-visible { filter: blur(0); }

/* Les blocs qui contiennent une image pleine largeur n'ont pas de flou. */
.plaque[data-revele],
.duo-portrait[data-revele],
.portrait[data-revele] { filter: none; }
[data-revele].est-visible { opacity: 1; transform: none; }

/* Un decalage de 60 ms entre les lignes d'une liste. En dessous de 30 ms il
   ne se voit pas, au-dela de 80 ms la derniere ligne se fait attendre.

   Des keyframes ici, et non une transition : c'est le seul moyen de decaler
   par animation-delay. La regle qui interdit les keyframes vise ce qu'on
   declenche souvent et qu'il faut pouvoir interrompre ; une entree qui ne
   joue qu'une fois n'a rien a interrompre. */
.rendezvous.est-visible .rendezvous__ligne { animation: entree 500ms var(--sortie) backwards; }
.rendezvous.est-visible .rendezvous__ligne:nth-child(2) { animation-delay: 60ms; }
.rendezvous.est-visible .rendezvous__ligne:nth-child(3) { animation-delay: 120ms; }
.rendezvous.est-visible .rendezvous__ligne:nth-child(4) { animation-delay: 180ms; }

@keyframes entree {
  from { opacity: 0; transform: translateY(0.5rem); }
}

/* ================================================== LE GRAIN
   Une surface sombre parfaitement plate donne deux defauts : les degrades y
   montrent leurs bandes, et l'ensemble parait synthetique. Un grain tres
   faible, fixe, corrige les deux.

   Le motif est genere par un filtre SVG en URI de donnees : aucun fichier a
   charger, et il tient en une ligne. Il ne capte aucun clic. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 300;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* Le grain couvre aussi les deux sections claires, et c'est voulu : une seule
   texture sur toute la page, sinon la limite entre le sombre et le clair se
   voit deux fois. A 3,5 % il ne se lit pas, il se sent.

   Il disparait pour qui a demande moins de transparence : ce reglage vient
   souvent d'une gene visuelle, et une texture superposee en fait partie. */
@media (prefers-reduced-transparency: reduce) {
  .grain { display: none; }
}

/* ================================================== divers */

.filet { height: 1px; border: 0; background: var(--voile); margin-block: var(--e-16); }

.hors-ecran {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ================================================== bandeau de page
   Les pages interieures ouvrent court : une photo, un titre, une phrase.
   Bien plus bas que le carrousel de l'accueil, qui lui est une destination ;
   ici on est deja en route, la page doit commencer vite. */

.bandeau {
  position: relative;
  display: grid;
  grid-template-areas: "pile";
  min-height: min(40dvh, 24rem);
  background: var(--nuit);
  overflow: hidden;
}

.bandeau__fond { grid-area: pile; position: relative; overflow: hidden; }
/* Meme raison que pour le carrousel : hors flux, sinon l'image impose sa
   hauteur native au bandeau. */
.bandeau__fond img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.bandeau__fond::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, var(--nuit) 0%, rgba(7, 26, 24, .72) 45%, rgba(7, 26, 24, .5) 100%);
}

.bandeau__contenu {
  grid-area: pile;
  align-self: end;
  position: relative; z-index: 1;
  padding-block: var(--e-24) var(--e-12);
}
.bandeau__contenu h1 { font-size: var(--t-2xl); max-width: 16ch; }

/* ================================================== portrait et contact
   Deux mises en page a part, pour ne pas refaire un « texte a cote d'une
   image » de plus. La regle est simple : deux sections de ce type au maximum
   par page, sinon la page devient un accordeon. */

.duo-portrait { display: grid; gap: var(--e-12); }
@media (min-width: 56rem) {
  .duo-portrait { grid-template-columns: 1fr 1.2fr; gap: var(--e-24); align-items: center; }
}
.duo-portrait__image { overflow: hidden; border-radius: var(--r-m); }
.duo-portrait__image img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }
.duo-portrait__texte .chapo { max-width: 54ch; }

.duo-contact { display: grid; gap: var(--e-16); }
@media (min-width: 56rem) {
  .duo-contact { grid-template-columns: 1fr 1fr; gap: var(--e-24); align-items: start; }
}

/* ================================================== LA GRILLE EDITORIALE
   Douze colonnes, et les sections n'occupent pas les memes.
 
   Jusqu'ici tout etait centre dans une enveloppe a marges egales : chaque
   section commencait au meme endroit, finissait au meme endroit, et la page
   avait le rythme d'un formulaire. Une composition se fait avec des appuis
   differents.
 
   La grille ne s'active qu'a partir de 62 rem. En dessous, tout est empile :
   une colonne unique est la bonne reponse sur un telephone, pas une grille
   ecrasee. */

.grille {
  display: grid;
  gap: var(--e-8);
  /* Une colonne, comme le dit le paragraphe ci-dessus -- et non quatre.
     Avec repeat(4, 1fr), les classes .c-* ne s'appliquant qu'a partir de
     62 rem, chaque bloc tombait dans une colonne d'un quart de l'ecran : sur
     un telephone, le titre « Prochains ateliers » et la frise se partageaient
     deux bandes de 90 px, et le formulaire de contact faisait de meme. Le
     texte descendait a un mot par ligne. */
  grid-template-columns: 1fr;
}
@media (min-width: 62rem) {
  .grille { grid-template-columns: repeat(12, 1fr); gap: var(--e-8) var(--e-6); }

  .c-1-5   { grid-column: 1 / 6; }
  .c-1-6   { grid-column: 1 / 7; }
  .c-1-7   { grid-column: 1 / 8; }
  .c-2-8   { grid-column: 2 / 9; }
  .c-4-13  { grid-column: 4 / 13; }
  .c-5-13  { grid-column: 5 / 13; }
  .c-6-13  { grid-column: 6 / 13; }
  .c-7-13  { grid-column: 7 / 13; }
  .c-tout  { grid-column: 1 / -1; }
}

/* Deborder l'enveloppe par la gauche ou la droite. C'est ce qui fait qu'une
   image touche le bord de l'ecran au lieu de s'arreter poliment a la marge. */
@media (min-width: 62rem) {
  .deborde-gauche { margin-left: calc(50% - 50vw); }
  .deborde-droite { margin-right: calc(50% - 50vw); }
}

/* ================================================== LE PORTRAIT
   L'image sort par la gauche, le texte se pose dessus. Un chevauchement dit
   que les deux appartiennent au meme geste ; deux blocs cote a cote disent
   seulement qu'ils sont voisins. */

.portrait { display: grid; gap: var(--e-8); }

@media (min-width: 62rem) {
  .portrait {
    grid-template-columns: repeat(12, 1fr);
    align-items: center;
    gap: 0;
  }
  /* Cinq colonnes, et pas de debord jusqu'au bord de l'ecran.
     Le portrait source fait 484 px de large : etale sur sept colonnes plus le
     debord, il etait affiche a plus de mille pixels, soit un agrandissement de
     deux fois. Ca se voyait. Sur cinq colonnes il tient a peu pres sa taille
     native.

     Le chevauchement reste : c'est lui qui distingue cette section d'un
     « texte a cote d'une image » de plus. Le jour ou un vrai portrait en
     1200 px arrive, le debord peut revenir. */
  .portrait__image {
    grid-column: 1 / 6;
    grid-row: 1;
  }
  .portrait__texte {
    grid-column: 5 / 13;
    grid-row: 1;
    z-index: 1;
    /* AUCUN PADDING VERTICAL, ET SEULEMENT LUI.
       Ce bloc a exactement la couleur de sa section -- il est pose sur le
       revers clair, et son fond vaut var(--jour). Son padding haut et bas ne
       se distingue donc pas de l'espacement de section : il s'y ajoutait en
       pur vide, et c'est ce vide qui se voyait au-dessus du titre et sous le
       dernier paragraphe.

       Le padding lateral reste, et il n'est pas decoratif : c'est lui qui,
       avec le fond opaque, fait chevaucher le bloc sur le portrait. Le mettre
       a zero ferait toucher le texte a la photo. */
    padding: 0 var(--e-16);
    background: var(--nuit);
    border-radius: var(--r-m);
  }
  /* Sur le revers clair, le bloc de texte prend la couleur du revers pour
     que le chevauchement se lise. */
  .section--jour .portrait__texte { background: var(--jour); }
}

.portrait__image img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
@media (min-width: 62rem) { .portrait__image img { aspect-ratio: 1 / 1; } }

/* ================================================== LA BANDE D'APPUIS
   Les ecoles et reseaux auxquels elle appartient. Ce n'est pas de la
   decoration : c'est ce qui repond a « pourquoi elle ». Une bande, famille de
   mise en page qui ne sert qu'ici. */

.appuis {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--e-4) var(--e-12);
  padding-block: var(--e-8);
  border-block: 1px solid var(--voile);
}
.appuis__intitule { color: var(--os-tenu); font-size: var(--t-xs); letter-spacing: 0.14em; text-transform: uppercase; }
.appuis__item { font-family: var(--titre); font-size: var(--t-l); letter-spacing: -0.02em; }

/* ================================================== LE TITRE DE RUBRIQUE COLLANT
   Sur une grille tarifaire de quatorze lignes, on oublie dans quelle
   categorie on se trouve. Le titre reste en vue pendant que les lignes
   defilent : c'est une aide a la lecture, pas un effet. */

@media (min-width: 62rem) {
  .rubrique { display: grid; grid-template-columns: 18rem 1fr; gap: var(--e-16); align-items: start; }
  .rubrique__titre { position: sticky; top: 7rem; }
}
.rubrique__titre h2 { font-size: var(--t-xl); }

/* Le prix devient un evenement typographique. Dans un tableau, un prix a la
   taille du texte courant se cherche ; ici il se voit. */
.tarif__prix { font-size: var(--t-xl); letter-spacing: -0.03em; }

/* ================================================== LE FORMULAIRE
   Pleine largeur, sur le fond profond, plutot qu'une troisieme section a deux
   colonnes egales. Les coordonnees passent en bande au-dessus. */

.contact-bande {
  display: grid;
  gap: var(--e-6);
  padding-block: var(--e-8);
  border-block: 1px solid var(--voile);
  margin-bottom: var(--e-16);
}
@media (min-width: 48rem) { .contact-bande { grid-template-columns: repeat(3, 1fr); } }
.contact-bande__intitule { display: block; margin-bottom: var(--e-2); color: var(--os-tenu); font-size: var(--t-xs); letter-spacing: 0.14em; text-transform: uppercase; }
.contact-bande p { margin: 0; }

/* Le duo texte / image des pages Soins et Accompagnement. Six sections de
   suite en « image a gauche, texte a droite » feraient un accordeon : c'est
   l'alternance, portee par --inverse, qui l'evite. */
.duo-portrait { display: grid; gap: var(--e-12); }
@media (min-width: 56rem) {
  .duo-portrait { grid-template-columns: 1fr 1.15fr; gap: var(--e-16); align-items: center; }
  .duo-portrait--inverse .duo-portrait__image { order: 2; }
}
.duo-portrait__image { overflow: hidden; border-radius: var(--r-m); }
.duo-portrait__image img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.duo-portrait__texte .chapo { max-width: 54ch; }

/* ================================================== LA FENETRE D'ANNONCE */

.popup-evenement {
  position: fixed;
  inset: 0;
  z-index: 200;   /* au-dessus de l'en-tete collante, qui monte a 100 */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--e-6);
}
.popup-evenement[hidden] { display: none; }

.popup-evenement__fond { position: absolute; inset: 0; background: rgba(4, 18, 15, .82); }

/* POURQUOI min-width ET min() -- LE CADRE DEBORDAIT DE L'ECRAN
   
   `max-width: 32rem` vaut 512 px : sur un telephone de 390, le cadre etait
   deja plus large que l'ecran avant meme de compter ses 96 px de marges
   interieures. L'affiche etait coupee a droite, et pas seulement en mode
   modification -- tout visiteur sur telephone voyait la moitie de l'annonce.
   
   Deux verrous, et il faut les deux :
   
     min-width: 0    un element flex ne descend pas sous sa taille min-content
                     par defaut. L'<img> en `width: 100%` y contribue avec sa
                     largeur NATIVE : le cadre refusait donc de retrecir, quel
                     que soit son max-width.
     min(32rem, 100%) le plafond suit la place reellement disponible.
   
   Les marges interieures suivent l'ecran : 3 rem de chaque cote sur 390 px de
   large, c'est un quart de la largeur mange par du vide. */
.popup-evenement__cadre {
  position: relative;
  min-width: 0;
  max-width: min(32rem, 100%);
  max-height: 88dvh;
  overflow-y: auto;
  padding: clamp(var(--e-6), 5vw, var(--e-12));
  border: 1px solid var(--voile);
  border-radius: var(--r-m);
  background: var(--nuit-haut);
  text-align: center;
}

.popup-evenement__fermer {
  position: absolute; top: var(--e-3); right: var(--e-4);
  border: 0; background: none;
  color: var(--os-tenu);
  font-size: 1.75rem; line-height: 1;
  cursor: pointer;
  transition: color var(--v-court) var(--glisse);
}
.popup-evenement__fermer:hover { color: var(--os); }

.popup-evenement__titre { margin-bottom: var(--e-6); font-size: var(--t-xl); }
.popup-evenement__texte { margin-bottom: var(--e-6); color: var(--os-doux); }
.popup-evenement__texte p:last-child { margin-bottom: 0; }
/* `max-width` en plus de `width` : sans lui, une image plus large que le cadre
   ressort par la droite au lieu de s'y ranger. */
.popup-evenement__image { width: 100%; max-width: 100%; height: auto; border-radius: var(--r-s); }

/* ============================================ LE MOUVEMENT AU DEFILEMENT
 *
 * Tout ce qui suit tourne sur une chronologie de defilement native. Deux
 * raisons de ne pas prendre de bibliotheque :
 *
 *   - une animation CSS liee au defilement tourne HORS du fil principal. Une
 *     bibliotheque, elle, calcule a chaque image sur ce fil, et perd des
 *     images pendant que la page charge ses photos -- exactement le moment ou
 *     l'on regarde ;
 *   - la plus courante pese 70 Ko, contre 54 Ko pour tout le site.
 *
 * La ou la chronologie n'existe pas encore -- Firefox a ce jour -- rien ne
 * s'anime, et tout reste a sa place finale. C'est le repli le plus sur : une
 * page immobile mais juste, jamais une page bloquee a l'etat de depart.
 */

@supports (animation-timeline: view()) {

  /* --- La parallaxe du carrousel -------------------------------------
     L'image monte plus lentement que la page. C'est la profondeur : le fond
     est loin, il defile moins vite. Elle est agrandie de 12 % pour avoir de
     la matiere a decouvrir en haut et en bas, sinon le bord apparait. */
  .carrousel__fond img {
    animation: parallaxe linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }

  @keyframes parallaxe {
    from { transform: scale(var(--parallaxe-zoom)) translateY(calc(var(--parallaxe) * -1)); }
    to   { transform: scale(var(--parallaxe-zoom)) translateY(var(--parallaxe)); }
  }

  /* --- Le titre s'efface en montant ----------------------------------
     Quand on quitte le carrousel, le texte part avant l'image : deux plans a
     deux vitesses, c'est ce qui fait la profondeur plutot qu'un simple
     defilement. */
  .carrousel__contenu {
    animation: depart linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 90%;
  }

  @keyframes depart {
    from { opacity: 1; transform: translateY(0); }
    to   { opacity: 0; transform: translateY(-3rem); }
  }

  /* --- La parallaxe des plaques --------------------------------------
     Deux fois plus discrete que celle du carrousel : ces images sont a cote
     du texte qu'on lit. */
  .plaque__visuel img {
    animation: parallaxe-douce linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }

  @keyframes parallaxe-douce {
    from { transform: scale(var(--parallaxe-douce-zoom)) translateY(calc(var(--parallaxe-douce) * -1)); }
    to   { transform: scale(var(--parallaxe-douce-zoom)) translateY(var(--parallaxe-douce)); }
  }
}

/* ============================================ LE TITRE, MOT PAR MOT
 *
 * Les mots montent l'un apres l'autre, par pas de 70 ms. Le decoupage se fait
 * cote serveur : le titre arrive deja en morceaux, il n'y a pas d'instant ou
 * l'on voit la phrase entiere sauter en pieces.
 *
 * Chaque mot est un bloc en ligne pour pouvoir se deplacer -- un <span> nu ne
 * se laisse pas transformer -- et le conteneur masque ce qui depasse par le
 * bas, ce qui donne l'impression que les mots sortent d'une fente.
 */
.mot {
  display: inline-block;
  animation: monte-mot 900ms var(--sortie) both;
  animation-delay: calc(var(--i, 0) * 70ms);
}

@keyframes monte-mot {
  from { opacity: 0; transform: translateY(0.9em) rotate(1.5deg); }
  to   { opacity: 1; transform: none; }
}

/* Moins d'animation : les mots apparaissent ensemble, sans deplacement. Le
   fondu reste, parce qu'il aide a comprendre que la page vient d'arriver. */
@media (prefers-reduced-motion: reduce) {
  .mot { animation: mot-simple 300ms var(--sortie) both; animation-delay: 0s; }
  @keyframes mot-simple { from { opacity: 0; } }
}

/* L'invite de lecture. La ligne entiere est cliquable ; ce mot est la pour le
   dire, comme le faisait le bouton « Lire la suite » de la version d'avant. */
.journal__invite {
  display: inline-block;
  margin-top: var(--e-3);
  color: var(--vif);
  font-size: var(--t-s);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.journal__invite::after {
  content: ' \2192';
  display: inline-block;
  transition: transform var(--v-court) var(--sortie);
}
@media (hover: hover) {
  .journal__entree:hover .journal__invite::after { transform: translateX(0.25em); }
}

/* ------------------------------------------------------------- note Google
   Le chiffre d'ensemble, sous le titre des temoignages.

   Pas une pastille : une ligne. Les etoiles, le nombre en gros, la phrase en
   petit -- c'est la composition d'une note de bas de page, pas d'un badge, et
   c'est ce qui la rend credible plutot que decorative.

   Les etoiles sont un seul SVG de cinq exemplaires du meme trace : cinq
   glyphes texte auraient pris la graisse et la chasse de la police du corps,
   et n'auraient pas tenu la couleur d'accent proprement. */
.note-google {
  display: inline-flex;
  align-items: baseline;
  gap: var(--e-3);
  margin-top: var(--e-6);
  color: var(--os);
  text-decoration: none;
}

.note-google__etoiles { align-self: center; line-height: 0; }
.note-google__etoiles svg { fill: var(--vif); display: block; }

.note-google__note {
  font-family: var(--titre);
  font-size: var(--t-xl);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
}

.note-google__texte {
  font-size: var(--t-s);
  color: var(--os-doux);
}

/* La fleche dit que le lien sort du site. En ::after et non dans le document :
   elle ne doit pas etre lue, ni se retrouver enregistree dans un texte. */
.note-google__texte::after {
  content: ' \2197';
  display: inline-block;
  transition: transform var(--v-court) var(--sortie);
}

@media (hover: hover) {
  .note-google:hover { color: var(--os); }
  .note-google:hover .note-google__texte { color: var(--os); }
  .note-google:hover .note-google__texte::after { transform: translate(0.15em, -0.15em); }
}

/* Sous 30rem, la phrase passe a la ligne plutot que de serrer les etoiles. */
@media (max-width: 30rem) {
  .note-google { flex-wrap: wrap; row-gap: var(--e-1); }
}
