/* La commune vivante, fabriquée par maquettes/fabrication/composer-site.js à partir de
   la maquette validée par Victor le 20/10/2026 (maquettes/commune-animee.html).
   NE PAS RETOUCHER À LA MAIN : corriger la source (voir maquettes/fabrication/README.md),
   puis refabriquer. Toutes les règles sont rangées sous .commune-vivante. */
  /* ---------- La scène de la commune ---------- */
  /* L'invitation à explorer (texte de Victor, 20/10) : une ligne sobre, centrée. */
.commune-vivante .invitation { max-width: 46rem; margin: 0 auto 14px; display: flex; align-items: flex-start; justify-content: center; gap: 10px; text-align: center; color: var(--marine); font-size: 1.05rem; font-weight: 500; line-height: 1.5; }
.commune-vivante .invitation__pointeur { flex: none; width: 18px; height: 20px; margin-top: 2px; }
.commune-vivante .commune { position: relative; width: 100%; max-width: 1180px; margin: 0 auto; aspect-ratio: 1448 / 1086; }
.commune-vivante .commune > img { position: absolute; inset: 0; width: 100%; height: 100%; }
  /* Le soir chez le visiteur, des fenêtres de la mairie et des services techniques
     s'allument (Victor, 20/10) : un calque fait par fabrication/fenetres-du-soir.py. */
.commune-vivante .commune > img.fenetres-du-soir { opacity: 0; transition: opacity 2s ease; }
.commune-vivante .commune.nuit > img.fenetres-du-soir { opacity: 1; }
.commune-vivante .figurants { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.commune-vivante .place { position: absolute; }
.commune-vivante .place .perso { position: relative; }
.commune-vivante .place .perso svg, .commune-vivante .place .panneau-mission svg { display: block; width: 100%; height: auto; overflow: visible; }
  /* La visibilité, choisie par Victor le 20/10 : plus grands (dans les tailles de
     PLACES), un socle à leur couleur, un contour blanc et une ombre portée. */
.commune-vivante .socle { position: absolute; left: 50%; bottom: -5%; width: 105%; aspect-ratio: 2.3 / 1; transform: translate(-50%, 35%); border-radius: 50%;
    background: color-mix(in srgb, var(--c) 30%, transparent); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--c) 85%, transparent); }
.commune-vivante .commune .perso svg { filter: drop-shadow(2px 0 0 #fff) drop-shadow(-2px 0 0 #fff) drop-shadow(0 2px 0 #fff) drop-shadow(0 -2px 0 #fff) drop-shadow(0 7px 8px rgba(17,35,71,0.35)); }
.commune-vivante .panneau-mission { display: block; cursor: pointer; border-radius: 6px; outline-offset: 4px; }
.commune-vivante .panneau-mission svg { filter: drop-shadow(0 5px 6px rgba(17,35,71,0.3)); }
.commune-vivante .bulle { position: absolute; left: 50%; bottom: calc(100% + 6px); transform: translateX(-50%); width: max-content; max-width: 240px;
    background: #fff; border-radius: 12px; box-shadow: 0 6px 22px rgba(17,35,71,0.18); padding: 9px 12px; font-size: 0.85rem; line-height: 1.35;
    color: var(--marine); font-weight: 600; opacity: 0; visibility: hidden; transition: opacity 0.2s ease; pointer-events: none; z-index: 3; }
.commune-vivante .bulle__app { display: block; width: max-content; margin: 0 0 5px; padding: 2px 8px; border-radius: 999px; color: #fff; font-size: 0.75rem; font-weight: 700; }
  /* La bulle au survol, seulement là où le survol existe. Sur iPhone, un toucher qui
     fait apparaître quelque chose au survol est pris pour un survol et non pour un
     clic : il fallait parfois trois touchers, et le lien de la bulle ne répondait
     plus (essai de Victor du 20/10). Au doigt, c'est le premier toucher qui l'ouvre. */
@media (hover: hover) {
  .commune-vivante .place:hover .bulle { opacity: 1; visibility: visible; }
}
.commune-vivante .place:focus-within .bulle { opacity: 1; visibility: visible; }
.commune-vivante .place:hover, .commune-vivante .place:focus-within { z-index: 4; }
  /* Les figurants qui se déplacent sont menés par le script : leurs pas
     commandent leur avancée, et ils sont redessinés du plus loin au plus proche.
     Les enfants et le ballon, qui restent sur place, bougent en CSS. */
.commune-vivante.vivant .saute { animation: saute 0.9s ease-in-out infinite alternate; }
.commune-vivante.vivant .saute--2 { animation-delay: -0.45s; }
@keyframes saute { from { transform: translateY(0); } to { transform: translateY(-5px); } }
.commune-vivante.vivant .ballon { animation: passe 1.8s ease-in-out infinite; }
@keyframes passe { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(52px, 22px); } }
.commune-vivante.vivant .ballon__rebond { animation: rebond 0.9s ease-in-out infinite; }
@keyframes rebond { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-16px); } }
.commune-vivante.sans-mouvement .figurants *, .commune-vivante .hors-champ .figurants * { animation-play-state: paused !important; }
.commune-vivante.sans-mouvement .figurants * { animation: none !important; }
@media (prefers-reduced-motion: reduce) {
  .commune-vivante .figurants * { animation: none !important; }
}
  /* ---------- Ce qui est commun ---------- */
.commune-vivante .perso { display: block; cursor: pointer; border-radius: 12px; outline-offset: 6px; }
.commune-vivante .perso svg { display: block; overflow: visible; }
.commune-vivante .corps-entier { transition: transform 0.7s ease; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .corps-entier { transform: translateY(-3px); }
  /* Les bras et les objets qui pivotent : une pose de repos (--repos) et
     une pose active (--actif), toutes deux portées par l'élément. */
.commune-vivante .pivot { transform: rotate(var(--repos)); transition: transform 0.7s cubic-bezier(.45,.05,.25,1); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .pivot { transform: rotate(var(--actif)); }
  /* Le clignement : deux fois à l'arrivée sur la page, en moins de cinq
     secondes (RGAA 13.8), puis plus rien tant que le visiteur ne le demande pas. */
.commune-vivante .cligne { transform-box: fill-box; transform-origin: center; }
.commune-vivante .perso.accueil .cligne { animation: clin 4.2s 0.8s both; }
@keyframes clin {
    0%, 6%, 100% { transform: scaleY(1); }
    3% { transform: scaleY(0.08); }
    55% { transform: scaleY(1); }
    58% { transform: scaleY(0.08); }
    61% { transform: scaleY(1); }
  }
  /* BâtiFocale : la mise au point */
.commune-vivante .ouverture { transform: scale(1) rotate(0deg); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .ouverture { animation: mise-au-point 1.3s 0.55s ease-in-out both; }
@keyframes mise-au-point {
    0% { transform: scale(1) rotate(0deg); }
    40%, 60% { transform: scale(0.62) rotate(26deg); }
    100% { transform: scale(1) rotate(0deg); }
  }
.commune-vivante .pupille { transition: transform 0.45s 0.45s ease; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .pupille { transform: scale(1.45); }
  /* Atrium : les ailes s'ouvrent, le bon dossier se détache, le trousseau tinte */
.commune-vivante .aile { transition: transform 0.5s cubic-bezier(.3,.1,.2,1); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .aile--haut { transform: translate(0, -24px); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .aile--bas { transform: translate(0, 24px); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .aile--gauche { transform: translate(-24px, 0); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .aile--droite { transform: translate(24px, 0); }
.commune-vivante .aile--prune { transition-delay: 0.15s; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .aile--prune { transform: translate(52px, 16px); }
.commune-vivante .regard { transition: transform 0.4s 0.35s ease; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .regard { transform: translate(18px, 18px); }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .cles { animation: tinte 0.7s 0.6s ease-in-out both; }
@keyframes tinte {
    0% { transform: rotate(-100deg); }
    25% { transform: rotate(-86deg); }
    50% { transform: rotate(-112deg); }
    75% { transform: rotate(-94deg); }
    100% { transform: rotate(-100deg); }
  }
  /* PanoTravaux : un tour de lames, une barre de plus au planning */
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .helice { animation: tour 1.4s 0.1s cubic-bezier(.5,0,.3,1) both; }
@keyframes tour { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.commune-vivante .barre-nouvelle { transform-box: fill-box; transform-origin: left center; transform: scaleX(0); transition: transform 0.5s 0.7s ease-out; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .barre-nouvelle { transform: scaleX(1); }
  /* Carto-Salles : les salles s'occupent une à une */
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .salle { animation: occupe 1.8s calc(var(--i) * 0.13s) ease-in-out both; }
@keyframes occupe { 25%, 70% { fill: #17936A; } }
  /* ChronoERP : les lignes de vitesse, et un tour d'aiguille */
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .barre { animation: file 0.8s calc(var(--i) * 0.1s) cubic-bezier(.3,0,.2,1) both; }
@keyframes file { 0% { transform: translateX(0); } 35% { transform: translateX(-36px); } 100% { transform: translateX(0); } }
.commune-vivante .pastille { transform-box: fill-box; transform-origin: center; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .pastille { animation: bat 0.9s 0.35s ease-in-out both; }
@keyframes bat { 0%, 100% { transform: rotate(0); } 30% { transform: rotate(14deg); } 65% { transform: rotate(-10deg); } }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .aiguille { animation: tour 1.2s 0.6s linear both; }
  /* AsbeSpot : il lève son plan, les prélèvements s'y posent un à un. Il ne
     repère rien lui-même : il montre ce que les rapports ont établi. */
.commune-vivante .spot { transform-box: fill-box; transform-origin: center; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .spot { animation: spot 0.8s 0.2s ease-in-out 2; }
@keyframes spot { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18); } }
.commune-vivante .prelevement { transform-box: fill-box; transform-origin: center; transform: scale(0); transition: transform 0.25s ease-out; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .prelevement { transform: scale(1); transition-delay: calc(0.55s + var(--i) * 0.22s); }
  /* Arvitria : les barres de sa tablette poussent l'une après l'autre */
.commune-vivante .barre-tablette { transform-box: fill-box; transform-origin: 50% 100%; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .barre-tablette { animation: pousse-barre 0.5s calc(0.55s + var(--i) * 0.12s) ease-out both; }
@keyframes pousse-barre { from { transform: scaleY(0.1); } to { transform: scaleY(1); } }
  /* Arvitria : les bâtiments se tassent puis s'élèvent, l'un après l'autre */
.commune-vivante .bati { transform-box: fill-box; transform-origin: 50% 100%; }
.commune-vivante .perso:is(:hover, :focus-visible, .actif) .bati { animation: batir 1.1s calc(var(--i) * 0.11s) cubic-bezier(.3,.1,.2,1) both; }
@keyframes batir { 0% { transform: scaleY(1); } 25% { transform: scaleY(0.55); } 70% { transform: scaleY(1.07); } 100% { transform: scaleY(1); } }
  /* ---------- La vie au repos, permanente et discrète ----------
     Active tant que la page porte la classe « vivant ». Le bouton « Mettre
     en pause les animations » la retire : RGAA 13.8, un contenu qui bouge
     seul plus de cinq secondes doit pouvoir être arrêté et relancé. Chaque
     personnage a son rythme (--p, --r, --d), pour qu'ils ne clignent pas
     ensemble. Les mouvements de repos qui touchent un élément du grand
     geste s'arrêtent pendant le survol, pour lui laisser la place. */
.commune-vivante .respire { transform-box: fill-box; transform-origin: 50% 100%; }
.commune-vivante.vivant .perso .respire { animation: respire var(--r) var(--d) ease-in-out infinite alternate; }
@keyframes respire { from { transform: scale(1, 1); } to { transform: scale(1.012, 1.024); } }
.commune-vivante.vivant .perso .cligne { animation: clin-repos var(--p) var(--d) infinite; }
@keyframes clin-repos { 0%, 94%, 100% { transform: scaleY(1); } 97% { transform: scaleY(0.08); } }
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif):not(.attentif) .yeux-repos { animation: regarde calc(var(--p) * 1.7) var(--d) ease-in-out infinite; }
  /* Le regard partagé : un personnage « attentif » tourne les yeux vers --vers,
     de -1 (tout à gauche) à 1 (tout à droite), le temps de regarder un voisin. */
.commune-vivante .perso .yeux-repos { transition: transform 0.35s ease; }
.commune-vivante .perso.attentif .yeux-repos { transform: translate(calc(var(--amp) * var(--vers, 0)), 0); }
@keyframes regarde {
    0%, 30% { transform: translate(0, 0); }
    38%, 55% { transform: translate(calc(var(--amp) * -1), 0); }
    63%, 80% { transform: translate(var(--amp), 0); }
    88%, 100% { transform: translate(0, 0); }
  }
  /* PanoTravaux : les lames tournent très lentement, sans fin. */
.commune-vivante.vivant .perso .helice-repos { animation: tour 48s linear infinite; }
  /* Carto-Salles : de temps en temps, une salle s'occupe. */
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .salle[data-k="1"] { animation: allume 7s 1.5s ease-in-out infinite; }
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .salle[data-k="5"] { animation: allume 7s 5s ease-in-out infinite; }
@keyframes allume { 76%, 92% { fill: #17936A; } }
  /* ChronoERP : la pastille bat comme un pouls. */
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .pastille { animation: pouls 1.8s ease-in-out infinite; }
@keyframes pouls { 0%, 60%, 100% { transform: scale(1); } 15% { transform: scale(1.14); } 30% { transform: scale(1); } 45% { transform: scale(1.07); } }
  /* Atrium : l'aile prune se signale, de loin en loin. */
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .aile--prune { animation: indice 6.5s var(--d) ease-in-out infinite; }
@keyframes indice { 0%, 80%, 100% { transform: translate(0, 0); } 86%, 94% { transform: translate(10px, 3px); } }
  /* BâtiFocale : l'ouverture se resserre un peu, comme une pupille. */
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .ouverture { animation: iris 5.5s var(--d) ease-in-out infinite; }
@keyframes iris { 0%, 70%, 100% { transform: scale(1) rotate(0deg); } 80%, 88% { transform: scale(0.86) rotate(8deg); } }
  /* Arvitria : un de ses bâtiments pousse un peu, de temps en temps. */
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .bati[data-k="2"] { animation: pousse 6s var(--d) ease-in-out infinite; }
@keyframes pousse { 0%, 75%, 100% { transform: scaleY(1); } 84%, 92% { transform: scaleY(1.05); } }
  /* AsbeSpot : son point bat doucement, comme un voyant. */
.commune-vivante.vivant .perso:not(:hover):not(:focus-visible):not(.actif) .spot { animation: pouls-spot 2.6s var(--d) ease-in-out infinite; }
@keyframes pouls-spot { 0%, 55%, 100% { transform: scale(1); } 20% { transform: scale(1.1); } 35% { transform: scale(0.97); } }
  /* Ce qui sort de l'écran s'arrête : ni ordinateur qui chauffe, ni batterie vidée. */
.commune-vivante .hors-champ .perso, .commune-vivante .hors-champ .perso * { animation-play-state: paused !important; }
  /* ---------- Réduire les animations : rien ne bouge ---------- */
.commune-vivante.sans-mouvement .perso, .commune-vivante.sans-mouvement .perso * { animation: none !important; transition: none !important; }
.commune-vivante.sans-mouvement .perso .pivot { transform: rotate(var(--repos)) !important; }
.commune-vivante.sans-mouvement .perso :is(.corps-entier, .ouverture, .pupille, .aile, .regard, .barre-nouvelle) { transform: none !important; }
.commune-vivante.sans-mouvement .perso .barre-nouvelle { transform: scaleX(0) !important; }
.commune-vivante.sans-mouvement .perso .prelevement { transform: scale(0) !important; }
.commune-vivante.sans-mouvement .perso .spot { transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  .commune-vivante .perso, .commune-vivante .perso * { animation: none !important; transition: none !important; }
  .commune-vivante .perso .pivot { transform: rotate(var(--repos)) !important; }
  .commune-vivante .perso :is(.corps-entier, .ouverture, .pupille, .aile, .regard) { transform: none !important; }
  .commune-vivante .perso .barre-nouvelle { transform: scaleX(0) !important; }
}

/* ---------- Dans le site (composer-site.js) ---------- */
/* La pause, obligatoire dès que la scène bouge plus de cinq secondes (RGAA 13.8). */
.commune-vivante__commandes { display: flex; justify-content: flex-end; margin: 0 0 6px; }
.commune-vivante__commandes button, .commune-vivante .grand-entete button {
  font: inherit; font-size: 0.9rem; font-weight: 600; min-height: 44px; padding: 0 16px; border-radius: 999px;
  border: 1.5px solid var(--bord-bouton); background: #fff; color: var(--marine); cursor: pointer; }
.commune-scene { position: relative; }
.commune-toucher, .commune-entrer { display: none; }
/* L'ACCUEIL AU TÉLÉPHONE : la scène y reste visible mais inerte, et sans vie (pas de
   bouton pause au téléphone, choix de Victor du 20/10, RGAA 13.8) ; la toucher ouvre la
   commune en grand. Le lien qui couvre l'image est un raccourci pour le doigt ; le lien
   écrit dessous est le vrai, celui que lisent le clavier et les lecteurs d'écran. */
@media (max-width: 700px) {
  .commune-vivante--accueil .commune-vivante__commandes, .commune-vivante--accueil .invitation { display: none; }
  .commune-vivante--accueil .bulle { display: none; }
  .commune-toucher { display: block; position: absolute; inset: 0; }
  /* La main du toucher, inclinée vers le haut à gauche : dressée à la verticale, elle se
     lisait comme un tout autre geste (Victor, 20/10). Ses rayons s'allument trois fois,
     en moins de trois secondes, puis restent : sous cinq secondes, le RGAA (13.8)
     n'exige pas de pause. */
  .commune-geste { position: absolute; left: 54%; top: 52%; width: 104px; transform: translate(-50%, -40%); pointer-events: none; filter: drop-shadow(0 4px 8px rgba(17,35,71,0.35)); }
  .commune-geste svg { display: block; width: 100%; height: auto; overflow: visible; }
  .commune-geste .rayon { animation: rayon-geste 0.8s ease-out 3 both; }
  .commune-geste .rayon--2 { animation-delay: 0.56s; }
  .commune-geste .rayon--3 { animation-delay: 0.62s; }
  .commune-geste .rayon--4 { animation-delay: 0.68s; }
  .commune-geste .rayon--5 { animation-delay: 0.74s; }
  .commune-geste .rayon--1 { animation-delay: 0.5s; }
  @media (prefers-reduced-motion: reduce) { .commune-geste .rayon { animation: none; } }
  .commune-entrer { display: inline-block; margin-top: 0.875rem; font-weight: 700; color: var(--sarcelle-texte); }
}
@keyframes rayon-geste { 0% { opacity: 0.15; } 45% { opacity: 1; } 100% { opacity: 1; } }

/* LA COMMUNE EN GRAND (commune.html). Sur ordinateur, une page ordinaire : la scène,
   sa pause, l'en-tête et le pied du site. Au téléphone, la commune entière, 880 pixels
   de large, plus large que l'écran, se parcourt du doigt comme un plan, dans sa propre
   boîte posée sur toute la page : si la page elle-même débordait, le navigateur du
   téléphone l'élargirait au lieu de la faire défiler (vu le 20/10). Un premier toucher
   ouvre la bulle, un second ou son lien mène à la page. */
.commune-vivante .grand-entete, .commune-vivante .bulle__lien { display: none; }
.commune-page__titre { margin-bottom: 0.5rem; }
.commune-page__liste { margin-top: 1.5rem; }
@media (max-width: 700px) {
  .commune-vivante--grand { position: fixed; inset: 0; z-index: 30; overflow: auto; overscroll-behavior: contain; padding: 104px 0 16px; touch-action: pan-x pan-y; background: #fff; }
  .commune-vivante--grand .grand-entete { display: flex; position: fixed; top: 0; left: 0; right: 0; z-index: 31; align-items: center; flex-wrap: wrap; gap: 6px 12px;
    padding: 12px 14px; background: rgba(255,255,255,0.95); box-shadow: 0 1px 0 var(--bord-carte); font-size: 0.85rem; line-height: 1.35; color: var(--gris-texte); }
  /* « Accueil » en bouton, pas en lien (Victor, 20/10) : la pastille des boutons du
     site, 44 pixels de haut pour le doigt. Le bouton pause y rejoint « Accueil ». */
  .commune-vivante--grand .grand-entete a { flex: none; display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px; border: 1.5px solid var(--marine);
    border-radius: 999px; background: #fff; font-weight: 700; color: var(--marine); text-decoration: none; }
  .commune-vivante--grand .grand-entete button { flex: none; margin-left: auto; font-size: 0.85rem; padding: 0 14px; }
  .commune-vivante--grand .grand-entete span { flex: 1 0 100%; order: 2; font-size: 0.8rem; }
  .commune-vivante--grand .commune-vivante__commandes, .commune-vivante--grand .invitation { display: none; }
  .commune-vivante--grand .commune { display: block; width: 880px; max-width: none; margin: 0 16px; }
  .commune-vivante--grand .place.ouverte { z-index: 5; }
  .commune-vivante--grand .place.ouverte .bulle { opacity: 1; visibility: visible; pointer-events: auto; }
  .commune-vivante--grand .bulle__lien { display: block; margin-top: 6px; color: var(--sarcelle-texte); font-weight: 700; }
}
