/* ============================================================
   Municipio — Design system « Solaire » (pages citoyennes)
   Bento vif · corail solaire · Urbanist · ton chaleureux
   Forme unifiée le 2026-08-03 (lot 2) : rayons courts, ombres discrètes.
   Mêmes noms de variables/classes que styles.css : les blocs
   extra_css des templates se rethèment automatiquement.
   NE PAS charger sur les pages admin (elles gardent styles.css).
   ============================================================ */

/* Les VALEURS vivent dans outils/tokens.json et arrivent par tokens.css,
   chargé juste avant ce fichier. Ici ne restent que les renvois : alias
   rétro-compat des anciens noms, et dégradés, qui sont des compositions de
   couleurs et non des tokens. */
:root {
  --navy: var(--ink);
  --navy2: var(--ink-soft);
  --accent2: var(--primary);
  --text: var(--ink);
  --text-muted: var(--muted);
  --orange: var(--coral);
  --purple: var(--violet);
  --teal: var(--accent);
  --card: var(--surface);
  --card-border: var(--line);

  --grad-primary: linear-gradient(160deg, #D13C1B 0%, #B8320C 100%);
  /* Seul dégradé bâti sur des tokens, et pour une raison : l'app le repeint de
     son côté (grand titre de l'accueil, `accueil_screen.dart`). Ses deux
     extrémités devaient donc exister dans la source commune — c'est fait au
     lot 5, après qu'on a découvert que l'app partait du corail vif #FF5C39 et
     le site de #DE4A26. Les quatre autres n'ont pas d'équivalent côté app et
     leurs teintes sombres n'ont pas de token : les tokeniser à moitié serait
     plus trompeur que de les laisser lisibles. */
  --grad-text:    linear-gradient(90deg, var(--grad-text-de) 0%, var(--violet) 100%);
  --grad-cyan:    linear-gradient(135deg, #4D96D9 0%, #1D6FBF 100%);
  --grad-emerald: linear-gradient(135deg, #0B855C 0%, #075A38 100%);
  --grad-amber:   linear-gradient(135deg, #B45309 0%, #8F4906 100%);
  --grad-violet:  linear-gradient(135deg, #A78BFA 0%, #7C3AED 100%);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }

body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--ink);
  min-height: 100vh;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, .display {
  font-family: var(--font-display);
  color: var(--ink);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-weight: 800;
}

a { color: var(--primary-700); text-decoration: none; }
::selection { background: var(--primary-100); color: var(--ink); }
:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-sm); }

/* ---------- Accessibilité : lien d'évitement (RGAA 12.7) ---------- */
.skip-link {
  position: absolute; left: 8px; top: -80px; z-index: 2000;
  background: var(--primary-700); color: #fff;
  padding: var(--esp-3) var(--esp-4); border-radius: var(--radius-sm); font-weight: 700; font-size: 14px;
  text-decoration: none; box-shadow: var(--shadow); transition: top var(--duree-courte) var(--courbe-entree);
}
.skip-link:focus { top: 8px; color: #fff; outline: none; box-shadow: var(--ring); }

/* ---------- Layout helpers ---------- */
.wrap { width: 100%; max-width: 1120px; margin: 0 auto; padding: 0 22px; }
.wrap-narrow { width: 100%; max-width: 560px; margin: 0 auto; padding: 0 22px; }
.stack > * + * { margin-top: 16px; }
.center { text-align: center; }

/* Texte en dégradé (mot accentué des h1) */
.grad-text, .hl {
  background: var(--grad-text);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ---------- Top bar ---------- */
.appbar {
  position: sticky; top: 0; z-index: 50;
  background: rgba(250,250,247,0.85);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
  transition: box-shadow var(--duree) var(--courbe-entree);
}
.appbar.scrolled { box-shadow: var(--shadow); }
.appbar-inner { height: 70px; display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.brand { display: inline-flex; align-items: center; gap: 12px; }
.brand-logo {
  width: 44px; height: 44px; border-radius: var(--radius);
  display: grid; place-items: center;
  background: var(--grad-primary);
  color: #fff; font-size: 20px;
  box-shadow: var(--shadow);
}
.brand-name { font-family: var(--font-display); font-weight: 800; font-size: 21px; letter-spacing: -0.03em; color: var(--ink); }
.brand-name b { color: var(--primary); }

/* ---------- Pastille (composant partagé) ----------
   Un des trois composants sur lesquels s'appuient les chantiers « liste
   d'événements » et « animations ». Sa forme vient des tokens : ne pas
   redéfinir de pastille locale dans un extra_css. */
.pill, .commune-badge {
  display: inline-flex; align-items: center; gap: var(--esp-2);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-pilule);
  padding: var(--esp-2) var(--esp-4); font-size: 13px; font-weight: 600;
  box-shadow: var(--shadow-sm);
}
.pill.is-green  { color: var(--green-encre); }
.pill.is-violet { color: var(--violet-encre); }
.pill.is-yellow { color: var(--yellow-encre); }
.pill.is-cyan   { color: var(--accent-encre); }
.pill-dot, .commune-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--primary);
}
@keyframes pulse { 0%,100%{opacity:1; transform: scale(1)} 50%{opacity:.5; transform: scale(.82)} }

/* Sonar du point de commune (recoloré corail) */
.commune-dot { position: relative; }
.commune-dot::before, .commune-dot::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  border: 2px solid rgba(209,60,27,0.45);
  animation: sonar 2.2s cubic-bezier(.16,1,.3,1) infinite;
}
.commune-dot::after { animation-delay: 1.1s; }
@keyframes sonar { 0% { transform: scale(1); opacity: .9; } 100% { transform: scale(3.6); opacity: 0; } }

/* ---------- Carte (composant partagé) ----------
   LE conteneur des pages citoyennes. Les gabarits qui définissent leur propre
   carte dans un extra_css doivent en reprendre la forme par les tokens, jamais
   par des valeurs littérales : c'est ce que vérifie
   listings/tests_design_system.GabaritsCitoyensTest. */
.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  border-radius: var(--radius); padding: var(--esp-6);
}
.panel-soft { box-shadow: var(--shadow-sm); }
.panel-header { margin-bottom: var(--esp-5); }
.panel h1 { font-size: 30px; margin-bottom: 6px; }
.card-subtitle { font-size: 14.5px; color: var(--muted); }

/* ---------- Boutons (pilules) ---------- */
.cbtn, .submit-btn, .btn-signaler {
  --btn-grad: var(--grad-primary); --btn-fg: #fff; --btn-glow: rgba(209,60,27,0.38);
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--esp-3);
  font-family: var(--font-display); font-weight: 700; font-size: 16px;
  line-height: 1; cursor: pointer; border: none;
  border-radius: var(--radius-pilule); padding: var(--esp-4) var(--esp-6);
  background: var(--btn-grad); color: var(--btn-fg);
  box-shadow: 0 12px 26px -8px var(--btn-glow);
  transition: transform var(--duree) var(--courbe-entree),
              box-shadow var(--duree) ease, filter var(--duree) ease;
  text-decoration: none;
}
.cbtn:hover, .submit-btn:hover, .btn-signaler:hover { transform: translateY(-2px); box-shadow: 0 18px 34px -8px var(--btn-glow); filter: saturate(1.06); }
.cbtn:active, .submit-btn:active, .btn-signaler:active { transform: translateY(0); }
.cbtn-block, .submit-btn { width: 100%; }
.cbtn-lg { padding: 19px 36px; font-size: 17px; }
.cbtn-green  { --btn-grad: var(--grad-emerald); --btn-glow: rgba(11,133,92,0.38); }
.cbtn-violet { --btn-grad: var(--grad-violet);  --btn-glow: rgba(124,58,237,0.38); }
.cbtn-cyan   { --btn-grad: var(--grad-cyan);    --btn-glow: rgba(29,111,191,0.38); }
.cbtn-dark   { --btn-grad: linear-gradient(135deg, #2A2A28, #141414); --btn-glow: rgba(20,20,20,0.30); }
.cbtn-ghost  { background: var(--surface); color: var(--ink); border: 1px solid var(--line); box-shadow: var(--shadow-sm); }
.cbtn-ghost:hover { background: var(--surface-2); box-shadow: var(--shadow-sm); }
.cbtn-soft   { background: var(--primary-50); color: var(--primary-700); border: 1px solid var(--primary-100); box-shadow: none; }
.cbtn-soft:hover { background: var(--primary-100); box-shadow: none; }

/* Lien « Espace mairie » (pilule noire) */
.admin-link {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--ink); color: #fff;
  border-radius: 999px; padding: 10px 18px;
  font-size: 13px; font-weight: 600; text-decoration: none; box-shadow: var(--shadow-sm);
  transition: transform var(--duree) var(--courbe-entree), box-shadow var(--duree) var(--courbe-entree);
}
.admin-link:hover { transform: translateY(-1px); color: #fff; box-shadow: var(--shadow); }

/* ---------- Barre de compte (partiel _barre_compte.html) ----------
   Composant partagé par toutes les pages citoyen : cloche de notifications,
   accès à l'espace mairie et menu du compte. Le z-index est nécessaire : sans
   lui, un .reveal voisin (qui crée un contexte d'empilement par son animation)
   se peint par-dessus le panneau déroulant et en intercepte les clics. */
/* `flex-wrap: wrap` : sans lui, la pastille de commune et `.top-actions` (cloche
   + « Espace mairie » + menu de compte) totalisent plus que la largeur
   disponible et ne peuvent pas rétrécir sous leur contenu — `.top-actions`
   dépassait alors de 15 px à DROITE de l'écran, entraînant la page (405 px sur
   390, mesuré le 2026-08-21). Le menu de compte, suspecté d'abord, n'y était
   pour rien : il est seulement positionné sur un parent déjà sorti de l'écran.
   Sur écran étroit les actions passent donc à la ligne. */
.top-bar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 30px; position: relative; z-index: 20; }
/* Les liens « ← Retour » des pages internes portent leur propre margin-bottom,
   qui décentrerait la ligne une fois posé dans la barre. */
.top-bar > a { margin-bottom: 0; }
.top-actions { display: flex; align-items: center; gap: 10px; }

.notif-bell {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-soft);
  text-decoration: none; font-size: 16px; box-shadow: var(--shadow-sm); transition: all var(--duree);
}
.notif-bell:hover { border-color: var(--primary); color: var(--primary-700); transform: translateY(-1px); }
.notif-bell .pastille {
  position: absolute; top: -4px; right: -4px; min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: 999px; background: var(--grad-primary); color: #fff;
  font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-sm);
}

.account-menu { position: relative; }
.account-menu > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px;
  height: 42px; padding: 0 14px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink);
  font-weight: 700; font-size: 13px; box-shadow: var(--shadow-sm);
}
.account-menu > summary::-webkit-details-marker { display: none; }
.account-menu > summary:hover { border-color: var(--primary); }
.account-menu .chev { font-size: 11px; color: var(--muted); transition: transform var(--duree); }
.account-menu[open] .chev { transform: rotate(180deg); }
.account-panel {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 240px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: 8px; z-index: 100;
}
/* En-tête du panneau : lien vers « Mon compte ». */
.account-head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border-radius: var(--radius-sm);
  text-decoration: none; color: inherit;
}
.account-head:hover { background: var(--surface-2); }
.account-head-corps { min-width: 0; display: flex; flex-direction: column; gap: 2px; flex: 1; }
.account-head strong { font-size: 14px; color: var(--ink); }
.account-head span { font-size: 12px; color: var(--muted); word-break: break-all; }
.account-head .chev-droite { font-size: 12px; color: var(--muted); flex: 0 0 auto; }
.account-sep { height: 1px; background: var(--line); margin: 6px 4px; border: none; }
.account-logout {
  width: 100%; text-align: left; display: flex; align-items: center; gap: 10px;
  padding: 9px 10px; border: none; border-radius: var(--radius-sm);
  background: none; color: var(--ink); font-size: 13px; font-weight: 600; cursor: pointer;
}
.account-logout:hover { background: var(--surface-2); }

/* ---------- Formulaires ---------- */
.form-group, .input-group { margin-bottom: 18px; }
.form-label, .input-label {
  display: block; font-size: 13px; font-weight: 700; color: var(--ink-soft);
  letter-spacing: 0.01em; margin-bottom: 8px;
}
.input-wrap { position: relative; }
.input-icon { position: absolute; left: 16px; top: 50%; transform: translateY(-50%); font-size: 16px; color: var(--muted); transition: color var(--duree); }
.has-icon:focus-within .input-icon { color: var(--primary); }
.form-input, textarea.form-input, select.form-input {
  width: 100%; background: var(--surface); border: 1.5px solid var(--line);
  border-radius: var(--radius-sm); padding: 15px 16px; color: var(--ink);
  font-family: var(--font-body); font-size: 15px; outline: none; resize: none;
  transition: border-color var(--duree), box-shadow var(--duree);
}
.has-icon .form-input { padding-left: 46px; }
.form-input::placeholder { color: var(--muted); opacity: .8; }
.form-input:focus { border-color: var(--primary); box-shadow: var(--ring); }
.form-input.password { letter-spacing: 3px; }
.form-input.password::placeholder { letter-spacing: 0; }

/* Floating labels (repris de Civic 2025, recolorés par les variables) */
.float-group { position: relative; margin-bottom: 22px; }
.float-group .form-input { padding-top: 22px; padding-bottom: 8px; }
.float-group .form-label, .float-group .input-label {
  position: absolute; left: 16px; top: 16px; margin: 0;
  font-size: 15px; font-weight: 500; color: var(--muted); pointer-events: none;
  transform-origin: left top;
  transition: transform var(--duree) var(--courbe-entree), color var(--duree) var(--courbe-entree);
}
.float-group.has-icon .form-label, .float-group.has-icon .input-label { left: 46px; }
.float-group .form-input:focus ~ .form-label,
.float-group .form-input:not(:placeholder-shown) ~ .form-label,
.float-group .form-input:focus ~ .input-label,
.float-group .form-input:not(:placeholder-shown) ~ .input-label {
  transform: translateY(-11px) scale(0.78);
  color: var(--primary); font-weight: 700;
}
.float-group textarea.form-input { padding-top: 26px; }
.float-group textarea.form-input ~ .form-label { top: 18px; }

/* ---------- Notices / erreurs ---------- */
.notice, .erreur, .acces-refuse {
  display: flex; align-items: center; gap: 10px; border-radius: var(--radius-sm);
  padding: 14px 16px; font-size: 14px; font-weight: 500; margin-bottom: 18px;
}
.notice-error, .erreur, .acces-refuse { background: var(--red-50); border: 1px solid #F5C2C2; color: var(--red); }
.notice-success { background: var(--green-50); border: 1px solid #A7F3D0; color: var(--green-encre); }
.notice-info { background: var(--accent-50); border: 1px solid #BFDCF5; color: var(--accent-encre); }
.notice-warning { background: var(--yellow-50); border: 1px solid var(--yellow); color: var(--yellow-encre); }

/* ---------- Bento (accueil commune) ---------- */
.bt {
  position: relative;
  border-radius: var(--radius); padding: 20px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  font-weight: 700; font-size: 15.5px; line-height: 1.3;
  text-decoration: none; color: inherit;
  transition: transform var(--duree) var(--courbe-entree), box-shadow var(--duree) var(--courbe-entree);
}
.bt:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.bt-pastille {
  position: absolute; top: 14px; right: 14px; min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: 999px; background: var(--grad-primary); color: #fff;
  font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-sm);
}
.bt-titre {
  display: block; width: 100%; overflow: hidden;
  white-space: nowrap; text-overflow: ellipsis;
}
/* Pas d'opacité ici : elle ne se calcule pas, donc aucun test ne peut la juger,
   et à .82 le sous-titre tombait sous AA sur les fonds les plus soutenus. Le
   sous-titre hérite de l'encre du service, dont le contraste sur le fond est
   garanti par tests_palette_service. La hiérarchie avec le titre tient à la
   taille et à la graisse, pas à un affaiblissement de la couleur. */
.bt small { display: block; min-height: 2.6em; font-weight: 400; font-size: 12.5px; }
.bt .ic {
  width: 42px; height: 42px; border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; margin-bottom: 12px;
}
/* ---------- Le thème de service d'une PAGE ----------
   Une page qui appartient à un service déclare `{% block service %}<nom>{% endblock %}`
   dans son gabarit ; `base_citoyen.html` en fait une classe sur <body>, et ces règles
   y branchent trois alias. Le CSS de la page n'écrit alors plus aucun nom de couleur :
   il consomme --service-fond, --service-accent et --service-encre. Ajouter un service
   plus tard, c'est une ligne ici et une dans son gabarit.

   ⚠️ Les deux rôles ne sont PAS interchangeables, et c'est une contrainte
   d'accessibilité, pas de goût :
   - --service-accent porte des GLYPHES (carré d'icône) → seuil WCAG 3:1, vérifié au lot 1.
     Il est trop clair pour du texte sur deux services : blanc sur l'accent de Rendez-vous
     tombe à 3,15 et sur celui de Carte à 3,03.
   - --service-encre porte du TEXTE, et sert de fond aux boutons à libellé blanc
     → seuil 4,5:1, respecté par les neuf services (5,54 au plus juste).
   Un test refuse l'inverse. */
.svc-rendezvous       { --service-fond: var(--svc-rendezvous-fond);       --service-accent: var(--svc-rendezvous-accent);       --service-encre: var(--svc-rendezvous-encre); }
.svc-carte            { --service-fond: var(--svc-carte-fond);            --service-accent: var(--svc-carte-accent);            --service-encre: var(--svc-carte-encre); }
.svc-dates            { --service-fond: var(--svc-dates-fond);            --service-accent: var(--svc-dates-accent);            --service-encre: var(--svc-dates-encre); }
.svc-consultations    { --service-fond: var(--svc-consultations-fond);    --service-accent: var(--svc-consultations-accent);    --service-encre: var(--svc-consultations-encre); }
.svc-idees            { --service-fond: var(--svc-idees-fond);            --service-accent: var(--svc-idees-accent);            --service-encre: var(--svc-idees-encre); }
.svc-petites-annonces { --service-fond: var(--svc-petites-annonces-fond); --service-accent: var(--svc-petites-annonces-accent); --service-encre: var(--svc-petites-annonces-encre); }
.svc-messages         { --service-fond: var(--svc-messages-fond);         --service-accent: var(--svc-messages-accent);         --service-encre: var(--svc-messages-encre); }
.svc-annonces         { --service-fond: var(--svc-annonces-fond);         --service-accent: var(--svc-annonces-accent);         --service-encre: var(--svc-annonces-encre); }
.svc-mes-signalements { --service-fond: var(--svc-mes-signalements-fond); --service-accent: var(--svc-mes-signalements-accent); --service-encre: var(--svc-mes-signalements-encre); }
/* « Signaler » est un dégradé : son fond ne se réduit pas à une valeur, on prend sa
   borne sombre pour le texte et les boutons. */
.svc-signaler         { --service-fond: var(--svc-signaler-de);           --service-accent: var(--svc-signaler-a);              --service-encre: var(--svc-signaler-a); }
/* Les pages qui n'appartiennent à aucun service (compte, mentions légales…) gardent
   le design system commun : les alias retombent sur les couleurs de marque. */
.svc-neutre           { --service-fond: var(--primary-50);                --service-accent: var(--primary);                     --service-encre: var(--primary-700); }

/* ---------- Une couleur par SERVICE, jamais par usage ----------
   Ces classes portaient un nom de couleur (« bt-carte », « bt-neutre ») et
   finissaient partagées : « bt-carte » servait la Carte ET les Petites
   annonces, « bt-neutre » quatre services d'un coup. Un nom de service rend
   la collision impossible à réintroduire sans s'en apercevoir.
   Les valeurs vivent dans outils/tokens.json ; tests_palette_service refuse
   toute palette dont deux fonds se confondent. */
.bt-svc-signaler { background: linear-gradient(135deg, var(--svc-signaler-de), var(--svc-signaler-a)); color: #fff; }
.bt-svc-signaler .ic { background: rgba(255,255,255,0.24); color: #fff; }

.bt-svc-rendezvous        { background: var(--svc-rendezvous-fond);        color: var(--svc-rendezvous-encre); }
.bt-svc-rendezvous .ic    { background: var(--svc-rendezvous-accent);      color: #fff; }
.bt-svc-carte             { background: var(--svc-carte-fond);             color: var(--svc-carte-encre); }
.bt-svc-carte .ic         { background: var(--svc-carte-accent);           color: #fff; }
.bt-svc-dates             { background: var(--svc-dates-fond);             color: var(--svc-dates-encre); }
.bt-svc-dates .ic         { background: var(--svc-dates-accent);           color: #fff; }
.bt-svc-consultations     { background: var(--svc-consultations-fond);     color: var(--svc-consultations-encre); }
.bt-svc-consultations .ic { background: var(--svc-consultations-accent);   color: #fff; }
.bt-svc-idees             { background: var(--svc-idees-fond);             color: var(--svc-idees-encre); }
.bt-svc-idees .ic         { background: var(--svc-idees-accent);           color: #fff; }
.bt-svc-petites-annonces     { background: var(--svc-petites-annonces-fond);   color: var(--svc-petites-annonces-encre); }
.bt-svc-petites-annonces .ic { background: var(--svc-petites-annonces-accent); color: #fff; }
.bt-svc-messages          { background: var(--svc-messages-fond);          color: var(--svc-messages-encre); }
.bt-svc-messages .ic      { background: var(--svc-messages-accent);        color: #fff; }
.bt-svc-annonces          { background: var(--svc-annonces-fond);          color: var(--svc-annonces-encre); }
.bt-svc-annonces .ic      { background: var(--svc-annonces-accent);        color: #fff; }
.bt-svc-mes-signalements     { background: var(--svc-mes-signalements-fond);   color: var(--svc-mes-signalements-encre); }
.bt-svc-mes-signalements .ic { background: var(--svc-mes-signalements-accent); color: #fff; }

/* ---------- L'encart blanc d'une tuile ----------
   Il dit ce que le service a de neuf (« 2 sondages ouverts »). Le libellé
   arrive tout écrit du serveur — voir services_accueil._encarts — pour que le
   site et l'app affichent la même phrase, accordée une seule fois.

   Le texte y prend l'encre du SERVICE, jamais celle du fond de tuile : c'est
   une seconde surface, et tests_palette_service vérifie que chaque encre passe
   4,5:1 sur ce blanc. Trois services n'ont pas d'encart — rendez-vous,
   messages et mes-signalements — parce que leur valeur est déjà dans la bande
   « Mon activité », au-dessus des tuiles. */
.bt-encart {
  margin-top: 10px; align-self: stretch;
  border-radius: var(--radius-sm); padding: 8px 11px;
  background: var(--surface);
  font-size: 12.5px; font-weight: 700; line-height: 1.25;
}
.bt-svc-carte .bt-encart            { color: var(--svc-carte-encre); }
.bt-svc-annonces .bt-encart         { color: var(--svc-annonces-encre); }
.bt-svc-dates .bt-encart            { color: var(--svc-dates-encre); }
.bt-svc-consultations .bt-encart    { color: var(--svc-consultations-encre); }
.bt-svc-idees .bt-encart            { color: var(--svc-idees-encre); }
.bt-svc-petites-annonces .bt-encart { color: var(--svc-petites-annonces-encre); }

/* « Participation citoyenne » n'est pas un service : c'est l'invitation à
   créer un compte, visible seulement hors connexion. Elle garde donc un
   traitement neutre, et surtout sa propre classe — sans elle, elle hériterait
   d'une classe supprimée et perdrait tout style en silence. */
.bt-svc-invitation { background: var(--surface); border: 1px solid var(--line); color: var(--ink); box-shadow: var(--shadow-sm); }
.bt-svc-invitation .ic { background: var(--primary-50); color: var(--primary-700); }

.bento { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
@media (max-width: 760px) { .bento { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .bento { grid-template-columns: 1fr; } }

/* ---------- Tuiles génériques (autres pages : restylées à plat) ---------- */
.tiles { display: grid; gap: 16px; }
@media (min-width: 720px) { .tiles-3 { grid-template-columns: repeat(3, 1fr); } .tiles-2 { grid-template-columns: repeat(2, 1fr); } }
.tile {
  display: flex; flex-direction: column; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px; box-shadow: var(--shadow-sm); text-decoration: none; color: var(--ink);
  transition: transform var(--duree) var(--courbe-entree), box-shadow var(--duree) var(--courbe-entree);
}
.tile:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.tile-ico {
  width: 46px; height: 46px; border-radius: var(--radius); display: grid; place-items: center;
  font-size: 20px; color: #fff;
}
.tile h3 { font-size: 18px; font-weight: 800; }
.tile p { font-size: 14px; color: var(--muted); }
.tile .go { margin-top: auto; font-weight: 700; font-size: 14px; color: var(--primary-700); display: inline-flex; gap: 4px; }
.tile:hover .go { transform: translateX(3px); }
.tile-blue   .tile-ico { background: var(--grad-primary); }
.tile-green  .tile-ico { background: var(--grad-emerald); }
.tile-violet .tile-ico { background: var(--grad-violet); }
.tile-yellow .tile-ico { background: var(--grad-amber); }
.tile-cyan   .tile-ico { background: var(--grad-cyan); }

/* ---------- Hero ---------- */
.hero { padding: 50px 0 30px; position: relative; }
.hero h1 { font-size: clamp(36px, 6.4vw, 56px); }
.hero .lead, .hero .subtitle { font-size: 17px; color: var(--muted); margin-top: 14px; max-width: 540px; }
/* Plus de blobs flottants dans Solaire */
.hero-blob { display: none; }
.hero-badge {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 18px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
  padding: 7px 14px; font-size: 12.5px; font-weight: 700; color: var(--ink-soft);
  box-shadow: var(--shadow-sm);
}

/* ---------- Footer ---------- */
.footer { text-align: center; padding: 30px 0; margin-top: 36px; font-size: 13px; color: var(--muted); }
.footer strong { color: var(--primary); }

/* ---------- Auth layout (fond ivoire, halos corail très doux) ----------
   Colonne, et non plus une simple boîte centrée : depuis le 2026-09-09 la
   dernière ligne de la page est l'illustration du bourg
   (`_illustration_bourg.html`), qui doit se poser au bas de l'écran sans
   jamais chevaucher le contenu. Le bloc reste centré dans la place qui
   reste — `flex: 1` sur `.auth-wrap` —, et sur une page longue (inscription)
   tout scrolle normalement, l'illustration restant à la fin du flux.
   Ne pas remplacer par un `position: fixed` : c'est ce que faisait la
   maquette, et le pied de page passait dessous dès que la page dépassait
   la hauteur de l'écran. */
.auth-body {
  display: flex; flex-direction: column; align-items: center;
  padding: 32px 0 0;
  position: relative; overflow-x: hidden;
}
.auth-body::before {
  content: ''; position: fixed; inset: -20%; z-index: -1;
  background:
    radial-gradient(closest-side at 80% 15%, rgba(255,122,89,0.16), transparent),
    radial-gradient(closest-side at 15% 85%, rgba(124,58,237,0.10), transparent);
  filter: blur(40px);
}
.auth-wrap {
  width: 100%; max-width: 460px; padding: 0 22px;
  flex: 1 0 auto; display: flex; flex-direction: column; justify-content: center;
  animation: fadeUp var(--duree-longue) var(--courbe-entree) both;
}

/* ---------- Le bourg (illustration des pages d'authentification) ----------
   Le dessin lui-même vit dans `_illustration_bourg.html`, avec ses trois
   décisions commentées. Ici, seulement sa place dans la page.
   La hauteur suit la largeur : sur un téléphone, `slice` recadre sur la
   mairie plutôt que de réduire tout le village à une frise illisible. */
.bourg-bande { position: relative; width: 100%; flex: none; line-height: 0; }
/* ⚠️ Cette hauteur n'est pas un réglage esthétique, c'est une CONTRAINTE.
   Le SVG est en `preserveAspectRatio="xMidYMax slice"` : il couvre la boîte et
   rogne ce qui dépasse. Le facteur d'échelle vaut `max(largeur/1280,
   hauteur/250)`. Tant que la hauteur reste sous **largeur × 250/1280**, c'est
   la largeur qui commande, la scène est agrandie, et le rognage se fait par le
   HAUT — donc sur le toit de la mairie. Mesuré le 2026-09-09 en 1440×900 avec
   une hauteur bornée à 198 px : il ne restait du bâtiment qu'une barre rouge.

   `max(19.6vw, 150px)` garantit l'inverse (19,6 % ≈ 250/1280) : la hauteur
   commande toujours, rien n'est rogné verticalement, et sur un téléphone le
   surplus est retiré sur les CÔTÉS — ce qui recadre sur la mairie au lieu de
   réduire le village à une frise de 76 px.

   Conséquence assumée : sur un écran large la bande est haute (376 px en
   1920). Ne pas « corriger » par un `max-height`, ce serait revenir au toit
   coupé. */
.bourg-dessin { display: block; width: 100%; height: max(19.6vw, 150px); }
/* Le pied de page des pages d'authentification portait 96 px de blanc avant
   lui (36 de marge + 30 de padding haut et bas), hérité du `.footer` général.
   Sur une page qui tient désormais un décor en bas, c'est ce blanc-là qui
   faisait défiler l'écran, pas l'illustration. */
.auth-body .footer {
  width: 100%; margin-top: var(--esp-5); padding: var(--esp-4) 0 var(--esp-5);
  order: 2;
}
.bourg-bande { order: 3; }

/* ⚠️ La permutation n'est pas cosmétique : elle décide si le dessin est vu.
   Sur un grand écran, le village se pose tout en bas, sous les liens légaux.
   Sur un téléphone, l'ordre du flux le renvoyait à 766 px du haut — derrière
   138 px de mentions légales — alors qu'un navigateur mobile n'offre qu'environ
   660 px utiles : la mairie n'apparaissait qu'en défilant. Mesuré le
   2026-09-10 sur signalement d'Antoine.
   On permute plutôt que de rogner : aucune hauteur de carte, de champ ou de
   pied de page n'a été réduite pour gagner cette place. */
@media (max-width: 700px) {
  .bourg-bande { order: 2; }
  .auth-body .footer { order: 3; margin-top: var(--esp-4); }

  /* Densité des pages d'authentification sur téléphone. La permutation seule
     amenait le dessin à 605 px, encore sous la ligne de flottaison d'un
     navigateur mobile serré (~600 px utiles). Ces réglages en récupèrent une
     centaine — tous portés par `.auth-body`, donc sans toucher aux autres
     pages citoyennes. */
  .auth-body { padding-top: var(--esp-4); }
  .auth-body .auth-head { margin-bottom: 18px; }
  .auth-body .panel { padding: 20px; }
  .auth-body .float-group { margin-bottom: 16px; }
  /* L'icône du titre est purement décorative (`aria-hidden`) et faisait passer
     « Content de vous revoir ! » sur deux lignes : 38 px pour un pictogramme
     que le texte à côté rend déjà. */
  .auth-body .panel h1 .fa-solid { display: none; }
  .auth-body .panel h1 { font-size: 26px; }
  .auth-body .panel-header { margin-bottom: var(--esp-4); }
}
.bourg-voile {
  position: absolute; left: 0; right: 0; bottom: 100%; height: 110px;
  background: linear-gradient(to top, var(--bg), transparent);
  pointer-events: none;
}
.auth-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 26px; }
.lien-retour-haut, .retour { font-size: 13.5px; color: var(--muted); text-decoration: none; font-weight: 600; transition: color var(--duree-courte); }
.retour { display: block; text-align: center; margin-top: 18px; }
.lien-retour-haut:hover, .retour:hover { color: var(--primary-700); }

/* ---------- Tables (au cas où une page citoyenne en garde une) ---------- */
.table-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-sm); overflow: hidden; }
table.data { width: 100%; border-collapse: collapse; font-size: 14px; }
table.data th { text-align: left; padding: 15px 16px; background: var(--surface-2); color: var(--ink-soft); font-weight: 700; font-size: 12.5px; border-bottom: 1px solid var(--line); white-space: nowrap; }
table.data td { padding: 15px 16px; border-bottom: 1px solid var(--line-soft); color: var(--ink-soft); vertical-align: middle; }
table.data tr:last-child td { border-bottom: none; }
table.data tr:hover td { background: var(--primary-50); }

/* ---------- Chips / statuts ---------- */
.chip { display: inline-flex; align-items: center; gap: 7px; padding: 5px 12px; border-radius: 999px; font-size: 12px; font-weight: 700; }
.chip::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.chip-pulse::before { animation: pulse 1.8s infinite; }
.chip-blue { background: var(--primary-50); color: var(--primary-700); }
.chip-cyan { background: var(--accent-50); color: var(--accent-encre); }
.chip-green { background: var(--green-50); color: var(--green-encre); }
.chip-yellow { background: var(--yellow-50); color: var(--yellow-encre); }
.chip-red { background: var(--red-50); color: var(--red); }
.chip-violet { background: var(--violet-50); color: var(--violet-encre); }
.chip-gray { background: #EFEDE8; color: var(--muted); }

/* ---------- Animations ---------- */
@keyframes fadeUp { from { opacity:0; transform: translateY(18px);} to { opacity:1; transform: translateY(0);} }
.reveal { animation: fadeUp var(--duree-longue) var(--courbe-entree) both; }
.reveal-2 { animation-delay: .08s; }
.reveal-3 { animation-delay: .16s; }
.reveal-4 { animation-delay: .24s; }
.reveal-5 { animation-delay: .32s; }

/* ---------- View Transitions ---------- */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: var(--duree) var(--courbe-entree) both vt-fade-out; }
::view-transition-new(root) { animation: var(--duree-longue) var(--courbe-entree) both vt-slide-in-from-bottom; }
@keyframes vt-slide-in-from-bottom { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: translateY(0); } }
@keyframes vt-fade-out { to { opacity: 0; } }

/* ---------- Scroll reveal (IntersectionObserver, JS de base_citoyen) ---------- */
.reveal-scroll {
  opacity: 0; transform: translateY(24px);
  transition: opacity var(--duree-longue) var(--courbe-entree), transform var(--duree-longue) var(--courbe-entree);
  will-change: opacity, transform;
}
.reveal-scroll.in-view { opacity: 1; transform: none; }
.reveal-scroll:nth-child(1) { transition-delay: 0ms; }
.reveal-scroll:nth-child(2) { transition-delay: 60ms; }
.reveal-scroll:nth-child(3) { transition-delay: 120ms; }
.reveal-scroll:nth-child(4) { transition-delay: 180ms; }
.reveal-scroll:nth-child(5) { transition-delay: 240ms; }
.reveal-scroll:nth-child(6) { transition-delay: 300ms; }
.reveal-scroll:nth-child(7) { transition-delay: 360ms; }
.reveal-scroll:nth-child(8) { transition-delay: 420ms; }

/* ---------- Ripple ---------- */
.ripple {
  position: absolute; border-radius: 50%;
  background: rgba(255,255,255,0.35);
  transform: scale(0);
  animation: ripple-expand var(--duree-longue) linear;
  pointer-events: none; z-index: 2;
}
@keyframes ripple-expand { to { transform: scale(4); opacity: 0; } }
.cbtn-ghost .ripple, .cbtn-soft .ripple { background: rgba(209,60,27,0.16); }

/* ---------- Skeleton (carte) ---------- */
.skeleton {
  position: relative; overflow: hidden; background: var(--surface-2);
  background-image: linear-gradient(100deg, rgba(236,234,228,0) 30%, rgba(255,255,255,0.75) 50%, rgba(236,234,228,0) 70%);
  background-size: 200% 100%; background-repeat: no-repeat;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
#carte-skeleton {
  height: 70vh; min-height: 360px;
  border-radius: var(--radius); border: 1px solid var(--line);
  display: grid; place-items: center;
  color: var(--muted); font-size: 14px; gap: 10px; text-align: center;
}
#carte-skeleton .sk-pin { font-size: 30px; opacity: .5; animation: float 2.4s ease-in-out infinite; }
@keyframes float { 0%,100%{ transform: translateY(0);} 50%{ transform: translateY(-12px);} }

/* ---------- Barre de progression de page ---------- */
#nprogress {
  position: fixed; top: 0; left: 0; right: 0; height: 3px;
  background: var(--grad-primary);
  z-index: 9999; transform-origin: left;
  box-shadow: var(--shadow-sm);
  animation: progress-bar 0.8s cubic-bezier(.16,1,.3,1) forwards;
}
#nprogress.done { animation: progress-done var(--duree-longue) var(--courbe-entree) forwards; }
@keyframes progress-bar { 0% { transform: scaleX(0); } 60% { transform: scaleX(0.7); } 100% { transform: scaleX(0.92); } }
@keyframes progress-done { from { transform: scaleX(0.92); opacity: 1; } to { transform: scaleX(1); opacity: 0; } }

/* ---------- Toasts ---------- */
.toast-stack {
  position: fixed; bottom: 22px; right: 22px;
  display: flex; flex-direction: column; gap: 12px;
  z-index: 10000; max-width: 360px; width: calc(100% - 44px);
  pointer-events: none;
}
.toast {
  pointer-events: auto; position: relative; overflow: hidden;
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 4px solid var(--primary);
  border-radius: var(--radius); padding: var(--esp-4) var(--esp-4) var(--esp-4);
  box-shadow: var(--shadow);
  color: var(--ink-soft); font-size: 14px; line-height: 1.45;
  animation: toast-in var(--duree-longue) var(--courbe-entree) both;
}
.toast.leaving { animation: toast-out var(--duree-longue) var(--courbe-entree) forwards; }
.toast-ico { flex: 0 0 auto; font-size: 17px; margin-top: 1px; color: var(--primary); }
.toast-msg { flex: 1 1 auto; font-weight: 500; }
.toast-close {
  flex: 0 0 auto; background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: 14px; padding: 2px 4px; line-height: 1;
  border-radius: var(--radius-sm); transition: color var(--duree-courte), background var(--duree-courte);
}
.toast-close:hover { color: var(--ink); background: var(--surface-2); }
.toast-bar {
  position: absolute; left: 0; bottom: 0; height: 3px; width: 100%;
  background: var(--primary); transform-origin: left;
  animation: toast-bar 4s linear forwards;
}
.toast.is-success { border-left-color: var(--green); }
.toast.is-success .toast-ico { color: var(--green); }
.toast.is-success .toast-bar { background: var(--green); }
.toast.is-error { border-left-color: var(--red); }
.toast.is-error .toast-ico { color: var(--red); }
.toast.is-error .toast-bar { background: var(--red); }
@keyframes toast-in { from { opacity: 0; transform: translateX(120%) scale(.96); } to { opacity: 1; transform: translateX(0) scale(1); } }
@keyframes toast-out { to { opacity: 0; transform: translateX(120%) scale(.96); } }
@keyframes toast-bar { from { transform: scaleX(1); } to { transform: scaleX(0); } }

/* ---------- Popups Leaflet (carte publique) ---------- */
.leaflet-popup-content-wrapper {
  border-radius: var(--radius); box-shadow: var(--shadow);
  font-family: var(--font-body); color: var(--ink);
}
.leaflet-popup-content { font-size: 13.5px; line-height: 1.5; }
.leaflet-container { font-family: var(--font-body); }

/* ---------- Overrides Bootstrap (pages admin uniquement) ----------
   Les pages citoyennes ne chargent pas Bootstrap : sans effet chez elles. */
.btn-primary {
  --bs-btn-bg: var(--primary);
  --bs-btn-border-color: var(--primary);
  --bs-btn-hover-bg: var(--primary-700);
  --bs-btn-hover-border-color: var(--primary-700);
  --bs-btn-active-bg: var(--primary-700);
  --bs-btn-active-border-color: var(--primary-700);
  /* Le corail de MARQUE (#D13C1B), pas le corail vif retiré au lot 1, qui échoue AA. */
  --bs-btn-focus-shadow-rgb: 209,60,27;
}
.form-control:focus, .form-select:focus {
  border-color: var(--primary);
  /* --ring EST l'indicateur de focus du système (RGAA 10.7). Cette ligne
     portait le corail VIF retiré au lot 1 parce qu'il échoue AA :
     l'anneau de focus des formulaires mairie affichait donc la seule teinte
     que le design system avait bannie. */
  box-shadow: var(--ring);
}

/* ---------- Bouton « Ajouter au calendrier » (_bouton_calendrier.html) ------
   Ici et pas dans un `extra_css` : le partiel sert des pages citoyennes ET
   des pages mairie, et `citoyen.css` est la seule feuille que `base_citoyen`
   et `base_admin` chargent toutes les deux. */
.cal-menu { position: relative; display: inline-block; }
.cal-menu > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center;
  gap: var(--esp-2); padding: 8px 13px; border-radius: var(--radius-pilule);
  background: var(--service-fond); border: 1px solid var(--service-accent);
  color: var(--service-encre); font-weight: 700; font-size: 12.5px;
  white-space: nowrap;
  transition: background var(--duree) var(--courbe-entree),
              border-color var(--duree) var(--courbe-entree);
}
.cal-menu > summary::-webkit-details-marker { display: none; }
.cal-menu > summary:hover { background: var(--service-fond); border-color: var(--service-encre); }
.cal-menu > summary:focus-visible { outline: none; box-shadow: var(--ring); }
.cal-menu-panel {
  position: absolute; top: calc(100% + var(--esp-2)); right: 0;
  min-width: 220px; z-index: 60;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-sm); box-shadow: var(--shadow); padding: var(--esp-2);
}
.cal-menu-panel a {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px;
  border-radius: var(--radius-sm); color: var(--ink);
  text-decoration: none; font-size: 14px; white-space: nowrap;
}
.cal-menu-panel a:hover { background: var(--surface-2); color: var(--service-encre); }
.cal-menu-panel a i { width: 16px; text-align: center; color: var(--muted); }
.cal-menu-panel a:hover i { color: var(--primary-700); }

/* Ce qui ne s'ajoute pas à un agenda : un tiret, pas un bouton grisé. */
.cal-indispo { color: var(--muted); }

/* ---------- Onglets « Rendez-vous » (_onglets_rendezvous.html) -------------
   Le pendant web du `TabBar` de l'application. Ici et pas dans un `extra_css` :
   le partiel est inclus par deux gabarits, `reservation.html` et
   `mes_rendezvous.html`. */
.rdv-onglets {
  display: flex; gap: var(--esp-1);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--esp-5);
}
.rdv-onglet {
  flex: 1 1 auto; text-align: center; white-space: nowrap;
  padding: 11px 14px; text-decoration: none;
  color: var(--muted); font-weight: 700; font-size: 13.5px;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--duree) var(--courbe-entree),
              border-color var(--duree) var(--courbe-entree);
}
.rdv-onglet:hover { color: var(--service-encre); }
.rdv-onglet.actif { color: var(--service-encre); border-bottom-color: var(--service-accent); }
.rdv-onglet:focus-visible { outline: none; box-shadow: var(--ring); }
.rdv-onglet i { margin-right: 6px; }

/* Sous 420 px, l'icône seule ferait deviner l'onglet : on garde le texte et
   on retire l'icône, qui n'apporte rien qu'un libellé ne dise déjà. */
@media (max-width: 420px) {
  .rdv-onglet { font-size: 12.5px; padding: 10px 6px; }
  .rdv-onglet i { display: none; }
}

/* Sur un écran étroit, un panneau ancré à droite d'un bouton lui-même proche
   du bord droit sort de l'écran : on l'ancre à gauche. */
@media (max-width: 560px) {
  .cal-menu-panel { right: auto; left: 0; }
}

/* ---------- Retour d'action de l'espace mairie ---------- */
/* La mairie a son idiome — le bloc .admin-flash en tête de page — et le citoyen
   a le sien, la pile de toasts flottants. On ANIME l'existant au lieu de le
   remplacer : convertir la mairie aux toasts serait un changement d'interface
   que personne n'a demandé, alors que le principe du chantier est de rendre
   perceptible ce qui existe déjà.
   Plafond de l'espace mairie : --duree, jamais --duree-longue. */
.admin-flash-item.is-entrant { animation: flash-in var(--duree) var(--courbe-entree) both; }
.admin-flash-item.is-sortant { animation: flash-out var(--duree) var(--courbe-sortie) forwards; }
@keyframes flash-in  { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@keyframes flash-out { to { opacity: 0; transform: translateY(-8px); } }

/* ---------- Ligne dont on vient de changer le statut ---------- */
/* `:target` suffit : la vue redirige vers #row-<id>, le navigateur amène
   l'agent sur sa ligne ET l'active. ZÉRO JavaScript, donc coupé par le bloc
   prefers-reduced-motion ci-dessous comme tout le reste.

   Seule exception au plafond de 200 ms de l'espace mairie, et elle est
   justifiée : cet événement survient une fois par action, jamais en rafale —
   ce qui est précisément ce que le plafond protège.

   Ce n'est PAS le fondu d'une couleur vers l'autre qu'annonçait le cadrage :
   après un POST + redirect, l'ancienne couleur n'existe plus dans le
   navigateur. Ce serait possible en AJAX seulement. Ici on dit « voici ce qui
   vient de changer », pas « regarde-le changer ». Côté application, où la
   liste est en mémoire, le vrai fondu est possible — c'est le lot 4. */
tr:target { animation: ligne-modifiee var(--duree-longue) var(--courbe-entree) 2 alternate; }
@keyframes ligne-modifiee { to { background: var(--primary-50); } }
tr:target .badge-statut { animation: fadeUp var(--duree) var(--courbe-entree) both; }

/* ---------- Reduced motion ---------- */
/* Les trois formes du sélecteur, et non « * » seul : un sélecteur universel ne
   matche PAS les pseudo-éléments. Sans « *::before, *::after », une animation
   posée sur un ::before continue de tourner chez quelqu'un qui a demandé
   l'arrêt du mouvement — c'est ce qui arrivait à .chip-pulse::before, et ce qui
   arrivait au sonar de .commune-dot avant qu'une ligne dédiée ne le rattrape.
   On bouche à la racine plutôt qu'au cas par cas. Même forme que
   frontend/src/styles/theme.css, qui l'avait déjà juste. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important; transition: none !important; scroll-behavior: auto !important;
  }
  /* Les transitions de vue vivent sur des pseudo-éléments du DOCUMENT : hors de
     portée du sélecteur ci-dessus, et jouées à CHAQUE navigation. base.html
     déclare le <meta name="view-transition"> — le glissement de page complet
     concernait donc aussi l'espace mairie. */
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
  .reveal-scroll { opacity: 1 !important; transform: none !important; }
  #nprogress, .toast-bar { display: none; }
  /* display:none et non animation:none : figer l'anneau du sonar le laisserait
     visible à son état initial, superposé à la pastille. */
  .commune-dot::before, .commune-dot::after { display: none; }
}
