/* OSDIGITALIS · mouvement et interactions partagés par tout le site.
   Chargé après styles.css : surcharge sans le modifier. Les comportements correspondants sont dans script.js.
   Sommaire : 1 visionneuse de captures · 2 police et ouverture · 3 fondu SportHub · 4 compteur Pendula
   · 5 en-tête · 6 titres et captures qui s'ouvrent · 7 panneaux (Expertises, menu mobile) · 8 bascule du thème · 9 impression.
   Règles : transform et opacité seulement, courbe var(--ease), aucun état de départ sans la classe js, rien en mouvement réduit. */

/* ===== 1. Visionneuse de captures (data-zoom) ===== */
/* Le bouton est créé par script.js : sans JavaScript, la capture reste une simple image. */
[data-zoom] { position: relative; }
.zoom-btn { position: absolute; inset: 0; z-index: 3; display: block; width: 100%; height: 100%; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: zoom-in; }
/* L'anneau de focus entoure tout le cadre, sur le fond de la page (visible aussi sur le cadre teinté).
   Sur un cadre .frame, l'anneau du bouton et celui du cadre se superposent ; sur un .phone (overflow masqué),
   seul celui du cadre reste visible. */
.zoom-btn:focus-visible { outline: 3px solid var(--focus); outline-offset: 4px; }
@supports selector(:has(*)) {
  [data-zoom]:has(> .zoom-btn:focus-visible) { outline: 3px solid var(--focus); outline-offset: 4px; }
}

.lightbox { width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: color-mix(in srgb, var(--bg) 94%, transparent); color: var(--text); overflow: hidden; }
.lightbox[open] { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; grid-template-columns: 100%; justify-items: center; }
/* Le voile est porté par la boîte elle-même (et non par ::backdrop) : la légende garde un fond connu, quel que soit le contenu de la page derrière. */
.lightbox::backdrop { background: transparent; }
.lightbox:not([open]) { pointer-events: none; }
html:has(.lightbox[open]) { overflow: hidden; scrollbar-gutter: stable; }
.lightbox-top { display: flex; justify-content: flex-end; width: 100%; padding: 12px clamp(12px, 2vw, 24px) 0; }
.lightbox-img { display: block; align-self: center; width: auto; height: auto; max-width: 92vw; max-height: min(88vh, 100%); object-fit: contain; border-radius: 6px; }
.lightbox-bar { display: flex; align-items: center; justify-content: center; gap: clamp(12px, 3vw, 32px); width: 100%; padding: 8px clamp(12px, 2vw, 24px) 16px; }
.lightbox-caption { flex: 0 1 70ch; color: var(--muted); font-size: 14px; line-height: 1.55; text-align: center; text-wrap: balance; }
.lightbox-btn { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; min-width: 44px; min-height: 44px; padding: 0 16px; border: 1px solid var(--line); border-radius: 6px; background: var(--bg); color: var(--text); font-family: var(--body); font-size: 14px; font-weight: 500; line-height: 1; transition: border-color .2s var(--ease); }
.lightbox-btn:hover { border-color: var(--accent); }
.lightbox-btn--step { padding: 0; font-size: 20px; }
.lightbox-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

@media (prefers-reduced-motion: no-preference) {
  /* Ouverture et fermeture en opacité, 200 ms. Sans prise en charge de overlay, la fermeture est simplement immédiate. */
  .lightbox, .lightbox::backdrop { opacity: 0; transition-property: opacity, overlay, display; transition-duration: 200ms; transition-timing-function: var(--ease); transition-behavior: allow-discrete; }
  .lightbox[open], .lightbox[open]::backdrop { opacity: 1; }
  @starting-style {
    .lightbox[open], .lightbox[open]::backdrop { opacity: 0; }
  }
}

/* ===== 2. Police et ouverture ===== */
/* Le titre ne doit jamais s'ouvrir dans la police de secours : l'animation d'ouverture attend la classe fonts-ok
   (posée par l'extrait du head, ou par script.js à défaut, au plus tard 1 s après le début du chargement). */
@media (prefers-reduced-motion: no-preference) {
  .js:not(.fonts-ok) :is(.mask-in, .hero-intro, .hero-lead, .hero-actions, .hero-services a),
  .js:not(.fonts-ok) .hero-services::before { animation-play-state: paused; }
}

/* ===== 3. Fondu SportHub sans double exposition ===== */
/* La capture entrante arrive par-dessus l'ancienne, qui reste opaque puis disparaît d'un coup une fois recouverte. */
@media (prefers-reduced-motion: no-preference) {
  .shot { transition: opacity 0s linear 450ms, transform 0s linear 450ms; }
  .shot.is-active { opacity: 1; transform: none; z-index: 1; transition: opacity 450ms var(--ease), transform 450ms var(--ease); }
}

/* ===== 4. Compteur de la scène Pendula (créé par script.js) ===== */
/* Réutilise .steps-count ; sa mise en page sous le téléphone (colonne, centrage) est dans styles.css.
   Sous 901 px le téléphone n'est pas épinglé et les temps de texte sont ailleurs dans la page : pas de compteur. */
@media (max-width: 900px) {
  .phone-count { display: none; }
}

/* ===== 5. En-tête compact : le visage apparaît en fondu ===== */
@keyframes face-in { from { opacity: 0; } }
@media (prefers-reduced-motion: no-preference) {
  .header-shell.is-compact .brand-face { animation: face-in 220ms var(--ease) both; }
}

/* ===== 6. Titres et captures qui s'ouvrent au défilement ===== */
/* Les classes rv, rv-text et rv-shot sont posées par script.js, seulement hors mouvement réduit :
   sans JavaScript ou en mouvement réduit, rien n'est masqué. is-instant = état final sans transition (élément déjà dépassé). */
@media (prefers-reduced-motion: no-preference) {
  /* Piège : .mask-in porte l'animation d'ouverture du H1 ; sans cette ligne elle se rejouerait à la création du masque. */
  .rv > .mask-in { animation: none; }
  /* Le titre contient un masque à marges négatives : un contexte de formatage propre évite tout décalage de mise en page. */
  .rv-host { display: flow-root; }
  .js .rv:not(.is-in) > .mask-in { transform: translateY(108%); }
  .js .rv.is-in > .mask-in { transition: transform 700ms var(--ease); }
  .js .rv.is-in.is-instant > .mask-in { transition: none; }

  .js .rv-text:not(.is-in) { opacity: 0; transform: translateY(12px); }
  .js .rv-text.is-in { transition: opacity 500ms var(--ease) 120ms, transform 500ms var(--ease) 120ms; }
  .js .rv-text.is-in.is-instant { transition: none; }

  .js .rv-shot:not(.is-in) { opacity: 0; transform: translateY(24px); }
  .js .rv-shot.is-in { transition: opacity 700ms var(--ease), transform 700ms var(--ease); }
  .js .rv-shot.is-in.is-instant { transition: none; }
}

/* ===== 7. Panneaux : Expertises (bureau) et menu mobile plein écran ===== */
/* Ouverture et fermeture symétriques. [hidden] reste la source de vérité : display bascule en fin de fermeture
   (allow-discrete), et script.js pose inert pendant la fermeture pour que rien ne reste atteignable au clavier. */
@media (prefers-reduced-motion: no-preference) {
  .expertises-panel { transition-property: opacity, transform, display; transition-duration: 160ms; transition-timing-function: var(--ease); transition-behavior: allow-discrete; }
  .expertises-panel:not([hidden]) { animation: none; }
  .expertises-panel[hidden] { opacity: 0; transform: translateY(-6px); pointer-events: none; }
  @starting-style {
    .expertises-panel:not([hidden]) { opacity: 0; transform: translateY(-6px); }
  }

  .menu-panel { transition-property: opacity, display; transition-duration: 200ms; transition-timing-function: var(--ease); transition-behavior: allow-discrete; }
  .menu-panel[hidden] { opacity: 0; pointer-events: none; }
  @starting-style {
    .menu-panel:not([hidden]) { opacity: 0; }
  }
  /* Cascade de 30 ms entre les liens, à l'ouverture seulement (l'animation n'existe que panneau ouvert). */
  @keyframes menu-link-in { from { opacity: 0; transform: translateY(10px); } }
  .menu-panel:not([hidden]) a { animation: menu-link-in 260ms var(--ease) calc(var(--i, 0) * 30ms) backwards; }
}

/* ===== 8. Bascule clair/sombre en fondu de 200 ms ===== */
/* Pendant la transition seulement, l'en-tête perd son nom de transition : il fond avec le reste de la page. */
@media (prefers-reduced-motion: no-preference) {
  .theme-switching .site-header { view-transition-name: none; }
  :root.theme-switching::view-transition-old(*), :root.theme-switching::view-transition-new(*) { animation-duration: 200ms; animation-timing-function: cubic-bezier(.2, .7, .2, 1); }
}

/* ===== 9. Impression : tout est visible ===== */
@media print {
  .rv > .mask-in, .rv-text, .rv-shot { opacity: 1 !important; transform: none !important; transition: none !important; }
}
