/* ==========================================================================
   funact — mouvement et toucher
   Ce qui fait qu'une page se comporte comme une application plutot que comme
   un document : la maniere dont elle entre, dont elle repond au doigt, et dont
   elle cede la place a la suivante.

   UNE SEULE FEUILLE POUR LE BUREAU ET POUR L'APP

   fun-act.com est servi tel quel a un PC et a la WebView Android (voir
   mobile/). Rien ici ne suppose un telephone : les regles tactiles ne
   s'appliquent qu'aux pointeurs grossiers (@media (pointer: coarse)), l'anneau
   de focus reste entier pour qui navigue au clavier, et les transitions de page
   ameliorent le bureau autant que le mobile. Quand une regle doit vraiment
   distinguer les deux, elle s'appuie sur .is-native / .is-web, poses sur <html>
   par native.js.

   AUCUN TOKEN DE COULEUR, ET C'EST DELIBERE

   results.html ne charge PAS theme.css — elle porte ses propres tokens (voir
   l'en-tete de nav.css, qui vit sous la meme contrainte). Cette feuille doit
   donc valoir sur toutes les pages sans exception : elle ne touche qu'a la
   geometrie, a l'opacite et au temps, jamais a une couleur.
   ========================================================================== */

/* --- Grammaire du mouvement ------------------------------------------------
   Quatre valeurs pour tout le site, plutot qu'une duree improvisee par
   composant. C'est ce qui fait qu'une app parait "d'une seule piece" : le
   tiroir, la boite de dialogue et la page changent au meme rythme.

   ENTRER EST PLUS LENT QUE SORTIR. Ce n'est pas une coquetterie : ce qui
   arrive doit etre suivi des yeux, ce qui part n'a plus a etre lu. Une sortie
   aussi lente que l'entree donne exactement la sensation de lourdeur qu'on
   reproche aux interfaces web.

   --ease-emphasized decelere tres fort en fin de course (le mobile arrive vite
   puis se pose) : c'est la courbe des tiroirs et des panneaux, celle que
   results.html utilisait deja seule dans son coin. --ease-standard est plus
   sobre, pour les changements sur place. */
:root {
  --ease-emphasized: cubic-bezier(.32, .72, 0, 1);
  --ease-standard: cubic-bezier(.2, 0, 0, 1);
  --dur-enter: 220ms;
  --dur-exit: 150ms;
}

/* --- Transition entre deux pages -------------------------------------------
   Le site est fait de documents separes (index, results, viewer, app...), et
   passer de l'un a l'autre recharge la WebView : fond nu, puis la page. C'est
   LE signe qui trahit un site emballe dans une app — aucune application native
   ne clignote entre deux ecrans.

   @view-transition confie la jointure au navigateur : il garde l'image de la
   page qu'on quitte a l'ecran pendant que la suivante se prepare, puis fait la
   liaison. Sur une connexion lente — la 4G d'un site de course — c'est la
   derniere page qui reste visible au lieu d'un fond vide, ce qui est
   exactement le comportement natif.

   Le navigateur qui ne connait pas la regle l'ignore et recharge comme avant :
   rien a detecter, rien a replier. */
@view-transition {
  navigation: auto;
}

/* Fondu court, plus une montee de 6px sur la page qui arrive. La montee suffit
   a donner un sens au mouvement — quelque chose remplace quelque chose —
   sans imiter un sens de navigation qu'on ne connait pas ici (avant ? arriere ?
   le navigateur ne le dit pas aux transitions inter-documents). */
::view-transition-old(root) {
  animation: funact-page-out 90ms ease-in both;
}
::view-transition-new(root) {
  animation: funact-page-in var(--dur-enter) var(--ease-standard) both;
}
@keyframes funact-page-out {
  to { opacity: 0; }
}
@keyframes funact-page-in {
  from { opacity: 0; transform: translateY(6px); }
}

/* --- Ce qui ne doit PAS changer d'ecran ------------------------------------
   La regle ci-dessus fait fondre la page ENTIERE, navigation comprise. Or le
   rail et la barre du haut sont les MEMES d'un ecran a l'autre : les voir
   disparaitre puis revenir a chaque passage est exactement ce qui distingue un
   site (on change de document) d'une application (on change d'ecran, le
   chassis reste en place).

   Un view-transition-name sort l'element du cliche de la racine et lui donne
   son propre groupe. Le navigateur retrouve le meme nom des deux cotes de la
   navigation et fait le lien tout seul : le rail ne bouge plus, et seul son
   surlignage d'entree active se fond de l'un vers l'autre.

   EFFET DE BORD RECHERCHE : ce qui reste dans "root" n'est plus que le
   contenu. Le fondu et la montee de 6px definis plus haut ne s'appliquent donc
   plus a toute la fenetre mais au seul panneau qui change — ce qui est le
   mouvement qu'on voulait decrire depuis le debut.

   Le nom doit etre UNIQUE dans le document. Les deux elements sont des
   singletons (nav.js et shell.js ressortent l'existant au lieu d'en monter un
   second), et le prefixe evite la collision avec une page qui nommerait un
   jour un element a elle.

   Quand l'element manque de l'autre cote — on quitte une page a coquille pour
   la carte du spectateur, qui n'en a pas — le navigateur se retrouve avec une
   demi-paire et la fond simplement. Rien a detecter, rien a replier. */

.app-bar { view-transition-name: funact-app-bar; }

@media (min-width: 1024px) {
  /* Le rail n'est nomme qu'au-dessus de 1024px, la ou il est pose a demeure.
     En dessous c'est un tiroir hors ecran (translateX(-100%), voir shell.css) :
     le nommer ferait rasteriser un calque de 280px de large a chaque
     navigation, pour un element que personne ne regarde. */
  .rail { view-transition-name: funact-rail; }
}

/* Le chassis n'ARRIVE pas, il est deja la : il garde le fondu que le navigateur
   met par defaut, mais au rythme du reste du site plutot qu'aux 0,25s de la
   feuille par defaut (voir la grammaire du mouvement en tete de fichier). */
::view-transition-group(funact-app-bar),
::view-transition-old(funact-app-bar),
::view-transition-new(funact-app-bar),
::view-transition-group(funact-rail),
::view-transition-old(funact-rail),
::view-transition-new(funact-rail) {
  animation-duration: var(--dur-enter);
  animation-timing-function: var(--ease-standard);
}

/* --- Hygiene tactile -------------------------------------------------------
   Quatre comportements que le navigateur offre a un DOCUMENT et qui n'ont
   aucun sens dans une APPLICATION. Aucun n'a d'effet sur un PC a la souris. */

html {
  /* Le rectangle gris que Chrome peint sur tout element touche. Il apparait
     APRES le doigt, dure plus longtemps que l'appui, et deborde de la forme du
     bouton : c'est le retour tactile d'un lien hypertexte, pas d'un bouton.
     On le remplace plus bas par un etat :active qui, lui, suit la forme. */
  -webkit-tap-highlight-color: transparent;

  /* Le tire-pour-rafraichir de Chrome et l'elastique en bout de liste. Dans un
     navigateur ils rechargent la page ; dans l'app ils rechargeraient fun-act.com
     par le reseau au moindre geste un peu vif vers le bas, au milieu d'un
     formulaire. Les tiroirs gardent leur propre overscroll-behavior:contain,
     qui joue a un autre niveau. */
  overscroll-behavior-y: none;
}

body {
  /* Supprime l'attente de 300ms du double-tap-pour-zoomer. Le pincement reste
     disponible (c'est ce que "manipulation" preserve), et les cartes MapLibre
     posent leur propre touch-action sur leur canvas. */
  touch-action: manipulation;
}

/* Le menu contextuel du long appui sur une image, et la selection qui part sur
   un glissement mal interprete. Restreint aux COMMANDES : le contenu — un
   resultat, un nom, un temps — doit rester selectionnable et copiable, sur PC
   comme sur telephone. */
button,
[role="button"],
.btn,
.rail-item,
.nav-item,
.switch-btn,
.action,
.app-bar,
.rail-brand,
.rail-group-title {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

/* --- Retour visuel au toucher ----------------------------------------------
   Remplace le rectangle gris supprime plus haut. L'enfoncement est minuscule
   (3%) et surtout IMMEDIAT : aucune transition a l'aller, pour que l'element
   ait deja bouge quand l'oeil arrive. Le retour, lui, est adouci.

   :active plutot qu'une classe posee en JS — le navigateur le pose des le
   contact et le retire des que le doigt part, y compris quand il glisse hors
   du bouton (donc quand le clic n'aura pas lieu), ce qu'un ecouteur maison
   oublie presque toujours de faire.

   Volontairement valable au clic souris aussi : un bouton qui s'enfonce sous
   le curseur n'a jamais desservi une interface de bureau. */
button,
[role="button"],
.btn,
.rail-item,
.nav-item,
.switch-btn,
.action {
  transition: transform var(--dur-exit) var(--ease-standard);
}
button:active,
[role="button"]:active,
.btn:active,
.rail-item:active,
.nav-item:active,
.switch-btn:active,
.action:active {
  transform: scale(.97);
  transition-duration: 0s;
}
/* Rien ne s'enfonce quand rien ne se passe. */
button:disabled:active,
.btn:disabled:active,
.action:disabled:active,
[aria-disabled="true"]:active {
  transform: none;
}
/* Les commandes de MapLibre sont dessinees par la bibliotheque, dans des
   cadres de taille fixe : les mettre a l'echelle les decale de leur bordure. */
.maplibregl-ctrl button:active {
  transform: none;
}

/* --- Anneau de focus : au clavier seulement --------------------------------
   Un bouton touche du doigt garde le focus, donc son anneau, longtemps apres
   que le doigt soit parti. Sur une page web on ne le remarque pas ; dans une
   app, ce contour persistant sur le dernier bouton touche est immediatement
   lu comme "ceci est une page web".

   :focus-visible confie l'arbitrage au navigateur — il le donne au clavier, le
   refuse au doigt et a la souris. La regle ne RETIRE donc rien a la
   navigation au clavier du bureau, qui reste entiere. */
:focus:not(:focus-visible) {
  outline: none;
}

/* --- Respect du reglage systeme --------------------------------------------
   Quelqu'un qui a demande moins de mouvement ne doit pas recevoir une app plus
   animee que le site. Couvre aussi les transitions de page ci-dessus : le
   navigateur saute la liaison et navigue sechement. */
@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
  button,
  [role="button"],
  .btn,
  .rail-item,
  .nav-item,
  .switch-btn,
  .action {
    transition: none;
  }
  button:active,
  [role="button"]:active,
  .btn:active,
  .rail-item:active,
  .nav-item:active,
  .switch-btn:active,
  .action:active {
    transform: none;
  }
}
