/* =========================================================================
   Ouraya, la couche de mouvement.

   REGLE QUE JE ME DONNE : chaque effet doit vouloir dire quelque chose. Une
   page qui raconte un chemin merite un trait qui se dessine a mesure qu'on
   descend. Un bloc qui glisse parce que c'est joli n'a rien a faire ici.

   TROIS CONTRAINTES TENUES :

   1. Rien d'autre que « transform » et « opacity » n'est anime. Ce sont les
      deux seules proprietes que le navigateur traite sans recalculer la mise
      en page, donc les seules qui tiennent soixante images par seconde sur
      une machine ordinaire.
   2. Sans JavaScript, TOUT reste lisible. Les elements a reveler sont
      visibles par defaut, et c'est le script qui les cache avant de les
      montrer. Un script qui ne se charge pas laisse donc une page complete,
      jamais une page blanche.
   3. « prefers-reduced-motion » coupe tout, y compris le trait qui se
      dessine. Ce reglage n'est pas un confort : le mouvement declenche des
      nausees et des migraines chez une partie des lecteurs.
   ========================================================================= */

/* -------------------------------------------------------- barre de lecture */
/* Elle dit ou l'on en est dans une page longue. Sur la charte, qui se lit en
   entier ou pas du tout, c'est l'information la plus utile de l'ecran. */
.progression {
  position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 30;
  background: transparent; pointer-events: none;
}
.progression i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--ambre-sombre), var(--ambre));
  transform-origin: left center;
}

/* ------------------------------------------------------------- revelation */
/* Visible par defaut. Le script ajoute « .voile » avant de reveler, ce qui
   garantit qu'une page sans JavaScript reste entiere. */
.voile { opacity: 0; transform: translate3d(0, 22px, 0); }
.voile.vu {
  opacity: 1; transform: none;
  transition: opacity .7s cubic-bezier(.16,1,.3,1), transform .7s cubic-bezier(.16,1,.3,1);
}
/* Les enfants d'une grille arrivent l'un apres l'autre, jamais tous ensemble.
   Le decalage reste court : au dela de 90 ms par carte, on attend. */
.voile.vu > * { animation: monter .62s cubic-bezier(.16,1,.3,1) backwards; }
.grille.voile.vu > *:nth-child(1) { animation-delay: .00s }
.grille.voile.vu > *:nth-child(2) { animation-delay: .07s }
.grille.voile.vu > *:nth-child(3) { animation-delay: .14s }
.grille.voile.vu > *:nth-child(4) { animation-delay: .21s }
.grille.voile.vu > *:nth-child(5) { animation-delay: .28s }
.grille.voile.vu > *:nth-child(6) { animation-delay: .35s }
.grille.voile.vu > *:nth-child(7) { animation-delay: .42s }
.grille.voile.vu > *:nth-child(8) { animation-delay: .49s }
@keyframes monter { from { opacity: 0; transform: translate3d(0, 16px, 0) } }

/* ---------------------------------------------------------------- aurore */
/* Le fond du hero respire. Trente secondes par cycle : assez lent pour qu'on
   ne le remarque pas en lisant, assez present pour que la page ne soit pas
   morte quand on s'arrete dessus. */
.hero .lueur { animation: respirer 30s ease-in-out infinite; }
@keyframes respirer {
  0%, 100% { opacity: 1;   transform: translateX(-50%) scale(1) }
  50%      { opacity: .72; transform: translateX(-50%) scale(1.09) }
}

/* Une seconde nappe, decalee, qui donne la profondeur. Elle vit dans le hero,
   qui est en position relative : sans cet ancetre elle echapperait au
   decoupage horizontal du corps de page. */
.hero .halo {
  position: absolute; z-index: 0; pointer-events: none;
  top: -12%; right: -8%; width: min(620px, 76%); aspect-ratio: 1;
  background: radial-gradient(circle at 50% 50%, rgba(232,163,61,.20), transparent 62%);
  animation: deriver 24s ease-in-out infinite alternate;
}
@keyframes deriver {
  from { transform: translate3d(0, 0, 0) scale(1) }
  to   { transform: translate3d(-40px, 34px, 0) scale(1.14) }
}

/* -------------------------------------------------------------- parallaxe */
/* Le decalage est pilote par le script, qui pose « --p » entre -1 et 1. La
   profondeur reste faible : au dela d'une quarantaine de pixels, l'effet se
   voit plus qu'il ne sert. */
[data-parallaxe] { will-change: transform; }
[data-parallaxe] { transform: translate3d(0, calc(var(--p, 0) * var(--profondeur, 30px)), 0); }

/* ------------------------------------------------- le trait qui se dessine */
/* La colonne vertebrale de la charte. Le trait avance avec la lecture, et les
   jalons s'allument au passage. C'est la seule animation de la page qui porte
   du sens plutot que du confort. */
.chemin { position: relative; }
.chemin .rail {
  position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--filet); border-radius: 2px;
}
.chemin .rail i {
  position: absolute; inset: 0 0 auto 0; height: 0;
  background: linear-gradient(180deg, var(--ambre), var(--ambre-sombre));
  border-radius: 2px;
}
.jalon { position: relative; padding-left: 34px; }
.jalon::before {
  content: ""; position: absolute; left: -5px; top: 9px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--papier); border: 2px solid var(--filet);
  transition: background .35s ease, border-color .35s ease, transform .35s ease;
}
.jalon.atteint::before {
  background: var(--ambre); border-color: var(--ambre-sombre); transform: scale(1.25);
}

/* --------------------------------------------------------- chiffres ronds */
/* Huit regles et sept refus se comptent. Les numeroter aide a s'y retrouver
   et a en citer une par son rang. */
.carte.numerotee { counter-increment: pastille; }
.carte.numerotee h3::before {
  content: counter(pastille, decimal-leading-zero);
  display: block; margin-bottom: 10px;
  font: 400 12px/1 var(--mono); letter-spacing: .14em;
  color: var(--ambre-sombre);
}
.grille.compteur { counter-reset: pastille; }

/* --------------------------------------------------------------- filigrane */
/* Le signe, tres pale, derriere une section. Il occupe le vide sans reclamer
   l'attention, et se deplace un peu moins vite que le texte. */
.filigrane {
  position: absolute; z-index: 0; pointer-events: none; user-select: none;
  opacity: .05; width: min(420px, 46%);
}

/* --------------------------------------------- survol des cartes, discret */
.carte, .porte {
  transition: transform .28s cubic-bezier(.16,1,.3,1), box-shadow .28s ease,
              border-color .28s ease;
}
.carte:hover {
  transform: translateY(-3px);
  border-color: rgba(232,163,61,.55);
  box-shadow: 0 14px 34px -18px rgba(18,33,58,.42);
}

/* ------------------------------------------------------------------ citation */
/* Le filet de la citation se remplit quand elle entre dans l'ecran, comme une
   phrase qu'on souligne en lisant. */
blockquote { position: relative; border-left-color: transparent; }
blockquote::before {
  content: ""; position: absolute; left: -3px; top: 0; width: 3px; height: 0;
  background: var(--ambre); border-radius: 3px;
  transition: height .8s cubic-bezier(.16,1,.3,1);
}
blockquote.vu::before { height: 100%; }


/* ------------------------------------------------------------ illustration */
/* Le seul dessin de la charte. Il montre ce que le texte dit : la dispersion
   d'un cote, ce qui tient de l'autre, et un passage entre les deux. */
.illustration { margin: 34px 0 0; }
.illustration svg { width: 100%; height: auto; display: block; max-width: 860px; }
.illustration figcaption { margin-top: 14px; max-width: 62ch; }

/* Le trait se dessine quand la figure entre a l'ecran. 620 est la longueur
   approchee du chemin ; une valeur trop courte laisserait un bout deja
   dessine au depart, ce qui se voit. */
.illustration .passage { stroke-dashoffset: 620; }
.illustration.vu .passage { animation: tracer 1.5s .25s cubic-bezier(.5,0,.2,1) forwards; }
@keyframes tracer { to { stroke-dashoffset: 0 } }

/* Les points disperses flottent, chacun a son rythme. C'est ce decalage qui
   donne l'impression du desordre plutot que d'une grille qui respire. */
.illustration .dispersion circle { animation: errer 9s ease-in-out infinite alternate; }
.illustration .dispersion circle:nth-child(3n)   { animation-duration: 11s; animation-delay: -2s }
.illustration .dispersion circle:nth-child(3n+1) { animation-duration: 8s;  animation-delay: -5s }
@keyframes errer {
  from { transform: translate(0, 0) }
  to   { transform: translate(5px, -7px) }
}

/* Le collectif, lui, ne bouge pas. Il respire, une fois toutes les six
   secondes, et c'est tout. La difference de traitement EST le propos. */
.illustration .collectif { transform-origin: 700px 128px; animation: pulser 6s ease-in-out infinite; }
@keyframes pulser {
  0%, 100% { transform: scale(1) }
  50%      { transform: scale(1.022) }
}

@media (prefers-reduced-motion: reduce) {
  .illustration .passage { stroke-dashoffset: 0 !important; animation: none !important }
  .illustration .dispersion circle,
  .illustration .collectif { animation: none !important }
}


/* ========================================================== bascule de mode */
/* LA TRANSITION ENTRE LES DEUX MODES

   Deux mecanismes, du plus beau au plus sur :

   1. « View Transitions », quand le navigateur le propose. Le nouveau mode
      est revele par un disque qui s'ouvre depuis le bouton. On dessine donc
      reellement le geste : la lumiere part de la ou on a appuye.
   2. A defaut, une transition de couleur sur les surfaces. Moins spectaculaire,
      et suffisant.

   La transition est POSEE PAR LE SCRIPT, le temps du changement, puis retiree.
   La laisser en permanence ferait trainer chaque survol de carte et chaque
   changement d'etat, ce qui donne cette impression de logiciel mou. */
html.change-de-mode,
html.change-de-mode body,
html.change-de-mode .barre,
html.change-de-mode .carte,
html.change-de-mode .porte,
html.change-de-mode .panneau,
html.change-de-mode section,
html.change-de-mode footer,
html.change-de-mode .champ textarea,
html.change-de-mode .champ input {
  transition: background-color .42s ease, color .42s ease, border-color .42s ease !important;
}

::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
/* L'ancien mode reste dessous, immobile ; le nouveau s'ouvre par-dessus. */
::view-transition-old(root) { z-index: 1 }
::view-transition-new(root) { z-index: 2 }

html.reveler-mode::view-transition-new(root) {
  animation: ouvrir .58s cubic-bezier(.4,0,.2,1);
}
@keyframes ouvrir {
  from { clip-path: circle(0 at var(--bascule-x, 50%) var(--bascule-y, 0)) }
  to   { clip-path: circle(160% at var(--bascule-x, 50%) var(--bascule-y, 0)) }
}

@media (prefers-reduced-motion: reduce) {
  html.change-de-mode, html.change-de-mode * { transition: none !important }
  html.reveler-mode::view-transition-new(root) { animation: none }
}

/* ==========================================================================
   Le reglage systeme l'emporte sur tout ce qui precede.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .voile, .voile.vu, .voile.vu > * { opacity: 1 !important; transform: none !important;
                                     animation: none !important; transition: none !important }
  .hero .lueur, .hero .halo { animation: none !important }
  [data-parallaxe] { transform: none !important }
  .chemin .rail i { height: 100% !important }
  .jalon::before { background: var(--ambre); border-color: var(--ambre-sombre) }
  blockquote { border-left-color: var(--ambre) }
  blockquote::before { display: none }
  .carte:hover { transform: none }
  .progression { display: none }
}
