/* ============ VOYAGE (hero collant pendant le voyage 3D) ============ */
.voyage { position: relative; height: 100vh; }
/* Hauteur du voyage = la course de scroll du hero 3D (--ecrans-voyage, posé par js/ocean.js) + l'écran du hero lui-même */
html.voyage-3d .voyage { height: calc((var(--ecrans-voyage, 1.35) + 1) * 100vh); }
/* Crans magnétiques : le navigateur pose le scroll sur l'escale la plus proche quand le geste s'arrête, et seulement
   s'il en passe une près (`proximity`) — la longue approche du coffre, elle, se traverse sans être retenue. Les cibles
   sont posées en pixels par js/ocean.js, une par escale. */
html.voyage-3d { scroll-snap-type: y proximity; }
html.voyage-3d .crans { position: absolute; inset: 0; pointer-events: none; }
html.voyage-3d .cran { position: absolute; left: 0; width: 1px; height: 1px; scroll-snap-align: start; }
@media (prefers-reduced-motion: reduce) { html.voyage-3d { scroll-snap-type: none; } }

/* ============ HERO ============ */
.hero {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  place-items: center;
  text-align: center;
  padding: var(--gouttiere);
  background: linear-gradient(180deg, var(--mer) 0%, var(--mer-profonde) 100%);
  color: var(--parchemin-clair);
  overflow: hidden;
}
.hero__contenu { position: relative; z-index: 2; max-width: min(60rem, 92vw); padding-bottom: 12vh; opacity: var(--hero-opacite, 1); visibility: var(--hero-visibilite, visible); }
.hero__sur-titre { font-family: var(--police-main); font-size: 1.6rem; color: var(--or); margin: 0; }
.hero__nom {
  font-size: clamp(2.6rem, 7vw, 6rem);
  letter-spacing: .01em;
  white-space: nowrap;
  margin: 0;
  color: var(--parchemin-clair);
  text-shadow: 0 4px 24px rgba(0, 0, 0, .55);
}
.hero__titre { font-family: var(--police-titre); font-size: clamp(1.4rem, 3vw, 2rem); color: var(--or); margin: .5rem 0 1rem; }
.hero__accroche { font-style: italic; opacity: .9; }
.hero__ancre {
  display: inline-block;
  margin-top: 1.5rem;
  padding: .75rem 1.6rem;
  border: 2px solid var(--or);
  border-radius: 999px;
  color: var(--or);
  text-decoration: none;
  font-family: var(--police-titre);
  font-size: 1.3rem;
  transition: background .3s, color .3s;
}
.hero__ancre:hover { background: var(--or); color: var(--mer-profonde); }

.rose { position: absolute; right: -8vw; top: -8vw; width: 46vw; min-width: 260px; opacity: .12; z-index: 1; }
.vagues { position: absolute; left: 0; right: 0; bottom: -2px; height: 18vh; min-height: 90px; z-index: 1; overflow: hidden; }
.vague { position: absolute; bottom: 0; left: 0; width: 200%; max-width: none; height: 100%; }

/* Hero 3D (ajouté par js/ocean.js quand WebGL est disponible) */
.hero__ocean { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; z-index: 0; display: block; }
/* Le décor plat du hero disparaît dès qu'on sait que la 3D aura lieu, et pas seulement quand la scène est prête :
   entre les deux il s'écoule le temps de charger Three.js, et on voyait la version de repli complète s'afficher puis
   se faire remplacer, ce qui donnait l'impression d'une vieille version. Le fond du hero est déjà un dégradé de mer,
   donc l'attente ressemble à une mer calme avant que la vraie n'arrive. Si la 3D renonce en route, la classe tombe
   et le décor revient. */
html.voyage-3d .vagues, html.voyage-3d .rose,
.hero--3d .vagues, .hero--3d .rose { display: none; }
/* Voile de lisibilité derrière le texte du hero */
.hero--3d .hero__contenu::before {
  content: "";
  position: absolute;
  inset: -20% -30%;
  z-index: -1;
  background: radial-gradient(ellipse at center, rgba(15, 43, 56, .6), transparent 70%);
}

/* ============ CARTE & ROUTE ============ */
.carte {
  position: relative;
  z-index: 3;
  width: 100%;
  margin: 0;
  padding: 340px 4vw 60px;
  border: 90px solid transparent;
  border-image: url("../assets/papier.jpg") 240 fill / 90px / 0 round;
  color: var(--encre);
}
#escales { max-width: 1600px; margin: 0 auto; }
/* Le voyage s'achève sur la dernière escale de la carte : la page parchemin ne reprend plus la main. Elle reste dans le
   document — c'est la version que lisent les moteurs de recherche, les lecteurs d'écran et l'impression, et c'est d'elle
   que sont clonés les cartouches d'escale — mais elle n'occupe plus de place et ne s'affiche jamais. */
html.voyage-3d .carte {
  /* Hors flux et de hauteur nulle : elle ne rallonge pas la page, qui s'arrête ainsi sur la dernière escale. Ses
     enfants gardent leur mise en page réelle à l'intérieur (c'est `scrollHeight` qui la mesure), si bien que la route
     et les marqueurs restent justes si la 3D renonce en cours de route ou si l'on imprime. */
  position: absolute; top: 0; left: 0; width: 100%; height: 0; overflow: hidden;
  opacity: 0; pointer-events: none;
}
/* Le cap actuel : la seule information de la page qu'un lecteur cherche vraiment en arrivant. Elle était en bas, en
   manuscrit, après deux paragraphes de prose — c'est-à-dire à l'endroit et dans le style où l'on met une note de bas
   de page. Elle passe en tête, sous le titre, et prend l'encre rouge : c'est la première chose qu'on lit. */
.port__cap {
  margin: 0 0 1rem;
  font-family: var(--police-main);
  font-size: 1.25rem;
  line-height: 1.35;
  color: var(--cire);
}
.port__cap strong { font-family: var(--police-corps); font-weight: 700; font-size: .92em; }
/* L'encre rouge se lit sur le papier et disparaît sur le fond sombre du panneau : chaque couleur posée pour une vue
   doit avoir sa réponse dans l'autre. */
.escale-panneau .port__cap { color: var(--or); }

/* Le chemin vers la version classique. Un recruteur qui veut lire et passer à la suite ne doit pas avoir à traverser
   l'archipel : le lien est sous l'appel à embarquer, et de nouveau à la taverne pour celui qui est allé jusqu'au bout. */
.hero__sobre { margin: .9rem 0 0; font-size: .92rem; }
.hero__sobre a { color: var(--parchemin-clair); opacity: .8; text-underline-offset: .2em; }
.hero__sobre a:hover { opacity: 1; }
.taverne__sobre { margin: 1rem 0 0; font-family: var(--police-main); font-size: 1.1rem; }

/* Le renvoi du chantier vers la page, dans le panneau du voyage : même ton que les annotations à la main */
.chantier__renvoi { margin: .6rem 0 0; font-family: var(--police-main); color: var(--or-sombre); font-size: 1rem; }

/* Les emprunts, au pied de la taverne : la mention que demande CC BY. Discrète — c'est une note de bas de page, pas
   une section — mais lisible, et jamais repliée : une attribution qu'il faut déplier remplit mal son office. */
.emprunts__intro { margin: 1.6rem 0 .3rem; font-size: .78rem; color: color-mix(in srgb, var(--encre) 75%, transparent); }
.emprunts {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: .78rem;
  line-height: 1.5;
  color: color-mix(in srgb, var(--encre) 75%, transparent);
  max-width: 62ch;
}
.emprunts li { margin-bottom: .15rem; }
.emprunts a { color: inherit; text-decoration-color: color-mix(in srgb, var(--cire) 55%, transparent); }
.emprunts a:hover { color: var(--cire); }

@media print { html.voyage-3d .carte { position: static; height: auto; overflow: visible; opacity: 1; } }
.route {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 1;
}
.route__trace {
  fill: none;
  stroke: var(--cire);
  stroke-width: 3;
  stroke-dasharray: 10 12;
  stroke-linecap: round;
}
.route__masque {
  fill: none;
  stroke: #fff;
  stroke-width: 18;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

/* Encre qui bave (filtre SVG #encre) — désactivée sur mobile */
.hero__nom, .escale h2, .escale__annotation { filter: url(#encre); }

/* ============ ESCALES ============ */
/* Escale = île illustrée + cartouche ancré, positionnés en cycle sur toute la largeur */
.escale {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 440px minmax(300px, 620px);
  align-items: start;
  margin: 0 0 90px calc(max(0px, 100% - 1060px) * var(--pos, 0) / 100);
}
.escale:last-child { margin-bottom: 0; }
/* La mesure du parchemin : 620 pixels, soit environ 66 signes par ligne dans le corps du texte.
   Il en faisait 400, c'est-à-dire 40 signes — une colonne de journal pour des phrases de CV. L'œil y revient à la
   marge toutes les six ou sept mots, les missions s'y découpaient en vers, et les trois quarts de la page restaient
   vides à côté. La fourchette lisible va de cinquante à soixante-quinze signes ; on s'y tient. */
.escale__ile { position: relative; width: 440px; }
.escale__ile svg { display: block; width: 100%; height: auto; overflow: visible; }

.escale__parchemin {
  position: relative;
  width: 100%;
  margin: 120px 0 0 -30px;
  padding: 2rem 2.25rem 2.25rem;
  transform: perspective(900px) rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg)) rotate(var(--rot, 0deg));
  /* Trois ombres, dont la première n'en est pas une : sans décalage ni presque de flou, elle cerne le papier d'un
     trait sombre qui suit exactement sa découpe déchirée. Il en faut un : le fond de carte et le parchemin partagent
     la teinte et la valeur (un rapport de 1,2 à 1), si bien que la feuille se confondait avec la carte et ne tenait
     que par son ombre portée. Une feuille posée sur une carte a un bord. */
  filter:
    drop-shadow(0 0 1.2px rgba(43, 29, 14, .6))
    drop-shadow(0 2px 2px rgba(43, 29, 14, .55))
    drop-shadow(var(--sx, 6px) var(--sy, 10px) 14px rgba(43, 29, 14, .5));
}
/* Calque papier : fond, découpe déchirée, épaisseur (ombre proche nette + ombre lointaine dynamique) */
.escale__papier {
  position: absolute;
  inset: 0;
  z-index: -1;
  clip-path: var(--decoupe, none);
  background:
    linear-gradient(135deg, rgba(255, 252, 240, .75), transparent 35%),
    radial-gradient(ellipse at 50% 40%, #f3e6c2, #e2cd9a 90%);
}

/* Marqueur sur le bord intérieur (côté centre de la page) */
.escale__marqueur {
  position: absolute;
  left: calc(50% - 11px);
  top: calc(54% - 11px);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--or);
  border: 3px solid var(--cire);
  box-shadow: 0 0 0 6px rgba(139, 30, 30, .15);
}

.escale__annotation {
  font-family: var(--police-main);
  font-size: 1.15rem;
  color: var(--cire);
  margin: 0 0 .25rem;
  opacity: .85;
}

/* ---- Port ---- */
.port__bord { font-family: var(--police-main); font-size: 1.15rem; color: var(--or-sombre); margin: 0; }
.port__dispo { margin: -.5rem 0 1rem; font-size: .95rem; color: color-mix(in srgb, var(--encre) 72%, transparent); }
.escale-panneau .fiche__dispo { margin: .2rem 0 0; font-size: .9em; color: color-mix(in srgb, var(--parchemin-clair) 72%, transparent); }
/* Le cap actuel : la mission en cours, annoncée dès le port pour qui n'ira pas jusqu'à la dernière île */

/* ---- Îles ---- */
.ile__entreprise { font-weight: bold; margin: 0; }
.ile__traversee { font-family: var(--police-main); font-size: 1.2rem; color: var(--or-sombre); margin: 0 0 .75rem; }
.ile__parcours { font-family: var(--police-main); font-size: 1.1rem; color: var(--or-sombre); margin: -.5rem 0 .75rem; opacity: .9; }
.ile__contexte { font-style: italic; opacity: .9; margin-bottom: .75rem; }
.ile__travaux { list-style: none; padding: 0; margin: 0; }
.ile__travaux li { padding-left: 1.5rem; position: relative; margin-bottom: .35rem; }
.ile__travaux li::before { content: "☠" / ""; position: absolute; left: 0; color: var(--cire); }
/* Résultat de la traversée : encart sur le parchemin */
.ile__resultat {
  margin: .9rem 0 0;
  padding: .6rem .9rem;
  background: rgba(139, 30, 30, .07);
  border-left: 4px solid var(--cire);
  border-radius: 0 6px 6px 0;
}
.ile__resultat strong { font-family: var(--police-titre); font-weight: 400; color: var(--cire); margin-right: .4rem; }

/* Étiquettes de stack (îles et chantier naval) : petites, à l'encre, sans le relief doré des pièces du coffre */
.etiquettes { list-style: none; padding: 0; margin: .9rem 0 0; display: flex; flex-wrap: wrap; gap: .35rem; }
.etiquette {
  padding: .1rem .6rem;
  border: 1px solid rgba(43, 29, 14, .55);
  border-radius: 999px;
  font-size: .85rem;
  color: var(--encre);
  background: rgba(255, 252, 240, .35);
}

/* ---- Chantier naval (projets personnels) ---- */
.chantier__intro { font-style: italic; opacity: .9; }
.projets { list-style: none; padding: 0; margin: 0; display: grid; gap: .6rem; }
.projet {
  padding: .7rem .9rem;
  background: var(--parchemin);
  border-radius: 8px;
  box-shadow: var(--sx, 2px) var(--sy, 3px) 8px rgba(43, 29, 14, .25);
}
.projet--principal { border-left: 6px solid var(--mer); }
.projet:not(.projet--principal) { padding: .45rem .8rem; background: rgba(212, 184, 128, .55); }
.projet__nom { margin: 0 0 .2rem; }
.projet:not(.projet--principal) .projet__nom { font-size: 1.15rem; }
.projet__depuis { font-size: .85rem; letter-spacing: .06em; text-transform: uppercase; color: color-mix(in srgb, var(--encre) 75%, transparent); margin: 0 0 .25rem; }
.projet__resume { font-family: var(--police-main); font-size: 1.15rem; color: var(--or-sombre); margin: 0 0 .4rem; }
.projet:not(.projet--principal) .projet__resume { display: inline; margin: 0; }
.projet__description { margin: 0; font-size: .98rem; }
.projet__etat {
  display: inline-block;
  margin-left: .5rem;
  padding: 0 .5rem;
  border-radius: 999px;
  font-family: var(--police-corps);
  font-size: .75rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  vertical-align: middle;
  color: var(--parchemin-clair);
  background: var(--or-sombre);
}
.projet__etat--live { background: var(--mer); }
.projet__etat--en-cours { background: var(--or); color: var(--encre); }
.projet .etiquettes { margin-top: .5rem; }
/* La pile s'affiche pour tous : `principal` décide de la coupe du PDF et du poids visuel, pas du droit de dire
   avec quoi c'est fait. Masquée, elle privait les fractales de Rust, WebAssembly et SIMD. */
.projet:not(.projet--principal) .etiquettes { margin-top: .35rem; }
/* Le nom du projet est le lien : un bouton « Visiter » sous chaque carte prenait une ligne pour redire l'évidence.
   La flèche prévient qu'on quitte le site ; elle est décorative, le lien porte déjà son adresse. */
.projet__nom a { color: inherit; text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); }
.projet__nom a:hover, .projet__nom a:focus-visible { text-decoration-color: currentColor; }
.lien-dehors { margin-left: .25em; font-size: .8em; vertical-align: .08em; opacity: .7; }
/* Le détail d'un projet, replié : le résumé et la description suffisent à comprendre, le reste attend qu'on demande */
.projet__detail { margin-top: .5rem; }
.projet__detail > summary {
  cursor: pointer; display: inline-block; list-style: none;
  font-family: var(--police-main); font-size: 1.05rem; color: var(--or-sombre);
  border-bottom: 1px dashed currentColor; padding-bottom: 1px;
}
.projet__detail > summary::-webkit-details-marker { display: none; }
.projet__detail > summary::after { content: " ▾"; }
.projet__detail[open] > summary::after { content: " ▴"; }
.projet__detail p { margin: .6rem 0 0; font-size: .98rem; }
@media print { .projet__detail > summary { display: none; } }

/* ---- Coffre ---- */
/* Le coffre.
   Il était en dégradés imitant du bois verni, avec des ferrures cloutées et de l'or brillant : seul objet du site à
   vouloir passer pour un volume, au milieu d'un CV entièrement dessiné à l'encre sur du papier. Il détonnait, et
   aucune mise en page ne corrigeait ça.
   Il garde sa forme et son couvercle qui s'ouvre, mais il est maintenant tracé plutôt que rendu : un trait, pas de
   remplissage. Le vide lui profite deux fois — il laisse voir le papier sur la page, et le fond sombre dans le
   panneau du voyage, là où un remplissage parchemin aurait fait une tache. Pour la même raison le texte hérite de sa
   couleur au lieu de la fixer. L'or ne reste que sur les pièces, où il veut dire quelque chose. */
.coffre { position: relative; margin-top: 1.1rem; perspective: 900px; }
.coffre__couvercle {
  height: 26px;
  border: 1.5px solid;
  border-color: color-mix(in srgb, currentColor 42%, transparent);
  border-bottom: 0;
  border-radius: 12px 12px 0 0;
  transform-origin: bottom center;
}
.coffre__corps {
  position: relative;
  border: 1.5px solid;
  border-color: color-mix(in srgb, currentColor 42%, transparent);
  border-top: 0;
  border-radius: 0 0 12px 12px;
  padding: 1.1rem 1.5rem 1.35rem;
  display: grid;
  gap: 1.1rem;
}
/* La serrure, au milieu de la ligne de couvercle : le seul ornement qu'on garde, parce qu'un coffre sans serrure
   n'est qu'une caisse. */
.coffre__corps::before {
  content: "";
  position: absolute;
  top: -8px;
  left: 50%;
  width: 15px;
  height: 15px;
  transform: translateX(-50%) rotate(45deg);
  border: 1.5px solid;
  border-color: color-mix(in srgb, currentColor 42%, transparent);
  background: var(--or);
  border-radius: 3px;
}
.coffre__groupe h3 { color: var(--cire); margin-bottom: .1rem; }
.escale-panneau .coffre__groupe h3 { color: var(--or); }
/* L'inventaire du coffre.
   Les pièces étaient des capsules dorées contenant des phrases de quarante-cinq caractères. Le dégradé conique y
   passait en diagonale à travers les mots : la même ligne se lisait tantôt sur de l'or clair, tantôt sur de l'or
   sombre, et le contraste changeait au milieu d'un mot. Élargir la colonne n'y changeait rien — le problème était
   sous le texte, pas autour.
   Une pièce de monnaie ne porte pas de phrase. Elle redevient donc une pièce, ronde et sans rien écrit dessus, et le
   texte se lit en clair sur le bois du coffre, où le contraste est entier. L'or reste ce qu'il doit être : l'accent. */
.coffre__pieces { list-style: none; padding: 0; margin: .4rem 0 0; display: grid; gap: .5rem; }
.piece {
  display: grid;
  grid-template-columns: 1.05em 1fr;
  align-items: baseline;
  gap: .7rem;
  color: inherit;
  font-size: 1.04rem;
  line-height: 1.5;
}
/* La pièce elle-même : le dégradé conique du métal, et par-dessus le reflet qui la balaie (une seule couche de fond
   animée, pas un élément à détourer — un pseudo-élément rond découpe son propre reflet). */
.piece::before {
  content: "";
  width: 1.05em;
  height: 1.05em;
  border-radius: 50%;
  transform: translateY(.1em);
  background:
    linear-gradient(120deg, transparent 40%, rgba(255, 255, 255, .55) 50%, transparent 60%) 100% 0 / 300% 100% no-repeat,
    conic-gradient(from 210deg, #f7dd8a, var(--or) 25%, #8c6520 50%, #e8c76a 75%, #f7dd8a);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 245, 200, .7), inset 0 -1px 2px rgba(80, 50, 10, .6);
}
@media (pointer: fine) {
  .piece { transition: color .25s; }
  .piece::before { transition: transform .25s cubic-bezier(.3, 1.4, .5, 1), box-shadow .25s; }
  .piece:hover { color: #fff8e4; }
  .piece:hover::before { transform: translateY(-.05em) scale(1.25); box-shadow: 0 3px 6px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 245, 200, .8), inset 0 -1px 2px rgba(80, 50, 10, .6); }
}

/* ---- Académie ---- */
.rouleaux { list-style: none; padding: 0; margin: 0; display: grid; gap: .75rem; }
.rouleau {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .1rem .9rem;
  align-items: baseline;
  padding: .75rem 1rem;
  background: var(--parchemin);
  border-left: 6px solid var(--cire);
  border-right: 6px solid var(--cire);
  border-radius: 8px;
  box-shadow: var(--sx, 2px) var(--sy, 3px) 8px rgba(43, 29, 14, .25);
}
.rouleau__annee { font-family: var(--police-titre); color: var(--cire); font-size: 1.3rem; grid-row: span 2; }
.rouleau__ecole { font-style: italic; opacity: .85; }
.rouleau__detail { grid-column: 2; font-size: .92rem; opacity: .85; }

/* ---- Taverne ---- */
.taverne__statut { font-family: var(--police-main); font-size: 1.25rem; color: var(--cire); margin: 0 0 .5rem; }
.bouteilles { list-style: none; padding: 0; margin: 0 0 1.5rem; display: flex; flex-wrap: wrap; gap: .75rem; }
.bouteille {
  display: inline-block;
  padding: .6rem 1.2rem;
  border: 2px solid var(--mer);
  border-radius: 999px 999px 8px 8px;
  color: var(--mer-profonde);
  text-decoration: none;
  background: rgba(29, 74, 92, .08);
  transition: background .3s, color .3s;
}
.bouteille:hover { background: var(--mer); color: var(--parchemin-clair); }
.sceau {
  position: absolute;
  right: 1.5rem;
  bottom: -1.5rem;
  width: 64px;
  height: 64px;
  border-radius: 50% 48% 52% 50% / 52% 50% 50% 48%;
  background: radial-gradient(circle at 35% 30%, #d24a4a, var(--cire) 55%, #4a0d0d);
  box-shadow: var(--sx, 3px) var(--sy, 5px) 10px rgba(0, 0, 0, .45), inset -3px -3px 6px rgba(0, 0, 0, .45), inset 3px 3px 6px rgba(255, 120, 120, .35);
}
/* Goutte de cire qui déborde */
.sceau::before {
  content: "";
  position: absolute;
  left: -9px;
  top: 30px;
  width: 18px;
  height: 22px;
  border-radius: 50% 50% 60% 40%;
  background: radial-gradient(circle at 40% 30%, #c23b3b, #6a1212);
  box-shadow: inset -2px -2px 3px rgba(0, 0, 0, .4);
}
/* Motif en creux */
.sceau::after {
  content: "☠";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: rgba(60, 5, 5, .9);
  font-size: 1.8rem;
  text-shadow: 0 1px 0 rgba(255, 160, 160, .5), 0 -1px 1px rgba(0, 0, 0, .6);
}
/* Sceau craquelé au survol de la taverne : fissures fines et motif plus dur */
.sceau .sceau__fissures {
  position: absolute; inset: 0; border-radius: inherit; opacity: 0; transition: opacity .4s;
  background:
    linear-gradient(35deg, transparent 47%, rgba(40, 5, 5, .8) 49%, transparent 51%),
    linear-gradient(118deg, transparent 58%, rgba(40, 5, 5, .7) 60%, transparent 62%),
    linear-gradient(80deg, transparent 30%, rgba(40, 5, 5, .6) 31.5%, transparent 33%);
}
.escale--taverne:hover .sceau .sceau__fissures { opacity: 1; }
.escale--taverne:hover .sceau::after { text-shadow: 0 1px 0 rgba(255, 160, 160, .7), 0 -1px 2px rgba(0, 0, 0, .9); }
.poussiere {
  position: absolute; left: 50%; top: 50%; width: 5px; height: 5px; border-radius: 50%;
  background: #6a1212; pointer-events: none;
  animation: poussiere .6s ease-out forwards;
}

/* ============ BOUSSOLE ============ */
.boussole { position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 10; }
.boussole__bouton {
  position: relative;
  width: 84px;
  height: 84px;
  padding: 7px;
  border-radius: 50%;
  border: 2px solid #5a3f14;
  background:
    radial-gradient(circle at 50% 50%, var(--parchemin-clair) 60%, transparent 61%),
    conic-gradient(from 0deg, #d9b568, #8c6520 18%, #f3d78a 36%, #a07a30 55%, #e9c96e 75%, #d9b568);
  box-shadow: var(--sx, 4px) var(--sy, 8px) 18px rgba(0, 0, 0, .4), inset 0 0 6px rgba(0, 0, 0, .35);
}
/* Vitre : reflet diagonal */
.boussole__bouton::before {
  content: "";
  position: absolute;
  inset: 7px;
  z-index: 1;
  border-radius: 50%;
  pointer-events: none;
  background: linear-gradient(135deg, rgba(255, 255, 255, .45), transparent 45%, transparent 60%, rgba(255, 255, 255, .15));
}
.boussole__bouton svg { width: 100%; height: 100%; display: block; }
.boussole__aiguille { transform-origin: 50px 50px; transition: transform .15s linear; }
.boussole__liste {
  position: absolute;
  right: 0;
  bottom: calc(100% + .75rem);
  min-width: 230px;
  margin: 0;
  padding: .5rem 0;
  list-style: none;
  background: var(--parchemin-clair);
  border: 1px solid var(--encre);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .3);
}
.boussole__liste a {
  display: block;
  padding: .5rem 1rem;
  text-decoration: none;
  color: var(--encre);
  font-family: var(--police-titre);
  font-size: 1.15rem;
}
.boussole__liste a:hover, .boussole__liste a:focus { background: var(--parchemin); color: var(--cire); }

/* ============ LANTERNE (jour / nuit) ============ */
.lanterne {
  position: fixed; left: 1.25rem; bottom: 1.25rem; z-index: 10;
  width: 56px; height: 56px; padding: 8px; border-radius: 50%; border: 2px solid #5a3f14; cursor: pointer;
  background: radial-gradient(circle at 50% 50%, var(--parchemin-clair) 62%, transparent 63%), conic-gradient(from 0deg, #d9b568, #8c6520 18%, #f3d78a 36%, #a07a30 55%, #e9c96e 75%, #d9b568);
  box-shadow: var(--sx, 4px) var(--sy, 8px) 14px rgba(0, 0, 0, .4), inset 0 0 5px rgba(0, 0, 0, .35);
}
.lanterne svg { width: 100%; height: 100%; display: block; }
.lanterne .lanterne__nuit { display: none; }
.lanterne[aria-pressed="true"] .lanterne__jour { display: none; }
.lanterne[aria-pressed="true"] .lanterne__nuit { display: block; }
.lanterne:focus-visible { outline: 3px solid #f3d78a; outline-offset: 3px; }
@media (max-width: 720px) { .lanterne { width: 48px; height: 48px; left: .75rem; bottom: .75rem; } }

/* ============ HALO (position ; animation dans effects.css) ============ */

/* ============ DÉCORS DE CARTE ANCIENNE ============ */
.decor { position: absolute; color: var(--encre); pointer-events: none; z-index: 0; }
.decor--rhumbs {
  inset: 0;
  opacity: .22;
  background: repeating-conic-gradient(from 0deg at calc(100% - 6vw - 140px) 300px, rgba(43, 29, 14, .9) 0 .25deg, transparent .25deg 22.5deg);
  -webkit-mask-image: radial-gradient(circle at calc(100% - 6vw - 140px) 300px, #000 250px, transparent 1100px);
  mask-image: radial-gradient(circle at calc(100% - 6vw - 140px) 300px, #000 250px, transparent 1100px);
}
.decor--echelle { left: 70px; bottom: 150px; width: 220px; opacity: .6; }
.cartouche__titre { margin: 0; font-family: var(--police-titre); font-size: 1.35rem; color: var(--cire); }
.cartouche__date { margin: 0; font-family: var(--police-main); font-size: 1.1rem; }

/* ============ GRAVURES DU DOMAINE PUBLIC (filigrane) ============ */
.gravure { position: absolute; margin: 0; pointer-events: none; mix-blend-mode: multiply; }
.gravure img { display: block; width: 100%; height: auto; }
.gravure--rose {
  right: 6vw; top: 160px; width: 280px; opacity: .85;
  filter: brightness(1.08) contrast(1.12);
  -webkit-mask-image: radial-gradient(circle closest-side, #000 90%, transparent 100%);
  mask-image: radial-gradient(circle closest-side, #000 90%, transparent 100%);
}
.gravure--cartouche {
  left: 5vw; top: 24px; width: 340px; pointer-events: auto;
  filter: brightness(1.1) contrast(1.15);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent), linear-gradient(180deg, transparent, #000 7%, #000 93%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent), linear-gradient(180deg, transparent, #000 7%, #000 93%, transparent);
  mask-composite: intersect;
}
.gravure--cartouche .cartouche {
  position: absolute;
  left: 23%; right: 23%; top: 20%; bottom: 33%;
  display: flex; flex-direction: column; justify-content: center;
  text-align: center;
  background: #f3e6c2;
  border-radius: 12px;
  color: var(--encre);
}
.gravure--serpent {
  left: 8%; top: 46%; width: 260px; opacity: .55;
  filter: sepia(.6) contrast(1.05);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 45%, transparent 72%);
  mask-image: radial-gradient(ellipse at center, #000 45%, transparent 72%);
}

/* ============ RESPONSIVE ============ */
@media (max-width: 1100px) {
  .escale { grid-template-columns: 300px minmax(220px, 1fr); }
  .escale__ile { width: 300px; }
  .escale__parchemin { margin: 90px 0 0 -20px; }
}
@media (max-width: 720px) {
  .hero__nom, .escale h2, .escale__annotation { filter: none; }
  .hero__nom { white-space: normal; }
  .carte { padding: 190px 8px 40px; border-width: 110px 24px; border-image-width: 110px 24px; }
  .escale { grid-template-columns: 1fr; margin: 0 0 56px; }
  .escale__ile { width: 260px; margin: 0 auto; }
  .escale__parchemin { max-width: none; margin: -24px 0 0; padding: 1.5rem 1.25rem 1.75rem; }
  .escale__marqueur { width: 18px; height: 18px; left: calc(50% - 9px); top: calc(54% - 9px); }
  .route__trace { stroke-width: 2; stroke-dasharray: 7 9; }
  .boussole { right: .75rem; bottom: .75rem; }
  .boussole__bouton { width: 60px; height: 60px; }
  .boussole__liste { min-width: 200px; }
  h2 { font-size: 1.8rem; }
  .decor--rhumbs { display: none; }
  .decor--echelle { width: 150px; left: 24px; bottom: 28px; }
  .gravure--rose { width: 140px; right: 12px; top: 200px; }
  .gravure--cartouche { width: 200px; left: 12px; top: 8px; }
  .cartouche__titre { font-size: .95rem; }
  .cartouche__date { font-size: .85rem; }
  .gravure--serpent { display: none; }
}

/* ============ ESPACE CARTE (cartouches ancrés aux îles en relief) ============ */
/* ---- Le panneau d'escale ----
   Le texte est cloné des sections de la page : il n'existe qu'une fois, dans le HTML. Il s'affiche ici dans un panneau
   à place fixe, toujours la même, et non plus dans un parchemin flottant qui devait tenir dans le vide laissé autour
   de son île — trois cent soixante pixels et un ascenseur interne dans le défilement. La caméra décale son cadrage de
   la largeur du panneau (js/ocean.js) : l'île abordée reste au centre de ce qui reste visible.

   À gauche, et non à droite : la carte se parcourt de gauche à droite — les îles sont posées sur un x croissant, le
   navire fait route vers la droite, et la prochaine escale est toujours à droite de celle qu'on lit. Un panneau à
   droite masquerait là où l'on va. */
.escale-panneau {
  /* Le panneau est inséré dans le hero (js/ocean.js), qui centre son contenu pour son titre et son bouton. Le corps
     du texte en héritait : des paragraphes entiers centrés, bord gauche en dents de scie, l'œil incapable de trouver
     le début de la ligne suivante. C'est la pire chose qu'on puisse faire à un texte courant. */
  text-align: left;
  /* Le plafond était à 620 pixels : sur un écran large, le panneau ne gardait plus que 31 % de la page pendant que la
     carte en prenait 69. Il suit maintenant la fenêtre jusqu'à 820. */
  --panneau: min(46vw, 820px);
  width: var(--panneau); padding: clamp(1.2rem, 2.4vh, 2rem) clamp(1.2rem, 2vw, 2.2rem);
  /* `contain` enfermait la molette : tant que le curseur était sur le panneau, le voyage ne bougeait plus. On laisse
     donc la chaîne se faire — on lit la fin de l'escale, puis le défilement reprend la mer où il l'avait laissée. */
  overflow-y: auto; z-index: 3;
  /* Le voile est à 88 % et non 84 : sur la partie claire de la carte, le fond composé passe de
     (46, 51, 48) à (36, 43, 39), ce qui remonte tout le panneau d'un demi-point de contraste sans
     que la différence se voie. */
  background: linear-gradient(to left, rgba(13, 23, 28, 0), rgba(13, 23, 28, .64) 5%, rgba(13, 23, 28, .88) 14%);
  color: var(--parchemin-clair); font-family: var(--police-corps);
  font-size: clamp(1rem, 1.9vh, 1.25rem); line-height: 1.62;
}
/* Le dégradé du bas, posé seulement quand l'escale dépasse la fenêtre (js/ocean.js) : il dit que le texte continue.
   Il est en `sticky` dans le panneau, donc il suit le défilement et s'efface quand on arrive au bout. */
.escale-panneau--deborde::after {
  content: ""; display: block; position: sticky; bottom: calc(-1 * clamp(1.2rem, 2.4vh, 2rem));
  height: 3.5rem; margin-bottom: calc(-1 * clamp(1.2rem, 2.4vh, 2rem)); pointer-events: none;
  margin-left: calc(-1 * clamp(1.2rem, 2vw, 2.2rem)); margin-right: calc(-1 * clamp(1.2rem, 2vw, 2.2rem));
  background: linear-gradient(to top, rgba(13, 23, 28, .92), rgba(13, 23, 28, 0));
}
/* la mesure : au-delà d'environ soixante-dix signes par ligne, l'œil perd la ligne suivante en revenant à la marge */
.escale-panneau > * { max-width: 68ch; }
/* Le titre du panneau porte un intitulé de poste, c'est-à-dire un renseignement : il passe dans la police de lecture.
   Le gothique reste sur la page, où il titre un carnet et non une fiche. */
.escale-panneau h2 { font-family: var(--police-corps); font-weight: 600; color: var(--parchemin-clair); font-size: clamp(1.35rem, 3.1vh, 1.95rem); margin: 0 0 .5rem; line-height: 1.2; letter-spacing: -.01em; }
.escale-panneau p { margin: 0 0 .4rem; }
.escale-panneau .escale__annotation, .escale-panneau .ile__traversee, .escale-panneau .ile__parcours { font-family: var(--police-main); color: var(--or); font-size: 1.12em; }
.escale-panneau .ile__entreprise { font-weight: 700; color: var(--parchemin-clair); }
.escale-panneau ul { list-style: none; padding: 0; margin: .5rem 0 0; }
.escale-panneau .ile__travaux li { padding-left: 1.3rem; position: relative; margin-bottom: .2rem; }
.escale-panneau .ile__travaux li::before { content: "☠"; position: absolute; left: 0; color: var(--or); }
/* Les étiquettes du panneau sont plus serrées que celles de la page : neuf technologies y tiennent sur deux rangs
   au lieu de trois, et c'est une escale entière qui reste dans la fenêtre. */
.escale-panneau .etiquettes { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .5rem; }
.escale-panneau .etiquette { padding: 0 .45rem; border: 1px solid rgba(232, 213, 168, .4); border-radius: 999px; font-size: .78em; }
/* le papier et le sceau de la page n'ont pas leur place ici : le panneau a son propre fond */
.escale-panneau .escale__papier, .escale-panneau svg.papier, .escale-panneau .sceau { display: none; }

/* ---- La traduction de la palette pour le fond sombre ----
   La page est de l'encre sur du papier : rouge de cire pour l'emphase, or sombre pour le second plan, encre pour le
   reste. Le panneau est l'exact inverse, du clair sur du sombre, et rien de tout cela n'y tient. Mesuré sur les six
   escales : les étiquettes de pile tombaient à 1,03 contre 1, les liens de contact à 1,14, les noms de projet et les
   années de formation à 1,85, les lignes de second plan à 2,14. Le seuil lisible est à 4,5.
   Trois classes avaient déjà leur réponse ici, ajoutées une par une au fil des pannes. Les voici toutes, au même
   endroit : sur fond sombre, l'or remplace le rouge et l'or sombre, le parchemin clair remplace l'encre. */
.escale-panneau .port__cap,
.escale-panneau .taverne__statut,
.escale-panneau .rouleau__annee,
.escale-panneau .projet__nom,
.escale-panneau .coffre__groupe h3,
.escale-panneau .ile__resultat strong { color: var(--or); }
.escale-panneau .port__bord,
.escale-panneau .projet__resume,
.escale-panneau .chantier__renvoi { color: var(--or); }
.escale-panneau .ile__resultat { background: rgba(201, 150, 58, .1); border-left-color: var(--or); }
.escale-panneau .rouleau { background: rgba(232, 213, 168, .07); border-left-color: var(--or); border-right-color: var(--or); box-shadow: none; }
.escale-panneau .etiquette { color: var(--parchemin-clair); background: transparent; }
.escale-panneau .bouteille {
  color: var(--parchemin-clair);
  border-color: var(--or);
  background: rgba(201, 150, 58, .1);
}
.escale-panneau .bouteille:hover { background: var(--or); color: #1a1208; }
/* Les accès de la taverne : la liste de fiche, comme ailleurs dans le panneau. Pas de filets — trois traits pour
   trois lignes dessinaient un tableau là où une puce suffit. */
.escale-panneau .fiche__liste--liens li { margin-bottom: .35rem; }
/* Les crédits tiennent dans le pied de la fiche : petits, sans chasse, et leurs liens restent repérables */
.escale-panneau .fiche__pied .emprunts { margin: 0; font-size: .82em; line-height: 1.45; }
.escale-panneau .fiche__pied .emprunts li { margin-bottom: .2rem; }
.escale-panneau .emprunts { color: color-mix(in srgb, var(--parchemin-clair) 72%, transparent); }
.escale-panneau .emprunts a { text-decoration-color: color-mix(in srgb, var(--or) 60%, transparent); }
.escale-panneau .emprunts a:hover { color: var(--or); }
.escale-panneau .taverne__sobre a { color: var(--or); }
.escale-panneau .fiche__cle a { color: var(--or); text-decoration-color: color-mix(in srgb, var(--or) 50%, transparent); }

/* ---- La fiche : la forme courte des escales dans le panneau ----
   Le panneau n'est pas la page. Sur la page on lit un carnet, avec son vocabulaire de carte et ses écritures à la
   main ; ici on consulte un renseignement, et il faut le trouver sans le lire. D'où des libellés en clair plutôt que
   des métaphores, et la police de lecture partout où il y a une information — une police d'enseigne se lit de loin
   et en trois mots, elle ralentit tout ce qui renseigne. */
.fiche__surtitre {
  font-family: var(--police-corps);
  font-size: .78em;
  letter-spacing: .12em;
  text-transform: uppercase;
  /* L'or plein et non dilué : sur ce fond, l'or n'atteint que 5,37 à pleine intensité, donc toute
     dilution tombe sous le seuil de 4,5. La petite capitale espacée suffit à le tenir au second rang. */
  color: var(--or);
  margin: 0 0 .5rem;
}
/* Serré d'un cran : cinq escales sur huit dépassaient la fenêtre et perdaient leur fin sous le bord. L'interligne
   du texte, lui, ne bouge pas : c'est le blanc entre les blocs qui payait. */
.escale-panneau .fiche__bloc { margin: 0 0 .7rem; }
.fiche__cle {
  font-family: var(--police-corps);
  font-size: .76em;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--parchemin-clair) 70%, transparent);
  margin: 0 0 .15rem;
}
.fiche__valeur { font-size: 1.12em; color: var(--or); margin: 0; }
/* Le pied de fiche : deux colonnes, le libellé aligné sur la clé des blocs au-dessus */
.fiche__pied {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .25rem 1.1rem;
  margin: .9rem 0 0;
  padding-top: .6rem;
  border-top: 1px solid color-mix(in srgb, var(--parchemin-clair) 22%, transparent);
  font-size: .95em;
}
.fiche__pied dt {
  font-size: .8em;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--parchemin-clair) 70%, transparent);
  align-self: baseline;
}
.fiche__pied dd { margin: 0; }
.escale-panneau .fiche__sous-titre { margin: -.7rem 0 .25rem; color: color-mix(in srgb, var(--parchemin-clair) 80%, transparent); }
.escale-panneau .fiche__dates { margin: 0 0 .5rem; font-size: .92em; color: color-mix(in srgb, var(--parchemin-clair) 70%, transparent); }
.escale-panneau .fiche__liste { list-style: none; padding: 0; margin: 0; display: grid; gap: .35rem; }
.escale-panneau .fiche__liste li { padding-left: 1.05rem; position: relative; }
.escale-panneau .fiche__liste li::before { content: ""; position: absolute; left: 0; top: .62em; width: .4rem; height: .4rem; border-radius: 50%; background: var(--or); }
.escale-panneau .fiche__liste--liens a { color: var(--or); text-underline-offset: .22em; }
.escale-panneau .fiche__etat {
  font-size: .78em; letter-spacing: .06em; text-transform: uppercase;
  color: color-mix(in srgb, var(--parchemin-clair) 70%, transparent);
}
/* Le reste des travaux dans la fiche : le bloc porte déjà son libellé, le bouton n'a plus à se répéter */
.escale-panneau .fiche__bloc .ile__detail { margin-top: 0; }
/* Le bouton qui déplie la suite des travaux est du texte de lecture, pas une enseigne. */
.escale-panneau .ile__detail > summary,
.escale-panneau .projet__detail > summary { font-family: var(--police-corps); font-size: .94em; letter-spacing: .02em; }
/* Le nom d'un projet dans le panneau : un titre, pas une étiquette. En capitales étroites il était le plus petit
   texte de la carte alors qu'il en nomme l'objet, et la phrase qui le décrit paraissait plus importante que lui.
   Un filet sépare les projets : sans lui, nom, phrase et bouton se répétaient à intervalle égal et rien ne disait
   où un projet finissait. */
.fiche__nom {
  font-family: var(--police-corps); font-size: 1.08em; font-weight: 600; color: var(--or);
  margin: 0 0 .2rem; letter-spacing: 0; text-transform: none;
}
.fiche__nom a { color: inherit; text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); }
.fiche__nom a:hover, .fiche__nom a:focus-visible { text-decoration-color: currentColor; }
.fiche__quand {
  margin-left: .6em; font-family: var(--police-corps); font-size: .68em; font-weight: 400;
  letter-spacing: .08em; text-transform: uppercase;
  color: color-mix(in srgb, var(--parchemin-clair) 70%, transparent);
}
/* Pas de filet entre les projets : un trait par projet faisait un tableau. C'est le blanc qui groupe — serré entre
   le nom, sa phrase et son bouton, large entre deux projets. */
.escale-panneau .fiche__nom { margin-top: 1.5rem; }
.escale-panneau .fiche__bloc:first-of-type .fiche__nom { margin-top: 0; }
/* Le repli d'un projet dans le panneau : discret, sinon sept boutons dorés alignés concurrencent sept titres */
.escale-panneau .projet__detail { margin-top: .35rem; }
.escale-panneau .projet__detail > summary {
  font-size: .88em; border-bottom: 0;
  color: color-mix(in srgb, var(--parchemin-clair) 70%, transparent);
}
/* Le repli des projets secondaires est un bloc à lui seul : il se détache comme un projet, pas comme un détail */
.escale-panneau .projet__detail--autres { margin-top: 1.5rem; }
.escale-panneau .projet__detail--autres > summary { font-size: 1em; color: var(--or); }
.escale-panneau .projet__detail--autres .fiche__nom { margin-top: 1.2rem; }
.escale-panneau .projet__detail > summary:hover,
.escale-panneau .projet__detail > summary:focus-visible { color: var(--or); }
.escale-panneau .projet__detail p { color: var(--parchemin-clair); }
/* Le nom d'un projet est un `p` : la règle ci-dessus l'attrapait et les projets du second rang perdaient leur or.
   Un nom garde sa couleur, qu'il soit déplié ou non. */
.escale-panneau .projet__detail .fiche__nom { color: var(--or); }
/* Les étiquettes dans un repli de projet : même forme que partout, serrées d'un cran parce qu'elles arrivent au
   bout d'un paragraphe et non au bout d'une fiche. */
.escale-panneau .projet__detail .etiquettes { margin-top: .5rem; }
/* La suite des travaux, repliée. Une escale se lit d'abord vite : le problème, les travaux de tête, ce qui a changé.
   Le reste attend qu'on le demande. */
.ile__detail { margin-top: .9rem; }
.ile__detail > summary {
  cursor: pointer; display: inline-block; list-style: none;
  font-family: var(--police-main); font-size: 1.15em; color: var(--or);
  border-bottom: 1px dashed currentColor; padding-bottom: 1px;
}
.ile__detail > summary::-webkit-details-marker { display: none; }
.ile__detail > summary::after { content: " ▾"; }
.ile__detail[open] > summary::after { content: " ▴"; }
.ile__detail > summary:hover, .ile__detail > summary:focus-visible { color: var(--parchemin-clair); }
.ile__detail .ile__travaux { margin-top: .6rem; }
/* à l'impression, rien ne reste replié : le papier n'a pas de bouton */
@media print { .ile__detail > summary { display: none; } }
/* Les deux contrôles se rangent du côté opposé au panneau, empilés, et ne bougent plus : leur place ne dépend plus de
   ce qui s'affiche. La boussole garde son coin ; la lanterne, qui vit à gauche partout ailleurs, la rejoint le temps
   du voyage. */
html.voyage-3d .lanterne { left: auto; right: 1.25rem; bottom: calc(1.25rem + 84px + .8rem); }
/* Écran étroit : le panneau passe en bas, sur toute la largeur — une colonne de 34 % y serait illisible */
@media (max-width: 720px) {
  .escale-panneau { --panneau: 100%; top: auto; width: 100%; max-height: 46%;
    background: linear-gradient(to bottom, rgba(13, 23, 28, 0), rgba(13, 23, 28, .86) 14%); }
  /* Panneau en bas sur écran étroit : les deux contrôles remontent au-dessus de lui */
  html.voyage-3d .boussole { right: .75rem; bottom: calc(.75rem + var(--fiche, 0) * 47vh); }
  html.voyage-3d .lanterne { left: auto; right: .75rem; bottom: calc(.75rem + 56px + .6rem + var(--fiche, 0) * 47vh); }
}
