/* ==========================================================================
   Dream Studio — mouvement
   Système unique de révélation au défilement, d'entrée du header et de
   transition entre pages. Rien n'est caché sans JavaScript : l'état de départ
   n'existe que sous `html.ds-mv`, posé dans <head> (header.php) quand le visiteur
   n'a pas demandé de mouvement réduit. Si mouvement.js ne répond pas dans les
   4 s, la classe est retirée et tout s'affiche.

   Quatre variantes seulement, posées par l'attribut data-ds-reveal :
     monte   fondu + montée légère (textes, titres, cartes)
     image   l'image se pose : fondu + léger zoom arrière (tuiles collées de la mosaïque)
     masque  l'image se dévoile du bas vers le haut, avec léger zoom arrière (images éditoriales)
     trait   un filet se trace de gauche à droite
   Retard manuel : style="--ds-d:.12s". Le rang d'arrivée (--ds-r, posé par le JS) étage
   les éléments qui entrent ensemble. Une fois la révélation terminée, le JS retire
   l'attribut : l'élément retrouve ses propres transitions (survol, etc.).
   ========================================================================== */

:root {
	--mv-monte: 24px;
	--mv-pas: 90ms;
	--mv-zoom: 1.08;
}

@media (max-width: 1099px) {
	:root { --mv-monte: 18px; --mv-pas: 70ms; --mv-zoom: 1.05; }
}

@media (max-width: 767px) {
	:root { --mv-monte: 14px; --mv-pas: 50ms; --mv-zoom: 1.03; }
}

/* --------------------------------------------------------------------------
   Révélations au défilement
   -------------------------------------------------------------------------- */

html.ds-mv [data-ds-reveal] {
	--mv-retard: calc(var(--ds-d, 0s) + var(--ds-r, 0) * var(--mv-pas));
}

/* monte */
html.ds-mv [data-ds-reveal="monte"] {
	opacity: 0;
	translate: 0 var(--mv-monte);
	transition: opacity .8s var(--ds-sortie) var(--mv-retard), translate .9s var(--ds-sortie) var(--mv-retard);
}

html.ds-mv [data-ds-reveal="monte"].est-vu {
	opacity: 1;
	translate: none;
}

/* trait */
html.ds-mv [data-ds-reveal="trait"] {
	scale: 0 1;
	transform-origin: left center;
	transition: scale 1.1s var(--ds-sortie) var(--mv-retard);
}

html.ds-mv [data-ds-reveal="trait"].est-vu { scale: none; }

/* image : on agit sur l'image seule, le fond de la tuile reste en place (pas de trou dans la mosaïque).
   La propriété `scale` se compose avec le `transform` du survol sans l'écraser. */
html.ds-mv [data-ds-reveal="image"] img {
	opacity: 0;
	scale: var(--mv-zoom);
	transition: opacity 1s var(--ds-sortie) var(--mv-retard), scale 1.4s var(--ds-sortie) var(--mv-retard), transform .7s var(--ds-sortie);
}

html.ds-mv [data-ds-reveal="image"].est-vu img {
	opacity: 1;
	scale: 1;
}

/* Dégradé et texte de la tuile arrivent un peu après l'image. */
html.ds-mv [data-ds-reveal="image"]::after,
html.ds-mv [data-ds-reveal="image"] .ds-projets__tuile-texte,
html.ds-mv [data-ds-reveal="image"] .ds-projet__voisin-texte {
	opacity: 0;
}

html.ds-mv [data-ds-reveal="image"].est-vu::after,
html.ds-mv [data-ds-reveal="image"].est-vu .ds-projets__tuile-texte,
html.ds-mv [data-ds-reveal="image"].est-vu .ds-projet__voisin-texte {
	opacity: 1;
	transition: opacity .9s var(--ds-sortie) calc(var(--mv-retard) + .25s), transform .35s var(--ds-sortie);
}

/* masque : le conteneur est observé tel quel, c'est l'image à l'intérieur qui se dévoile du bas vers le haut.
   (Un clip-path sur l'élément observé ou sur une image paresseuse le rend « invisible » pour
   IntersectionObserver et pour le chargement différé : il resterait masqué pour toujours. Une bande
   de 2 px reste donc toujours découverte.) Les ornements du conteneur ne sont jamais rognés.
   Cadre sans débord (arche, contact) : style="--mv-zoom:1" supprime le zoom. */
html.ds-mv [data-ds-reveal="masque"] img {
	clip-path: inset(0 0 calc(100% - 2px) 0);
	scale: var(--mv-zoom);
	transition: clip-path 1.2s var(--ds-sortie) var(--mv-retard), scale 1.6s var(--ds-sortie) var(--mv-retard), transform .7s var(--ds-sortie);
}

html.ds-mv [data-ds-reveal="masque"].est-vu img {
	clip-path: inset(0);
	scale: 1;
}

/* --------------------------------------------------------------------------
   Header : fondu à la première arrivée sur l'accueil de la session
   (l'indicateur html.ds-premiere est posé dans <head>, avant le premier rendu)
   -------------------------------------------------------------------------- */

@keyframes ds-mv-fondu { from { opacity: 0; } }

html.ds-premiere .ds-header {
	animation: ds-mv-fondu 1s var(--ds-sortie) .2s backwards;
}

/* --------------------------------------------------------------------------
   Hero des pages intérieures : l'image se pose en un zoom arrière lent (sans fondu : le LCP n'attend pas)
   -------------------------------------------------------------------------- */

@keyframes ds-mv-pose { from { scale: var(--mv-zoom); } }

html.ds-mv .ds-hero-page > img {
	animation: ds-mv-pose 2s var(--ds-sortie) backwards;
}

/* --------------------------------------------------------------------------
   Parallax architectural, en CSS pur (animations liées au défilement, sans JavaScript).
   Ordinateur seulement, hors mouvement réduit, et seulement si le navigateur sait faire :
   ailleurs les images restent simplement fixes.
   - Hero des pages : l'image, surdimensionnée de 60 px vers le haut, descend de 48 px pendant que la
     page défile, donc plus lentement qu'elle.
   - Arche d'Expertise : l'image, le cadre rouge et le sceau flottent à des vitesses différentes (±10 px).
   -------------------------------------------------------------------------- */

@media (min-width: 1100px) and (prefers-reduced-motion: no-preference) {
	@supports (animation-timeline: view()) {
		@keyframes ds-mv-profondeur { to { translate: 0 48px; } }
		@keyframes ds-mv-flotte-image { from { translate: 0 -8px; } to { translate: 0 8px; } }
		@keyframes ds-mv-flotte-cadre { from { translate: 0 6px; } to { translate: 0 -6px; } }
		@keyframes ds-mv-flotte-sceau { from { translate: 0 10px; } to { translate: 0 -10px; } }

		/* La chronologie est celle de la section, pas de l'image : l'image qui bouge ne doit pas
		   déplacer sa propre chronologie. */
		.ds-hero-page { view-timeline: --ds-hero block; }

		.ds-hero-page > img {
			inset: -60px 0 0 0;
			height: calc(100% + 60px);
			animation: ds-mv-profondeur linear both;
			animation-timeline: --ds-hero;
			animation-range: exit 0% exit 100%;
		}

		html.ds-mv .ds-hero-page > img {
			animation: ds-mv-pose 2s var(--ds-sortie) backwards, ds-mv-profondeur linear both;
			animation-timeline: auto, --ds-hero;
			animation-range: normal, exit 0% exit 100%;
		}

		.ds-expertise__arche { view-timeline: --ds-arche block; }

		.ds-expertise__arche img,
		.ds-expertise__arche::before,
		.ds-expertise__sceau {
			animation-timing-function: linear;
			animation-fill-mode: both;
			animation-timeline: --ds-arche;
			animation-range: cover;
		}

		.ds-expertise__arche img { animation-name: ds-mv-flotte-image; }
		.ds-expertise__arche::before { animation-name: ds-mv-flotte-cadre; }
		.ds-expertise__sceau { animation-name: ds-mv-flotte-sceau; }
	}
}

/* --------------------------------------------------------------------------
   Pied de page : le filet rouge se trace quand le pied entre dans l'écran
   -------------------------------------------------------------------------- */

.ds-footer { position: relative; }

.ds-footer::before {
	content: "";
	position: absolute;
	top: -1px;
	left: var(--ds-gouttiere);
	width: 56px;
	height: 2px;
	background: var(--ds-rouge);
}

html.ds-mv .ds-footer[data-ds-reveal]::before {
	scale: 0 1;
	transform-origin: left center;
	transition: scale 1.1s var(--ds-sortie) .15s;
}

html.ds-mv .ds-footer[data-ds-reveal].est-vu::before { scale: none; }

/* Le texte du pied est révélé avec le pied lui-même : tout en bas de page il se trouve dans la marge basse
   de l'observateur (-6 %) et ne serait jamais détecté seul. */
html.ds-mv .ds-footer[data-ds-reveal] .ds-footer__texte {
	opacity: 0;
	translate: 0 12px;
	transition: opacity .8s var(--ds-sortie) .2s, translate .9s var(--ds-sortie) .2s;
}

html.ds-mv .ds-footer[data-ds-reveal].est-vu .ds-footer__texte {
	opacity: 1;
	translate: none;
}

/* --------------------------------------------------------------------------
   Transition entre pages (même origine) : fondu croisé court, sans JavaScript.
   Navigateurs sans prise en charge : navigation classique.
   -------------------------------------------------------------------------- */

@view-transition { navigation: auto; }

::view-transition-group(root) {
	animation-duration: .45s;
	animation-timing-function: cubic-bezier(.16, 1, .3, 1);
}

@media (prefers-reduced-motion: reduce) {
	@view-transition { navigation: none; }
}
