/* ================= LE CIEL, ET LE PASSAGE D'UNE PAGE À L'AUTRE =================

   Il n'y a plus de voile. Rien ne vient se poser devant la page.

   ---- L'IDÉE ----

   Toutes les pages partagent LE MÊME décor : un seul élément, une seule
   composition de dégradé, aux mêmes endroits. Ce qui change d'une page à
   l'autre, ce sont uniquement SES QUATRE COULEURS.

   Quand on clique un lien, on ne masque pas la page : on donne au ciel les
   couleurs de la page de destination, et on le laisse virer. Le contenu, lui,
   se dissout doucement pendant ce temps. Quand la nouvelle page arrive, son
   ciel est DÉJÀ de la bonne couleur — puisque c'est le même élément, avec la
   même formule, et que la couleur a fini de changer avant la navigation.

   Résultat : on ne voit jamais de transition. On voit le monde virer, et le
   contenu se recomposer dedans. Le décor, lui, n'a jamais cligné.

   ---- POURQUOI C'EST POSSIBLE ----

   Une propriété personnalisée ne s'anime pas : le navigateur la traite comme
   du texte et saute d'une valeur à l'autre. `@property` lui donne un type —
   ici `<color>` — et elle devient interpolable. Le navigateur mélange alors
   les couleurs lui-même, sur le compositeur, sans qu'une seule ligne de
   JavaScript ne touche à un pixel.

   C'est la pièce qui rend toute la mécanique possible. Sans elle, il faudrait
   calculer les couleurs intermédiaires en JavaScript et les réécrire à chaque
   image — ce qui reviendrait à repeindre le fond soixante fois par seconde.

   ---- LE CAS DE L'ACCUEIL ----

   L'accueil a en plus son canvas WebGPU, qui couvre le ciel. Au départ il se
   dissout, et le ciel CSS — déjà passé aux couleurs de la destination —
   apparaît dessous. À l'arrivée, il se reforme par-dessus. Le canvas n'a donc
   rien à savoir de la transition : il fond, c'est tout.

   ---- LE REPLI ----

   Si `@property` manque (Firefox avant 128), les couleurs sautent au lieu de
   virer, mais le fondu du contenu reste : la transition dégrade en fondu
   simple, jamais en à-coup. */

@property --ciel-clair { syntax: "<color>"; inherits: true; initial-value: #c5dcda; }
@property --ciel-masse { syntax: "<color>"; inherits: true; initial-value: #7ea3a3; }
@property --ciel-chaud { syntax: "<color>"; inherits: true; initial-value: #ddc8af; }
@property --ciel-fond  { syntax: "<color>"; inherits: true; initial-value: #4e6e70; }

/* ---- LES PALETTES ----
   Une par page. C'est le SEUL endroit ou elles sont ecrites, et le script de
   repli les lit ici meme (voir transition.js) : aucune couleur n'est
   dupliquee en JavaScript.

   Le selecteur est [data-page] et non body[data-page], volontairement : le
   script fabrique une SONDE — un div portant le data-page de la destination —
   pour demander au navigateur quelles couleurs cette page utilisera. Limite
   au body, le selecteur n'aurait jamais atteint la sonde, et le repli aurait
   silencieusement garde la palette de la page courante.

   ---- UNE SEULE FAMILLE, SIX DECLINAISONS ----

   Turquoise, petrole, vert d'eau, sable, cuivre, ardoise. Ni rose ni violet :
   toutes les teintes froides tiennent entre le bleu-vert et le bleu ardoise
   (170 a 200 degres), toutes les chaudes entre le sable et le cuivre (35 a 70).
   C'est etroit, et c'est fait expres — six pages doivent se distinguer sans
   avoir l'air de six sites.

   Ce qui les separe n'est donc pas la teinte mais la TEMPERATURE : de la plus
   froide (le referencement, bleu ardoise) a la plus chaude (le contact, sable
   et ambre), en passant par le neutre (la methode). On sent le changement
   d'ambiance sans pouvoir nommer la couleur — c'est le but.

   Toutes montent haut en clarte : le ciel est une lumiere, pas une masse. La
   teinte la plus sombre de chaque page — celle du bord — reste claire, ce qui
   garde le decor ouvert jusque dans ses angles. */
:root {
  /* L'accueil : turquoise et peche. Les teintes de la scene du toucan,
     portees en CSS pour que le ciel puisse continuer sans le canvas. */
  --ciel-clair: #e4f2f0;
  --ciel-masse: #b6dad6;
  --ciel-chaud: #fae2c8;
  --ciel-fond:  #8fbebc;
}

/* L'accueil, nomme explicitement : la sonde du repli interroge un div portant
   data-page="accueil", et elle doit y trouver la meme chose que :root. Les
   deux sont ecrits cote a cote pour qu'ils ne puissent pas diverger. */
[data-page="accueil"] {
  --ciel-clair: #e4f2f0;
  --ciel-masse: #b6dad6;
  --ciel-chaud: #fae2c8;
  --ciel-fond:  #8fbebc;
}

/* L'acces client : LA PLUS SOBRE DES SIX. C'est une page de connexion — on y
   vient pour faire une chose et repartir, pas pour regarder. Le ciel y est
   donc SOBRE — un petrole doux, grise, sans eclat — avec un rappel de sable
   en bas a droite. Assez de couleur pour qu'on reconnaisse le site, jamais
   assez pour distraire du formulaire. Ni un blanc d'hopital, ni une page qui
   cherche a plaire : une page ou l'on travaille.

   Consequence a assumer : sur un fond aussi clair, le verre fume du panneau
   ne suffit plus a detacher son encre blanche. Il est donc epaissi ici, et
   ici seulement (voir --barre-verre dans acces.css). */
[data-page="acces"] {
  --ciel-clair: #d8e4e3;
  --ciel-masse: #adc3c3;
  --ciel-chaud: #dcc3a2;
  --ciel-fond:  #82a0a1;
}

/* Le contact : sable et ambre. La plus chaude des six — c'est la page ou l'on
   tend la main. */
/* CONTACT PORTE LE CIEL DE L'ACCUEIL, a l'identique. Sa palette doree
   posait un foyer orange en plein sous la table — illisible pour une page
   de lecture, et etrangere au reste du parcours. Les quatre valeurs sont
   donc celles de l'accueil : on ne voit plus le monde virer entre les deux
   pages, on le voit CONTINUER. */
[data-page="contact"] {
  --ciel-clair: #e4f2f0;
  --ciel-masse: #b6dad6;
  --ciel-chaud: #fae2c8;
  --ciel-fond:  #8fbebc;
}

/* Le design : vert d'eau et laiton. */
[data-page="design"] {
  --ciel-clair: #e6f2e8;
  --ciel-masse: #bcdcc4;
  --ciel-chaud: #f0deb2;
  --ciel-fond:  #8cb89b;
}

/* Le referencement : bleu ardoise et or pale. La plus froide des six. */
[data-page="geo"] {
  --ciel-clair: #e0ecf1;
  --ciel-masse: #b0cad7;
  --ciel-chaud: #ebdfb9;
  --ciel-fond:  #7e9cad;
}

/* La methode : gris vert tres clair, presque neutre. La page qui explique n'a
   pas besoin de couleur. */
[data-page="methode"] {
  --ciel-clair: #f0f3f1;
  --ciel-masse: #ced5d2;
  --ciel-chaud: #e5ddcf;
  --ciel-fond:  #a6b0ad;
}

/* ---- LE CIEL ----
   Un seul élément, fixe, sous tout le reste. La composition ne change JAMAIS
   — deux foyers et une masse, toujours aux mêmes endroits. C'est cette
   constance qui fait qu'on lit un changement de couleur et non un changement
   de décor.

   La transition ne porte que sur les quatre couleurs. 1100 ms, une courbe
   symétrique et molle : ni départ sec, ni freinage. */
.ciel {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(52% 58% at 78% 76%, var(--ciel-chaud), transparent 70%),
    radial-gradient(125% 112% at 22% 26%,
      var(--ciel-clair) 0%,
      var(--ciel-masse) 55%,
      var(--ciel-fond) 100%);
  transition:
    --ciel-clair 1100ms cubic-bezier(0.4, 0, 0.2, 1),
    --ciel-masse 1100ms cubic-bezier(0.4, 0, 0.2, 1),
    --ciel-chaud 1100ms cubic-bezier(0.4, 0, 0.2, 1),
    --ciel-fond  1100ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Le grain : un aplat de dégradé sur un écran 8 bits fait des anneaux. Même
   remède que la scène — un bruit sous le seuil visible. */
.ciel::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* ---- LE CONTENU ----
   Tout sauf le ciel. Il se dissout au départ et se reforme à l'arrivée.

   Un fondu SEUL suffirait, mais il donnerait l'impression d'une image qu'on
   éteint. Le souffle de flou et le demi-pourcent d'échelle en plus font que
   le contenu semble s'éloigner dans le décor plutôt que disparaître de
   l'écran — c'est la différence entre un fondu et une dissolution.

   La sortie est plus rapide que l'entrée (620 contre 900) : on quitte
   franchement, on arrive doucement. */
/* Le repli suit le meme rythme que le natif : l'ancien part (760), le nouveau
   arrive apres un temps (1000, retard 520). Pendant ce temps, seul le ciel.

   L'en-tete et la barre de chat sont EXCLUS du fondu : ils ne bougent pas
   d'une page a l'autre, ils n'ont pas a disparaitre puis revenir. */
body > *:not(.ciel):not(.entete):not(.barre) {
  transition:
    opacity 1000ms cubic-bezier(0, 0, 0.2, 1) 520ms,
    filter 1000ms cubic-bezier(0, 0, 0.2, 1) 520ms,
    transform 1000ms cubic-bezier(0, 0, 0.2, 1) 520ms;
}

html[data-passage="part"] body > *:not(.ciel):not(.entete):not(.barre) {
  opacity: 0;
  filter: blur(8px);
  transform: scale(1.008);
  transition-duration: 760ms;
  transition-delay: 0s;
  transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}

/* L'arrivée : l'état de départ est posé par le script AVANT le premier rendu,
   donc le contenu n'apparaît jamais net avant de se fondre. */
html[data-passage="arrive"] body > *:not(.ciel):not(.entete):not(.barre) {
  opacity: 0;
  filter: blur(8px);
  transform: scale(0.994);
  transition: none;
}

/* Mouvement réduit : aucun fondu, aucune attente. Le ciel garde sa transition
   de couleur — ce n'est pas un mouvement, et la supprimer ferait un à-coup
   plus violent que la garder. */
@media (prefers-reduced-motion: reduce) {
  body > *:not(.ciel) { transition: none; }
  html[data-passage] body > * {
    opacity: 1;
    filter: none;
    transform: none;
  }
}


/* ================= LE PASSAGE, EN NATIF =================

   Tout ce qui precede decrit CE QU'ON VEUT voir. Ce qui suit dit au
   navigateur de le faire lui-meme.

   `@view-transition { navigation: auto }` fait qu'un changement de page
   dans le meme site n'est plus une coupure : le navigateur photographie l'ancienne
   page, charge la nouvelle, et anime le passage entre les deux. Sans script,
   sans voile, et sans le clignotement blanc du chargement.

   ---- CE QUI PERSISTE, ET CE QUI SE FOND ----

   C'est le point qui change tout. Un element nomme par `view-transition-name`
   n'est PAS traite avec le reste : le navigateur le reconnait des deux cotes
   et l'anime d'une position a l'autre, au lieu de le faire disparaitre puis
   reapparaitre.

   On nomme donc les quatre pieces qui existent sur toutes les pages :

     — LE CIEL. Meme element, memes foyers, seules ses couleurs different :
       le navigateur fond l'un dans l'autre, et c'est exactement le  monde qui
       vire  qu'on cherchait. Sans ce nom, le ciel serait redessine d'un coup
       avec le reste.
     — L'EN-TETE. Les etiquettes ne bougent pas d'un pixel entre deux pages :
       elles doivent rester en place, pas clignoter. Seule celle qui devient
       active change d'etat.
     — LA BARRE DE CHAT, pour la meme raison. Elle est fixe en bas, elle n'a
       aucune raison de partir et de revenir.
     — L'HEURE.

   Le reste — le contenu — se croise en fondu. C'est le comportement par
   defaut de `root`, on ne fait que l'allonger et l'adoucir.

   ---- LE REPLI ----

   Firefox et les Safari anciens ignorent tout ce bloc. transition.js prend
   alors le relais et refait la meme chose a la main : le ciel vire, le
   contenu se dissout. Le script se desactive tout seul quand le natif est
   disponible. */

@view-transition { navigation: auto; }

/* ---- CE QUI PORTE UN NOM, ET CE QUI N'EN PORTE PAS ----

   LE CIEL en porte un : c'est toute l'idee. Le navigateur le reconnait des
   deux cotes et fond l'un dans l'autre — le monde vire au lieu d'etre
   remplace.

   L'EN-TETE en porte un aussi, mais pour une autre raison : sans nom, il
   serait redessine avec le reste et les etiquettes clignoteraient alors
   qu'elles ne bougent pas d'un pixel. Avec un nom, il garde sa place.

   LA BARRE DE CHAT EN PORTE UN A NOUVEAU. L'ancienne barre de verre avait un
   `backdrop-filter` — sa photographie emportait le decor de l'ancienne page,
   d'ou le nom retire a l'epoque. La barre d'aujourd'hui est un pave noir
   PLEIN : sa photographie n'emporte rien. Nommee, elle reste a l'ecran d'une
   page a l'autre au lieu d'attendre le fondu du contenu (demande de Quentin :
   la chatbar est immediatement visible sur la nouvelle page). Le `.scene-barre`
   de la page contact porte le meme nom : une seule barre existe a la fois, et
   le navigateur fait glisser l'une vers l'autre. */

.ciel   { view-transition-name: ciel; }
.entete { view-transition-name: entete; }
.barre, .scene-barre { view-transition-name: barre; }

/* ---- LE RYTHME ----

   Le defaut du navigateur croise l'ancien et le nouveau EN MEME TEMPS. Sur
   des pages qui portent du texte au meme endroit, les deux se superposent a
   mi-course et tout devient illisible pendant un instant — c'est ce qui
   donnait l'impression de brutalite.

   On les met donc BOUT A BOUT au lieu de les superposer : l'ancien s'efface
   d'abord (760 ms), le nouveau n'entre qu'ensuite (1000 ms, apres 520 de
   retard). Il y a un moment, au milieu, ou l'on ne voit QUE le ciel. C'est ce
   moment-la qui fait la douceur : la page ne se remplace pas, elle se vide
   puis se remplit. */
::view-transition-old(root) {
  animation-duration: 760ms;
  animation-timing-function: cubic-bezier(0.4, 0, 1, 1);   /* part doucement, s'en va franchement */
}
::view-transition-new(root) {
  animation-duration: 1000ms;
  animation-delay: 520ms;
  animation-timing-function: cubic-bezier(0, 0, 0.2, 1);   /* arrive vite, se pose longuement */
}

/* L'EN-TETE NE SE CROISE PAS : IL EST LA, TOUT DE SUITE (demande de Quentin).
   Onglets et logo sont identiques d'une page a l'autre au pixel pres — seuls
   l'onglet actif et l'encre changent. Les faire sortir puis revenir avec un
   retard, c'etait montrer une absence. On coupe donc les deux fondus :
   l'ancien disparait a la premiere image (`animation: none` seul le FIGERAIT
   a pleine opacite — l'opacite explicite fait le vrai travail), le nouveau
   est plein des le depart. Le remplacement est imperceptible.

   Le groupe garde une courte course : si l'on quitte une page defilee, ou
   l'en-tete etait replie hors ecran, il GLISSE a sa place en 380 ms au lieu
   d'y apparaitre d'un coup. */
::view-transition-old(entete) { animation: none; opacity: 0; }
::view-transition-new(entete) { animation: none; opacity: 1; }
::view-transition-group(entete) { animation-duration: 380ms; }

/* LA BARRE, meme regle : elle est fixe en bas sur toutes les pages, elle n'a
   aucune raison d'attendre le fondu du contenu. Le groupe anime le passage
   d'une geometrie a l'autre (la barre de contact n'a pas la meme largeur). */
::view-transition-old(barre) { animation: none; opacity: 0; }
::view-transition-new(barre) { animation: none; opacity: 1; }
::view-transition-group(barre) { animation-duration: 380ms; }

/* LE CIEL est le plus lent de tous, et de loin. C'est lui qui tient le
   passage d'un bout a l'autre : quand le contenu a fini de partir et n'est
   pas encore revenu, il est la seule chose a l'ecran, et il est en train de
   virer. La transition dure ce qu'il dure. */
::view-transition-group(ciel) { animation-duration: 1800ms; }
::view-transition-old(ciel),
::view-transition-new(ciel) {
  animation-duration: 1800ms;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}
