/* ════════════════════════════════════════════════════════════════════
   SpotUp — l'accueil : « la planche d'affiches » (27 sept. 2026)

   Chaque écran est une affiche avec SA mise en page. Aucune ne se répète :
     1 la une    — texte, puis un téléphone droit que le bas de l'écran coupe
     2 ce soir   — le seul écran centré, un téléphone dont le fil DÉFILE
                   quand on descend la page
     3 un clic   — titre au fer à droite ; la fiche entière, son bouton
                   S'inscrire mis en valeur en place, puis tapé : l'app répond
                   comme elle le fait vraiment (bouton « ✓ Rejoint », bandeau)
     4 le groupe — question et réponse en diagonale, deux bulles de la
                   conversation agrandies qui sortent du cadre
     5 une idée  — le titre le plus grand, qui mord sur un téléphone penché
     6 la beta   — le formulaire (celui de site.css, piloté par site.js)

   Ce fichier ne contient QUE la mise en page de l'accueil. En-tête, menu,
   pied de page, boutons et formulaire vivent dans site.css, partagés avec
   les autres pages. Jetons : ceux de l'app (lib/theme.ts, palette sombre),
   déclarés dans site.css.

   Les captures font 420 px de large : toutes les cotes « de capture »
   ci-dessous sont en pixels de cette version-là.
   ════════════════════════════════════════════════════════════════════ */

/* La courbe de tout le mouvement de la page : un ease-out fort (skill animate :
   jamais d'ease-in à l'entrée, et les courbes intégrées sont trop molles).
   C'est aussi celle des boutons de site.css. */
:root { --ac-ease: cubic-bezier(0.23, 1, 0.32, 1); }

/* ─── La voix des affiches : Fraunces, un mot fort en italique corail ─── */
.ac-t {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  letter-spacing: -0.035em;
  line-height: 0.98;
  text-wrap: balance;
}
.ac-t em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
  letter-spacing: -0.03em;
}
.ac-dit {
  font: 400 18px/1.45 var(--sans);
  color: var(--ink2);
  letter-spacing: -0.005em;
  text-wrap: pretty;
}
@media (min-width: 1024px) { .ac-dit { font-size: 21px; } }
/* La mention d'honnêteté : ce sont des captures, les gens sont des exemples. */
.ac-mention { font: 400 15px/1.4 var(--sans); color: var(--muted); }

/* ─── Une affiche ─── */
.ac-affiche { position: relative; isolation: isolate; overflow: hidden; }
@supports (overflow: clip) { .ac-affiche { overflow: clip; } }
/* ════════ LA LUEUR — une seule, attachée au haut de l'ÉCRAN (28 sept., v2) ════════
   Historique, pour ne pas y revenir : chaque affiche avait SA lueur. Même
   recentrées et adoucies, elles faisaient des taches çà et là — Nono : « les
   lueurs orange ça fait pas clean du tout ». Dans l'app, la lueur vit en HAUT
   DE L'ÉCRAN (glow → glowFade) : c'est ce qu'on reprend. Elle est FIXE, le
   contenu défile par-dessus : aucune jonction de section ne peut plus la
   couper, par construction.
   - Peinte par body::before en z-index −1 : le <body> de l'accueil devient
     transparent (le noir de fond est celui de <html>), sinon il la couvrirait.
   - Extinction par paliers (intensité × 1 · 0,8 · 0,56 · 0,34 · 0,17 · 0,07 ·
     0,02 · 0) et un grain très fin (bruit SVG en data: URI, rien de chargé
     ailleurs) : sur un fond aussi sombre, un dégradé lisse se voit en marches
     de couleur ; le grain les casse.
   - Un masque fond l'ensemble vers le bas : ni la lueur ni le grain n'ont de
     bord.
   - Fixe = une couche composée : le défilement ne la repeint jamais. */
body.page-accueil { background: transparent; }
.page-accueil .glow { display: none; }
body.page-accueil::before {
  content: "";
  position: fixed; z-index: -1;
  left: 0; right: 0; top: 0; height: 90vh;
  pointer-events: none;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 0.62 0 0 0 0 0.5 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"),
    radial-gradient(140% 100% at 50% 0%,
      rgba(255, 112, 69, 0.15) 0%, rgba(255, 112, 69, 0.12) 18%,
      rgba(255, 112, 69, 0.084) 34%, rgba(255, 112, 69, 0.051) 48%,
      rgba(255, 112, 69, 0.026) 60%, rgba(255, 112, 69, 0.011) 70%,
      rgba(255, 112, 69, 0.003) 78%, rgba(255, 112, 69, 0) 86%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 50%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 50%, transparent 100%);
}
/* Hauteur FIGÉE (accueil.js, 8 oct. — voir la une) : la lueur ne change plus de
   taille quand la barre du navigateur va et vient. */
html.fige body.page-accueil::before { height: calc(var(--ac-vh) * 90); }

/* ════════ Le téléphone : un cadre en CSS, la capture telle quelle dedans ════════
   --w (hérité du parent) : largeur extérieure. --b : le bord. --S : largeur
   de l'écran. --s : 1 px de capture à l'échelle affichée.
   Pas de fausse barre d'état : une bande de la couleur du haut de la capture
   (--haut, relevée au pixel) et l'îlot de la caméra. */
.ac-tel {
  --b: calc(var(--w, 280px) * 0.03);
  --S: calc(var(--w, 280px) - 2 * var(--b));
  --s: calc(var(--S) / 420);
  position: relative;
  width: var(--w, 280px);
  padding: var(--b);
  border-radius: calc(var(--S) * 0.13 + var(--b));
  background: linear-gradient(150deg, #2e2e2e 0%, #161616 26%, #0d0d0d 64%, #232323 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.09),
    0 0 0 1px #000,
    0 50px 90px -30px rgba(0, 0, 0, 0.95);
}
.ac-ecran {
  position: relative;
  overflow: hidden;
  border-radius: calc(var(--S) * 0.13);
  background: var(--haut, #1a1110);
  padding-top: calc(var(--S) * 0.115);
}
.ac-ecran::before {
  content: "";
  position: absolute; z-index: 2;
  top: calc(var(--S) * 0.03); left: 50%;
  width: calc(var(--S) * 0.29); height: calc(var(--S) * 0.085);
  margin-left: calc(var(--S) * -0.145);
  border-radius: 99px;
  background: #000;
}
.ac-ecran > img { display: block; width: 100%; max-width: none; height: auto; }
/* La fiche : la photo monte jusqu'en haut de l'écran, sous l'îlot, comme dans l'app. */
.ac-ecran-plein { padding-top: 0; }

/* ════════ 1 · LA UNE — le téléphone est coupé par le bas de l'écran ════════ */
.ac-une { position: relative; }
.ac-une .wrap {
  position: relative;
  display: flex; flex-direction: column;
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100svh - var(--header-h));
  /* 26 → 52 px (Nono, 29 sept. : « elle touche presque la bannière au top »). */
  padding-top: 52px;
}
/* 🔴 8 oct. — LA UNE NE SUIT PLUS LA BARRE DU NAVIGATEUR. Sur iPhone, hors
   Safari (Opera, Chrome, Firefox…), svh vaut « la hauteur du moment » : la une
   grandissait de 119 px quand la barre rentrait, rétrécissait quand elle
   sortait, et TOUTE LA PAGE dessous sautait d'autant à chaque demi-tour du
   doigt (Nono : « ça fait comme si ça reset les animations »). accueil.js
   relève une fois ce que vaut 1svh (--ac-svh) et pose html.fige ; sans lui,
   on garde svh ci-dessus. Dans Safari, où svh est déjà fixe, c'est la même
   valeur : rien ne change. */
html.fige .ac-une .wrap { min-height: calc(var(--ac-svh) * 100 - var(--header-h)); }
.ac-une h1 { font-size: clamp(40px, 11.3vw, 104px); }
.ac-une h1 em { display: block; }
.ac-une .ac-dit { margin-top: 18px; max-width: 30ch; }
.ac-une .btn { margin-top: 26px; }
@media (max-width: 599px) { .ac-une .btn { display: flex; width: 100%; } }
.ac-note { margin-top: 14px; font: 400 16px/1.45 var(--sans); color: var(--muted); max-width: 36ch; }
.ac-une-scene {
  display: flex; flex-direction: column;
  flex: 1 1 auto;
  min-height: 300px;
  margin: 30px calc(-1 * var(--gutter)) 0;
  overflow: hidden;
}
.ac-une-scene .ac-mention { padding-inline: var(--gutter); text-align: center; }
.ac-une-cadre { position: relative; flex: 1 1 0; min-height: 250px; margin-top: 14px; }
.ac-une-cadre .ac-tel {
  --haut: #1a1110;
  position: absolute; left: 50%; top: 0;
  transform: translateX(-50%);
  /* Pas d'ombre portée ici (Nono, 28 sept. : « le premier iPhone a comme une
     ombre derrière lui »). Ce téléphone est le seul posé sur la lueur du haut
     de l'écran : le noir de l'ombre y creusait un halo sombre autour de lui.
     Plus bas, sur le fond #0a0a0a, l'ombre des autres ne se voit pas — elle
     ne sert qu'à les décoller des titres et des bulles qui les chevauchent.
     On garde les deux liserés qui dessinent le bord. */
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.09), 0 0 0 1px #000;
}
.ac-une-scene { --w: min(304px, 76vw); }
@media (min-width: 1024px) {
  .ac-une .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
    column-gap: 40px;
    padding-top: 0;
  }
  .ac-une-texte { align-self: center; padding: 40px 0 64px; }
  .ac-une h1 { font-size: clamp(64px, 7.5vw, 104px); }
  .ac-une .ac-dit { margin-top: 28px; }
  .ac-une .btn { margin-top: 36px; }
  /* 404 px, sans jamais dépasser sa colonne (0,75 fr sur 2 fr, à 1024 px elle fait 327 px) */
  /* padding-top 28 → 64 px : la légende et le téléphone collaient à la barre du haut (29 sept.). */
  .ac-une-scene { --w: min(404px, calc((100vw - 2 * var(--gutter) - 40px) * 0.375)); margin: 0; min-height: 0; padding-top: 64px; }
  .ac-une-cadre { margin-top: 18px; }
}

/* ════════ 2 · CE SOIR — le seul écran centré, un téléphone dont le fil défile ════════
   Historique : deux téléphones en éventail, le 2e « se dépliait » à côté du
   1er. Nono (28 sept.) : « ça ne fait pas trop de sens ». Le geste qui a du
   sens ici, c'est celui de l'app : faire défiler le fil. Quand on descend la
   page, le fil du téléphone descend avec elle (voir « LE MOUVEMENT »), de
   « À la une » jusqu'aux catégories — des plans, les uns après les autres.
   Le contenu (fil-defile) est fait de deux vraies captures mises bout à bout,
   SANS la lueur de l'app et avec un fond TRANSPARENT ; la lueur est posée
   DESSOUS par .ac-fil-lueur, fixe en haut de l'écran, comme dans l'app où elle
   est derrière des cartes opaques (assemble-fil.mjs explique pourquoi).
   Cotes de capture (420 de large) : la fenêtre fait 779,44 de haut (le fil
   entre la barre d'état et la barre d'onglets), le contenu 1271,63 ; au repos
   il est défilé au maximum (−38,71 % de sa hauteur) et la fenêtre montre alors
   EXACTEMENT la 2e capture : sans mouvement, on voit les catégories, pas une
   2e fois la une, et aucun morceau de montage. Sur téléphone, il prend presque
   toute la largeur pour que les titres des cartes restent lisibles. */
/* Haut 96 → 56 px (130 → 80 sur ordinateur) : Nono, 29 sept. : « un énorme écart
   entre la première phrase et la deuxième ». Le vide se cumulait : le bas de la
   une, cette marge, et la montée de 48 px du titre qui entre (« LE MOUVEMENT »). */
.ac-soir { padding: 56px 0 72px; text-align: center; }
.ac-soir h2 { font-size: clamp(40px, 11vw, 104px); max-width: 11ch; margin-inline: auto; }
.ac-soir h2 em { white-space: nowrap; }
.ac-soir .ac-dit { margin: 18px auto 0; max-width: 26ch; }
.ac-fil {
  --w: min(320px, calc(100vw - 2 * var(--gutter)));
  width: var(--w);
  margin: 52px auto 0;
  text-align: left;
}
.ac-fil .ac-tel { --haut: #261611; }
.ac-fenetre {
  position: relative;
  height: calc(var(--s) * 779.44);
  overflow: hidden;
  isolation: isolate;
  background: #0a0a0a;
}
.ac-defile {
  position: relative; z-index: 1;
  display: block; width: 100%; max-width: none; height: auto;
  translate: 0 -38.71%;
}
/* La lueur de l'app (glow → glowFade), relevée tous les 60 px sur la capture
   d'origine : de #261611 à #0a0a0a sur les 214,8 premiers px de capture, soit
   27,56 % de la fenêtre. SOUS le fil (z-index 0 contre 1) : elle ne se voit
   qu'à travers son fond transparent, jamais sur une carte ou une photo.
   (1ʳᵉ version : par-dessus, en « lighten » — elle éclaircissait le bas sombre
   de la carte de la une quand il passait en haut de l'écran.) */
.ac-fil-lueur {
  position: absolute; z-index: 0; left: 0; right: 0; top: 0; height: 27.56%;
  background: linear-gradient(180deg, #261611 0%, #241510 9.09%, #211410 18.18%, #1e120e 27.27%,
    #1c110e 36.36%, #19100e 45.45%, #170f0d 54.55%, #140e0c 63.64%, #110d0b 72.73%,
    #100d0c 81.82%, #0d0c0b 90.91%, #0a0a0a 100%);
  pointer-events: none;
}
.ac-ecran > .ac-fil-barre { display: block; width: 100%; height: auto; }
@media (min-width: 700px) { .ac-fil { --w: 300px; } }
@media (min-width: 1024px) {
  .ac-soir { padding: 80px 0 72px; }
  .ac-soir h2 { max-width: 15ch; }
  .ac-soir .ac-dit { margin-top: 26px; max-width: 40ch; }
  .ac-fil { --w: 320px; margin-top: 64px; }
}

/* ════════ 3 · UN CLIC — la fiche entière, et son bouton S'inscrire ════════
   Historique : la barre du bas se soulevait en loupe, agrandie par-dessus le
   téléphone. Nono (28 sept.) : « j'aime pas que toute la barre s'agrandisse ».
   Le bouton est maintenant mis en valeur EN PLACE (un anneau corail qui
   respire), puis tapé : l'app répond comme elle le fait vraiment. Ces états
   sont redessinés à l'identique du code de l'app, pas imaginés :
   - app/activity/[id].tsx, pied de fiche : une fois inscrit, le bouton passe
     à « ✓ Rejoint · Annuler » (t('activity.joined')), fond surface2 #1F1F1F,
     encre #F7F7F7 (plus large, il laisse la méta entière) ;
   - components/hifi/FeedbackBanner.tsx : le bandeau corail « Activité
     rejointe ! Le chat du groupe t'attend. », 60 pt sous le haut de l'écran.
   Cotes : en POINTS de l'app (l'écran fait 430 pt de large ; --p = 1 pt à
   l'échelle affichée), relevées au pixel sur la capture d'origine
   (outils/mesure-originaux.mjs). La capture commence à 55 pt (barre d'état
   coupée) : une cote y de l'app devient (y − 55) × --p.
     bouton S'inscrire : x 296,67 → 409,67, y 850 → 898 (48 pt de haut) ;
     pied : padding 20, gap 12 ; méta 15/17, InterTight 500 ; bouton 14,
     InterTight 600, padding 28, rayon 12.
   Le bandeau est posé 12 pt sous l'îlot de NOTRE téléphone (comme sur un
   iPhone : îlot jusqu'à 48 pt, bandeau à 60). Juste par rapport à l'écran,
   pas par rapport au contenu : la capture étant coupée sous la barre d'état,
   dans l'app le bandeau recouvre aussi la rangée ‹ ↗ ⋯ ; ici il tombe juste
   en dessous, sur la photo. On ne peut pas faire les deux sans passer sur
   l'îlot. */
.ac-clic { padding: 96px 0 80px; }
.ac-clic-texte { text-align: right; position: relative; z-index: 2; }
.ac-clic h2 { font-size: clamp(50px, 16.4vw, 128px); }
.ac-clic h2 em { display: block; }
.ac-clic .ac-dit { margin: 18px 0 0 auto; max-width: 22ch; }
.ac-clic-scene {
  --w: min(300px, calc(100vw - 2 * var(--gutter) - 16px));
  position: relative;
  width: var(--w);
  margin: 34px auto 0;
}
/* Sur un écran PEU HAUT, le téléphone rapetisse pour que le bandeau du tap se
   voie : le tap part quand le bas du bouton passe au-dessus de 88 % de la
   hauteur (accueil.js) ; le haut du bandeau est alors à 0,88·H − 1,709·w (le
   bandeau est à 0,164·w du haut du téléphone, le bas du bouton à 1,873·w). On
   veut ce haut sous l'en-tête fixe, avec 8 px de marge. Relecture du 28 sept. :
   sans ce plafond, à 375 × 553 (iPhone SE, barres de Safari affichées) ou à
   1366 × 657 (portable courant), le bandeau descendait SOUS l'en-tête.
   Plancher 220 px : en paysage, on préfère un téléphone lisible. svh (hauteur
   avec les barres du navigateur affichées) dans un @supports : une variable
   CSS invalide ne retomberait pas sur la valeur d'avant. */
@supports (height: 1svh) {
  .ac-clic-scene { --w: min(300px, calc(100vw - 2 * var(--gutter) - 16px), max(220px, calc((88svh - var(--header-h) - 8px) / 1.709))); }
}
.ac-clic-scene .ac-ecran { --p: calc(var(--S) / 430); }
.ac-pied {
  position: absolute; z-index: 2;
  left: calc(20 * var(--p)); right: calc(20 * var(--p));
  top: calc(795 * var(--p)); height: calc(48 * var(--p));
  display: flex; gap: calc(12 * var(--p));
}
/* La méta de la capture reste telle quelle : « Rejoint », plus large que
   S'inscrire, lui laisse encore toute la place (mesuré : la méta finit à
   186 pt, « Rejoint » commence à 222 pt) — dans l'app non plus, elle ne se
   raccourcit pas. Cet espaceur ne fait que pousser « Rejoint » à droite. */
.ac-pied-meta { flex: 1 1 auto; min-width: 0; }
.ac-rejoint {
  flex: none; position: relative; z-index: 1; /* devant le cache de l'ancien bouton */
  display: flex; align-items: center;
  height: calc(48 * var(--p));
  padding: 0 calc(28 * var(--p));
  border-radius: calc(12 * var(--p));
  background: #1F1F1F; color: #F7F7F7;
  /* 600 dans l'app ; 560 ici : rendu en direct à 9-10 px, le 600 paraît plus
     gras que le texte des captures (réduites depuis du @3x), mesuré côte à côte */
  font: 560 calc(14 * var(--p)) / 1 var(--sans);
  letter-spacing: calc(-0.2 * var(--p));
  white-space: nowrap;
  transform-origin: 100% 50%;
}
/* Le cache recouvre le bouton de la capture (3 pt de marge, fond du pied
   #141414), pour qu'on puisse ENFONCER le bouton sans voir l'original derrière.
   Le bouton enfoncé est un morceau de la MÊME capture, cadré sur ses cotes :
   pixel pour pixel celui de l'app, aucune police à imiter. */
.ac-cache {
  position: absolute;
  right: calc(-3 * var(--p)); top: calc(-3 * var(--p));
  width: calc(119.33 * var(--p)); height: calc(54 * var(--p));
  background: #141414;
}
.ac-sinscrire {
  position: absolute; left: calc(3 * var(--p)); top: calc(3 * var(--p));
  width: calc(113.33 * var(--p)); height: calc(48 * var(--p));
  overflow: hidden;
  border-radius: calc(12 * var(--p));
}
.ac-sinscrire img {
  position: absolute; max-width: none;
  width: var(--S); height: auto;
  left: calc(-296.67 * var(--p)); top: calc(-795 * var(--p));
}
.ac-rejoint, .ac-cache { opacity: 0; }
/* L'anneau autour de S'inscrire (x 296,67 → 409,67, y 850 → 898 pt). */
.ac-anneau {
  position: absolute; z-index: 3;
  left: calc(296.67 * var(--p)); top: calc(795 * var(--p));
  width: calc(113 * var(--p)); height: calc(48 * var(--p));
  border-radius: calc(12 * var(--p));
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  pointer-events: none;
}
/* La respiration : un SECOND anneau qui s'élargit en s'effaçant, l'anneau fixe
   restant en place. Seulement scale + opacity : la carte graphique s'en charge,
   rien n'est repeint. Elle ne tourne que quand l'affiche est à l'écran
   (data-live, posé par accueil.js) et s'arrête au tap (data-tape).
   Échelle en deux valeurs : l'anneau est 2,4 fois plus large que haut. */
.ac-anneau::after {
  content: "";
  position: absolute; inset: -5px;
  border: 2px solid var(--accent);
  border-radius: calc(12 * var(--p) + 5px);
  opacity: 0;
  pointer-events: none;
}
/* La zone du tap, invisible : du haut du bandeau (--S × 0,115 + 12 pt) au bas
   du bouton (898 − 55 = 843 pt). accueil.js attend qu'elle soit ENTIÈREMENT à
   l'écran avant de lancer le tap : le bouton et le bandeau se verront. */
.ac-zone-tap {
  position: absolute; left: 0; right: 0;
  top: calc(var(--S) * 0.115 + 12 * var(--p));
  height: calc(843 * var(--p) - var(--S) * 0.115 - 12 * var(--p));
  visibility: hidden;
  pointer-events: none;
}
/* L'îlot de la caméra passe DEVANT le bandeau : sur un iPhone, rien ne se
   dessine jamais par-dessus. Le bandeau sort donc de dessous, comme une
   notification. */
.ac-clic-scene .ac-ecran::before { z-index: 6; }
.ac-bandeau {
  position: absolute; z-index: 5;
  left: calc(20 * var(--p)); right: calc(20 * var(--p));
  top: calc(var(--S) * 0.115 + 12 * var(--p));
  display: flex; align-items: center; gap: calc(10 * var(--p));
  padding: calc(12 * var(--p)) calc(16 * var(--p));
  border-radius: calc(14 * var(--p));
  background: #FF7045; color: #0A0A0A;
  font: 600 calc(13 * var(--p)) / calc(18 * var(--p)) var(--sans);
  box-shadow: 0 calc(4 * var(--p)) calc(12 * var(--p)) rgba(0, 0, 0, 0.25);
  opacity: 0;
  pointer-events: none;
}
.ac-bandeau svg {
  flex: none; width: calc(16 * var(--p)); height: calc(16 * var(--p));
  fill: none; stroke: #0A0A0A; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
@media (min-width: 1024px) {
  .ac-clic { padding: 120px 0 110px; }
  .ac-clic-grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 40px;
    align-items: center;
  }
  .ac-clic-texte { grid-column: 2; grid-row: 1; align-self: end; padding-bottom: 40px; }
  .ac-clic .ac-dit { margin-top: 26px; }
  .ac-clic-scene { --w: 336px; grid-column: 1; grid-row: 1; margin: 0 0 0 12%; }
  .ac-anneau { outline-width: 3px; }
  .ac-anneau::after { border-width: 3px; }
}
/* le même plafond sur ordinateur (voir plus haut), APRÈS les 336 px du bureau */
@supports (height: 1svh) {
  @media (min-width: 1024px) {
    .ac-clic-scene { --w: min(336px, max(220px, calc((88svh - var(--header-h) - 8px) / 1.709))); }
  }
}
/* les deux mêmes plafonds, sur la hauteur FIGÉE (accueil.js, 8 oct. : voir la
   une) — sinon, sur un petit iPhone hors Safari, ce téléphone changeait de
   taille à chaque fois que la barre du navigateur allait et venait */
html.fige .ac-clic-scene { --w: min(300px, calc(100vw - 2 * var(--gutter) - 16px), max(220px, calc((var(--ac-svh) * 88 - var(--header-h) - 8px) / 1.709))); }
@media (min-width: 1024px) {
  html.fige .ac-clic-scene { --w: min(336px, max(220px, calc((var(--ac-svh) * 88 - var(--header-h) - 8px) / 1.709))); }
}

/* ════════ 4 · LE GROUPE — question et réponse en diagonale ════════
   Sur téléphone, la question et sa réponse restent ENSEMBLE au-dessus du
   téléphone. Les bulles agrandies sont des morceaux de LA MÊME capture,
   posés sur leur original et sortis du cadre. */
.ac-groupe { padding: 88px 0 96px; }
.ac-question, .ac-reponse { font-size: clamp(46px, 13.5vw, 118px); }
.ac-reponse { text-align: right; margin-top: 6px; }
.ac-reponse em { display: block; }
.ac-groupe .ac-dit { margin: 16px 0 0 auto; max-width: 24ch; text-align: right; }
.ac-chat {
  --w: min(300px, 78vw);
  position: relative;
  width: var(--w);
  margin: 44px auto 0;
}
.ac-chat .ac-tel { --haut: #241410; }
.ac-bulle {
  --k: 1.5;
  --b: calc(var(--w) * 0.03);
  --S: calc(var(--w) - 2 * var(--b));
  --s: calc(var(--S) / 420);
  position: absolute; z-index: 3;
  overflow: hidden;
  border-radius: calc(var(--s) * var(--k) * 13.5);
  box-shadow: 0 22px 44px -10px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(0, 0, 0, 0.4);
}
.ac-bulle img { position: absolute; width: calc(var(--s) * var(--k) * 420); max-width: none; height: auto; }
/* Mehdi : x 47 → 349, y 121 → 178 dans la capture */
.ac-bulle-g {
  width: calc(var(--s) * var(--k) * 302);
  height: calc(var(--s) * var(--k) * 58);
  left: calc(var(--w) * -0.13);
  top: calc(var(--b) + var(--S) * 0.115 + var(--s) * 149.5 - var(--s) * var(--k) * 29);
  transform: rotate(-3deg);
}
.ac-bulle-g img { left: calc(var(--s) * var(--k) * -47); top: calc(var(--s) * var(--k) * -121); }
/* la mienne, en corail : x 124 → 403, y 601 → 637 */
.ac-bulle-d {
  width: calc(var(--s) * var(--k) * 280);
  height: calc(var(--s) * var(--k) * 37);
  right: calc(var(--w) * -0.13);
  top: calc(var(--b) + var(--S) * 0.115 + var(--s) * 619 - var(--s) * var(--k) * 18.5);
  transform: rotate(2.5deg);
  box-shadow: 0 22px 44px -10px rgba(0, 0, 0, 0.85), 0 10px 30px -8px rgba(255, 112, 69, 0.35);
}
.ac-bulle-d img { left: calc(var(--s) * var(--k) * -124); top: calc(var(--s) * var(--k) * -601); }
@media (min-width: 1024px) {
  .ac-groupe { padding: 150px 0 140px; }
  .ac-groupe-grille {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    grid-template-rows: auto 1fr auto;
    column-gap: 72px;
  }
  .ac-question { grid-column: 1; grid-row: 1; font-size: clamp(64px, 7.4vw, 108px); }
  .ac-chat { --w: 330px; grid-column: 2; grid-row: 1 / 4; margin: 150px 0 0; }
  .ac-groupe-bas { grid-column: 3; grid-row: 3; align-self: end; padding-top: 40px; }
  .ac-reponse { font-size: clamp(64px, 7.4vw, 108px); text-align: left; margin-top: 0; }
  .ac-groupe .ac-dit { margin: 24px 0 0; text-align: left; }
  .ac-bulle { --k: 1.55; }
}

/* ════════ 5 · UNE IDÉE — le titre passe par-dessus le téléphone ════════ */
.ac-idee { padding: 96px 0 56px; }
.ac-idee h2 {
  position: relative; z-index: 2;
  font-size: clamp(60px, 18vw, 196px);
  line-height: 0.9;
  text-shadow: 0 2px 30px rgba(10, 10, 10, 0.85);
}
.ac-idee h2 span, .ac-idee h2 em { display: block; }
.ac-idee-scene {
  position: relative; z-index: 1;
  display: flex; justify-content: flex-end;
  margin: -0.78em calc(-1 * var(--gutter) - 14px) 0 0;
  font-size: clamp(60px, 18vw, 196px);
}
.ac-idee-scene .ac-tel {
  --w: min(300px, 76vw);
  --haut: #251512;
  transform: rotate(-6deg);
  transform-origin: 70% 0;
  -webkit-mask-image: linear-gradient(180deg, #000 80%, transparent 99%);
  mask-image: linear-gradient(180deg, #000 80%, transparent 99%);
}
.ac-idee-scene .ac-ecran { padding-bottom: calc(var(--S) * 0.16); background: linear-gradient(180deg, var(--haut) 0, var(--haut) 8%, var(--bg) 8.1%); }
.ac-idee .ac-dit { margin-top: 18px; max-width: 26ch; position: relative; z-index: 2; }
/* Tablette : le téléphone grandit pour que « Lance-la. » vienne encore mordre dessus. */
@media (min-width: 700px) and (max-width: 1023px) { .ac-idee-scene .ac-tel { --w: 370px; } }
@media (min-width: 1024px) {
  .ac-idee { padding: 150px 0 72px; }
  .ac-idee-grille { position: relative; min-height: 800px; }
  .ac-idee h2 { font-size: clamp(120px, 15vw, 196px); }
  /* la 2e ligne rentre vers la droite et vient mordre sur le téléphone */
  .ac-idee h2 em { padding-left: 1.15em; }
  .ac-idee-scene { position: absolute; left: 57%; top: 224px; margin: 0; font-size: 1rem; }
  .ac-idee-scene .ac-tel { --w: 370px; transform: rotate(-7deg); }
  .ac-idee .ac-dit { margin-top: 48px; max-width: 22ch; }
}

/* ════════ 6 · LA BETA — le formulaire ════════
   Le formulaire lui-même (champs, erreurs, confirmation) est dans site.css,
   section 8, et son comportement dans site.js : partagés avec l-app.html. */
/* Pas de filet en haut de cette section : c'était une « coupure » de plus au
   défilement (retour de Nono, 28 sept.). La lueur suffit à marquer le début. */
.ac-beta { padding: 96px 0 88px; }
.ac-beta h2 { font-size: clamp(52px, 15vw, 132px); }
.ac-beta h2 em { display: block; }
.ac-beta .ac-dit { margin-top: 20px; max-width: 32ch; }
.ac-beta-icone { display: none; }
.ac-beta .fdemande,
.ac-beta .fmerci {
  margin-top: 36px;
  padding: 24px 18px 24px;
  background: var(--surface);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 20px;
}
.ac-beta .fmerci { border-left: 5px solid var(--accent); }
.ac-beta .fdemande .btn { width: 100%; margin-top: 10px; }
.ac-beta .fduo { grid-template-columns: 1fr; }
.ac-detail { margin-top: 26px; }
.ac-detail a {
  display: inline-block; padding: 10px 0;
  color: var(--ink2); font: 500 17px/1.45 var(--sans); text-decoration: none;
  transition: color 0.2s ease;
}
.ac-detail a:hover { color: var(--accent); }
.ac-detail .i { margin-left: 8px; color: var(--accent); font-size: 18px; vertical-align: -0.2em; }
@media (min-width: 1024px) {
  .ac-beta { padding: 150px 0 130px; }
  .ac-beta-grille { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 480px); column-gap: 80px; align-items: start; }
  .ac-beta .ac-dit { margin-top: 30px; }
  .ac-beta-icone { display: block; margin-top: 64px; transform: rotate(-8deg); transform-origin: 30% 60%; }
  .ac-beta-icone .app-icon { --size: 168px; }
  .ac-beta .fdemande, .ac-beta .fmerci { margin-top: 12px; padding: 30px 28px; }
}

/* ════════ LE MOUVEMENT (28 sept. 2026, v2 : lié au défilement) ════════
   Demandes de Nono : « un scroll original, fait pro », puis « encore plus
   fluide, et qu'en remontant elles se fassent dans le sens inverse, sans
   devoir rafraîchir ». D'où cette v2 : le mouvement est LIÉ AU DÉFILEMENT
   (animation-timeline: view()). Il suit le doigt : on remonte, il se déroule
   à l'envers ; on s'arrête, il s'arrête. Le navigateur le calcule hors du fil
   principal : c'est la voie la plus fluide qui existe sur le web.
   Ce que chaque affiche raconte :
     la une      cascade au chargement ; en descendant, le texte s'éloigne et
                 le téléphone monte un peu plus vite que la page
     ce soir     le téléphone monte, et son fil DÉFILE avec la page : on
                 descend, il descend ; on remonte, il remonte
     un clic     le titre glisse depuis la droite, le téléphone monte ; l'anneau
                 respire autour de S'inscrire ; une fois le téléphone à
                 l'écran, on laisse 1,4 s pour le regarder, puis le bouton
                 s'enfonce, l'anneau éclate, et l'app répond (bouton
                 « ✓ Rejoint », bandeau). Ce geste-là est un ÉVÉNEMENT, pas
                 une position : il se joue dans le temps (un bouton à moitié
                 enfoncé parce qu'on s'est arrêté de défiler n'aurait pas de
                 sens), et se défait si on remonte au-dessus
     le groupe   le téléphone monte, puis les deux bulles s'en soulèvent
     une idée    le téléphone se penche en place, « Lance-la. » arrive par la
                 droite et vient mordre dessus
   Règles tenues :
   - seulement opacity + translate / rotate / scale (propriétés INDIVIDUELLES :
     elles se composent avec le `transform` de la mise en page — les téléphones
     penchés — au lieu de l'écraser, et ne relancent jamais la mise en page) ;
   - chaque élément suit SA PROPRE entrée à l'écran (view()) : plus bas, il
     entre plus tard — le décalage vient tout seul ; les plages
     (animation-range) écrivent le reste de la chorégraphie ;
   - les bulles partent EXACTEMENT de leur original (mesuré au pixel :
     outils/mesure-depart.mjs), apparaissent posées dessus, puis se
     soulèvent. En route, leurs bords s'écartent tous vers l'extérieur : elles
     recouvrent toujours entièrement leur original, donc jamais de texte en
     double, même arrêté à mi-chemin. Et leur plage ne commence qu'une fois le
     téléphone posé (sa plage à lui finit à cover 25 %) ;
   - courbe easeOutCubic (easings.net) : départ franc, arrivée posée ;
   - « réduire les animations » : RIEN ne bouge (tout ce bloc est sous
     prefers-reduced-motion: no-preference) ;
   - html.sda est posé dans le <head> si le navigateur sait lier au défilement ;
     sinon, REPLI : des transitions déclenchées par accueil.js, qui se
     rejouent aussi à l'envers quand l'élément redescend sous l'écran ;
   - sans JavaScript : ni sda ni anim, tout est visible et immobile. */
@media (prefers-reduced-motion: no-preference) {

  /* ── 1 · La une : l'entrée orchestrée au chargement (temps, CSS pur) ── */
  .ac-une h1, .ac-une h1 em, .ac-une .ac-dit, .ac-une .btn, .ac-une .ac-note, .ac-une-scene .ac-mention {
    animation: ac-monte 800ms var(--ac-ease) both;
  }
  .ac-une h1 em { animation-delay: 90ms; }
  .ac-une .ac-dit { animation-delay: 170ms; }
  .ac-une .btn { animation-delay: 240ms; }
  .ac-une .ac-note { animation-delay: 300ms; }
  .ac-une-scene .ac-mention { animation-delay: 360ms; }
  /* le téléphone remonte de sous la coupe du bas */
  .ac-une-cadre { animation: ac-surgit 1100ms var(--ac-ease) 220ms both; }
  @keyframes ac-monte { from { opacity: 0; translate: 0 26px; } }
  @keyframes ac-surgit { from { opacity: 0; translate: 0 140px; } }

  /* Les bulles : écart entre le centre de leur original et le leur, en % de
     leur largeur, tiré des cotes de capture (voir la section du groupe) :
     (b + s·198 + 0,13·w − s·k·151) / (s·k·302) à gauche,
     (b + s·263,5 − (1,13·w − s·k·140)) / (s·k·280) à droite. */
  .ac-bulle-g { --bx: 9.5%; --br: 3deg; }
  .ac-bulle-d { --bx: -4.3%; --br: -2.5deg; }
  @media (min-width: 1024px) { .ac-bulle-g { --bx: 7.6%; } .ac-bulle-d { --bx: -2.5%; } }

  /* ── 2 · Lié au défilement (html.sda) ── */
  /* --ac-vue : la ligne de temps « mon entrée à l'écran » de chaque élément. */
  html.sda { --ac-scrub: cubic-bezier(0.33, 1, 0.68, 1); --ac-vue: view(); }

  /* 🔴 8 oct. — LA FENÊTRE DE RÉFÉRENCE EST FIGÉE. view() mesure l'entrée d'un
     élément depuis le BAS de la zone visible. Sur iPhone, la barre du
     navigateur sort dès qu'on remonte : ce bas remonte de 136 px en une image,
     et tout ce qui était dans le tiers bas de l'écran reculait d'un coup dans
     son animation (jusqu'à disparaître). On mesure donc depuis une ligne qui ne
     bouge pas : le HAUT de l'écran + --ac-bas (accueil.js : la hauteur visible
     barres sorties, celle qu'on voit TOUJOURS). Le retrait du bas vaut
     « hauteur du moment − --ac-bas » : nul quand la barre est sortie, et quand
     elle rentre la fenêtre de référence ne grandit pas avec elle.
     Le retrait du HAUT reste « auto » : c'est celui de view() tout court, qui
     reprend scroll-padding-top (l'en-tête fixe, site.css) — écrire 0 allongeait
     chaque plage de 76 px et décalait toutes les entrées (vu à la comparaison).
     Sans accueil.js, ou si le navigateur ne connaît pas ce retrait : view()
     tout court, comme avant. Tests : outils/essai/webkit-barre.mjs (la barre va
     et vient, rien ne bouge) et compare-etats.mjs (barre immobile : identique
     au site d'avant). */
  @supports (animation-timeline: view(block auto calc(100% - 100px))) {
    html.sda.fige { --ac-vue: view(block auto calc(100% - var(--ac-bas))); }
    html.sda.fige .ac-fil { view-timeline-inset: auto calc(100% - var(--ac-bas)); }
  }

  /* la une : en descendant, le texte s'éloigne ; en remontant, il revient */
  html.sda .ac-une-texte { animation: ac-une-recule linear both; animation-timeline: scroll(root); animation-range: 0 70vh; }
  html.sda .ac-une-cadre .ac-tel { animation: ac-emerge linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
  /* La légende S'EFFACE avant que le téléphone ne l'atteigne (Nono, 11 oct. :
     « le "Captures de l'app…" passe derrière le téléphone, c'est pas joli »).
     Le téléphone monte de 9 % de sa hauteur pendant qu'on descend ; la légende,
     posée 14 px au-dessus, restait en place : il la recouvrait par le milieu
     et, comme elle est plus large que lui, ses deux bouts dépassaient de chaque
     côté. Il la touche après 29 à 36 % d'un écran de défilement selon la
     taille : elle a disparu à 20 %, et revient quand on remonte.
     Essayé et écarté le même jour : la faire MONTER avec le téléphone — la
     scène coupe ce qui dépasse (overflow: hidden, pour le bas du téléphone), et
     la légende se faisait rogner par le haut.
     C'est le <span> qui porte ce fondu : le <figcaption> garde son entrée du
     chargement (deux animations sur le même élément se disputeraient
     « opacity »). */
  html.sda .ac-une-scene .ac-mention span { animation: ac-legende-fond linear both; animation-timeline: scroll(root); animation-range: 0 20vh; }
  /* même raison : hors Safari « vh » suit la barre ; --ac-vh est relevé une fois */
  html.sda.fige .ac-une-texte { animation-range: 0 calc(var(--ac-vh) * 70); }
  html.sda.fige .ac-une-cadre .ac-tel { animation-range: 0 calc(var(--ac-vh) * 100); }
  html.sda.fige .ac-une-scene .ac-mention span { animation-range: 0 calc(var(--ac-vh) * 20); }

  /* textes : ils montent en entrant */
  html.sda .ac-affiche :is(.ac-t, .ac-dit, .ac-detail) {
    animation: ac-s-monte var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 30%;
  }
  /* un clic : le titre est au fer à droite, il glisse depuis la droite */
  html.sda .ac-affiche.ac-clic .ac-t { animation-name: ac-s-droite; }
  html.sda :is(.ac-clic, .ac-idee) .ac-t em {
    animation: ac-s-droite-loin var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 34%;
  }
  html.sda .ac-beta .ac-t em {
    animation: ac-s-monte var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 32%;
  }

  /* ce soir : le téléphone monte, et son fil défile avec la page. Les deux
     suivent la MÊME ligne de temps, --fil, posée sur .ac-fil qui, lui, ne
     bouge pas (l'image qui défile est plus haute que sa fenêtre : sa propre
     entrée à l'écran ne voudrait rien dire). Le fil part quand 60 % du
     téléphone est visible et arrive quand il est presque centré (cover 48 %) :
     ~350 px de page pour ~330 px de fil sur un téléphone — le fil suit le
     doigt presque 1 pour 1. Courbe ease-in-out : il démarre et s'arrête en
     douceur, comme un défilement qu'on lance puis qui se pose. */
  html.sda .ac-fil { view-timeline: --fil block; }
  html.sda .ac-fil .ac-tel {
    animation: ac-s-tel var(--ac-scrub) both;
    animation-timeline: --fil; animation-range: entry 0% cover 30%;
  }
  html.sda .ac-defile {
    animation: ac-s-defile cubic-bezier(0.65, 0, 0.35, 1) both;
    animation-timeline: --fil; animation-range: entry 60% cover 48%;
  }

  /* les téléphones : ils montent, et sont posés à cover 25 % */
  html.sda :is(.ac-clic-cadre, .ac-chat .ac-tel) {
    animation: ac-s-tel var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 25%;
  }
  html.sda .ac-idee-scene .ac-tel {
    animation: ac-s-idee var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 30%;
  }

  /* les bulles se soulèvent de leur original, téléphone posé */
  html.sda .ac-bulle {
    animation: ac-s-bulle var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: cover 32% cover 62%;
  }

  /* la beta */
  html.sda .ac-beta .fdemande {
    animation: ac-s-form var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 22%;
  }
  html.sda .ac-beta-icone {
    animation: ac-s-icone var(--ac-scrub) both;
    animation-timeline: var(--ac-vue); animation-range: entry 0% cover 35%;
  }

  @keyframes ac-une-recule { to { opacity: 0.25; translate: 0 -56px; } }
  @keyframes ac-emerge { to { translate: 0 -9%; } }
  @keyframes ac-legende-fond { to { opacity: 0; } }
  @keyframes ac-s-monte { from { opacity: 0; translate: 0 48px; } }
  @keyframes ac-s-droite { from { opacity: 0; translate: 64px 0; } }
  @keyframes ac-s-droite-loin { from { opacity: 0; translate: 0.6em 0; } }
  @keyframes ac-s-tel { from { opacity: 0; translate: 0 110px; } }
  /* du haut du fil (« À la une ») jusqu'à la position de repos (−38,71 %) */
  @keyframes ac-s-defile { from { translate: 0 0; } }
  @keyframes ac-s-idee { from { opacity: 0; translate: 0 120px; rotate: 9deg; } }
  @keyframes ac-s-bulle {
    0% { opacity: 0; translate: var(--bx) 0; rotate: var(--br); scale: calc(1 / var(--k)); }
    5% { opacity: 1; translate: var(--bx) 0; rotate: var(--br); scale: calc(1 / var(--k)); }
    100% { opacity: 1; translate: 0 0; rotate: 0deg; scale: 1; }
  }
  @keyframes ac-s-form { from { opacity: 0; translate: 0 60px; } }
  @keyframes ac-s-icone { from { opacity: 0; scale: 0.86; rotate: -10deg; } }

  /* ── 3 · Repli (navigateur sans animation-timeline) : transitions posées
     par accueil.js, data-vu mis ET retiré (l'élément qui redescend sous
     l'écran rejoue son entrée à l'envers) ── */
  html.anim:not(.sda) .ac-affiche :is(.ac-t, .ac-t em, .ac-dit, .ac-detail, .ac-fil .ac-tel, .ac-clic-cadre, .ac-chat .ac-tel, .ac-idee-scene .ac-tel, .ac-beta-icone, .ac-beta .fdemande) {
    transition:
      opacity 700ms var(--ac-ease) var(--d, 0ms),
      translate 950ms var(--ac-ease) var(--d, 0ms),
      rotate 1100ms var(--ac-ease) var(--d, 0ms),
      scale 900ms var(--ac-ease) var(--d, 0ms);
  }
  html.anim:not(.sda) .ac-affiche:not([data-vu]) :is(.ac-t, .ac-dit, .ac-detail) { opacity: 0; translate: 0 30px; }
  .ac-soir .ac-dit { --d: 110ms; }
  .ac-fil .ac-tel { --d: 60ms; }
  html.anim:not(.sda) .ac-fil:not([data-vu]) .ac-tel { opacity: 0; translate: 0 90px; }
  /* le fil défile quand son haut passe au-dessus de 55 % de l'écran
     (data-defile, accueil.js) ; redescendu sous l'écran, il revient au début
     (plus vite : on ne le voit pas faire) */
  html.anim:not(.sda) .ac-defile { transition: translate 2000ms cubic-bezier(0.65, 0, 0.35, 1) 150ms; }
  html.anim:not(.sda) .ac-fil:not([data-defile]) .ac-defile { translate: 0 0; transition-duration: 700ms; transition-delay: 0ms; }
  .ac-clic .ac-t em { --d: 90ms; }
  .ac-clic .ac-dit { --d: 180ms; }
  html.anim:not(.sda) .ac-clic:not([data-vu]) .ac-t { translate: 56px 0; }
  html.anim:not(.sda) .ac-clic:not([data-vu]) .ac-t em { opacity: 0; translate: 72px 0; }
  html.anim:not(.sda) .ac-clic-scene:not([data-vu]) .ac-clic-cadre { opacity: 0; translate: 0 90px; }
  .ac-reponse { --d: 240ms; }
  .ac-groupe .ac-dit { --d: 320ms; }
  html.anim:not(.sda) .ac-chat:not([data-vu]) .ac-tel { opacity: 0; translate: 0 80px; }
  /* 650 ms : le téléphone doit avoir fini de monter avant que la bulle parte */
  .ac-bulle-g { --d: 650ms; }
  .ac-bulle-d { --d: 780ms; }
  html.anim:not(.sda) .ac-bulle {
    transition:
      opacity 120ms linear var(--d),
      translate 850ms var(--ac-ease) calc(var(--d) + 60ms),
      rotate 850ms var(--ac-ease) calc(var(--d) + 60ms),
      scale 850ms var(--ac-ease) calc(var(--d) + 60ms);
  }
  html.anim:not(.sda) .ac-bulle:not([data-vu]) { opacity: 0; translate: var(--bx) 0; rotate: var(--br); scale: calc(1 / var(--k)); }
  .ac-idee h2 em { --d: 150ms; }
  .ac-idee .ac-dit { --d: 300ms; }
  html.anim:not(.sda) .ac-idee:not([data-vu]) .ac-t em { opacity: 0; translate: 0.6em 0; }
  html.anim:not(.sda) .ac-idee-scene:not([data-vu]) .ac-tel { opacity: 0; translate: 0 100px; rotate: 8deg; }
  .ac-beta .ac-t em { --d: 90ms; }
  .ac-beta .fdemande { --d: 120ms; }
  .ac-beta .ac-dit { --d: 170ms; }
  .ac-detail { --d: 260ms; }
  .ac-beta-icone { --d: 320ms; }
  html.anim:not(.sda) .ac-beta:not([data-vu]) .ac-t em { opacity: 0; translate: 0 26px; }
  html.anim:not(.sda) .ac-beta .fdemande:not([data-vu]) { opacity: 0; translate: 0 44px; }
  html.anim:not(.sda) .ac-beta:not([data-vu]) .ac-beta-icone { opacity: 0; scale: 0.86; rotate: -10deg; }

  /* ── 4 · Le tap sur S'inscrire (les deux modes) ──
     data-tape est posé sur .ac-clic-scene par accueil.js quand la zone du tap
     (du haut du bandeau au bas du bouton) est ENTIÈREMENT à l'écran depuis
     1,4 s — le temps de voir la fiche et S'inscrire qui respire (Nono, 28 sept. :
     « on n'a même pas le temps de voir le bouton S'inscrire »). Si on continue
     de défiler avant, rien ne part. Retiré quand on remonte au-dessus. Déroulé,
     une fois posé :
         0 ms  l'anneau cesse de respirer (il s'éteint, sans se figer) ;
       180     le morceau de capture du bouton prend la place de l'original —
               identique, donc invisible — pour pouvoir être enfoncé ;
       200     appui : le bouton s'enfonce (150 ms) et l'anneau ÉCLATE — il
               s'élargit en s'effaçant (350 ms) ;
       560     l'app répond : « ✓ Rejoint · Annuler » remplace S'inscrire D'UN
               COUP, comme dans l'app (un fondu croisé écrivait les deux
               libellés l'un sur l'autre pendant 100 ms) ; l'éclat est éteint ;
       700     le bandeau corail sort de sous l'îlot et descend (460 ms).
     Ce qui est l'app et ce qui est de la mise en scène : les ÉTATS (bouton
     « ✓ Rejoint · Annuler », bandeau, textes, couleurs) sont ceux de l'app ;
     le GESTE est une mise en scène — dans l'app, le bouton s'estompe à l'appui
     (TouchableOpacity) et le bandeau apparaît sans glisser.
     Historique : un « doigt » (un rond blanc de démonstration) venait taper le
     bouton. Nono (28 sept.) : « l'animation en soi est bien, mais le tap
     non ». Retiré : l'appui du bouton et l'éclat de l'anneau disent le tap
     sans rien dessiner de plus sur l'écran de l'app.
     Au retrait : tout revient en 240 ms, sans délai. */
  .ac-anneau::after { animation: ac-tape 2.6s var(--ac-ease) 0.6s infinite paused; }
  .ac-clic[data-live] .ac-clic-scene:not([data-tape]) .ac-anneau::after { animation-play-state: running; }
  /* au tap, la respiration s'éteint au lieu de se figer à mi-course (un 2e
     anneau pâle restait suspendu autour du premier) ; au retrait, elle repart
     de son début */
  [data-tape] .ac-anneau::after { animation: none; }
  @keyframes ac-tape {
    0%, 30% { opacity: 1; scale: 1; }
    100% { opacity: 0; scale: 1.08 1.19; }
  }
  .ac-anneau, .ac-cache, .ac-sinscrire, .ac-rejoint, .ac-bandeau {
    transition: opacity 240ms var(--ac-ease), translate 240ms var(--ac-ease), scale 240ms var(--ac-ease);
  }
  .ac-rejoint { scale: 0.95; }
  .ac-bandeau { translate: 0 -140%; }

  [data-tape] .ac-cache { opacity: 1; transition: opacity 0s linear 180ms; }
  [data-tape] .ac-sinscrire { scale: 0.95; opacity: 0; transition: scale 150ms var(--ac-ease) 200ms, opacity 0s linear 560ms; }
  /* l'éclat : la même déformation que la respiration (plus haut que large, en
     proportion de l'anneau), un cran plus loin. L'opacité s'efface en LINÉAIRE
     (et pas avec la courbe forte) : l'anneau reste vif pendant qu'il s'élargit ;
     avec la courbe forte, il virait au brun avant d'avoir bougé (vu image par
     image dans le navigateur). */
  [data-tape] .ac-anneau { opacity: 0; scale: 1.1 1.28; transition: opacity 350ms linear 200ms, scale 350ms var(--ac-ease) 200ms; }
  [data-tape] .ac-rejoint { opacity: 1; scale: 1; transition: opacity 0s linear 560ms, scale 300ms var(--ac-ease) 560ms; }
  [data-tape] .ac-bandeau { opacity: 1; translate: 0 0; transition: opacity 260ms var(--ac-ease) 700ms, translate 460ms var(--ac-ease) 700ms; }
}

/* ════════ Impression ════════ */
@media print {
  .ac-une *, .ac-affiche * { animation: none !important; transition: none !important; opacity: 1 !important; translate: none !important; scale: none !important; rotate: none !important; }
  body.page-accueil::before, .ac-tel, .ac-bulle, .ac-une-scene, .ac-fil, .ac-clic-scene, .ac-chat, .ac-idee-scene, .ac-beta-icone, .ac-beta .fdemande { display: none !important; }
  .ac-t, .ac-t em, .ac-dit, .ac-note, .ac-mention { color: #000 !important; text-shadow: none !important; }
  .ac-affiche { overflow: visible; padding: 16px 0 !important; min-height: 0 !important; }
  .ac-une .wrap { min-height: 0; }
}
