/* ==========================================================================
   carnet.css — style « carnet de voyage » collé à la main
   --------------------------------------------------------------------------
   Papier kraft, couches déchirées, polaroïds scotchés, billets perforés,
   tampons ronds, cachets postaux, rosaces, grilles de points, épingles de
   carte et dessins au trait.

   Tout le décor est en CSS ou en SVG inline : aucune image de fond n'est
   téléchargée, seules les photos du voyage le sont.

   Utilisée par article-manic5.html — le carnet de route, page modèle des
   futurs articles de voyage.
   ========================================================================== */

/* Teinte d'en-tête qui identifie une page de voyage : reprend --sarcelle-pal
   et --sarcelle, déjà les couleurs d'accent des pages de voyages dans
   assets/css/refonte.css (couche d'harmonisation chargée par ce carnet)
   plutôt que d'inventer une couleur qui jurerait avec le reste du site. Les
   valeurs de repli (#ccdddc / #a4c4c3) sont les mêmes, au cas où refonte.css
   ne serait pas chargé. */
.minimal-header.voyage-teinte {
  background-color: var(--sarcelle-pal, #ccdddc);
  border-bottom-color: var(--sarcelle, #a4c4c3);
}

:root {
  --papier:       #e7dece;
  --papier-clair: #f2ece0;
  --kraft:        #cbb492;
  --kraft-fonce:  #b3986f;
  --encre:        #35322c;
  --encre-pale:   #6d6559;
  --vert:         #3c5148;
  --vert-pale:    #7d9287;
  --ruban:        #d9a08f;
  --ruban-vert:   #a8b5a0;
  --blanc:        #fffdf7;
  --rouge:        #a8503f;

  /* Teintes du dessin du R1S. Changer --r1s-carrosserie (et son ombre)
     suffit à repeindre la voiture sur les trois pages. */
  --r1s-carrosserie: #2f8fb5;
  --r1s-ombre:       #1f6d8c;
  --r1s-sombre:      #3b4145;
  --r1s-sombre2:     #262b2e;
  --r1s-vitre:       #c6d4db;
  --r1s-vitre2:      #aebfc8;
  --r1s-jante:       #c4cbcf;
  --r1s-pneu:        #2b2f32;
  --r1s-rouge:       #d3392f;
  --r1s-phare:       #f0f5f7;
  --r1s-contour:     #1a1f22;

  --script:  "Caveat", cursive;
  --main:    "Kalam", "Comic Sans MS", cursive;
  --affiche: "Playfair Display", Georgia, serif;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--main);
  color: var(--encre);
  line-height: 1.5;
  overflow-x: hidden;
  background-color: var(--papier);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23n)' opacity='0.17'/%3E%3C/svg%3E"),
    radial-gradient(ellipse at 15% 8%,  rgba(255,255,255,.42), transparent 55%),
    radial-gradient(ellipse at 88% 72%, rgba(150,125,90,.22), transparent 60%);
}

img { display: block; max-width: 100%; }
a { color: inherit; }

.page { width: min(1180px, 95vw); margin-inline: auto; padding: 2.2rem 0 4rem; }

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

.affiche {
  font-family: var(--affiche); font-weight: 400;
  font-size: clamp(2.6rem, 8vw, 6rem); line-height: .95;
  letter-spacing: .02em; text-transform: uppercase;
  color: var(--vert); margin: 0;
}
.affiche-petit {
  font-family: var(--affiche); font-weight: 400;
  font-size: clamp(1.3rem, 3.4vw, 2.2rem); line-height: 1.05;
  letter-spacing: .04em; color: var(--vert); margin: 0;
}
.script {
  font-family: var(--script); font-weight: 600;
  font-size: clamp(1.8rem, 4.6vw, 3.2rem); line-height: 1;
  color: var(--encre); margin: 0;
}
.manuscrit { font-family: var(--script); font-size: clamp(1.3rem, 2.4vw, 1.9rem); line-height: 1.15; margin: 0; }

/* repère de route : titre, ligne pointillée, panneaux, phrase de clôture,
   empilés sur toute la hauteur de la rangée (align-self:stretch au lieu
   d'utilisation) plutôt qu'un texte écrasé au milieu de deux photos. */
.signet-route { display: flex; flex-direction: column; align-items: center; justify-content: space-between; text-align: center; padding: 1.4rem .2rem; }
.signet-route .signet-ligne { flex: 1 1 auto; width: 0; min-height: 1.1rem; border-left: 2.5px dashed rgba(53,50,44,.4); }
.signet-route .signet-panneau {
  background: #fffdf7; border: 3px solid var(--encre); border-radius: 6px;
  padding: .3rem .65rem; font-family: var(--main); font-weight: 700; font-size: 1.15rem;
  color: var(--encre); box-shadow: 1px 2px 5px rgba(55,45,30,.18); flex: none;
}
.etape {
  font-family: var(--main); font-weight: 700;
  font-size: .78rem; letter-spacing: .26em; text-transform: uppercase; margin: 0;
}
.petit { font-size: .84rem; color: var(--encre-pale); line-height: 1.5; }
.corps { font-size: .92rem; line-height: 1.62; }

/* ---------- couche de papier déchiré ---------- */

.dechire {
  position: relative;
  background: var(--papier-clair);
  padding: clamp(1.2rem, 3vw, 2.2rem);
  box-shadow: 2px 5px 16px rgba(55,45,30,.20);
  clip-path: polygon(
    0% 2%, 6% 0%, 19% 3%, 33% 0%, 48% 2%, 62% 0%, 77% 3%, 91% 0%, 100% 2%,
    99% 18%, 100% 34%, 98% 52%, 100% 68%, 99% 84%, 100% 98%,
    88% 100%, 72% 97%, 58% 100%, 43% 98%, 27% 100%, 12% 97%, 0% 100%,
    1% 82%, 0% 66%, 2% 50%, 0% 33%, 1% 17%
  );
}
.dechire.vert  { background: var(--vert); color: var(--papier-clair); }
.dechire.vert .petit { color: rgba(242,236,224,.78); }
.dechire.kraft { background: linear-gradient(160deg, var(--kraft), var(--kraft-fonce)); color: #453a2b; }

/* ---------- photos ---------- */

.polaroid { background: var(--blanc); padding: 11px 11px 0; box-shadow: 3px 6px 16px rgba(55,45,30,.28); position: relative; }
.polaroid img { width: 100%; aspect-ratio: 1/1; object-fit: cover; }
.polaroid figcaption { font-family: var(--script); font-size: 1.22rem; text-align: center; padding: .45rem 0 .7rem; }
.polaroid::before {
  content: ""; position: absolute; top: -12px; left: 50%;
  width: 78px; height: 24px; transform: translateX(-50%) rotate(-3deg);
  background: var(--ruban); opacity: .8; box-shadow: 0 1px 3px rgba(55,45,30,.2);
}
.polaroid.ruban-vert::before { background: var(--ruban-vert); }
.polaroid.ruban-g::before { left: 20%; transform: translateX(-50%) rotate(-10deg); }
.polaroid.ruban-d::before { left: 80%; transform: translateX(-50%) rotate(8deg); }
/* sans légende : la marge basse d'un polaroid vient normalement du
   figcaption ; sans lui, on la garde quand même pour conserver l'épaisse
   bande blanche du bas typique d'un polaroid, plutôt qu'une photo coupée net. */
.polaroid.sans-legende { padding-bottom: 20px; }

/* grille de polaroids (sans légende) : trois colonnes, deux rangées pour six
   photos — chacune garde son ruban adhésif plutôt que d'être une simple
   vignette dans une grille compacte. */
.grille-polaroids { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px 16px; }
.grille-polaroids figure { margin: 0; }
@media (max-width: 860px) {
  .grille-polaroids { grid-template-columns: repeat(2, 1fr); }
}

/* mur de photos en quinconce : deux rangées de 3, la seconde décalée d'une
   pleine largeur de photo (25% du mur) — voir le commentaire au lieu
   d'utilisation dans le HTML pour le calcul.
   Pas de fond ni de padding partagés : sur un mur en quinconce, ce fond
   commun dessine deux grands rectangles blancs vides (en haut-gauche et
   bas-droite, là où l'autre rangée ne s'étend pas) — plus laid qu'utile.
   Chaque photo porte donc son propre contour blanc et son ombre. */
.mur-photos .ligne { display: flex; gap: 10px; width: 75%; }
.mur-photos .ligne + .ligne { margin-top: 10px; }
.mur-photos .ligne:first-child { margin-left: 25%; }
.mur-photos .ligne img {
  flex: 1 1 0; min-width: 0; width: 100%; aspect-ratio: 4/3; object-fit: cover;
  background: var(--blanc); padding: 6px; box-shadow: 2px 4px 13px rgba(55,45,30,.24);
  box-sizing: border-box;
}

/* mur 2 + 1 : deux photos côte à côte au format horizontal, la 3e en
   dessous, à demi-largeur — plutôt que 3 photos carrées serrées sur une
   seule rangée, ça laisse les 2 premières s'agrandir dans l'espace resté
   vide sous une rangée trop courte pour la hauteur qui lui était réservée. */
.mur-2plus1 .ligne-haut { display: flex; gap: 10px; }
.mur-2plus1 .ligne-bas { margin: 10px auto 0; width: calc(50% - 5px); }
.mur-2plus1 .ligne-haut img,
.mur-2plus1 .ligne-bas img {
  width: 100%; aspect-ratio: 3/2; object-fit: cover;
  background: var(--blanc); padding: 6px; box-shadow: 2px 4px 13px rgba(55,45,30,.24);
  box-sizing: border-box;
}
.mur-2plus1 .ligne-haut img { flex: 1 1 0; min-width: 0; }

/* ---------- petit traversier animé ----------
   Comble le vide sous les 3 photos carrées, bien plus courtes que la vidéo
   à côté. Un seul traversier (pas de 2e copie comme la voiture) : il
   traverse rarement, et laisser un vrai blanc entre deux passages convient
   mieux à un traversier qu'à une route où on veut du trafic continu. */
.piste-eau { position: relative; height: clamp(120px, 14vw, 170px); margin-top: 1rem; overflow: hidden; border-radius: 4px; }
.piste-eau .eau-fond { position: absolute; inset: 0; width: 100%; height: 100%; }

.piste-eau .traversier-forme { position: absolute; bottom: 14%; width: clamp(90px, 16%, 150px); animation: vogue-droite 42s linear infinite; }
.piste-eau .traversier-forme svg { display: block; width: 100%; height: auto; overflow: visible; }
@keyframes vogue-droite { from { left: -22%; } to { left: 118%; } }

.piste-eau .mouette { position: absolute; }
.piste-eau .mouette svg { display: block; width: 100%; height: 100%; overflow: visible; }
.piste-eau .mouette .aile { transform-box: fill-box; transform-origin: center; animation: battre-aile .7s ease-in-out infinite alternate; }
@keyframes battre-aile { from { transform: scaleY(1); } to { transform: scaleY(.35); } }

.piste-eau .mouette-1 { top: 18%; left: 20%; width: 34px; animation: planer-1 6s ease-in-out infinite; }
.piste-eau .mouette-2 { top: 10%; left: 55%; width: 26px; animation: planer-2 7.5s ease-in-out infinite; }
.piste-eau .mouette-3 { top: 30%; left: 72%; width: 30px; animation: planer-3 5.5s ease-in-out infinite; }
@keyframes planer-1 { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(18px,-14px); } }
@keyframes planer-2 { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(-14px,10px); } }
@keyframes planer-3 { 0%, 100% { transform: translate(0,0); } 50% { transform: translate(12px,12px); } }

@media (prefers-reduced-motion: reduce) {
  .piste-eau .traversier-forme { animation: none; left: 40%; }
  .piste-eau .mouette, .piste-eau .mouette .aile { animation: none; }
}

/* ---------- bande « baleines » ----------
   Même grammaire que .piste-eau (fond d'eau, silhouettes qui traversent,
   mouettes au-dessus), mais peuplée de baleines. Elle ferme la sous-partie
   du CIMM : posée en column-span, elle occupe toute la largeur sous les
   colonnes et comble le bas irrégulier de la maçonnerie. */
.piste-baleines {
  position: relative;
  height: clamp(140px, 16vw, 200px);
  margin: 1.1rem 0 .4rem;
  overflow: hidden;
  border-radius: 4px;
}
.mur-dense > .piste-baleines { column-span: all; }
.piste-baleines .eau-fond { position: absolute; inset: 0; width: 100%; height: 100%; }

.piste-baleines .baleine { position: absolute; }
.piste-baleines .baleine svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Chaque baleine combine DEUX animations : le deplacement horizontal (left)
   et la remontee en surface (margin-bottom). Le souffle, plus bas, partage la
   duree et le delai de la remontee, pour partir exactement au sommet. */
.piste-baleines .b-1 { --rem: 56px; bottom:  8%; width: clamp(110px, 17%, 180px);
  animation: nage-droite 40s linear infinite, remonte 9s ease-in-out infinite; }
.piste-baleines .b-2 { --rem: 88px; bottom:  2%; width: clamp( 76px, 11%, 125px); opacity: .68;
  animation: nage-droite 56s linear infinite, remonte 11s ease-in-out infinite;
  animation-delay: -20s, -3s; }
.piste-baleines .b-3 { --rem: 62px; bottom: 21%; width: clamp( 58px,  9%,  95px); opacity: .45;
  animation: nage-gauche 48s linear infinite, remonte 10s ease-in-out infinite;
  animation-delay: 0s, -6s; }
.piste-baleines .b-4 { --rem: 70px; bottom: 13%; width: clamp( 70px, 10.5%, 118px); opacity: .58;
  animation: nage-gauche 62s linear infinite, remonte 12s ease-in-out infinite;
  animation-delay: -26s, -8.5s; }

/* SENS. Le dessin, tel quel, regarde vers la GAUCHE : l'oeil est a gauche du
   viewBox (cx=36) et la caudale a droite (x=158-202). Ce sont donc les baleines
   qui se deplacent vers la DROITE qu'il faut retourner — celles qui n'ont PAS
   la classe « gauche ». La regle inverse faisait nager les quatre a reculons.
   Retournement statique sur le <svg> : dans l'animation, il entrerait en
   conflit avec les transformations du corps et du souffle. */
.piste-baleines .baleine:not(.gauche) svg { transform: scaleX(-1); }

/* la remontee vers la surface, puis la replongee */
@keyframes remonte {
  0%, 40%   { margin-bottom: 0; }
  60%, 78%  { margin-bottom: var(--rem, 60px); }
  100%      { margin-bottom: 0; }
}
@keyframes nage-droite { from { left: -26%; } to { left: 122%; } }
@keyframes nage-gauche { from { left: 122%; } to { left: -26%; } }

/* le corps ondule doucement, comme un animal qui respire en nageant */
.piste-baleines .corps { transform-box: fill-box; transform-origin: center; animation: onduler 3.6s ease-in-out infinite; }
@keyframes onduler {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-4px) rotate(-1.6deg); }
}

/* le souffle, qui ne part que de temps en temps */
.piste-baleines .souffle { transform-box: fill-box; transform-origin: bottom center; animation: souffle-court 6s ease-out infinite; }
@keyframes souffle-court {
  0%, 56%   { opacity: 0;   transform: scaleY(.12); }
  64%       { opacity: .95; transform: scaleY(1); }
  74%       { opacity: .75; transform: scaleY(1.14); }
  84%       { opacity: .2;  transform: scaleY(1.3); }
  100%      { opacity: 0;   transform: scaleY(1.34); }
}
.piste-baleines .b-1 .souffle { animation-duration:  9s; }
.piste-baleines .b-2 .souffle { animation-duration: 11s; animation-delay: -3s; }
.piste-baleines .b-3 .souffle { animation-duration: 10s; animation-delay: -6s; }
.piste-baleines .b-4 .souffle { animation-duration: 12s; animation-delay: -8.5s; }

.piste-baleines .mouette { position: absolute; }
.piste-baleines .mouette svg { display: block; width: 100%; height: 100%; overflow: visible; }
.piste-baleines .mouette .aile { transform-box: fill-box; transform-origin: center; animation: battre-aile .7s ease-in-out infinite alternate; }
.piste-baleines .mouette-1 { top: 14%; left: 16%; width: 32px; animation: planer-1 6.5s ease-in-out infinite; }
.piste-baleines .mouette-2 { top:  8%; left: 48%; width: 24px; animation: planer-2 8s   ease-in-out infinite; }
.piste-baleines .mouette-3 { top: 22%; left: 78%; width: 28px; animation: planer-3 5.8s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .piste-baleines .baleine { animation: none; left: 30%; }
  .piste-baleines .b-2 { left: 62%; }
  .piste-baleines .b-3 { left: 8%; }
  .piste-baleines .b-4 { left: 78%; }
  .piste-baleines .corps, .piste-baleines .souffle,
  .piste-baleines .baleine,
  .piste-baleines .mouette, .piste-baleines .mouette .aile { animation: none; }
  .piste-baleines .souffle { opacity: .6; }
}

.photo { background: var(--blanc); padding: 7px; box-shadow: 2px 4px 13px rgba(55,45,30,.24); }
.photo img { width: 100%; object-fit: cover; }
.photo video { display: block; width: 100%; object-fit: cover; background: #000; }
.photo-nue img { width: 100%; object-fit: cover; box-shadow: 2px 4px 13px rgba(55,45,30,.24); }

/* bande de photos type planche-contact */
.bande-photos { display: grid; grid-auto-flow: column; gap: 6px; background: var(--blanc); padding: 7px; box-shadow: 2px 4px 13px rgba(55,45,30,.24); }
.bande-photos img { width: 100%; aspect-ratio: 1/1; object-fit: cover; }
/* variante 2×2 : mêmes photos, deux fois plus grandes chacune — l'espace
   total occupé ne change pas, seule la répartition (2 rangées de 2 plutôt
   qu'une rangée de 4) donne plus de surface à chaque image. */
.bande-photos.g2 { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); }

.grille-photos { display: grid; gap: 9px; }
.grille-photos img { width: 100%; aspect-ratio: 1/1; object-fit: cover; box-shadow: 2px 3px 10px rgba(55,45,30,.22); }
.g4 { grid-template-columns: repeat(4, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g2 { grid-template-columns: repeat(2, 1fr); }

/* ---------- mur dense (page « album ») ----------
   Inspiré des pages de voyage très remplies : les photos se touchent
   presque, les orientations alternent (portrait / paysage), et rien ne
   laisse de grand blanc. Utilisé par article-manic5.html.

   Empilement en colonnes (masonry) et non en grille : avec une grille, une
   rangée prend la hauteur de son plus grand élément et laisse un trou sous
   tous les autres — exactement le « vide » qu'on veut éviter. En colonnes,
   chaque élément se cale sous le précédent quelle que soit sa hauteur, donc
   portraits et paysages se mélangent sans laisser de blanc.
   .pleine fait déborder un élément sur toute la largeur (image d'ouverture). */
.mur-dense { column-count: 4; column-gap: 12px; }
.mur-dense > * { break-inside: avoid; margin: 0 0 12px; display: block; width: 100%; }
/* Image d'ouverture pleine largeur : hauteur plafonnée plutôt que ratio
   libre — une photo 4/3 étirée sur 1180 px ferait 885 px de haut et
   écraserait toute l'étape. En bandeau, elle ouvre sans dominer. */
/* Intertitre à l'intérieur d'une étape : sépare un long mur en sous-parties
   thématiques (le village, l'hôtel, la chapelle…). `column-span: all` casse
   volontairement le flux des colonnes — c'est ce qui crée la respiration et
   empêche deux thèmes de se retrouver côte à côte dans la même colonne. */
.mur-dense > .sous-partie {
  column-span: all;
  margin: 26px 0 16px;
  display: flex;
  align-items: baseline;
  gap: .8rem;
}
.mur-dense > .sous-partie:first-child { margin-top: 0; }
.sous-partie .mot {
  font-family: var(--script);
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  line-height: 1;
  color: var(--encre);
  flex: none;
}
.sous-partie .trait-fin {
  flex: 1 1 auto;
  height: 1px;
  background: currentColor;
  opacity: .22;
}
.sous-partie .compte {
  font-family: var(--main);
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--encre-pale);
  flex: none;
}
@media (max-width: 700px) {
  .mur-dense > .sous-partie { margin: 18px 0 12px; }
  .sous-partie .compte { display: none; }
}

.mur-dense > .pleine { column-span: all; margin-bottom: 26px; }
/* `d12` vient du vocabulaire de grille (« douze colonnes sur douze ») et
   n'avait aucun effet dans un conteneur multi-colonnes : la bande de
   doodles de la route 389 se retrouvait comprimee dans une colonne de
   286 px, haute de 416 px. On lui donne l'effet qu'elle annonce. */
.mur-dense > .d12 { column-span: all; }
.mur-dense > .pleine img { aspect-ratio: auto; height: clamp(240px, 32vw, 430px); }
/* Pas d'inclinaison sur une image pleine largeur. Deux raisons, mesurees :
   1) a ~1180 px de large, 1,4° deplace chaque coin de ~15 px en hauteur — la
      marge basse ne les rattrapait pas et le cadre blanc mordait sur le texte
      juste en dessous (4 px de chevauchement sur les 5 bandeaux) ;
   2) a cette largeur l'inclinaison ne se lit plus comme « pose a la main »
      mais comme un defaut d'alignement. Le charme du carnet vient des petites
      photos de travers, pas des bandeaux. */
.mur-dense > .pleine.r-g,
.mur-dense > .pleine.r-d,
.mur-dense > .pleine.r-g-f,
.mur-dense > .pleine.r-d-f,
.mur-dense > .pleine.r-g-ff,
.mur-dense > .pleine.r-d-ff { transform: none; }
.mur-dense img { display: block; width: 100%; object-fit: cover; }
/* Rotations adoucies dans le mur : à cette densité, les 5° de .r-*-f font
   mordre les coins sur les voisins. On garde l'inclinaison « posé à la
   main », sans collision. */
.mur-dense .r-g, .mur-dense .r-g-f, .mur-dense .r-g-ff { transform: rotate(-1.4deg); }
.mur-dense .r-d, .mur-dense .r-d-f, .mur-dense .r-d-ff { transform: rotate(1.4deg); }
@media (max-width: 1100px) { .mur-dense { column-count: 3; } }
.mur-dense .cadre {
  background: var(--blanc); padding: 6px;
  box-shadow: 2px 4px 12px rgba(55,45,30,.22);
}
.mur-dense .nu img { box-shadow: 2px 4px 12px rgba(55,45,30,.22); }
.d2 { grid-column: span 2; } .d3 { grid-column: span 3; }
.d4 { grid-column: span 4; } .d5 { grid-column: span 5; }
.d6 { grid-column: span 6; } .d7 { grid-column: span 7; }
.d8 { grid-column: span 8; } .d12 { grid-column: span 12; }
.mur-dense .v img { aspect-ratio: 3/4; }
.mur-dense .p img { aspect-ratio: 4/3; }
.mur-dense .c img { aspect-ratio: 1/1; }
.mur-dense .large img { aspect-ratio: 16/9; }
/* légende manuscrite sous une photo du mur */
.mur-dense figcaption {
  font-family: var(--script); font-size: 1.05rem; line-height: 1.15;
  color: var(--encre-pale); padding-top: .3rem;
}
@media (max-width: 860px) { .mur-dense { column-count: 2; } }
@media (max-width: 560px) { .mur-dense { column-count: 1; } }

/* Bandeau d'étape : gros titre façon affiche, avec le numéro d'étape et un
   filet — c'est lui qui rythme la lecture chronologique de l'album. */
/* flex-wrap indispensable : sans lui, une mention de lieu un peu longue
   (« Baie-Sainte-Catherine → Tadoussac ») pousse la ligne au-delà du
   viewport sur mobile et fait déborder toute la page de 125 px. */
.etape-titre { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem .9rem; margin: 0 0 .7rem; }
.etape-titre .num {
  font-family: var(--main); font-weight: 700; font-size: .82rem;
  letter-spacing: .22em; color: var(--vert);
  border: 2px solid var(--vert); border-radius: 3px;
  padding: .12rem .5rem; flex: none;
}
.etape-titre h2 {
  font-family: var(--affiche); font-weight: 400;
  font-size: clamp(1.8rem, 4.4vw, 3.1rem); line-height: 1;
  letter-spacing: .02em; color: var(--encre); margin: 0;
}
.etape-titre .filet { flex: 1 1 auto; height: 0; border-top: 1.5px solid rgba(53,50,44,.28); }
.etape-lieu { font-family: var(--main); font-size: .74rem; letter-spacing: .2em; text-transform: uppercase; color: var(--encre-pale); flex: 0 1 auto; min-width: 0; }
/* Sur mobile le titre passe sur deux lignes : le filet disparaît (il n'a
   plus de place utile) et le lieu prend sa propre ligne. */
@media (max-width: 700px) {
  .etape-titre .filet { display: none; }
  .etape-lieu { flex: 1 0 100%; letter-spacing: .14em; }
}

/* ---------- bulle manuscrite ---------- */

.bulle {
  display: inline-block; position: relative;
  font-family: var(--script); font-size: 1.4rem; line-height: 1;
  padding: .68rem 1.35rem;
  border: 2px solid var(--encre);
  border-radius: 48% 52% 47% 53% / 58% 44% 56% 42%;
  background: rgba(255,253,247,.6);
}
.bulle::after {
  content: ""; position: absolute; left: 26%; bottom: -12px;
  width: 14px; height: 14px;
  border-right: 2px solid var(--encre); border-bottom: 2px solid var(--encre);
  background: rgba(255,253,247,.6);
  transform: rotate(38deg) skew(-8deg); border-radius: 0 0 4px 0;
}

/* ---------- billet perforé ---------- */

.billet {
  background: var(--papier-clair); position: relative;
  padding: .95rem 1.1rem .95rem 1.6rem;
  box-shadow: 2px 4px 12px rgba(55,45,30,.22);
  border-left: 2px dashed rgba(53,50,44,.35);
}
.billet::before {
  /* perforation le long du bord gauche */
  content: ""; position: absolute; left: -6px; top: 0; bottom: 0; width: 12px;
  background-image: radial-gradient(circle at 6px 6px, var(--papier) 4.5px, transparent 5px);
  background-size: 12px 14px;
}
.billet .etape { color: var(--encre-pale); }
.billet .ref { font-family: var(--main); font-weight: 700; font-size: 1.02rem; letter-spacing: .04em; }

/* ---------- tampon rond ---------- */

.tampon { color: var(--vert-pale); width: 132px; }
.tampon svg { width: 100%; height: auto; display: block; }
.tampon text { font-family: var(--main); font-size: 11px; letter-spacing: 2.6px; fill: currentColor; text-transform: uppercase; }

/* ---------- cachet postal ---------- */

.cachet { color: rgba(53,50,44,.45); width: 190px; }
.cachet svg { width: 100%; height: auto; display: block; }

/* ---------- rosace ornementale ---------- */

.rosace { color: rgba(60,81,72,.38); width: 120px; }
.rosace svg { width: 100%; height: auto; display: block; }

/* ---------- grille de points ---------- */

.points {
  width: 90px; height: 60px;
  background-image: radial-gradient(circle, rgba(53,50,44,.5) 1.4px, transparent 1.6px);
  background-size: 11px 11px;
}

/* ---------- dessins au trait ---------- */

.dessin { color: var(--encre); }
.dessin svg { display: block; width: 100%; height: auto; overflow: visible; }
.trait { fill: none; stroke: currentColor; stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }
.pointille { fill: none; stroke: var(--encre); stroke-width: 2.4; stroke-linecap: round; stroke-dasharray: 1 11; }

/* ---------- appareil photo qui déclenche ----------
   Le boîtier est dessiné au trait comme les autres doodles ; seul l'éclair
   est animé. Deux éléments distincts : le halo blanc qui éclaire la scène et
   les traits qui jaillissent du flash. */

.appareil { color: var(--encre); width: clamp(120px, 15vw, 178px); }
.appareil svg { display: block; width: 100%; height: auto; overflow: visible; }

/* `transform-box: view-box` est indispensable : sans lui, l'origine de la
   transformation d'un élément SVG se calcule dans le repère du document et non
   dans le viewBox, et l'éclair part en diagonale hors du cadre au lieu de
   grandir depuis le flash. */
.appareil .halo,
.appareil .rayons {
  transform-box: view-box;
  transform-origin: 48px 38px;
  animation: declic 2s ease-out infinite;
}

@keyframes declic {
  0%, 84%  { opacity: 0; transform: scale(.5); }
  88%      { opacity: 1; transform: scale(1); }
  93%      { opacity: .55; transform: scale(1.25); }
  100%     { opacity: 0; transform: scale(1.5); }
}

/* Le voyant du boîtier clignote au même rythme. */
.appareil .voyant { animation: voyant 2s ease-out infinite; }
@keyframes voyant { 0%, 84%, 100% { opacity: .25; } 88%, 93% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .appareil .halo, .appareil .rayons { animation: none; opacity: .5; transform: none; }
  .appareil .voyant { animation: none; opacity: .6; }
}

/* ---------- carte ---------- */

.carte { color: var(--vert); }
.carte svg { width: 100%; height: auto; display: block; }
/* Le fleuve et les terres avaient la même désaturation que tout le reste du
   dessin au trait — d'où la carte « pas assez colorée » : le relief et la
   forêt qu'on longe jusqu'à Manic-5 ne se voyaient pas. --sarcelle vient de
   refonte.css (chargé par ce carnet pour l'en-tête) : c'est déjà la couleur
   d'eau/voyage du site, pas une teinte ajoutée au hasard. */
.carte .eau      { fill: var(--sarcelle-pal, #ccdddc); opacity: .8; stroke: var(--sarcelle, #a4c4c3); stroke-width: .8; }
.carte .terre    { fill: var(--kraft); opacity: .38; stroke: rgba(60,81,72,.30); stroke-width: 1.2; }
.carte .route    { fill: none; stroke: var(--rouge); stroke-width: 2.4; stroke-dasharray: 7 6; stroke-linecap: round; }
.carte .route-2  { fill: none; stroke: var(--rouge); stroke-width: 2.4; stroke-dasharray: 2 7; stroke-linecap: round; }
.carte .etiq     { font-family: var(--main); font-size: 11px; fill: var(--vert); letter-spacing: .5px; }
.carte .etiq-fort{ font-family: var(--main); font-weight: 700; font-size: 12.5px; fill: var(--vert); }

/* ---------- illustration du R1S ----------
   Image fournie par l'auteur, déposée dans assets/img/Rivian/.

   Le PNG fourni est déjà détouré (35 % de pixels transparents) : aucun mode
   de fusion n'est appliqué. Un `mix-blend-mode: multiply`, prévu au cas où le
   fond aurait été blanc, aurait multiplié le bleu de la carrosserie par le
   beige du papier et terni la couleur.

   Si le fichier est absent, le script de la page masque le bloc plutôt que
   d'afficher une icône d'image cassée. */
.r1s-photo { line-height: 0; }
.r1s-photo img {
  width: 100%; height: auto;
  filter: drop-shadow(3px 6px 10px rgba(40,32,22,.22));
}
.r1s-photo.absente { display: none; }

/* ---------- la voiture qui roule ----------
   Une piste à hauteur fixe, la route en pointillé, et l'illustration qui la
   traverse lentement. C'est `left` qui est animé, pas `transform` : celui-ci
   porte déjà le retournement, et animer les deux sur la même propriété les
   ferait s'écraser l'un l'autre. */

.piste-route {
  position: relative;
  height: clamp(86px, 11vw, 132px);
  margin: .4rem 0 .2rem;
  overflow: hidden;
}
/* Décor de collines/forêt, propre à la piste de départ — voir la note dans
   le HTML. Premier enfant du bloc, donc peint en premier : reste sous la
   voiture et la ligne pointillée sans avoir besoin de z-index. */
.piste-route .decor-montagne { position: absolute; inset: 0; width: 100%; height: 100%; }
/* panneau planté au bord de la piste (route 389 uniquement pour l'instant) :
   le pied touche la ligne pointillée comme un vrai panneau planté au sol. */
.piste-route .panneau-piste { position: absolute; left: 1.5%; bottom: 4px; width: clamp(26px, 4%, 36px); z-index: 2; color: var(--encre); }
.piste-route .panneau-piste svg { display: block; width: 100%; height: auto; }
.piste-route::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 14px;
  border-top: 3px dotted rgba(53,50,44,.5);
}
.piste-route .vehicule {
  position: absolute; bottom: 16px;
  width: clamp(132px, 19%, 220px);
}
.piste-route .vehicule img {
  display: block; width: 100%; height: auto;
  filter: drop-shadow(2px 4px 8px rgba(40,32,22,.26));
}

/* vers la droite : l'illustration regarde à gauche, on la retourne */
.piste-route .vers-droite { transform: scaleX(-1); animation: roule-droite 55.78125s linear infinite; }
@keyframes roule-droite { from { left: -78.5%; } to { left: 159.5%; } }

/* vers la gauche : sens d'origine, aucun retournement */
.piste-route .vers-gauche { animation: roule-gauche 55.78125s linear infinite; }
@keyframes roule-gauche { from { left: 159.5%; } to { left: -78.5%; } }

/* Bouclage à une seule voiture visible à la fois — la contrainte qui compte
   vraiment est que la durée VISIBLE d'un passage (V) tienne dans la MOITIÉ du
   cycle (V ≤ T/2). Deux tentatives précédentes l'ont raté en ne vérifiant que
   l'instant où une copie sort pile quand l'autre entre, sans vérifier l'autre
   bord de la fenêtre visible — hors, si V > T/2, les deux fenêtres visibles
   (chacune de largeur V) se recouvrent forcément sur 2V−T, quel que soit le
   délai choisi. C'est exactement ce qui produisait deux voitures pleinement
   à l'écran en même temps.
   Ici, avec une largeur de véhicule mesurée à 19 % de la piste et la vitesse
   de croisement d'origine (128 %/30 s), la voiture reste visible 27,890625 s
   pour traverser l'écran (nez à gauche jusqu'à queue disparue à droite). En
   étalant la course sur une plage de -78,5 % à 159,5 % (au lieu de la marge
   d'origine, trop courte), le cycle complet dure 55,78125 s — soit tout
   juste le double de la durée visible (V = T/2). Un délai de -T/2 sur la
   copie fait alterner les deux fenêtres visibles bord à bord, sans trou et
   sans recouvrement : au pire un instant où l'une finit de sortir pendant
   que l'autre commence tout juste à entrer, jamais les deux carrosseries
   pleinement affichées ensemble. */
.piste-route .copie2 { animation-delay: -27.890625s; }

.piste-route.absente { display: none; }

@media (prefers-reduced-motion: reduce) {
  .piste-route .vers-droite, .piste-route .vers-gauche { animation: none; left: 34%; }
  .piste-route .copie2 { display: none; }
}

/* Les revêtements dessinés (chaussée, piste de terre), le mouvement du
   véhicule et les roues qui tournent vivent dans assets/css/piste-route.css,
   chargé par les seuls articles qui s'en servent. */

/* ---------- scène animée de l'Hôtel Tadoussac ----------
   Le bâtiment au trait sur sa pelouse, le soleil qui respire, des oiseaux
   qui planent et des voitures qui passent devant. Même principe que
   .piste-route et .piste-eau : entièrement dessiné, aucune image chargée. */
.scene-hotel {
  position: relative;
  height: clamp(190px, 22vw, 280px);
  margin: 1.1rem 0 .4rem;
  overflow: hidden;
  border-radius: 4px;
  background: linear-gradient(180deg,
              rgba(198,212,219,.32) 0%, rgba(198,212,219,.12) 52%, transparent 53%);
}
.mur-dense > .scene-hotel { column-span: all; }
.scene-hotel .decor-fond { position: absolute; inset: 0; width: 100%; height: 100%; }

/* le soleil : halo qui respire, rayons qui tournent très lentement */
.scene-hotel .soleil { position: absolute; top: 11%; right: 8%; width: clamp(52px, 7vw, 88px); }
.scene-hotel .soleil svg { display: block; width: 100%; height: auto; overflow: visible; }
.scene-hotel .soleil .halo   { transform-box: fill-box; transform-origin: center; animation: respire-soleil 6s ease-in-out infinite; }
.scene-hotel .soleil .rayons { transform-box: fill-box; transform-origin: center; animation: tourne-soleil 70s linear infinite; }
@keyframes respire-soleil { 0%,100% { transform: scale(1); opacity: .9; } 50% { transform: scale(1.09); opacity: 1; } }
@keyframes tourne-soleil  { to { transform: rotate(360deg); } }

/* l'hôtel, au centre */
.scene-hotel .hotel-forme {
  position: absolute; left: 50%; bottom: 19%;
  width: clamp(210px, 34%, 400px); transform: translateX(-50%);
}
.scene-hotel .hotel-forme svg { display: block; width: 100%; height: auto; overflow: visible; }

/* les voitures qui vont et viennent devant */
.scene-hotel .auto { position: absolute; bottom: 5%; width: clamp(44px, 6.5%, 78px); }
.scene-hotel .auto svg { display: block; width: 100%; height: auto; overflow: visible; }
.scene-hotel .auto-1 { animation: roule-est   19s linear infinite; }
.scene-hotel .auto-2 { animation: roule-ouest 26s linear infinite; animation-delay: -9s; }
.scene-hotel .auto-3 { animation: roule-est   33s linear infinite; animation-delay: -21s; bottom: 1%; opacity: .72; }
@keyframes roule-est   { from { left: -12%; } to { left: 106%; } }
@keyframes roule-ouest { from { left: 106%; transform: scaleX(-1); } to { left: -12%; transform: scaleX(-1); } }

/* les oiseaux */
.scene-hotel .oiseau { position: absolute; }
.scene-hotel .oiseau svg { display: block; width: 100%; height: 100%; overflow: visible; }
.scene-hotel .oiseau .aile { transform-box: fill-box; transform-origin: center; animation: battre-aile .8s ease-in-out infinite alternate; }
.scene-hotel .oiseau-1 { top: 15%; left: 17%; width: 30px; animation: planer-1 7s   ease-in-out infinite; }
.scene-hotel .oiseau-2 { top:  9%; left: 35%; width: 22px; animation: planer-2 8.5s ease-in-out infinite; }
.scene-hotel .oiseau-3 { top: 21%; left: 61%; width: 26px; animation: planer-3 6.2s ease-in-out infinite; }

@media (max-width: 700px) {
  .scene-hotel .hotel-forme { width: 62%; }
  .scene-hotel .oiseau-2 { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .scene-hotel .soleil .halo, .scene-hotel .soleil .rayons,
  .scene-hotel .oiseau, .scene-hotel .oiseau .aile,
  .scene-hotel .auto { animation: none; }
  .scene-hotel .auto-1 { left: 12%; }
  .scene-hotel .auto-2 { left: 68%; transform: scaleX(-1); }
  .scene-hotel .auto-3 { left: 40%; }
}

/* ---------- scène animée : la galerie d'art ----------
   Baie-Saint-Paul peint depuis les années 1860 : un peintre à son chevalet,
   des toiles au mur, des visiteurs qui les regardent. Même langage que les
   autres scènes — tout au trait, rien de téléchargé. */
.scene-galerie {
  position: relative;
  height: clamp(200px, 23vw, 290px);
  margin: 1.1rem 0 .4rem;
  overflow: hidden;
  border-radius: 4px;
  background: linear-gradient(180deg,
              rgba(203,180,146,.16) 0%, rgba(203,180,146,.07) 66%, transparent 67%);
}
.mur-dense > .scene-galerie { column-span: all; }
.scene-galerie .decor-fond { position: absolute; inset: 0; width: 100%; height: 100%; }
.scene-galerie .piece { position: absolute; }
.scene-galerie .piece svg { display: block; width: 100%; height: auto; overflow: visible; }

/* les toiles accrochées : chacune s'éclaire à son tour, comme un éclairage
   de galerie qui balaie le mur */
.scene-galerie .toile-1 { top: 16%; left:  9%; width: clamp(58px,  8%, 104px); }
.scene-galerie .toile-2 { top: 11%; left: 23%; width: clamp(66px,  9%, 118px); }
.scene-galerie .toile-3 { top: 18%; left: 74%; width: clamp(54px, 7.5%, 96px); }
.scene-galerie .toile-4 { top: 12%; left: 86%; width: clamp(62px, 8.5%, 110px); }
.scene-galerie .toile .cadre-int { animation: eclaire 12s ease-in-out infinite; }
.scene-galerie .toile-2 .cadre-int { animation-delay: -3s; }
.scene-galerie .toile-3 .cadre-int { animation-delay: -6s; }
.scene-galerie .toile-4 .cadre-int { animation-delay: -9s; }
@keyframes eclaire { 0%, 74%, 100% { opacity: .30; } 12%, 26% { opacity: .95; } }

/* le peintre : le bras au pinceau va et vient sur la toile */
.scene-galerie .peintre { bottom: 10%; left: 45%; width: clamp(96px, 13%, 168px); }
.scene-galerie .peintre .bras {
  transform-box: fill-box; transform-origin: 12% 82%;
  animation: peint 2.6s ease-in-out infinite alternate;
}
@keyframes peint { from { transform: rotate(-13deg); } to { transform: rotate(9deg); } }
/* la toile du chevalet se couvre peu à peu, puis repart à blanc */
.scene-galerie .peintre .en-cours { animation: se-remplit 14s ease-in-out infinite; }
@keyframes se-remplit {
  0%, 6%   { opacity: 0; }
  46%, 80% { opacity: .85; }
  96%,100% { opacity: 0; }
}

/* les visiteurs : léger balancement, et l'un d'eux traverse lentement */
.scene-galerie .visiteur { bottom: 10%; width: clamp(34px, 4.6%, 62px); }
.scene-galerie .visiteur-1 { left: 30%; animation: se-balance 7s ease-in-out infinite; }
.scene-galerie .visiteur-2 { left: 63%; animation: se-balance 8.5s ease-in-out infinite; animation-delay: -3s; }
/* ---- le visiteur qui traverse : il MARCHE, et il s'arrete ----
   Foulee et vitesse accordees : jambe de 37px, oscillation de +-23 deg,
   soit 32px de foulee ; a un pas toutes les 1.3 s cela impose
   25 px/s. A +-15 deg il avancait de 49px pour une foulee de 19px :
   les pieds patinaient de 30px par pas. C'etait ca, le glissement.

   Le deplacement horizontal, le balancement des jambes et le tangage du corps
   partagent la MEME duree (58.5 s), faute de quoi il pedalerait sur place
   pendant l'arret devant le peintre. */
/* Le marcheur a un viewBox plus large que les visiteurs immobiles (il est de
   profil, avec le nez) : a largeur egale il serait plus PETIT qu'eux. On lui
   donne donc sa propre largeur, calculee pour que tous fassent la meme
   hauteur — 125px, mesures. */
.scene-galerie .visiteur-3 {
  width: clamp(37px, 5.03%, 68px);
  animation: traverse-galerie 58.5s linear infinite;
}

@keyframes traverse-galerie {
  0% { left: -8.0%; }
  35.556% { left: 35.4%; }
  44.444% { left: 35.4%; }
  100% { left: 103.2%; }
}

.scene-galerie .visiteur-3 .jambe-av,
.scene-galerie .visiteur-3 .jambe-ar,
.scene-galerie .visiteur-3 .bras-av,
.scene-galerie .visiteur-3 .bras-ar { transform-box: fill-box; transform-origin: 50% 0%; }

.scene-galerie .visiteur-3 .jambe-av { animation: marche-av 58.5s ease-in-out infinite; }
.scene-galerie .visiteur-3 .jambe-ar { animation: marche-ar 58.5s ease-in-out infinite; }
/* les bras balancent a contretemps de la jambe du meme cote */
.scene-galerie .visiteur-3 .bras-av  { animation: marche-ar 58.5s ease-in-out infinite; }
.scene-galerie .visiteur-3 .bras-ar  { animation: marche-av 58.5s ease-in-out infinite; }

.scene-galerie .visiteur-3 .corps-marche {
  transform-box: fill-box;
  animation: tangue-marche 58.5s ease-in-out infinite;
}

@keyframes marche-av {
  0.0% { transform: rotate(23deg); }
  2.222% { transform: rotate(-23deg); }
  4.444% { transform: rotate(23deg); }
  6.667% { transform: rotate(-23deg); }
  8.889% { transform: rotate(23deg); }
  11.111% { transform: rotate(-23deg); }
  13.333% { transform: rotate(23deg); }
  15.556% { transform: rotate(-23deg); }
  17.778% { transform: rotate(23deg); }
  20.0% { transform: rotate(-23deg); }
  22.222% { transform: rotate(23deg); }
  24.444% { transform: rotate(-23deg); }
  26.667% { transform: rotate(23deg); }
  28.889% { transform: rotate(-23deg); }
  31.111% { transform: rotate(23deg); }
  33.333% { transform: rotate(-23deg); }
  35.556% { transform: rotate(0deg); }
  44.444% { transform: rotate(0deg); }
  46.667% { transform: rotate(23deg); }
  48.889% { transform: rotate(-23deg); }
  51.111% { transform: rotate(23deg); }
  53.333% { transform: rotate(-23deg); }
  55.556% { transform: rotate(23deg); }
  57.778% { transform: rotate(-23deg); }
  60.0% { transform: rotate(23deg); }
  62.222% { transform: rotate(-23deg); }
  64.444% { transform: rotate(23deg); }
  66.667% { transform: rotate(-23deg); }
  68.889% { transform: rotate(23deg); }
  71.111% { transform: rotate(-23deg); }
  73.333% { transform: rotate(23deg); }
  75.556% { transform: rotate(-23deg); }
  77.778% { transform: rotate(23deg); }
  80.0% { transform: rotate(-23deg); }
  82.222% { transform: rotate(23deg); }
  84.444% { transform: rotate(-23deg); }
  86.667% { transform: rotate(23deg); }
  88.889% { transform: rotate(-23deg); }
  91.111% { transform: rotate(23deg); }
  93.333% { transform: rotate(-23deg); }
  95.556% { transform: rotate(23deg); }
  97.778% { transform: rotate(-23deg); }
  100.0% { transform: rotate(23deg); }
}

@keyframes marche-ar {
  0.0% { transform: rotate(-23deg); }
  2.222% { transform: rotate(23deg); }
  4.444% { transform: rotate(-23deg); }
  6.667% { transform: rotate(23deg); }
  8.889% { transform: rotate(-23deg); }
  11.111% { transform: rotate(23deg); }
  13.333% { transform: rotate(-23deg); }
  15.556% { transform: rotate(23deg); }
  17.778% { transform: rotate(-23deg); }
  20.0% { transform: rotate(23deg); }
  22.222% { transform: rotate(-23deg); }
  24.444% { transform: rotate(23deg); }
  26.667% { transform: rotate(-23deg); }
  28.889% { transform: rotate(23deg); }
  31.111% { transform: rotate(-23deg); }
  33.333% { transform: rotate(23deg); }
  35.556% { transform: rotate(0deg); }
  44.444% { transform: rotate(0deg); }
  46.667% { transform: rotate(-23deg); }
  48.889% { transform: rotate(23deg); }
  51.111% { transform: rotate(-23deg); }
  53.333% { transform: rotate(23deg); }
  55.556% { transform: rotate(-23deg); }
  57.778% { transform: rotate(23deg); }
  60.0% { transform: rotate(-23deg); }
  62.222% { transform: rotate(23deg); }
  64.444% { transform: rotate(-23deg); }
  66.667% { transform: rotate(23deg); }
  68.889% { transform: rotate(-23deg); }
  71.111% { transform: rotate(23deg); }
  73.333% { transform: rotate(-23deg); }
  75.556% { transform: rotate(23deg); }
  77.778% { transform: rotate(-23deg); }
  80.0% { transform: rotate(23deg); }
  82.222% { transform: rotate(-23deg); }
  84.444% { transform: rotate(23deg); }
  86.667% { transform: rotate(-23deg); }
  88.889% { transform: rotate(23deg); }
  91.111% { transform: rotate(-23deg); }
  93.333% { transform: rotate(23deg); }
  95.556% { transform: rotate(-23deg); }
  97.778% { transform: rotate(23deg); }
  100.0% { transform: rotate(-23deg); }
}

@keyframes tangue-marche {
  0.0% { transform: translateY(0px); }
  1.111% { transform: translateY(-2px); }
  2.222% { transform: translateY(0px); }
  3.333% { transform: translateY(-2px); }
  4.444% { transform: translateY(0px); }
  5.556% { transform: translateY(-2px); }
  6.667% { transform: translateY(0px); }
  7.778% { transform: translateY(-2px); }
  8.889% { transform: translateY(0px); }
  10.0% { transform: translateY(-2px); }
  11.111% { transform: translateY(0px); }
  12.222% { transform: translateY(-2px); }
  13.333% { transform: translateY(0px); }
  14.444% { transform: translateY(-2px); }
  15.556% { transform: translateY(0px); }
  16.667% { transform: translateY(-2px); }
  17.778% { transform: translateY(0px); }
  18.889% { transform: translateY(-2px); }
  20.0% { transform: translateY(0px); }
  21.111% { transform: translateY(-2px); }
  22.222% { transform: translateY(0px); }
  23.333% { transform: translateY(-2px); }
  24.444% { transform: translateY(0px); }
  25.556% { transform: translateY(-2px); }
  26.667% { transform: translateY(0px); }
  27.778% { transform: translateY(-2px); }
  28.889% { transform: translateY(0px); }
  30.0% { transform: translateY(-2px); }
  31.111% { transform: translateY(0px); }
  32.222% { transform: translateY(-2px); }
  33.333% { transform: translateY(0px); }
  34.444% { transform: translateY(-2px); }
  35.556% { transform: translateY(0px); }
  44.444% { transform: translateY(0px); }
  45.556% { transform: translateY(-2px); }
  46.667% { transform: translateY(0px); }
  47.778% { transform: translateY(-2px); }
  48.889% { transform: translateY(0px); }
  50.0% { transform: translateY(-2px); }
  51.111% { transform: translateY(0px); }
  52.222% { transform: translateY(-2px); }
  53.333% { transform: translateY(0px); }
  54.444% { transform: translateY(-2px); }
  55.556% { transform: translateY(0px); }
  56.667% { transform: translateY(-2px); }
  57.778% { transform: translateY(0px); }
  58.889% { transform: translateY(-2px); }
  60.0% { transform: translateY(0px); }
  61.111% { transform: translateY(-2px); }
  62.222% { transform: translateY(0px); }
  63.333% { transform: translateY(-2px); }
  64.444% { transform: translateY(0px); }
  65.556% { transform: translateY(-2px); }
  66.667% { transform: translateY(0px); }
  67.778% { transform: translateY(-2px); }
  68.889% { transform: translateY(0px); }
  70.0% { transform: translateY(-2px); }
  71.111% { transform: translateY(0px); }
  72.222% { transform: translateY(-2px); }
  73.333% { transform: translateY(0px); }
  74.444% { transform: translateY(-2px); }
  75.556% { transform: translateY(0px); }
  76.667% { transform: translateY(-2px); }
  77.778% { transform: translateY(0px); }
  78.889% { transform: translateY(-2px); }
  80.0% { transform: translateY(0px); }
  81.111% { transform: translateY(-2px); }
  82.222% { transform: translateY(0px); }
  83.333% { transform: translateY(-2px); }
  84.444% { transform: translateY(0px); }
  85.556% { transform: translateY(-2px); }
  86.667% { transform: translateY(0px); }
  87.778% { transform: translateY(-2px); }
  88.889% { transform: translateY(0px); }
  90.0% { transform: translateY(-2px); }
  91.111% { transform: translateY(0px); }
  92.222% { transform: translateY(-2px); }
  93.333% { transform: translateY(0px); }
  94.444% { transform: translateY(-2px); }
  95.556% { transform: translateY(0px); }
  96.667% { transform: translateY(-2px); }
  97.778% { transform: translateY(0px); }
  98.889% { transform: translateY(-2px); }
  100.0% { transform: translateY(0px); }
}

/* l'enseigne de la galerie */
.scene-galerie .enseigne {
  position: absolute; top: 6%; left: 50%; transform: translateX(-50%);
  font-family: var(--affiche); font-size: clamp(.95rem, 1.7vw, 1.5rem);
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--encre); opacity: .62; white-space: nowrap;
}
.scene-galerie .enseigne::before,
.scene-galerie .enseigne::after {
  content: ""; position: absolute; top: 55%; width: clamp(18px, 3vw, 40px);
  height: 1px; background: currentColor; opacity: .5;
}
.scene-galerie .enseigne::before { left: -.9em; transform: translateX(-100%); }
.scene-galerie .enseigne::after  { right: -.9em; transform: translateX(100%); }

@media (prefers-reduced-motion: reduce) {
  .scene-galerie .toile .cadre-int, .scene-galerie .peintre .bras,
  .scene-galerie .peintre .en-cours, .scene-galerie .visiteur { animation: none; }
  .scene-galerie .toile .cadre-int { opacity: .8; }
  .scene-galerie .peintre .en-cours { opacity: .8; }
  .scene-galerie .visiteur-3 { left: 14%; }
  .scene-galerie .visiteur-3 .jambe-av, .scene-galerie .visiteur-3 .jambe-ar,
  .scene-galerie .visiteur-3 .bras-av, .scene-galerie .visiteur-3 .bras-ar,
  .scene-galerie .visiteur-3 .corps-marche { animation: none; }
}

/* ---------- doodles animés de la laiterie ----------
   Deux dessins qui comblent les colonnes restées courtes de l'étape :
   la vache Canadienne à gauche, l'homme fort à droite. Animations discrètes
   — une queue, une oreille, une mâchoire, un souffle d'effort. */

/* la vache : queue qui balaie, oreille qui frémit, mâchoire qui rumine */
.doodle-anim .queue-vache {
  transform-box: fill-box; transform-origin: 12% 2%;
  animation: balaie-queue 3.4s ease-in-out infinite alternate;
}
@keyframes balaie-queue { from { transform: rotate(-9deg); } to { transform: rotate(13deg); } }

.doodle-anim .oreille {
  transform-box: fill-box; transform-origin: 8% 60%;
  animation: fremit 4.6s ease-in-out infinite;
}
@keyframes fremit {
  0%, 62%, 100% { transform: rotate(0deg); }
  70%           { transform: rotate(-17deg); }
  78%           { transform: rotate(6deg); }
  86%           { transform: rotate(0deg); }
}

.doodle-anim .machoire {
  transform-box: fill-box; transform-origin: 78% 20%;
  animation: rumine 1.9s ease-in-out infinite alternate;
}
@keyframes rumine { from { transform: translateY(0) rotate(0deg); } to { transform: translateY(1.6px) rotate(1.4deg); } }

/* l'homme fort : la meule monte et redescend, les bras flechissent */
.doodle-anim .charge {
  transform-box: fill-box; transform-origin: center bottom;
  animation: souleve 4.2s ease-in-out infinite;
}
@keyframes souleve {
  0%, 100% { transform: translateY(0); }
  38%      { transform: translateY(-7px); }
  62%      { transform: translateY(-7px); }
}
.doodle-anim .effort { animation: effort-pulse 4.2s ease-in-out infinite; }
@keyframes effort-pulse {
  0%, 26%, 100% { opacity: 0; }
  44%, 58%      { opacity: .85; }
}

/* la fumee du village monte et se dissipe */
.doodle-anim .fumee {
  transform-box: fill-box; transform-origin: bottom center;
  animation: monte-fumee 7s ease-out infinite;
}
@keyframes monte-fumee {
  0%   { opacity: 0;   transform: translateY(4px) scale(.7); }
  22%  { opacity: .75; }
  70%  { opacity: .35; }
  100% { opacity: 0;   transform: translateY(-16px) scale(1.25); }
}
/* l'eau de la riviere ondule */
.doodle-anim .flot-riviere {
  transform-box: fill-box;
  animation: onde-riviere 6s ease-in-out infinite alternate;
}
@keyframes onde-riviere { from { transform: translateX(-3px); } to { transform: translateX(4px); } }

@media (prefers-reduced-motion: reduce) {
  .doodle-anim .queue-vache, .doodle-anim .oreille, .doodle-anim .machoire,
  .doodle-anim .charge, .doodle-anim .effort,
  .doodle-anim .fumee, .doodle-anim .flot-riviere { animation: none; }
  .doodle-anim .effort { opacity: .5; }
  .doodle-anim .fumee { opacity: .5; }
}

/* ---------- fiche de recharge ----------
   Reprise de la carte « Infos de charge » du carnet de bord, transposée dans
   la matière du carnet plutôt que dans son dégradé d'origine. */

/* La mesure réelle (getBoundingClientRect) a montré le bas de la fiche
   13 px plus bas que le haut de la rangée de photos suivante, alors que la
   grille leur réservait des rangées séparées et suffisantes : la rotation
   (.r-d/.r-g, ~2°) ne change rien à la hauteur de rangée que CSS Grid
   calcule — elle ne voit que la boîte non tournée — mais elle fait déborder
   le coin visuel de la fiche de plusieurs pixels sous cette limite. Ce
   n'était donc pas un problème de rembourrage interne (déjà resserré une
   fois) ni de rangée partagée (déjà séparée une fois) : marge de sécurité
   directe pour absorber ce débord, sur les 4 fiches du site. */
.fiche {
  background: var(--papier-clair);
  box-shadow: 3px 6px 18px rgba(55,45,30,.24);
  border: 1px solid rgba(60,81,72,.18);
  overflow: hidden;
  margin-bottom: 20px;
}
.fiche-titre {
  background: var(--vert); color: var(--papier-clair);
  padding: .55rem 1.1rem; display: flex; align-items: center; gap: .8rem;
}
.fiche-titre .script { font-size: 1.7rem; color: var(--papier-clair); }
.fiche-titre svg { width: 34px; height: 34px; flex: none; color: var(--papier-clair); }

/* Rembourrage un peu resserré (.7rem à l'origine) : la fiche s'étend sur 2
   rangées de la grille (l1-3) à côté de contenus bien plus courts (la bulle
   « Charlevoix ! » et le texte de La Malbaie) — sur un écran étroit, où le
   texte des lignes se met sur plusieurs lignes, la fiche pouvait dépasser
   dans la rangée des photos en dessous. Moins de padding = moins de risque,
   quelle que soit la largeur. */
.fiche-bloc { padding: .55rem 1.1rem; display: flex; align-items: center; gap: .9rem; border-bottom: 1px dashed rgba(60,81,72,.22); }
.fiche-bloc:last-child { border-bottom: none; }
.fiche-bloc.pale   { background: rgba(168,181,160,.20); }
.fiche-bloc.pale2  { background: rgba(125,146,135,.16); }
.fiche-bloc.jaune  { background: rgba(203,180,146,.26); }
.fiche-bloc.rose   { background: rgba(217,160,143,.18); }

.fiche-ico { width: 40px; height: 40px; flex: none; color: var(--vert); }
.fiche-ico svg { width: 100%; height: 100%; }
.fiche-corps { flex: 1 1 auto; min-width: 0; }
.fiche-l { display: flex; justify-content: space-between; gap: .8rem; align-items: baseline; font-size: .88rem; }
.fiche-l + .fiche-l { margin-top: .18rem; }
.fiche-l span:first-child { color: var(--encre-pale); }
.fiche-l b { font-weight: 700; white-space: nowrap; }
/* Valeur numérique d'une fiche (CCS, kW) : même graisse et même taille que les
   chiffres des autres lignes (23 mn, 405 km…), pour que rien ne détonne. Le
   lieu de charge n'est pas concerné — il garde son style propre. */
.fiche-valeur { font-weight: 700; font-size: .88rem; white-space: nowrap; }
/* « CCS » est l'étiquette de la valeur « 320 kW », pas une valeur elle-même :
   comme les autres étiquettes de la fiche (Prévisions de charge, Temps de
   charge…), elle ne doit pas être en gras — et, comme elles, en encre pâle :
   .fiche-valeur n'hérite pas de la couleur que .fiche-l span:first-child
   donne aux autres étiquettes, il fallait la répéter ici. */
.fiche-valeur.etiquette { font-weight: 400; color: var(--encre-pale); }
.fiche-etiq { font-size: .62rem; letter-spacing: .22em; text-transform: uppercase; color: var(--encre-pale); margin-top: .25rem; }

/* mention verticale sur le flanc, comme sur la carte d'origine */
.fiche-flanc {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-family: var(--script); font-size: 1.15rem; color: var(--vert-pale);
  align-self: center; padding: .3rem 0;
}

/* ---------- liste à pictogrammes ---------- */

.liste-picto { list-style: none; margin: .5rem 0 0; padding: 0; }
.liste-picto li { display: flex; align-items: center; gap: .7rem; padding: .22rem 0; font-size: .82rem; letter-spacing: .18em; text-transform: uppercase; }
.liste-picto svg { width: 26px; height: 20px; flex: none; color: var(--encre); }

/* ---------- rangée ----------
   Utilisée à 4 endroits (les duos panneau+texte, borne+batterie+texte) mais
   jamais définie : sans `display: flex`, ces éléments retombaient en bloc et
   s'empilaient au lieu de s'aligner côte à côte. */
.rangee { display: flex; flex-wrap: wrap; }

/* ---------- rotations ---------- */
.r-g   { transform: rotate(-2.2deg); }
.r-g-f { transform: rotate(-5deg); }
.r-g-ff{ transform: rotate(-8deg); }
.r-d   { transform: rotate(2deg); }
.r-d-f { transform: rotate(4.5deg); }
.r-d-ff{ transform: rotate(7.5deg); }

/* ---------- grille de collage ----------
   12 colonnes où plusieurs éléments partagent les mêmes rangées : c'est ce
   recouvrement qui donne l'aspect « collé à la main ». */
.collage { display: grid; grid-template-columns: repeat(12, 1fr); column-gap: .9rem; align-items: start; }
.collage > * { min-width: 0; }

/* placement : c<debut>-<fin> = colonnes, l<n> = lignes.
   Série complète générée : une classe manquante ne produit aucune erreur,
   elle laisse simplement l'élément en placement automatique — un bloc se
   retrouvait ainsi réduit à une colonne. */
.c1-2{grid-column:1/2} .c1-3{grid-column:1/3} .c1-4{grid-column:1/4} .c1-5{grid-column:1/5} .c1-6{grid-column:1/6} .c1-7{grid-column:1/7} .c1-8{grid-column:1/8} .c1-9{grid-column:1/9} .c1-10{grid-column:1/10} .c1-11{grid-column:1/11} .c1-12{grid-column:1/12} .c1-13{grid-column:1/13}
.c2-3{grid-column:2/3} .c2-4{grid-column:2/4} .c2-5{grid-column:2/5} .c2-6{grid-column:2/6} .c2-7{grid-column:2/7} .c2-8{grid-column:2/8} .c2-9{grid-column:2/9} .c2-10{grid-column:2/10} .c2-11{grid-column:2/11} .c2-12{grid-column:2/12} .c2-13{grid-column:2/13}
.c3-4{grid-column:3/4} .c3-5{grid-column:3/5} .c3-6{grid-column:3/6} .c3-7{grid-column:3/7} .c3-8{grid-column:3/8} .c3-9{grid-column:3/9} .c3-10{grid-column:3/10} .c3-11{grid-column:3/11} .c3-12{grid-column:3/12} .c3-13{grid-column:3/13}
.c4-5{grid-column:4/5} .c4-6{grid-column:4/6} .c4-7{grid-column:4/7} .c4-8{grid-column:4/8} .c4-9{grid-column:4/9} .c4-10{grid-column:4/10} .c4-11{grid-column:4/11} .c4-12{grid-column:4/12} .c4-13{grid-column:4/13}
.c5-6{grid-column:5/6} .c5-7{grid-column:5/7} .c5-8{grid-column:5/8} .c5-9{grid-column:5/9} .c5-10{grid-column:5/10} .c5-11{grid-column:5/11} .c5-12{grid-column:5/12} .c5-13{grid-column:5/13}
.c6-7{grid-column:6/7} .c6-8{grid-column:6/8} .c6-9{grid-column:6/9} .c6-10{grid-column:6/10} .c6-11{grid-column:6/11} .c6-12{grid-column:6/12} .c6-13{grid-column:6/13}
.c7-8{grid-column:7/8} .c7-9{grid-column:7/9} .c7-10{grid-column:7/10} .c7-11{grid-column:7/11} .c7-12{grid-column:7/12} .c7-13{grid-column:7/13}
.c8-9{grid-column:8/9} .c8-10{grid-column:8/10} .c8-11{grid-column:8/11} .c8-12{grid-column:8/12} .c8-13{grid-column:8/13}
.c9-10{grid-column:9/10} .c9-11{grid-column:9/11} .c9-12{grid-column:9/12} .c9-13{grid-column:9/13}
.c10-11{grid-column:10/11} .c10-12{grid-column:10/12} .c10-13{grid-column:10/13}
.c11-12{grid-column:11/12} .c11-13{grid-column:11/13}
.c12-13{grid-column:12/13}

.l1{grid-row:1} .l2{grid-row:2} .l3{grid-row:3} .l4{grid-row:4} .l5{grid-row:5} .l6{grid-row:6} .l1-2{grid-row:1/2} .l1-3{grid-row:1/3} .l1-4{grid-row:1/4} .l1-5{grid-row:1/5} .l1-6{grid-row:1/6} .l1-7{grid-row:1/7} .l2-3{grid-row:2/3} .l2-4{grid-row:2/4} .l2-5{grid-row:2/5} .l2-6{grid-row:2/6} .l2-7{grid-row:2/7} .l3-4{grid-row:3/4} .l3-5{grid-row:3/5} .l3-6{grid-row:3/6} .l3-7{grid-row:3/7} .l4-5{grid-row:4/5} .l4-6{grid-row:4/6} .l4-7{grid-row:4/7} .l5-6{grid-row:5/6} .l5-7{grid-row:5/7}
.z1{z-index:1} .z2{z-index:2} .z3{z-index:3} .z4{z-index:4}
.mt-1{margin-top:-1rem} .mt-2{margin-top:-2rem} .mt-3{margin-top:-3rem} .mt-4{margin-top:-4rem}
.pt1{margin-top:1.2rem} .pt2{margin-top:2.4rem} .pt3{margin-top:3.6rem}

/* ---------- navigation entre les pages du carnet ---------- */

.nav-carnet {
  display: flex; justify-content: center; align-items: center; gap: 1.4rem;
  flex-wrap: wrap; margin: 3rem 0 0; font-family: var(--script); font-size: 1.3rem;
}
.nav-carnet a { text-decoration: none; border-bottom: 2px dotted rgba(53,50,44,.4); padding-bottom: 2px; }
.nav-carnet a[aria-current="page"] { color: var(--rouge); border-bottom-color: var(--rouge); }
.nav-carnet .sep { color: var(--encre-pale); }

/* ---------- adaptatif ---------- */
@media (max-width: 860px) {
  .collage { grid-template-columns: 1fr; row-gap: 1.2rem; }
  .collage > * {
    grid-column: 1 !important; grid-row: auto !important;
    margin-top: 0 !important;
  }
  .r-g, .r-g-f, .r-g-ff, .r-d, .r-d-f, .r-d-ff { transform: rotate(-1deg); }
  .cache-mobile { display: none; }
  .bande-photos { grid-auto-flow: row; grid-template-columns: repeat(3, 1fr); }
}

/* ---- l'enseigne de la Route des Saveurs, suspendue a sa potence ----
   Le pivot est le crochet, a 74/36 dans les unites du viewBox — d'ou
   transform-box: view-box, qui laisse raisonner dans ces unites-la plutot
   que dans la boite du groupe (le crochet est AU-DESSUS d'elle). */
.panneau-saveurs .txt-anneau {
  font-family: var(--affiche);
  font-size: 8px;
  fill: currentColor;
  stroke: none;
}
.panneau-saveurs {
  transform-box: view-box;
  transform-origin: 72px 22px;
  animation: balance-enseigne 5.6s ease-in-out infinite;
}
@keyframes balance-enseigne {
  0%, 100% { transform: rotate(-2.4deg); }
  50%      { transform: rotate(2.4deg); }
}
@media (prefers-reduced-motion: reduce) {
  .panneau-saveurs .txt-anneau {
  font-family: var(--affiche);
  font-size: 8px;
  fill: currentColor;
  stroke: none;
}
.panneau-saveurs { animation: none; }
}

/* ==================== plancher de lisibilite mobile ====================
   Mesure a 390 px sur la page Manic-5 : 47 etiquettes .titre-v tombaient a
   10,9 px et 12 .etape-lieu a 11,8 px. En capitales, avec .22em d'interlettrage,
   c'est sous le seuil de lecture confortable sur telephone.

   Uniquement sous 820 px (tablette en portrait comprise) : sur ordinateur ces tailles sont calibrees pour un
   mur a quatre colonnes, ou l'espace horizontal est compte. Sur telephone le
   mur passe a une colonne et la place ne manque plus.

   Le lettrage a l'interieur des dessins (SVG) n'est pas concerne : il suit
   l'echelle de son dessin, l'agrandir le ferait deborder de son cadre. */
@media (max-width: 820px) {
  /* `.page` en tete n'est pas decoratif : la page declare ses propres regles de
     vignette dans un <style> EN LIGNE, place APRES le lien vers ce fichier.
     A specificite egale, c'est le dernier declare qui gagne — ma premiere
     version de cette regle etait donc morte, .titre-v restait a 10,9 px.
     Le selecteur descendant supplementaire (0-3-0 contre 0-2-0) tranche. */
  .page .vignette .titre-v { font-size: .79rem; letter-spacing: .18em; }
  .etape-lieu { font-size: .82rem; }
}

/* ==================== ouverture d'article ====================
   Le titre s'accompagne d'un dessin place a cote. Trois petites pieces. */

/* L'ecusson de route, glisse dans la phrase : c'est ainsi qu'on lit un numero
   de route sur un panneau, et ca evite d'ecrire « la route 389 » en toutes
   lettres au milieu du corps de texte. */
.ecusson {
  display: inline-block;
  font-family: var(--main);
  font-weight: 700;
  font-size: .82em;
  letter-spacing: .06em;
  background: var(--vert);
  color: var(--papier-clair);
  padding: .05em .42em .12em;
  border-radius: 3px;
  vertical-align: .06em;
}

/* Le trait sous le titre : trace a la main, pas une bordure droite — le reste
   de la page est dessine, une regle nette y jurerait. */
.trait-titre {
  display: block;
  width: clamp(110px, 40%, 200px);
  height: auto;
  margin: .55rem 0 .1rem;
  overflow: visible;
}
.trait-titre path {
  fill: none; stroke: var(--vert); stroke-width: 2.2;
  stroke-linecap: round; opacity: .6;
  /* Sans ceci, l'epaisseur suit l'echelle du dessin : mesure a 390 px, le
     trait tombait a 1,6 px et disparaissait a 60 pour cent d'opacite, alors
     qu'il fait 2,2 px sur ordinateur. Un ornement qui s'evapore sur telephone
     est pire que pas d'ornement. */
  vector-effect: non-scaling-stroke;
}

/* Le barrage dessine. Le lettrage des plaques est en unites du viewBox : il
   suit l'echelle du dessin, donc il retrecit avec lui sur telephone sans
   media-query — et il ne doit surtout PAS etre repris par le plancher de
   lisibilite mobile, qui le ferait deborder de son panneau. */
.dessin-barrage .doodle { color: var(--encre); }
/* Quand la grille se replie en une colonne, le dessin heriterait de toute la
   largeur : mesure a 768 px, il faisait 730 x 608 px et repoussait le texte de
   deux ecrans. On le borne et on le centre. Sur telephone (371 px) la borne ne
   mord pas — c'est bien l'illustration d'ouverture, elle a le droit d'occuper
   la largeur. */
@media (max-width: 900px) {
  .dessin-barrage .doodle { max-width: 420px; margin-inline: auto; }
}
.dessin-barrage .txt-panneau {
  font-family: var(--main); font-weight: 700; font-size: 15px;
  letter-spacing: .5px; fill: currentColor;
}
.dessin-barrage .txt-plaque {
  font-family: var(--main); font-weight: 700; font-size: 14px;
  letter-spacing: .5px; fill: currentColor;
}

/* L'eau du reservoir respire doucement. */
.dessin-barrage .eau-barrage {
  transform-box: view-box;
  animation: onduler-reservoir 8s ease-in-out infinite;
}
@keyframes onduler-reservoir {
  0%, 100% { transform: translateX(-3px); }
  50%      { transform: translateX(3px); }
}
@media (prefers-reduced-motion: reduce) {
  .dessin-barrage .eau-barrage { animation: none; }
}
