@charset "UTF-8";

/* ==========================================================================
   MaFamille — feuille de style
   Charte « Verger » : fond blanc, une couleur de marque verte reprise du
   logo, cartes à grands arrondis et ombres douces, barre latérale à gauche.
   Structure calquée sur celle de linxia-connect (tableau de bord clair),
   avec le vert du logo à la place du violet.
   Polices système : aucune requête externe, conforme à la CSP stricte.
   ========================================================================== */

/*
 * L'attribut « hidden » doit l'emporter : plusieurs composants posent un
 * display (flex, grid) par leur classe, ce qui sinon les rend visibles alors
 * que le script les avait masqués.
 */
[hidden] { display: none !important; }

/* --------------------------------------------------------------- variables */

:root {
  /* Marque — vert du logo et ses déclinaisons */
  --vert:         #2e7d4f;
  --vert-fonce:   #23603c;
  --vert-clair:   #eaf4ed;
  --vert-bord:    #cfe6d7;

  /* Accents secondaires, pour coder les rubriques et les données */
  --abricot:      #d97b28;
  --abricot-clair:#fdf2e6;
  --bleu:         #b0561f;
  --bleu-clair:   #ecf4f8;
  --prune:        #8d5a8f;

  /* Surfaces */
  --fond:          #f7f9f7;
  --surface:       #ffffff;
  --surface-2:     #f2f6f3;
  --bordure:       #e4ebe6;
  --bordure-forte: #cbd8cf;

  /* Texte — contrastes vérifiés sur --surface */
  --texte:         #16261b;   /* 14.6:1 */
  --texte-doux:    #4d6154;   /* 7.4:1  */
  --texte-tenu:    #6b7d72;   /* 5.1:1  */

  /* Sémantique */
  --succes:        #2e7d4f;
  --succes-fond:   #eaf4ed;
  --erreur:        #a32b22;
  --erreur-fond:   #fbeae8;
  --info:          #b0561f;
  --info-fond:     #ecf4f8;

  /* Rythme typographique */
  --serif:  ui-serif, Georgia, "Iowan Old Style", "Palatino Linotype", Palatino, "Times New Roman", serif;
  --sans:   "Avenir Next", Avenir, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono:   ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Espacement */
  --e1: 0.25rem;
  --e2: 0.5rem;
  --e3: 0.75rem;
  --e4: 1rem;
  --e5: 1.5rem;
  --e6: 2rem;
  --e7: 3rem;
  --e8: 4rem;

  /* Arrondis généreux, comme sur linxia-connect */
  --rayon:    9px;
  --rayon-lg: 16px;
  --rayon-xl: 24px;

  /* Ombres douces et basses, jamais dures */
  --ombre-1: 0 1px 4px rgba(133, 146, 173, .20);
  --ombre-2: 0 2px 10px rgba(133, 146, 173, .22);
  --ombre-3: 0 12px 32px rgba(133, 146, 173, .28);

  --largeur-max: 84rem;
  --largeur-texte: 68ch;
  --largeur-barre: 15rem;

  --transition: 180ms cubic-bezier(0.4, 0, 0.2, 1);

  --z-carte:   10;
  --z-barre:   25;
  --z-entete:  30;
  --z-menu:    40;
  --z-modale:  50;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --fond:          #121714;
    --surface:       #1a211d;
    --surface-2:     #222b26;
    --bordure:       #2e3a33;
    --bordure-forte: #3d4c43;

    --texte:         #e9f0eb;
    --texte-doux:    #b6c6bc;
    --texte-tenu:    #91a698;

    --vert:          #519f6f;
    --vert-fonce:    #8ed0a7;
    --vert-clair:    #1f2f26;
    --vert-bord:     #2f4738;

    --abricot:       #e9a463;
    --abricot-clair: #2e2419;
    --bleu:          #c8783a;
    --bleu-clair:    #1b2831;

    --succes:        #519f6f;
    --succes-fond:   #1f2f26;
    --erreur:        #ef9d92;
    --erreur-fond:   #2f1c1a;
    --info:          #c8783a;
    --info-fond:     #1b2831;

    --ombre-1: 0 1px 4px rgba(0, 0, 0, .35);
    --ombre-2: 0 2px 10px rgba(0, 0, 0, .40);
    --ombre-3: 0 12px 32px rgba(0, 0, 0, .50);
  }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] {
    --fond:          #121714;
    --surface:       #1a211d;
    --surface-2:     #222b26;
    --bordure:       #2e3a33;
    --bordure-forte: #3d4c43;

    --texte:         #e9f0eb;
    --texte-doux:    #b6c6bc;
    --texte-tenu:    #91a698;

    --vert:          #519f6f;
    --vert-fonce:    #8ed0a7;
    --vert-clair:    #1f2f26;
    --vert-bord:     #2f4738;

    --abricot:       #e9a463;
    --abricot-clair: #2e2419;
    --bleu:          #c8783a;
    --bleu-clair:    #1b2831;

    --succes:        #519f6f;
    --succes-fond:   #1f2f26;
    --erreur:        #ef9d92;
    --erreur-fond:   #2f1c1a;
    --info:          #c8783a;
    --info-fond:     #1b2831;

    --ombre-1: 0 1px 4px rgba(0, 0, 0, .35);
    --ombre-2: 0 2px 10px rgba(0, 0, 0, .40);
    --ombre-3: 0 12px 32px rgba(0, 0, 0, .50);
  }


/* ------------------------------------------------------------------ socle */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  /* 17px : au-dessus du minimum de 16px sur mobile */
  font: 400 1.0625rem/1.6 var(--sans);
  color: var(--texte);
  background: var(--fond);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.25;
  color: var(--texte);
  margin: 0 0 var(--e3);
  text-wrap: balance;
}

h1 { font-size: clamp(1.75rem, 1.3rem + 2vw, 2.5rem); }
h2 { font-size: clamp(1.375rem, 1.15rem + 1vw, 1.75rem); }
h3 { font-size: 1.1875rem; }
h4 { font-size: 1.0625rem; }

p { margin: 0 0 var(--e4); max-width: var(--largeur-texte); }

a {
  color: var(--vert-fonce);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: color var(--transition);
}

a:hover { color: var(--vert); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) a { color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] a { color: var(--vert); }


/* Anneau de focus visible partout : jamais outline:none sans remplacement. */
:focus-visible {
  outline: 3px solid var(--vert);
  outline-offset: 2px;
  border-radius: 3px;
}

img { max-width: 100%; height: auto; display: block; }

hr {
  border: 0;
  border-top: 1px solid var(--bordure);
  margin: var(--e6) 0;
}

/* Lien d'évitement pour la navigation au clavier */
.saut-contenu {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--vert);
  color: #fff;
  padding: var(--e3) var(--e4);
  z-index: var(--z-modale);
  border-radius: 0 0 var(--rayon) 0;
}

.saut-contenu:focus {
  left: 0;
}

.visuellement-cache {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------- disposition */

.conteneur {
  width: 100%;
  max-width: var(--largeur-max);
  margin-inline: auto;
  padding-inline: var(--e4);
}

@media (min-width: 48rem) {
  .conteneur { padding-inline: var(--e5); }
}

.page { padding-block: var(--e5) var(--e8); }

.grille {
  display: grid;
  gap: var(--e5);
}

/* Grille éditoriale asymétrique : contenu principal + colonne latérale */
@media (min-width: 62rem) {
  .grille--editoriale {
    grid-template-columns: minmax(0, 2.2fr) minmax(16rem, 1fr);
    align-items: start;
  }
}

.grille--auto {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}

.grille--trois,
.grille--deux {
  grid-template-columns: 1fr;
}

@media (min-width: 48rem) {
  .grille--deux  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grille--trois { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.pile > * + * { margin-top: var(--e4); }
.pile-serree > * + * { margin-top: var(--e2); }

.rangee {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
}

.rangee--espacee { justify-content: space-between; }
.rangee--enroulee { row-gap: var(--e2); }
.pousse-droite { margin-left: auto; }
.ml1 { margin-left: var(--e1); }
.ml2 { margin-left: var(--e3); }

/* ------------------------------------------------- en-tête et navigation */

.entete {
  position: sticky;
  top: 0;
  z-index: var(--z-entete);
  background: var(--surface);
  border-bottom: 1px solid var(--bordure);
  box-shadow: var(--ombre-1);
}

.entete__interieur {
  display: flex;
  align-items: center;
  gap: var(--e4);
  padding: var(--e3) var(--e4);
}

@media (min-width: 62rem) {
  .entete__interieur { padding-inline: var(--e5); }
}

/* Le logo et le nom du site */
.marque {
  display: inline-flex;
  align-items: center;
  gap: var(--e3);
  text-decoration: none;
  color: var(--texte);
  white-space: nowrap;
}

.marque__logo { width: 2.5rem; height: auto; flex: none; }

.marque__nom {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.marque__ext { color: var(--vert); }

/* Sur très petit écran le nom reste affiché, simplement réduit. */
@media (max-width: 34rem) {
  .marque__logo { width: 2rem; }
  .marque__nom  { font-size: 1rem; }
  .entete__interieur { gap: var(--e2); padding-inline: var(--e3); }
}

@media (max-width: 26rem) {
  .marque__nom { font-size: 0.875rem; }
  .marque__ext { display: none; }
}

/* Champ de recherche de l'en-tête */
.recherche-entete {
  position: relative;
  flex: 1 1 12rem;
  max-width: 26rem;
}

.recherche-entete__loupe {
  position: absolute;
  left: var(--e3);
  top: 50%;
  transform: translateY(-50%);
  width: 1.05rem;
  height: 1.05rem;
  color: var(--texte-tenu);
  pointer-events: none;
}

.recherche-entete input[type="search"] {
  width: 100%;
  min-height: 2.5rem;
  padding: var(--e2) var(--e3) var(--e2) 2.4rem;
  border: 1px solid var(--bordure);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--texte);
  font: 400 0.9375rem/1.4 var(--sans);
}

.recherche-entete input[type="search"]:focus {
  outline: none;
  background: var(--surface);
  border-color: var(--vert);
  box-shadow: 0 0 0 3px var(--vert-clair);
}

/* Photo tirée au sort, avec la personne et son lien de parenté */
.moment {
  display: none;
  align-items: stretch;
  gap: var(--e3);
  padding: 0;
  overflow: hidden;
  border-radius: var(--rayon-lg);
  background: var(--surface);
  border: 1px solid var(--bordure);
  box-shadow: var(--ombre-1);
  text-decoration: none;
  color: inherit;
  max-width: 26rem;
  /*
   * Hauteur fixe : sans elle, une photo en portrait étirait la barre entière.
   * La marge basse négative laisse la vignette déborder sur les onglets sans
   * allonger l'en-tête ; le plan la fait passer au-dessus d'eux.
   */
  position: relative;
  z-index: 1;
  height: 6.25rem;
  align-self: center;
  margin-block: calc(var(--e2) * -1) calc(var(--e7) * -1);
  transition: box-shadow var(--transition), border-color var(--transition);
}

.moment:hover {
  box-shadow: var(--ombre-2);
  border-color: var(--vert);
  color: inherit;
}

@media (min-width: 68rem) { .moment { display: inline-flex; } }

/* Rectangulaire et large : la photo doit se voir, pas se deviner. */
.moment__image {
  width: 9rem;
  height: 100%;
  object-fit: cover;
  flex: none;
  background: var(--surface-2);
}

.moment__texte {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--e2) var(--e4) var(--e2) 0;
}

.moment__surtitre {
  display: block;
  margin-bottom: 0.15rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--vert);
}

.moment__legende {
  display: block;
  font-size: 0.6875rem;
  color: var(--texte-tenu);
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.moment__texte { min-width: 0; line-height: 1.25; }

.moment__nom {
  display: block;
  font-size: 0.9375rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.moment__lien {
  display: block;
  font-size: 0.75rem;
  color: var(--texte-tenu);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ----------------------------------------- messagerie dans la barre */

.messagerie { position: relative; }

.messagerie__declencheur {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  color: var(--texte-doux);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.messagerie__declencheur:hover { background: var(--surface-2); color: var(--vert-fonce); }
.messagerie__declencheur svg { width: 1.35rem; height: 1.35rem; }

/* La pastille chevauche l'icône, comme partout ailleurs. */
.messagerie__compteur {
  position: absolute;
  top: 0.15rem;
  right: 0.1rem;
  min-width: 1.05rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: var(--erreur);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.05rem;
  text-align: center;
}

.messagerie__calque {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + var(--e2));
  z-index: var(--z-menu);
  /* Élargi de 22 à 27 rem : les aperçus de conversation tenaient sur trois
     lignes chacun, ce qui rendait la liste illisible d'un coup d'œil. */
  width: 27rem;
  max-width: calc(100vw - 2rem);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
  overflow: hidden;
}

.messagerie__bascule:checked ~ .messagerie__calque { display: block; }

.messagerie__entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 0;
  padding: var(--e3) var(--e4);
  border-bottom: 1px solid var(--bordure);
  font-weight: 600;
}

.apercu {
  display: block;
  padding: var(--e3) var(--e4);
  border-bottom: 1px solid var(--bordure);
  color: inherit;
  text-decoration: none;
}

.apercu:hover { background: var(--surface-2); color: inherit; }

/* Un fil non lu se distingue par la couleur et le trait, pas seulement le gras. */
.apercu--nouveau {
  border-left: 3px solid var(--vert);
  background: var(--vert-clair);
}

.apercu__qui {
  display: block;
  font-size: 0.9375rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.apercu__texte {
  display: block;
  font-size: 0.8125rem;
  color: var(--texte-doux);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.apercu__date { display: block; margin-top: 2px; font-size: 0.6875rem; color: var(--texte-tenu); }

.messagerie__pied {
  display: block;
  padding: var(--e3);
  color: var(--vert-fonce);
  font-size: 0.875rem;
  font-weight: 600;
  text-align: center;
  text-decoration: none;
}

.messagerie__pied:hover { background: var(--surface-2); }

/* ------------------------------------------------ menu de l'utilisateur */

.moi { position: relative; }

.moi__declencheur {
  display: flex;
  align-items: center;
  gap: var(--e2);
  padding: var(--e1) var(--e2) var(--e1) var(--e1);
  border-radius: 999px;
  border: 1px solid var(--bordure);
  background: var(--surface);
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}

.moi__declencheur:hover { background: var(--surface-2); border-color: var(--bordure-forte); }

.moi__portrait,
.moi__initiales {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  flex: none;
  object-fit: cover;
}

.moi__initiales {
  display: grid;
  place-items: center;
  background: var(--vert-clair);
  color: var(--vert);
  font-size: 0.75rem;
  font-weight: 700;
}

.moi__prenom {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--texte);
  white-space: nowrap;
}

.moi__chevron {
  width: 1rem;
  height: 1rem;
  color: var(--texte-tenu);
  transition: transform var(--transition);
}

.moi__bascule:checked ~ .moi__declencheur .moi__chevron { transform: rotate(180deg); }

@media (max-width: 40rem) {
  .moi__prenom, .moi__chevron { display: none; }
  .moi__declencheur { padding: var(--e1); }
}

/* Le calque, ouvert par la case à cocher — aucun script nécessaire. */
.moi__calque {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + var(--e2));
  z-index: var(--z-menu);
  /* Deux centimètres de plus : « Revoir la visite guidée » et l'adresse
     électronique s'y repliaient sur deux lignes. */
  min-width: 17.5rem;
  padding: var(--e2);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
}

.moi__bascule:checked ~ .moi__calque { display: block; }

.moi__entete {
  margin: 0;
  padding: var(--e3);
  border-bottom: 1px solid var(--bordure);
}

.moi__nom {
  display: block;
  font-size: 0.9375rem;
  font-weight: 600;
}

.moi__mail {
  display: block;
  font-size: 0.8125rem;
  color: var(--texte-tenu);
  overflow: hidden;
  text-overflow: ellipsis;
}

.moi__lien {
  display: block;
  width: 100%;
  padding: var(--e3);
  margin-top: 2px;
  border: 0;
  border-radius: var(--rayon);
  background: none;
  color: var(--texte-doux);
  font: 400 0.9375rem/1.4 var(--sans);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.moi__lien:hover { background: var(--surface-2); color: var(--texte); }

.moi__lien--bouton {
  margin-top: var(--e2);
  border-top: 1px solid var(--bordure);
  border-radius: 0 0 var(--rayon) var(--rayon);
  color: var(--erreur);
}

/* Onglets de premier niveau */
.onglets {
  display: flex;
  gap: var(--e1);
  padding: 0 var(--e4);
  overflow-x: auto;
  scrollbar-width: none;
}

.onglets::-webkit-scrollbar { display: none; }

@media (min-width: 62rem) {
  .onglets { padding-inline: var(--e5); }
}

.onglets__lien {
  padding: var(--e3) var(--e4);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--texte-doux);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 3px solid transparent;
  transition: color var(--transition), border-color var(--transition);
}

.onglets__lien:hover { color: var(--texte); }

.onglets__lien[aria-current="page"] {
  color: var(--vert);
  border-bottom-color: var(--vert);
}

/* Bouton hamburger : n'apparaît que quand la barre latérale est repliée */
.entete__hamburger {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  border-radius: var(--rayon);
  border: 1px solid var(--bordure);
  color: var(--texte-doux);
  cursor: pointer;
}

.entete__hamburger svg { width: 1.25rem; height: 1.25rem; }
.entete__hamburger:hover { background: var(--surface-2); }

@media (min-width: 62rem) { .entete__hamburger { display: none; } }

/* ----------------------------------------------- cadre et barre latérale */

.cadre {
  display: grid;
  grid-template-columns: 1fr;
  max-width: var(--largeur-max);
  margin-inline: auto;
}

@media (min-width: 62rem) {
  .cadre { grid-template-columns: var(--largeur-barre) minmax(0, 1fr); }

  /* Sans barre latérale, le contenu prend toute la largeur. */
  .cadre--large { grid-template-columns: minmax(0, 1fr); }
}

.barre {
  display: none;
  padding: var(--e5) var(--e3);
  border-right: 1px solid var(--bordure);
  background: var(--surface);
}

/* Sur mobile, la barre se déplie sous l'en-tête via la case à cocher. */
.barre-bascule:checked ~ .cadre .barre { display: block; }

@media (min-width: 62rem) {
  .barre {
    display: block;
    position: sticky;
    top: 7.5rem;
    align-self: start;
    max-height: calc(100dvh - 7.5rem);
    overflow-y: auto;
  }
}

.barre__titre {
  margin: 0 0 var(--e3);
  padding-left: var(--e3);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--texte-tenu);
}

.barre__liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }

.barre__lien {
  display: block;
  padding: var(--e3);
  border-radius: var(--rayon);
  font-size: 0.9375rem;
  color: var(--texte-doux);
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}

.barre__lien:hover { background: var(--surface-2); color: var(--texte); }

.barre__lien[aria-current="page"] {
  background: var(--vert);
  color: #fff;
  font-weight: 600;
  box-shadow: var(--ombre-1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .barre__lien[aria-current="page"] { color: #10221a; }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .barre__lien[aria-current="page"] { color: #10221a; }


.barre__pied {
  margin-top: var(--e5);
  padding: var(--e3);
  border-top: 1px solid var(--bordure);
}

.barre__moi {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--texte-tenu);
}

.contenu {
  min-width: 0;
  padding: var(--e5) var(--e4) var(--e8);
}

@media (min-width: 62rem) {
  .contenu { padding: var(--e6) var(--e6) var(--e8); }
}

/* ------------------------------------------------------------------ cartes */

.carte {
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-xl);
  padding: var(--e5);
  box-shadow: var(--ombre-1);
}

.carte__titre {
  font-size: 1.0625rem;
  font-family: var(--sans);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--texte-tenu);
  margin-bottom: var(--e4);
}

/* ------------------------------------------------- carte « personne » */

.personne {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e3);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  /* La bordure change de couleur, pas la taille : aucun décalage au survol. */
  transition: border-color var(--transition), box-shadow var(--transition), background var(--transition);
}

.personne:hover {
  border-color: var(--vert);
  box-shadow: var(--ombre-2);
  background: var(--surface);
}

.personne__portrait {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-2);
  flex-shrink: 0;
}

.personne__initiales {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--vert-clair);
  color: var(--vert-fonce);
  font-weight: 600;
  font-size: 0.9375rem;
  flex-shrink: 0;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .personne__initiales { background: var(--surface-2); color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .personne__initiales { background: var(--surface-2); color: var(--vert); }


.personne__texte { min-width: 0; }

.personne__nom {
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.personne__meta {
  font-size: 0.8125rem;
  color: var(--texte-tenu);
  line-height: 1.4;
}

.personne--compacte { padding: var(--e2); }
.personne--compacte .personne__portrait,
.personne--compacte .personne__initiales { width: 2.25rem; height: 2.25rem; font-size: 0.8125rem; }

/* Repère de sexe, doublé d'un libellé textuel : la couleur n'est jamais
   le seul porteur d'information. */
.personne--f { border-left: 3px solid var(--vert); }
.personne--m { border-left: 3px solid var(--bleu); }

/* --------------------------------------------------------------- arbre */

.arbre {
  overflow-x: auto;
  padding-bottom: var(--e4);
  -webkit-overflow-scrolling: touch;
}

.arbre__niveaux {
  display: flex;
  gap: var(--e5);
  align-items: center;
  min-width: min-content;
}

.arbre__colonne {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  gap: var(--e2);
  min-width: 12.5rem;
}

.arbre__couple {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  padding-left: var(--e4);
  position: relative;
}

/* Traits de filiation dessinés en CSS, sans images. */
.arbre__couple::before {
  content: "";
  position: absolute;
  left: 0;
  top: 25%;
  bottom: 25%;
  width: 2px;
  background: var(--bordure-forte);
}

.arbre__couple::after {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: var(--e3);
  height: 2px;
  background: var(--bordure-forte);
  transform: translateX(-100%);
}

.arbre__vide {
  display: grid;
  place-items: center;
  min-height: 3.25rem;
  padding: var(--e2);
  border: 1px dashed var(--bordure-forte);
  border-radius: var(--rayon);
  color: var(--texte-tenu);
  font-size: 0.8125rem;
  font-style: italic;
}

/* Arbre familial : parents au-dessus, fratrie et enfants en dessous */
.foyer {
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  padding: var(--e4);
  background: var(--surface-2);
}

.foyer__couple {
  display: grid;
  gap: var(--e3);
  margin-bottom: var(--e4);
}

@media (min-width: 40rem) {
  .foyer__couple { grid-template-columns: 1fr auto 1fr; align-items: center; }
}

.foyer__lien {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  padding: var(--e1) var(--e3);
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--bordure);
  font-size: 0.8125rem;
  color: var(--texte-doux);
  white-space: nowrap;
}

.foyer__enfants {
  padding-top: var(--e4);
  border-top: 1px dashed var(--bordure-forte);
}

/* Descendance : liste imbriquée avec traits de rattachement */
.descendance,
.descendance ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.descendance ul {
  margin-left: var(--e4);
  padding-left: var(--e5);
  border-left: 2px solid var(--bordure);
}

.descendance li { margin-block: var(--e2); position: relative; }

.descendance ul > li::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--e5));
  top: 1.5rem;
  width: var(--e4);
  height: 2px;
  background: var(--bordure);
}

/* -------------------------- arbre d'ascendance dans un viewport « télé »
 *
 * Le sujet est en bas, ses ancêtres remontent au-dessus. La structure DOM
 * est un arbre récursif : chaque .tv-branche empile un bloc d'ancêtres
 * (deux .tv-branche filles côte à côte) puis sa propre carte. Comme le
 * sujet est la racine, ses cartes filles se dessinent naturellement
 * au-dessus et sa carte à lui ferme l'arbre : il apparaît en bas.
 *
 * Les traits sont dessinés en CSS, jamais en image ni en style inline
 * (bloqués par la CSP). Deux pseudo-éléments par carte suffisent : une
 * barre horizontale entre les deux parents, une verticale qui descend
 * vers l'enfant.
 */

.tv-arbre {
  --tv-carte-l: 11rem;
  --tv-carte-h: 4.75rem;
  --tv-gap-h:   1.25rem;
  --tv-gap-v:   2rem;
  --tv-trait:   var(--bordure-forte);

  position: relative;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-lg);
  background: var(--surface-2);
  box-shadow: var(--ombre-1);
  overflow: hidden;
  isolation: isolate;
  contain: layout paint;
}

/* Le viewport, c'est ce qu'on voit — la « télé ». Sans JS il défile
   comme n'importe quel conteneur ; avec JS, la scène est déplacée par
   transform et le défilement natif est coupé (touch-action: none). */
.tv-arbre__viewport {
  height: min(72vh, 640px);
  overflow: auto;
  cursor: grab;
  background:
    radial-gradient(circle at 1px 1px, var(--bordure) 1px, transparent 1.5px);
  background-size: 24px 24px;
  background-position: center;
  -webkit-overflow-scrolling: touch;
}

.tv-arbre__viewport:focus-visible {
  outline: 2px solid var(--vert);
  outline-offset: -2px;
}

/* Piloté par JS quand le déplacement est en cours. */
.tv-arbre__viewport.tv-glisse         { cursor: grabbing; }
.tv-arbre__viewport.tv-pilote         { overflow: hidden; touch-action: none; }
.tv-arbre__viewport.tv-pilote .tv-arbre__scene { will-change: transform; }

/* La scène : on lui applique un transform translate + scale depuis JS.
   L'origine est fixée en haut-gauche pour rendre le calcul simple. */
.tv-arbre__scene {
  display: inline-block;
  padding: var(--e5);
  transform-origin: 0 0;
  user-select: none;
  -webkit-user-select: none;
}

/* -------- l'arbre récursif */

.tv-branche {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Espace horizontal entre deux branches sœurs : appliqué par la mère. */
}

.tv-branche__ancetres {
  display: flex;
  align-items: flex-end;
  gap: var(--tv-gap-h);
  position: relative;
}

/* Les deux sous-branches parentales prennent des parts égales, quelle que
   soit la profondeur qu'elles portent. C'est ce qui garantit que le père
   est à 25 % et la mère à 75 % de leur bloc d'ancêtres, et donc que le
   bracket horizontal tombe sur leurs centres. */
.tv-branche__ancetres > .tv-branche {
  flex: 1 1 0;
  min-width: 0;
}

.tv-branche__moi {
  position: relative;
}

/* Quand une branche a des ancêtres au-dessus, on réserve la place des
   traits en bas de __ancetres et on les dessine à cet endroit — pas sur
   __moi, qui est bien plus étroit et ferait un bracket ridicule.
   :has() : la géométrie découle de la structure, autant que le CSS la lise. */
.tv-branche:has(> .tv-branche__ancetres) > .tv-branche__ancetres {
  padding-bottom: var(--tv-gap-v);
}

/* Barre horizontale reliant les centres des deux parents. */
.tv-branche:has(> .tv-branche__ancetres) > .tv-branche__ancetres::before {
  content: "";
  position: absolute;
  bottom: var(--tv-gap-v);
  left: 25%;
  right: 25%;
  height: 2px;
  background: var(--tv-trait);
}

/* Descente verticale depuis le milieu du bracket vers la carte enfant. */
.tv-branche:has(> .tv-branche__ancetres) > .tv-branche__ancetres::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 2px;
  height: var(--tv-gap-v);
  background: var(--tv-trait);
  transform: translateX(-50%);
}

/* -------- descendance : structure top-down, branchement variable

   La descendance n'est pas binaire — quelqu'un peut avoir zéro, un ou
   sept enfants. La structure DOM suit : un .tv-desc-noeud contient sa
   carte, puis un flex-row .tv-desc-noeud__enfants pour ses enfants
   directs. Chaque enfant est à son tour un .tv-desc-noeud récursif.

   Le bracket qui joint les enfants à leur parent est dessiné en
   pseudo-éléments sur les cartes enfants : une descente verticale, et
   une barre horizontale qui court dans les gouttières entre voisins.
   Les enfants extrêmes tronquent la moitié externe pour finir sur leur
   propre centre — la connexion pointe alors bien vers le centre du
   groupe, quel que soit le nombre d'enfants. */

.tv-desc-noeud {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tv-desc-noeud__moi {
  position: relative;
}

.tv-desc-noeud__enfants {
  display: flex;
  align-items: flex-start;
  gap: var(--tv-gap-h);
  padding-top: var(--tv-gap-v);
}

.tv-desc-noeud__enfants > .tv-desc-noeud {
  position: relative;
}

/* Barre horizontale entre les enfants, dans la gouttière au-dessus.
   Pour les enfants du milieu : elle traverse toute leur largeur plus
   la moitié des gouttières adjacentes. */
.tv-desc-noeud__enfants > .tv-desc-noeud::before {
  content: "";
  position: absolute;
  top: calc(-1 * var(--tv-gap-v));
  left: calc(-1 * var(--tv-gap-h) / 2);
  right: calc(-1 * var(--tv-gap-h) / 2);
  height: 2px;
  background: var(--tv-trait);
}

/* Le premier enfant démarre son bracket à son propre centre. */
.tv-desc-noeud__enfants > .tv-desc-noeud:first-child::before {
  left: 50%;
}

/* Le dernier enfant arrête son bracket à son propre centre. */
.tv-desc-noeud__enfants > .tv-desc-noeud:last-child::before {
  right: 50%;
}

/* Enfant unique : pas de bracket horizontal, juste la descente. */
.tv-desc-noeud__enfants > .tv-desc-noeud:only-child::before {
  display: none;
}

/* Descente verticale du bracket vers le haut de la carte enfant. */
.tv-desc-noeud__enfants > .tv-desc-noeud::after {
  content: "";
  position: absolute;
  top: calc(-1 * var(--tv-gap-v));
  left: 50%;
  width: 2px;
  height: var(--tv-gap-v);
  background: var(--tv-trait);
  transform: translateX(-50%);
}

/* -------- une carte

   La carte n'est plus un lien : c'est un conteneur avec deux liens à
   l'intérieur — un lien-zone en overlay qui couvre tout et mène à
   l'arbre de la personne, et un petit lien « Fiche » posé au-dessus qui
   mène à sa fiche. La CSS ci-dessous les positionne et prévient l'effet
   d'un lien-dans-un-lien (interdit en HTML) tout en gardant la carte
   entièrement cliquable. */

.tv-carte {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--e2);
  width: var(--tv-carte-l);
  min-height: var(--tv-carte-h);
  padding: var(--e2) var(--e3);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  color: var(--texte);
  transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition);
  box-shadow: var(--ombre-1);
}

.tv-carte:hover,
.tv-carte:focus-within {
  border-color: var(--vert);
  box-shadow: var(--ombre-2);
  transform: translateY(-1px);
  color: var(--texte);
}

/* Le lien-zone : couvre toute la carte, mène à l'arbre de la personne.
   Aucun contenu visuel, aucun texte : c'est un rectangle cliquable. */
.tv-carte__zone {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  text-decoration: none;
}

.tv-carte__zone:focus-visible {
  outline: 2px solid var(--vert);
  outline-offset: -2px;
}

/* Le lien « Fiche » : petite pastille en bas à droite, remontée au-dessus
   du lien-zone pour capter son propre clic sans ambiguïté. */
.tv-carte__fiche {
  position: absolute;
  bottom: 3px;
  right: 4px;
  z-index: 2;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--texte-doux);
  text-decoration: none;
  padding: 3px 8px;
  border-radius: 4px;
  background: var(--surface-2);
  border: 1px solid var(--bordure);
  line-height: 1.1;
  opacity: .8;
  transition: opacity var(--transition), color var(--transition), background var(--transition), border-color var(--transition);
  -webkit-tap-highlight-color: transparent;
}

/* Cible tactile élargie : un carré invisible autour du bouton, qui capte
   les doigts imprécis sans agrandir le visuel. */
.tv-carte__fiche::before {
  content: "";
  position: absolute;
  inset: -6px;
}

.tv-carte:hover .tv-carte__fiche,
.tv-carte:focus-within .tv-carte__fiche {
  opacity: 1;
}

.tv-carte__fiche:hover,
.tv-carte__fiche:focus-visible {
  color: var(--vert-fonce);
  background: var(--vert-clair);
  border-color: var(--vert);
  outline: 0;
  opacity: 1;
}

/* Sur tactile, le lien est toujours au maximum de lisibilité. */
@media (hover: none) {
  .tv-carte__fiche { opacity: 1; }
}

.tv-carte--m { border-left: 3px solid var(--bleu); }
.tv-carte--f { border-left: 3px solid var(--abricot); }

.tv-carte--moi {
  border: 2px solid var(--vert);
  box-shadow: 0 0 0 3px var(--vert-clair);
}

/* Surbrillance temporaire : quand la recherche pointe une carte, un halo
   vert pulse trois secondes autour d'elle pour attirer l'œil. La CSS
   s'empile par-dessus le cadre existant du sujet — la pulsation reste
   visible même sur .tv-carte--moi. */
@keyframes tv-carte-surligne {
  0%   { box-shadow: 0 0 0 0   rgba(46, 125, 79, .55), 0 0 0 0 rgba(46, 125, 79, .35); }
  40%  { box-shadow: 0 0 0 6px rgba(46, 125, 79, .00), 0 0 0 3px rgba(46, 125, 79, .85); }
  100% { box-shadow: 0 0 0 6px rgba(46, 125, 79, .00), 0 0 0 3px rgba(46, 125, 79, .00); }
}

.tv-carte--surligne {
  animation: tv-carte-surligne 3s ease-out 1;
  animation-fill-mode: forwards;
  z-index: 4;                        /* passe devant le halo permanent du sujet */
  border-color: var(--vert) !important;
}

.tv-carte--vide {
  cursor: default;
  border-style: dashed;
  border-color: var(--bordure-forte);
  background: transparent;
  color: var(--texte-tenu);
  box-shadow: none;
}

.tv-carte--vide:hover,
.tv-carte--vide:focus-visible {
  border-color: var(--bordure-forte);
  box-shadow: none;
  transform: none;
}

.tv-carte__portrait {
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-2);
}

.tv-carte__portrait--initiales {
  display: grid;
  place-items: center;
  font-weight: 600;
  color: var(--vert-fonce);
  background: var(--vert-clair);
}

.tv-carte__portrait--anonyme {
  display: inline-block;
  color: var(--texte-tenu);
}

.tv-carte__portrait--anonyme svg {
  width: 100%;
  height: 100%;
  display: block;
}

.tv-anonyme__fond  { fill: var(--surface-2); }
.tv-anonyme__trait { fill: currentColor; opacity: .55; }

.tv-carte__texte {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.tv-carte__nom {
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--texte);
  /* Autorise le retour à la ligne pour ne rien tronquer : les noms longs
     s'étalent sur deux lignes plutôt que d'être coupés par une ellipse.
     La carte s'étire verticalement en conséquence. */
  overflow-wrap: anywhere;
  word-break: break-word;
  hyphens: auto;
  max-width: 8rem;
}

.tv-carte--vide .tv-carte__nom {
  font-style: italic;
  color: var(--texte-tenu);
}

.tv-carte__annees {
  font-size: 0.75rem;
  color: var(--texte-tenu);
}

/* -------- contrôles flottants */

.tv-arbre__ctrl {
  position: absolute;
  z-index: 2;
  display: none;              /* révélé par JS via classe sur .tv-arbre */
  gap: var(--e1);
  padding: var(--e1);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  box-shadow: var(--ombre-2);
}

.tv-arbre.tv-pret .tv-arbre__ctrl { display: inline-flex; }

.tv-arbre__ctrl--zoom { left: var(--e3);  bottom: var(--e3); }
.tv-arbre__ctrl--rech { right: var(--e3); top:    var(--e3); }

.tv-btn {
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--texte);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background var(--transition), color var(--transition);
}

.tv-btn:hover  { background: var(--surface-2); color: var(--vert-fonce); }
.tv-btn:active { background: var(--vert-clair); }

.tv-btn:focus-visible {
  outline: 2px solid var(--vert);
  outline-offset: 2px;
}

.tv-btn svg {
  width: 1.125rem;
  height: 1.125rem;
  display: block;
}

/* Le bouton plein écran porte deux icônes empilées ; on ne montre que
   celle qui décrit la CIBLE du clic (l'inverse de l'état courant).
   Les sélecteurs doublent la classe pour battre la spécificité du
   « .tv-btn svg { display: block } » défini plus haut ; sans ça les
   deux icônes s'affichaient en même temps. */
.tv-btn .tv-btn__icone--sortir { display: none; }
.tv-arbre.tv-plein-ecran .tv-btn .tv-btn__icone--entrer { display: none; }
.tv-arbre.tv-plein-ecran .tv-btn .tv-btn__icone--sortir { display: block; }

/* En plein écran, le .tv-arbre remplit tout : le viewport prend
   toute la hauteur disponible, les coins arrondis disparaissent. */
.tv-arbre:fullscreen,
.tv-arbre.tv-plein-ecran {
  width: 100vw;
  height: 100vh;
  border-radius: 0;
  border: 0;
}

.tv-arbre:fullscreen .tv-arbre__viewport,
.tv-arbre.tv-plein-ecran .tv-arbre__viewport {
  height: 100vh;
  border-radius: 0;
}

/* -------- dialogue de recherche */

.tv-arbre__dialog {
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-lg);
  padding: 0;
  background: var(--surface);
  color: var(--texte);
  box-shadow: var(--ombre-3);
  max-width: min(28rem, 92vw);
  width: 100%;
}

.tv-arbre__dialog::backdrop {
  background: rgba(0, 0, 0, .35);
  backdrop-filter: blur(2px);
}

.tv-arbre__dialog-form {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  padding: var(--e3);
  min-height: 8rem;
  max-height: min(70vh, 32rem);
}

.tv-arbre__dialog-tete {
  display: flex;
  align-items: center;
  gap: var(--e2);
}

.tv-arbre__dialog-tete input {
  flex: 1;
  min-width: 0;
  padding: var(--e2) var(--e3);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  background: var(--surface-2);
  color: var(--texte);
  font: inherit;
}

.tv-arbre__dialog-tete input:focus-visible {
  outline: 2px solid var(--vert);
  outline-offset: 1px;
  border-color: var(--vert);
}

.tv-arbre__dialog-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  border-top: 1px solid var(--bordure);
  border-radius: var(--rayon);
}

.tv-arbre__dialog-liste li { margin: 0; }

.tv-arbre__dialog-liste button {
  width: 100%;
  padding: var(--e2) var(--e3);
  border: 0;
  background: transparent;
  color: var(--texte);
  text-align: left;
  font: inherit;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  gap: var(--e2);
  border-bottom: 1px solid var(--bordure);
}

.tv-arbre__dialog-liste button:hover,
.tv-arbre__dialog-liste button:focus-visible {
  background: var(--vert-clair);
  color: var(--vert-fonce);
  outline: 0;
}

.tv-arbre__dialog-liste .tv-arbre__gen {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--texte-tenu);
}

.tv-arbre__dialog-vide {
  margin: var(--e3) 0 0;
  color: var(--texte-tenu);
  text-align: center;
}

.tv-arbre__noscript {
  padding: var(--e2) var(--e3);
  background: var(--surface);
  border-top: 1px solid var(--bordure);
}

/* -------- bascules de vues (ascendance / descendance)

   Deux cases à cocher au-dessus des viewports, alignées horizontalement.
   Sans style particulier ce serait juste une paire de checkboxes ; on
   soigne l'espacement, on remonte le libellé de la case désactivée en
   discret, on aligne aux mêmes lignes que les autres rangees du site. */
.tv-bascule {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
  padding: var(--e2) var(--e3);
  margin: 0 0 var(--e3);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.tv-bascule label {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  font-size: 0.9375rem;
  cursor: pointer;
}

.tv-bascule label:has(input[disabled]) {
  cursor: not-allowed;
  color: var(--texte-tenu);
}

.tv-bascule input {
  accent-color: var(--vert);
  width: 1.1em; height: 1.1em;
}

.tv-bascule small {
  font-size: 0.75rem;
  color: var(--texte-tenu);
}

/* Séparation entre les deux viewports quand ils s'affichent ensemble. */
.tv-vue + .tv-vue { margin-top: var(--e5); }

/* -------- vue combinée : asc + sujet + desc dans le même viewport

   La descendance rend sa carte de tête (le sujet) en « fantôme » : elle
   occupe la place mais ne se voit pas — un négatif de marge la fait
   remonter jusqu'à la superposition avec la vraie carte du sujet, tout
   en bas de l'ascendance. Résultat : une seule silhouette du sujet à
   l'écran, avec le bracket des enfants qui en descend et le bracket des
   parents qui y monte.

   Le calcul du décalage vertical dépend de la hauteur d'une carte
   (--tv-carte-h) et de la bordure d'une pixel autour. On l'exprime en
   variable pour ne pas se répéter. */

.tv-arbre__scene--complet {
  padding-top:    var(--e4);
  padding-bottom: var(--e4);
}

.tv-complet {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.tv-complet__asc,
.tv-complet__desc,
.tv-complet__seul-sujet {
  display: flex;
  justify-content: center;
}

/* Remonte la descendance pour que sa carte de tête (fantôme) recouvre
   pixel pour pixel la carte du sujet. La hauteur réelle de la carte peut
   dépasser --tv-carte-h quand un nom long passe sur deux lignes : le JS
   mesure et pose --tv-carte-h-sujet sur .tv-complet ; on retombe sur
   --tv-carte-h si JS est absent.

   La règle vaut dans les DEUX cas, que le sujet vienne de l'ascendance
   ou du .tv-complet__seul-sujet rendu quand on ne lui connaît aucun
   ancêtre. Une exception existait ici pour ce second cas ; elle laissait
   le fantôme se poser sous la vraie carte au lieu de disparaître dessous,
   et la même personne s'affichait deux fois. */
.tv-complet__desc {
  margin-top: calc(-1 * (var(--tv-carte-h-sujet, var(--tv-carte-h)) + 2px));
}

.tv-carte--fantome {
  visibility: hidden;
  pointer-events: none;
}

/* Le fantôme ET tout son parenté immédiate doivent être transparents
   aux clics : la carte fantôme est superposée à la vraie carte du sujet
   (celle en ascendance), et sans ça le badge ou la fiche du sujet sont
   captés par le .tv-desc-noeud__moi qui les recouvre, particulièrement
   sur mobile où certains navigateurs remontent l'événement plus haut
   dans la chaîne que la spec ne le voudrait. On coupe tout à la racine
   de la descendance quand la vraie carte est ailleurs (dans l'asc). */
.tv-complet__desc > .tv-desc-noeud > .tv-desc-noeud__moi {
  pointer-events: none;
}

/* Sur mobile, --tv-carte-h vaut moins ; le calc s'ajuste
   automatiquement grâce à la variable. Rien à faire ici. */

/* Quand deux vues autonomes (asc et desc séparées) sont affichées ensemble,
   chaque viewport se compresse — legacy pour le mode « vues empilées ». */
.tv-vue--compact .tv-arbre__viewport {
  height: min(44vh, 380px);
}

@media (max-width: 40rem) {
  .tv-vue--compact .tv-arbre__viewport {
    height: min(48vh, 340px);
  }
}

/* -------- bulle de survol : « qui c'est pour moi » */

.tv-bulle {
  position: absolute;
  z-index: 3;
  transform: translate(-50%, calc(-100% - 10px));
  padding: 0.25rem 0.55rem;
  background: var(--texte);
  color: var(--fond);
  border-radius: 0.375rem;
  font-size: 0.75rem;
  line-height: 1.3;
  font-weight: 500;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms ease-out;
  box-shadow: var(--ombre-2);
}

.tv-bulle::after {
  /* Petite pointe qui tombe vers la carte. */
  content: "";
  position: absolute;
  left: 50%;
  bottom: -4px;
  width: 8px; height: 8px;
  background: var(--texte);
  transform: translateX(-50%) rotate(45deg);
  border-bottom-right-radius: 2px;
}

.tv-bulle--visible { opacity: 1; }

/* -------- badge « + » sur une carte qui a des extras */

.tv-carte__extras {
  position: absolute;
  top: -10px;
  right: -10px;
  z-index: 3;                 /* au-dessus de la zone (1) et de la fiche (2) */
  width: 1.875rem;
  height: 1.875rem;
  padding: 0;
  border: 2px solid var(--surface);
  border-radius: 50%;
  background: var(--vert);
  color: #fff;
  line-height: 1;
  cursor: pointer;
  display: grid;
  place-items: center;
  box-shadow: var(--ombre-1);
  opacity: .55;
  transition: opacity var(--transition), transform var(--transition);
  /* Étend la surface tactile bien au-delà du visuel : le doigt vise
     le rond, la marge invisible autour évite les ratés. */
  -webkit-tap-highlight-color: transparent;
}

.tv-carte__extras::before {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: 50%;
}

/* Sur appareils sans survol (téléphones, tablettes), la pastille reste
   toujours opaque — inutile d'attendre un hover qui n'existe pas. */
@media (hover: none) {
  .tv-carte__extras { opacity: 1; }
}

/* L'icône « deux personnes » : suit currentColor (blanc en clair,
   texte sombre en thème sombre — géré plus bas), taille agrandie pour
   qu'on repère la pastille du premier coup d'œil. */
.tv-carte__extras svg {
  width: 1.25rem;
  height: 1.25rem;
  display: block;
}

.tv-carte { position: relative; }

.tv-carte:hover .tv-carte__extras,
.tv-carte:focus-within .tv-carte__extras,
.tv-carte__extras:hover,
.tv-carte__extras:focus-visible {
  opacity: 1;
}

.tv-carte__extras:hover,
.tv-carte__extras:focus-visible {
  transform: scale(1.1);
  outline: 0;
}

/* En thème sombre, le vert clair ferait un halo trop crémeux : on garde
   le vert mais on assombrit le texte (comme les autres pastilles vertes). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tv-carte__extras { color: #10221a; }
}
:root[data-theme="dark"] .tv-carte__extras { color: #10221a; }

/* -------- popover ancré à une carte */

.tv-popover {
  position: absolute;
  z-index: 4;
  transform: translateX(-50%);
  min-width: 14rem;
  max-width: min(20rem, 90vw);
  background: var(--surface);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-3);
  color: var(--texte);
  animation: tv-popover-entre 140ms ease-out;
}

@keyframes tv-popover-entre {
  from { opacity: 0; transform: translate(-50%, -4px); }
  to   { opacity: 1; transform: translate(-50%, 0);    }
}

.tv-popover::before {
  /* Pointe vers la carte, en haut. */
  content: "";
  position: absolute;
  top: -6px;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  width: 12px; height: 12px;
  background: var(--surface);
  border-top: 1px solid var(--bordure-forte);
  border-left: 1px solid var(--bordure-forte);
}

.tv-popover__tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e2);
  padding: var(--e2) var(--e3);
  border-bottom: 1px solid var(--bordure);
  background: var(--surface-2);
  border-radius: var(--rayon) var(--rayon) 0 0;
}

.tv-popover__titre {
  font-size: 0.875rem;
  color: var(--texte);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tv-popover__fermer {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--texte-doux);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  border-radius: 4px;
}

.tv-popover__fermer:hover,
.tv-popover__fermer:focus-visible {
  background: var(--surface);
  color: var(--texte);
  outline: 0;
}

.tv-popover__corps {
  padding: var(--e2) var(--e3);
  max-height: 14rem;
  overflow-y: auto;
  /* Défilement inertiel natif sur iOS, et on isole le scroll pour qu'un
     coup de doigt à l'intérieur ne fasse pas défiler la page derrière. */
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

.tv-popover__section + .tv-popover__section {
  margin-top: var(--e2);
  padding-top: var(--e2);
  border-top: 1px solid var(--bordure);
}

.tv-popover__section h4 {
  margin: 0 0 0.25rem;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--texte-tenu);
  font-weight: 700;
}

.tv-popover__section ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.tv-popover__section li {
  padding: 0.125rem 0;
  font-size: 0.875rem;
  display: flex;
  align-items: baseline;
  gap: var(--e2);
}

.tv-popover__nom {
  color: var(--texte);
  text-decoration: none;
  border-bottom: 1px dotted var(--bordure-forte);
  flex: 1 1 auto;
  min-width: 0;
}

.tv-popover__nom:hover,
.tv-popover__nom:focus-visible {
  color: var(--vert-fonce);
  border-bottom-color: var(--vert);
  outline: 0;
}

.tv-popover__fiche {
  font-size: 0.6875rem;
  color: var(--texte-tenu);
  text-decoration: none;
  padding: 1px 5px;
  border-radius: 3px;
  flex: 0 0 auto;
}

.tv-popover__fiche:hover,
.tv-popover__fiche:focus-visible {
  color: var(--vert-fonce);
  background: var(--vert-clair);
  outline: 0;
}

/* Compatibilité rétro : si un ancien rendu envoie encore <a> nu dans un
   li de section, on ne casse pas complètement le style. */
.tv-popover__section li > a:not(.tv-popover__nom):not(.tv-popover__fiche) {
  color: var(--texte);
  text-decoration: none;
  border-bottom: 1px dotted var(--bordure-forte);
}

.tv-popover__vide {
  margin: 0;
  padding: var(--e2) 0;
  color: var(--texte-tenu);
  font-size: 0.875rem;
  text-align: center;
}

/* Sur téléphone, le popover se transforme en feuille glissée en bas
   d'écran : plein largeur, ancré au sol, impossible à rater. Le JS
   n'a pas à changer — c'est la CSS mobile qui détache le popover de
   sa position d'ancrage. */
@media (max-width: 40rem) {
  .tv-popover {
    position: fixed;
    left: 0 !important;
    right: 0 !important;
    top: auto !important;
    bottom: 0;
    transform: none;
    min-width: 0;
    max-width: none;
    width: 100%;
    border-radius: var(--rayon-lg) var(--rayon-lg) 0 0;
    border-bottom: 0;
    box-shadow: 0 -12px 32px rgba(0, 0, 0, .4);
    animation: tv-popover-entre-mobile 200ms ease-out;
  }

  .tv-popover::before { display: none; }

  .tv-popover__corps {
    max-height: 55vh;
  }

  .tv-popover__section li { font-size: 1rem; padding: var(--e1) 0; }
}

@keyframes tv-popover-entre-mobile {
  from { transform: translateY(100%); }
  to   { transform: translateY(0);    }
}

/* Mode sombre : la trame de fond du viewport prend moins de contraste
   pour ne pas moucheter l'écran, et le vert du sujet suit son ton clair
   déjà défini plus haut. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tv-arbre__viewport {
    background:
      radial-gradient(circle at 1px 1px, var(--bordure) 1px, transparent 1.5px);
    background-size: 24px 24px;
    background-position: center;
  }
}
:root[data-theme="dark"] .tv-arbre__viewport {
  background:
    radial-gradient(circle at 1px 1px, var(--bordure) 1px, transparent 1.5px);
  background-size: 24px 24px;
  background-position: center;
}

/* Sur téléphone, la carte se resserre : la largeur descend, le nom rétrécit. */
@media (max-width: 40rem) {
  .tv-arbre {
    --tv-carte-l: 9.5rem;
    --tv-carte-h: 4.75rem;
    --tv-gap-h:   0.75rem;
    --tv-gap-v:   1.5rem;
  }

  .tv-carte__nom    { max-width: 6rem; font-size: 0.75rem; }
  .tv-carte__annees { font-size: 0.6875rem; padding-right: 2.5rem; }
  .tv-carte__portrait { width: 2rem; height: 2rem; }
  .tv-arbre__viewport { height: min(70vh, 520px); }

  /* La fiche prend moins de place visuelle mais garde une grande cible
     tactile grâce à son ::before qui déborde. Elle sort aussi un peu du
     bord droit pour ne pas empiéter sur les années. */
  .tv-carte__fiche {
    font-size: 0.625rem;
    padding: 2px 5px;
    bottom: 2px;
    right: 2px;
  }

  .tv-carte__fiche::before {
    inset: -10px;
  }
}

/* -------------------------------------------------------------- galerie */

.galerie {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr));
  gap: var(--e3);
}

.vignette {
  position: relative;
  display: block;
  border-radius: var(--rayon);
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--bordure);
  cursor: pointer;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.vignette:hover {
  border-color: var(--vert);
  box-shadow: var(--ombre-2);
}

.vignette__image {
  /* Le rapport est réservé avant chargement : pas de saut de mise en page. */
  aspect-ratio: 1;
  width: 100%;
  object-fit: cover;
}

.vignette__legende {
  padding: var(--e2) var(--e3);
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--texte-doux);
  background: var(--surface);
}

.photo-pleine {
  max-width: 100%;
  border-radius: var(--rayon-lg);
  border: 1px solid var(--bordure);
  background: var(--surface-2);
}


/* --------------------------------------- identification sur les photos */

/*
 * Les repères sont positionnés en pourcentage : ils suivent l'image quelle
 * que soit sa taille d'affichage. Les variables --x et --y sont posées par
 * le script (la CSP interdit l'attribut « style » dans le HTML).
 */
.marquage {
  position: relative;
  display: inline-block;
  max-width: 100%;
}

/*
 * L'image est un bloc, ce qui suffit à supprimer le blanc que laissait sous
 * elle la ligne de texte de son conteneur. Un « line-height: 0 » sur la zone
 * entière y pourvoyait aussi, mais le panneau de saisie vit maintenant à
 * l'intérieur : les noms proposés s'y empilaient à la même hauteur, chaque
 * suggestion écrite par-dessus la précédente.
 */
.marquage img.photo-pleine {
  display: block;
}

.marquage--actif img.photo-pleine {
  cursor: crosshair;
}

.marqueur {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  width: 0;
  height: 0;
  line-height: 1;
  text-decoration: none;
  color: inherit;
}

/* Le cadre est centré sur le point cliqué. */
.marqueur__cadre {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4.5rem;
  height: 4.5rem;
  transform: translate(-50%, -50%);
  border: 2px solid rgb(255 255 255 / 0.9);
  /*
   * Un cercle, et non un carré. Un visage est rond, et le cercle épouse mieux
   * ce qu'il désigne : les angles d'un carré englobaient du décor — l'épaule
   * du voisin, un bout de mur — sur des photos de groupe où les visages se
   * touchent presque.
   */
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35), inset 0 0 0 1px rgb(0 0 0 / 0.2);
  opacity: 0.55;
  transition: opacity 0.15s ease, border-color 0.15s ease;
}

.marqueur__nom {
  position: absolute;
  left: 50%;
  top: calc(50% + 2.5rem);
  transform: translateX(-50%);
  padding: 0.15rem 0.5rem;
  max-width: 11rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.8125rem;
  color: #fff;
  background: rgb(0 0 0 / 0.72);
  border-radius: var(--rayon);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

.marqueur:hover .marqueur__cadre,
.marqueur:focus-visible .marqueur__cadre,
.marqueur--vu .marqueur__cadre {
  opacity: 1;
  border-color: #fff;
}

.marqueur:hover .marqueur__nom,
.marqueur:focus-visible .marqueur__nom,
.marqueur--vu .marqueur__nom {
  opacity: 1;
}

.marqueur--provisoire .marqueur__cadre {
  opacity: 1;
  border-style: dashed;
  /*
   * Quand le repère naît d'un visage détecté, il en prend la taille : un cercle
   * fixe conviendrait à l'un et engloberait le voisin de l'autre. Le script
   * fournit des pixels — un pourcentage se résoudrait ici contre un repère de
   * largeur nulle, donc contre rien.
   */
  width: var(--taille, 4.5rem);
  height: var(--taille, 4.5rem);
}

.est-vise {
  border-radius: var(--rayon-lg);
  box-shadow: 0 0 0 2px var(--vert);
}

.marquage-barre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
  margin-top: var(--e3);
}

/*
 * Le champ de saisie flotte sur la photo, sous le carré qu'on vient de poser.
 *
 * Il vivait dans une carte au-dessous de l'image : on cliquait un visage en
 * haut, puis on cherchait des yeux où taper le nom, et le lien entre les deux
 * gestes se perdait. Sa position est calculée par le script, à la manière du
 * halo de la visite guidée.
 */
.marquage-choix {
  position: absolute;
  z-index: 5;
  width: min(20rem, calc(100% - 1rem));
  padding: var(--e3) var(--e4);
  box-shadow: var(--ombre-3);
}

/* La zone de marquage est déjà l'ancre des repères ; elle l'est aussi de ce
   panneau, et ne doit donc rien rogner. */
.marquage { overflow: visible; }

/* Bouton discret présenté comme un lien (retirer une identification). */
.lien-nu {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--texte-doux);
  text-decoration: underline;
  cursor: pointer;
}

.lien-nu:hover {
  color: var(--vert);
}


/* ------------------------------------------- comparaison de deux fiches */

table.comparaison th[scope="row"] {
  width: 12rem;
  text-align: left;
  font-weight: 600;
  color: var(--texte-doux);
  vertical-align: top;
}

table.comparaison td {
  vertical-align: top;
}

/* Les lignes qui diffèrent sont celles qu'il faut regarder. */
table.comparaison tr.comparaison__differe > td,
table.comparaison tr.comparaison__differe > th {
  background: var(--abricot-clair);
}

.choix-fiche {
  display: flex;
  align-items: flex-start;
  gap: var(--e2);
  cursor: pointer;
}

.choix-fiche input[type="radio"] {
  margin-top: 0.2rem;
  flex: none;
}

.choix-fiche__texte {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  align-items: flex-start;
}

.choix-fiche__titre {
  font-weight: 600;
}


/* ------------------------------------------------------- calendrier */

/* Le groupe jour/mois/année sert d'ancrage au calque. */
.champ__inline[data-date] {
  position: relative;

  /*
   * UNE SEULE LIGNE, TOUJOURS. Jour, mois, année et le bouton du calendrier
   * forment une seule date ; sur deux lignes, ils se lisent comme deux champs
   * sans rapport.
   *
   * J'ai tourné deux fois autour du vrai problème. « nowrap » faisait déborder
   * le groupe hors de sa carte dans une colonne étroite ; j'ai alors autorisé
   * l'enroulement, ce qui a réglé le débordement et cassé la ligne unique.
   * Aucun des deux n'était la cause.
   *
   * La cause, ce sont les largeurs minimales : tant que chaque champ refuse de
   * se comprimer, la somme dépasse forcément le cadre et il faut bien que
   * quelque chose cède. En les laissant se réduire — le mois prenant ce qui
   * reste — les quatre tiennent sur une ligne dans 266 pixels comme dans 900.
   */
  flex-wrap: nowrap;
}

/*
 * Le jour et l'année sont bornés par leur contenu : deux et quatre chiffres,
 * qui ne s'abrègent pas. Le mois absorbe la place restante, et c'est lui qui
 * se rogne quand elle manque — « septembre » tronqué reste identifiable, un
 * jour tronqué ne l'est pas.
 */
/*
 * Les largeurs se mesurent en « ch », la largeur d'un chiffre dans la police du
 * champ — non en rem, qui ne dépend que de la racine.
 *
 * Un navigateur réglé sur une taille de texte minimale grossit les caractères
 * sans élargir les boîtes : « Année » se lisait « Anı » dans un champ de
 * 3,5 rem. En « ch », la boîte suit la police qu'on lui impose, quelle qu'en
 * soit l'origine — réglage d'accessibilité, préférence système, zoom du texte
 * seul. Le padding s'ajoute à part, la boîte devant contenir le texte ET son
 * espacement intérieur.
 */
.champ__inline[data-date] select[id$="_d"] {
  flex: 0 0 auto;
  width: calc(5ch + 2 * var(--e2) + 1.2em);
  min-width: 0;
  padding-inline: var(--e2);
}

.champ__inline[data-date] select[id$="_m"] {
  flex: 1 1 auto;
  /* Le mois est celui qui cède quand la place manque, mais pas au point de
     devenir illisible : « sep… » se comprend, une fenêtre de dix pixels non. */
  min-width: 6ch;
  /* Sans plafond, le mois avalait toute la largeur restante sur un
     formulaire large : « septembre » dans un champ de sept cents pixels. */
  max-width: calc(11ch + 2 * var(--e2) + 1.2em);
  padding-inline: var(--e2);
}

/*
 * La ligne ne s'étale pas non plus : une date reste un petit objet. Sa largeur
 * est celle de son contenu, bornée par la colonne — et non un nombre fixe, qui
 * étouffait le mois dès que la police grossissait : les quatre champs
 * s'élargissaient dans un cadre qui, lui, restait le même.
 */
.champ__inline[data-date] {
  width: fit-content;
  max-width: 100%;
}

.champ__inline[data-date] input[type="number"],
.champ__inline[data-date] input[id$="_y"] {
  flex: 0 0 auto;
  width: calc(6ch + 2 * var(--e2));
  min-width: 0;
  padding-inline: var(--e2);
}

.champ__inline[data-date] .date-ouvrir {
  flex: 0 0 2.25rem;
  width: 2.25rem;
  height: 2.25rem;
}

.champ__inline[data-date] select { min-width: 0; flex: 1 1 auto; }



.date-ouvrir {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  padding: 0;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  background: var(--surface);
  color: var(--texte-doux);
  cursor: pointer;
  transition: border-color var(--transition), color var(--transition);
}

.date-ouvrir svg { width: 1.15rem; height: 1.15rem; }

.date-ouvrir:hover {
  border-color: var(--vert);
  color: var(--vert);
}

.calendrier-calque {
  position: absolute;
  top: calc(100% + var(--e2));
  left: 0;
  z-index: var(--z-menu);
  width: 19rem;
  max-width: calc(100vw - 2rem);
  padding: var(--e3);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  background: var(--surface);
  box-shadow: var(--ombre-3);
}

.calendrier-calque__entete {
  display: flex;
  align-items: center;
  gap: var(--e1);
  margin-bottom: var(--e2);
}

.calendrier-calque__fleche,
.calendrier-calque__titre,
.calendrier-calque__action,
.calendrier-calque__case {
  border: 0;
  background: none;
  font: inherit;
  color: var(--texte);
  cursor: pointer;
  border-radius: var(--rayon);
  transition: background var(--transition), color var(--transition);
}

.calendrier-calque__fleche {
  width: 2rem;
  height: 2rem;
  flex: none;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--texte-doux);
}

.calendrier-calque__titre {
  flex: 1;
  padding: var(--e1) var(--e2);
  font-weight: 600;
  text-align: center;
}

.calendrier-calque__fleche:hover,
.calendrier-calque__titre:hover,
.calendrier-calque__case:hover,
.calendrier-calque__action:hover {
  background: var(--vert-clair);
  color: var(--vert-fonce);
}

.calendrier-calque__grille {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.calendrier-calque__grille--large {
  grid-template-columns: repeat(4, 1fr);
  gap: var(--e1);
}

.calendrier-calque__jour-nom {
  padding: var(--e1) 0;
  font-size: 0.6875rem;
  font-weight: 700;
  text-align: center;
  color: var(--texte-tenu);
}

.calendrier-calque__case {
  padding: var(--e2) 0;
  font-size: 0.8125rem;
  text-align: center;
}

.calendrier-calque__case.est-choisi {
  background: var(--vert);
  color: #fff;
  font-weight: 600;
}

.calendrier-calque__vide { visibility: hidden; }

.calendrier-calque__pied {
  display: flex;
  gap: var(--e2);
  margin-top: var(--e2);
  padding-top: var(--e2);
  border-top: 1px solid var(--bordure);
}

.calendrier-calque__action {
  flex: 1;
  padding: var(--e2);
  font-size: 0.8125rem;
  color: var(--texte-doux);
}


/* --------------------------------------------- frise des photos par année */

.graphe--frise {
  margin: 0;
}

/* preserveAspectRatio="none" : la frise s'étire en largeur, pas en hauteur. */
.graphe--frise svg {
  display: block;
  width: 100%;
  height: 8rem;
}

.graphe--frise .grille { stroke: var(--bordure); }
.graphe--frise .axe-texte { fill: var(--texte-tenu); font-size: 11px; }

.frise__barre { fill: var(--vert); }

/* Hors de la période choisie : présent, mais en retrait. */
.frise__barre--hors { fill: var(--bordure-forte); }

/* Rectangle transparent plein-hauteur : la cible du clic. */
.frise__zone {
  fill: transparent;
}

.graphe--frise a:hover .frise__zone {
  fill: var(--vert-clair);
}

.graphe--frise a:hover .frise__barre {
  fill: var(--vert-fonce);
}

.graphe--frise a:focus-visible .frise__zone {
  fill: var(--vert-clair);
  stroke: var(--vert);
}


/* --------------------------------------------- menu « Ajouter » d'une fiche */

.ajout { position: relative; }

.ajout__declencheur {
  gap: var(--e2);
  cursor: pointer;
}

.ajout__declencheur svg { width: 1rem; height: 1rem; }
.ajout__chevron { transition: transform var(--transition); }
.ajout__bascule:checked ~ .ajout__declencheur .ajout__chevron { transform: rotate(180deg); }

.ajout__calque {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + var(--e2));
  z-index: var(--z-menu);
  min-width: 12rem;
  padding: var(--e2);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
}

.ajout__bascule:checked ~ .ajout__calque { display: block; }

.ajout__lien {
  display: block;
  padding: var(--e3);
  margin-top: 2px;
  border-radius: var(--rayon);
  color: var(--texte-doux);
  font-size: 0.9375rem;
  text-decoration: none;
}

.ajout__lien:hover { background: var(--surface-2); color: var(--texte); }

/* ------------------------------------------------------------ messagerie */

.fils { display: flex; flex-direction: column; gap: var(--e2); }

.fil {
  display: flex;
  align-items: center;
  gap: var(--e4);
  padding: var(--e4);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  background: var(--surface);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.fil:hover { border-color: var(--vert); box-shadow: var(--ombre-1); color: inherit; }

.fil--nouveau { border-left: 3px solid var(--vert); }

.fil__portraits { display: flex; flex: none; }
.fil__portraits > * + * { margin-left: -0.6rem; }

.fil__portrait {
  width: 2.125rem;
  height: 2.125rem;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid var(--surface);
  background: var(--surface-2);
}

.fil__portrait--initiales {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--texte-doux);
}

.fil__texte { min-width: 0; flex: 1; }

.fil__personnes { display: block; font-weight: 600; }
.fil--nouveau .fil__personnes { color: var(--vert-fonce); }

.fil__sujet { display: block; font-size: 0.875rem; color: var(--texte-doux); }

.fil__extrait {
  display: block;
  font-size: 0.875rem;
  color: var(--texte-tenu);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.fil__date {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--e2);
  font-size: 0.75rem;
  color: var(--texte-tenu);
  white-space: nowrap;
}

.fil__pastille,
.moi__pastille {
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--vert);
}

.moi__compteur {
  float: right;
  min-width: 1.25rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--vert);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  text-align: center;
}

/* Aperçu d'un échange, sur la fiche d'une personne. */
.echange {
  display: block;
  padding: var(--e3);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface-2);
  text-decoration: none;
  color: inherit;
}

.echange:hover { border-color: var(--vert); color: inherit; }

.echange__qui {
  display: block;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--vert-fonce);
}

.echange__texte { display: block; font-size: 0.875rem; }

.echange__date {
  display: block;
  margin-top: var(--e1);
  font-size: 0.6875rem;
  color: var(--texte-tenu);
}

/* ---------------------------------------------------------- discussion */

.discussion { display: flex; flex-direction: column; gap: var(--e4); }

.bulle { display: flex; gap: var(--e3); align-items: flex-end; }
.bulle--moi { flex-direction: row-reverse; }

.bulle__portrait {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-2);
}

.bulle__portrait--initiales {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--texte-doux);
}

.bulle__corps {
  max-width: 34rem;
  padding: var(--e3) var(--e4);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  background: var(--surface);
}

/* Ses propres messages se distinguent par la couleur, pas seulement le côté. */
.bulle--moi .bulle__corps {
  background: var(--vert-clair);
  border-color: var(--vert-bord);
}

.bulle__nom {
  margin: 0 0 var(--e1);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--vert-fonce);
}

.bulle__texte { margin: 0; }

.bulle__date {
  margin: var(--e1) 0 0;
  font-size: 0.6875rem;
  color: var(--texte-tenu);
}

.bulle--moi .bulle__date { text-align: right; }


/* ------------------------------------------- carte semée de points (Agora) */

.carte-dessin--points .carte__fond {
  fill: var(--surface-2);
  stroke: var(--bordure);
  stroke-width: 0.6;
}

.carte-dessin--vise { cursor: crosshair; }

.carte__halo {
  fill: var(--vert);
  opacity: 0.18;
}

.carte__pastille {
  fill: var(--vert);
  stroke: var(--surface);
  stroke-width: 1.5;
}

.carte__point:hover .carte__halo { opacity: 0.35; }
.carte__point:hover .carte__pastille { fill: var(--vert-fonce); }

.carte__point:focus-visible .carte__pastille {
  stroke: var(--texte);
  stroke-width: 2.5;
}


/* --------------------------------------------- diagnostic des courriels */

.controle {
  display: flex;
  gap: var(--e3);
  align-items: flex-start;
  padding: var(--e3) 0;
  border-bottom: 1px solid var(--bordure);
}

.controle:last-child { border-bottom: 0; }

.controle__icone {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-weight: 700;
  font-size: 0.8125rem;
}

.controle--ok .controle__icone        { background: var(--succes-fond); color: var(--succes); }
.controle--attention .controle__icone { background: var(--abricot-clair); color: var(--abricot); }
.controle--erreur .controle__icone    { background: var(--erreur-fond); color: var(--erreur); }

.controle__detail {
  display: block;
  font-size: 0.875rem;
  color: var(--texte-doux);
  word-break: break-word;
}

/* Le dialogue avec le serveur : lisible tel quel, sans mise en forme. */
.dialogue {
  margin: 0;
  padding: var(--e4);
  border-radius: var(--rayon);
  background: var(--surface-2);
  border: 1px solid var(--bordure);
  font: 0.8125rem/1.6 var(--mono);
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

.dialogue__envoi   { color: var(--texte-doux); }
.dialogue__reponse { color: var(--vert-fonce); }

/* ------------------------------------------------------- suivi des erreurs */

.erreur { border-left: 3px solid var(--bordure-forte); }
.erreur--active,
.erreur--revenue  { border-left-color: var(--erreur); }
.erreur--corrigee { border-left-color: var(--succes); opacity: 0.75; }

.erreur summary {
  cursor: pointer;
  color: var(--texte-doux);
}

/* ------------------------------------------------- en-tête d'une fiche */

.fiche-entete {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  /* Serré : quand les actions passent sous le nom, cet écart est tout ce qui
     les en sépare, et il n'a pas à faire une respiration. */
  gap: var(--e3);
}

.fiche-entete__identite {
  display: flex;
  align-items: center;
  gap: var(--e4);
  min-width: 0;
}

.fiche-entete__portrait {
  width: 4.5rem;
  height: 4.5rem;
  flex: none;
  /* Arrondi franc plutôt que cercle : la charte du site est aux grands
     rayons, et un portrait carré arrondi recadre moins les visages. */
  border-radius: var(--rayon-lg);
  object-fit: cover;
  background: var(--surface-2);
  box-shadow: var(--ombre-1);
}

.fiche-entete__portrait--initiales {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--texte-doux);
}

.fiche-entete__texte { min-width: 0; }

.fiche-entete__parente {
  margin-top: var(--e1);
  font-size: 0.9375rem;
  color: var(--vert-fonce);
}

/*
 * LES ACTIONS SUR UNE SEULE LIGNE, « Modifier » compris.
 *
 * Elles s'empilaient : « Modifier » seul au-dessus, le reste en dessous. Sur un
 * écran où le nom et les boutons ne tiennent pas côte à côte — la plupart des
 * portables et beaucoup d'écrans de bureau — le bloc passe sous le nom, et
 * cette pile ajoutait une ligne entière entre le visage et les boutons :
 * soixante-quatre pixels de vide, pour un bouton seul aligné à droite.
 *
 * Une ligne unique qui s'enroule au besoin. « Modifier » y reste le premier,
 * détaché du reste par sa couleur, et l'on gagne la hauteur d'un bouton.
 */
.fiche-entete__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--e2);
  /*
   * « align-items » ne suffisait pas. Sur un nom long, le bloc d'identité
   * occupe toute la largeur et les actions passent à la ligne suivante ; seules
   * sur cette ligne, « justify-content: space-between » les ramenait à gauche,
   * et le bouton Modifier flottait au milieu. La marge automatique les tient à
   * droite quel que soit le retour à la ligne.
   */
  margin-left: auto;
}

.fiche-entete__actions .rangee {
  flex-wrap: wrap;
  justify-content: flex-end;
}

.fiche-entete__actions .bouton svg { width: 1rem; height: 1rem; }

@media (max-width: 48rem) {
  /* Sur un téléphone, la colonne reprend ses droits : des boutons pleine
     largeur se visent au pouce, une ligne de vignettes non. */
  .fiche-entete__actions {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
}

/* --------------------------------------------- titre d'une fiche */

.titre-personne {
  display: flex;
  align-items: center;
  gap: var(--e4);
  min-width: 0;
}

.titre-personne__portrait {
  width: 3.5rem;
  height: 3.5rem;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-2);
  border: 2px solid var(--surface);
  box-shadow: var(--ombre-1);
}

.titre-personne__portrait--initiales {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--texte-doux);
}

/* ---------------------------------------------- onglets de filtrage */

.onglets-filtre {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
}

.onglets-filtre__lien {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  padding: var(--e2) var(--e4);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  background: var(--surface);
  color: var(--texte-doux);
  font-size: 0.9375rem;
  text-decoration: none;
  transition: border-color var(--transition), color var(--transition);
}

.onglets-filtre__lien:hover { border-color: var(--vert); color: var(--vert-fonce); }

.onglets-filtre__lien.est-actif {
  background: var(--vert);
  border-color: var(--vert);
  color: #fff;
  font-weight: 600;
}

.onglets-filtre__nombre {
  min-width: 1.5rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--texte-doux);
  font-size: 0.8125rem;
  font-weight: 700;
  text-align: center;
}

.onglets-filtre__lien.est-actif .onglets-filtre__nombre {
  background: rgb(255 255 255 / 0.25);
  color: #fff;
}

/* En sombre, `a { color: var(--vert) }` l'emporte en spécificité sur la classe
   et repeignait le libellé en vert sur le vert du fond : l'onglet actif
   devenait illisible. Même traitement que .barre__lien[aria-current="page"],
   qui repose sur le même aplat. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .onglets-filtre__lien.est-actif { color: #10221a; }

  :root:not([data-theme="light"]) .onglets-filtre__lien.est-actif .onglets-filtre__nombre {
    background: rgb(255 255 255 / 0.32);
    color: #10221a;
  }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .onglets-filtre__lien.est-actif { color: #10221a; }

:root[data-theme="dark"] .onglets-filtre__lien.est-actif .onglets-filtre__nombre {
  background: rgb(255 255 255 / 0.32);
  color: #10221a;
}

/* --------------------------------------------------------- émoticônes */

.emoticones { position: relative; margin-top: var(--e2); }

.emoticones__declencheur {
  padding: var(--e1) var(--e3);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  background: var(--surface);
  font-size: 1.125rem;
  line-height: 1.2;
  cursor: pointer;
}

.emoticones__declencheur:hover { border-color: var(--vert); }

.emoticones__choix {
  position: absolute;
  bottom: calc(100% + var(--e2));
  left: 0;
  z-index: var(--z-menu);
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 2px;
  width: max-content;
  max-width: min(24rem, 90vw);
  padding: var(--e2);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  background: var(--surface);
  box-shadow: var(--ombre-3);
}

.emoticones__item {
  padding: var(--e1);
  border: 0;
  border-radius: var(--rayon);
  background: none;
  font-size: 1.25rem;
  line-height: 1.2;
  cursor: pointer;
}

.emoticones__item:hover { background: var(--vert-clair); }

@media (max-width: 30rem) {
  .emoticones__choix { grid-template-columns: repeat(6, 1fr); }
}

/* ------------------------------------------------------ boîte à idées */

.idee--faite   { opacity: 0.7; }
.idee--ecartee { opacity: 0.55; }

.idee__corps { display: flex; gap: var(--e4); align-items: flex-start; }
.idee__texte { min-width: 0; flex: 1; }
.idee__soutien { flex: none; }

.idee__vote {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 3.25rem;
  padding: var(--e2);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  background: var(--surface);
  color: var(--texte-doux);
  cursor: pointer;
  transition: border-color var(--transition), color var(--transition);
}

.idee__vote:hover { border-color: var(--vert); color: var(--vert-fonce); }

.idee__vote.est-soutenue {
  background: var(--vert-clair);
  border-color: var(--vert);
  color: var(--vert-fonce);
}

.idee__fleche { font-size: 0.75rem; line-height: 1; }
.idee__nombre { font-size: 1.0625rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* La réponse de l'administration se distingue de la proposition. */
.idee__reponse {
  padding: var(--e3);
  border-left: 3px solid var(--vert);
  background: var(--surface-2);
  border-radius: var(--rayon);
  font-size: 0.9375rem;
}

/* --------------------------------------------------- connexion Google */

/*
 * Un « ou » centré, sans filet d'aucune sorte. Il en portait trois : deux qui
 * l'encadraient, et un troisième par-dessous — celui-là venu de la classe
 * utilitaire « separateur », qui sert à séparer les lignes d'une liste et dont
 * ce bloc partageait le nom par hasard. Aucun des trois ne séparait quoi que ce
 * soit que le mot ne dise déjà, et ils prenaient de la hauteur sur l'écran où
 * elle est le plus comptée.
 */
.ou {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: var(--e4) 0;
  color: var(--texte-tenu);
  font-size: 0.875rem;
}

/* Le bouton reprend la charte de Google, qui l'impose pour son usage. */
.bouton-tiers,
.bouton-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e3);
  width: 100%;
  min-height: 2.75rem;
  padding: var(--e2) var(--e5);
  border: 1px solid #dadce0;
  border-radius: var(--rayon);
  background: #ffffff;
  color: #3c4043;
  font: 600 0.9375rem/1.4 var(--sans);
  text-decoration: none;
  transition: box-shadow var(--transition), background var(--transition);
}

/*
 * L'écart entre deux boutons de connexion tiers. Il tenait auparavant à un
 * « margin-bottom » posé sur .bouton-tiers seul : le jour où Google est passé
 * devant, la marge s'est retrouvée sous le dernier bouton et les deux se sont
 * collés. La règle porte maintenant sur la succession, quel que soit l'ordre.
 */
.bouton-tiers + .bouton-tiers,
.bouton-tiers + .bouton-google,
.bouton-google + .bouton-tiers,
.bouton-google + .bouton-google {
  margin-top: var(--e3);
}

.bouton-tiers:hover,
.bouton-google:hover {
  background: #f8f9fa;
  box-shadow: var(--ombre-1);
  color: #3c4043;
}

/* -------------------------------------------------------------- boutons */

.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e2);
  min-height: 2.75rem;
  padding: var(--e2) var(--e5);
  border: 1px solid transparent;
  border-radius: var(--rayon);
  background: var(--vert);
  color: #fff;
  font: 600 0.9375rem/1.2 var(--sans);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}

.bouton:hover { background: var(--vert-fonce); color: #fff; }

.bouton:disabled,
.bouton[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

.bouton--secondaire {
  background: var(--surface);
  color: var(--texte);
  border-color: var(--bordure-forte);
}

.bouton--secondaire:hover {
  background: var(--surface-2);
  color: var(--texte);
  border-color: var(--vert);
}

.bouton--discret {
  background: transparent;
  color: var(--texte-doux);
  border-color: transparent;
  padding-inline: var(--e3);
}

.bouton--discret:hover { background: var(--surface-2); color: var(--texte); }

.bouton--danger { background: var(--erreur); }
.bouton--danger:hover { background: #7d241a; color: #fff; }

.bouton--petit { min-height: 2.25rem; padding: var(--e1) var(--e3); font-size: 0.8125rem; }

.bouton__icone { width: 1.125rem; height: 1.125rem; flex-shrink: 0; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bouton { color: #1a1510; }
  :root:not([data-theme="light"]) .bouton:hover { color: #1a1510; }
  :root:not([data-theme="light"]) .bouton--secondaire { color: var(--texte); }
  :root:not([data-theme="light"]) .bouton--secondaire:hover { color: var(--texte); }
  :root:not([data-theme="light"]) .bouton--danger { color: #1a1510; }
  :root:not([data-theme="light"]) .bouton--danger:hover { background: #d98577; color: #1a1510; }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .bouton { color: #1a1510; }
  :root[data-theme="dark"] .bouton:hover { color: #1a1510; }
  :root[data-theme="dark"] .bouton--secondaire { color: var(--texte); }
  :root[data-theme="dark"] .bouton--secondaire:hover { color: var(--texte); }
  :root[data-theme="dark"] .bouton--danger { color: #1a1510; }
  :root[data-theme="dark"] .bouton--danger:hover { background: #d98577; color: #1a1510; }


/* ------------------------------------------------------------ formulaires */

.champ { margin-bottom: var(--e4); }

.champ__label {
  display: block;
  margin-bottom: var(--e2);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--texte-doux);
}

.champ__aide {
  display: block;
  margin-top: var(--e1);
  font-size: 0.8125rem;
  color: var(--texte-tenu);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="tel"],
input[type="number"],
input[type="date"],
input[type="file"],
select,
textarea {
  width: 100%;
  min-height: 2.75rem;
  padding: var(--e2) var(--e3);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  background: var(--surface);
  color: var(--texte);
  /* 16px minimum : en dessous, iOS zoome au focus. */
  font: 400 1rem/1.5 var(--sans);
  transition: border-color var(--transition), box-shadow var(--transition);
}

textarea { min-height: 8rem; resize: vertical; }

input:hover,
select:hover,
textarea:hover { border-color: var(--vert); }

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--vert);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--vert) 25%, transparent);
}

input::placeholder,
textarea::placeholder { color: var(--texte-tenu); opacity: 1; }

select {
  appearance: none;
  padding-right: var(--e6);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236f6558'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--e3) center;
  background-size: 1rem;
}

.champ__inline {
  display: flex;
  gap: var(--e2);
  align-items: center;
  flex-wrap: wrap;
}

/* Jour / mois / année sur une seule ligne, chacun à sa largeur utile.
   Les sélecteurs sont qualifiés par leur type : sinon la règle générique
   « input[...] { width: 100% } », de spécificité supérieure à une simple
   classe, reprend le dessus et l'année occupe toute la largeur. */
.champ__inline select,
.champ__inline input[type="number"],
.champ__inline input[type="text"] {
  width: auto;
  flex: 0 0 auto;
}

.champ__inline select { min-width: 5.5rem; }

/* Le mois porte un libellé long (« septembre ») : il lui faut plus de place. */
.champ__inline select[id$="_m"] { min-width: 8rem; }

.champ__inline input[type="number"] { width: 6rem; }

/* Cases et boutons radio : la zone cliquable englobe le libellé. */
.case {
  display: flex;
  align-items: flex-start;
  gap: var(--e3);
  padding: var(--e2) 0;
  min-height: 2.75rem;
  cursor: pointer;
}

.case input[type="checkbox"],
.case input[type="radio"] {
  width: 1.25rem;
  height: 1.25rem;
  min-height: 0;
  margin-top: 0.1875rem;
  accent-color: var(--vert);
  flex-shrink: 0;
  cursor: pointer;
}

.case__texte { font-size: 0.9375rem; line-height: 1.5; }

fieldset {
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: var(--e4);
  margin: 0 0 var(--e5);
}

legend {
  padding-inline: var(--e2);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--texte-doux);
}

.formulaire__actions {
  display: flex;
  gap: var(--e3);
  flex-wrap: wrap;
  padding-top: var(--e4);
  border-top: 1px solid var(--bordure);
}

/* --------------------------------------- champ mot de passe avec œil */

.champ-mdp { position: relative; }

/* De la place pour le bouton, sans que le texte passe dessous. */
.champ-mdp input { padding-right: 3rem; }

.champ-mdp__oeil {
  position: absolute;
  top: 0;
  right: 0;
  /* 44×44 : cible tactile réglementaire, alignée sur la hauteur du champ. */
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 0;
  background: none;
  color: var(--texte-tenu);
  cursor: pointer;
  border-radius: var(--rayon);
  transition: color var(--transition);
}

.champ-mdp__oeil:hover { color: var(--vert); }

.champ-mdp__oeil svg { width: 1.25rem; height: 1.25rem; }

/* ------------------------------------------- autocomplétion et jetons */

.suggestions-enveloppe { position: relative; }

.suggestions {
  position: absolute;
  z-index: var(--z-menu);
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  margin: 0;
  padding: var(--e1);
  list-style: none;
  max-height: 17rem;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-3);
}

.suggestions li {
  padding: var(--e2) var(--e3);
  min-height: 2.75rem;
  display: flex;
  align-items: center;
  border-radius: var(--rayon);
  font-size: 0.9375rem;
  cursor: pointer;
}

.suggestions li:hover,
.suggestions li[aria-selected="true"] {
  background: var(--surface-2);
  color: var(--vert-fonce);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .suggestions li:hover, :root:not([data-theme="light"]) .suggestions li[aria-selected="true"] { color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .suggestions li:hover, :root[data-theme="dark"] .suggestions li[aria-selected="true"] { color: var(--vert); }


.jetons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
  margin-top: var(--e3);
  min-height: 1.5rem;
}

.jeton__retirer {
  border: 0;
  background: none;
  color: inherit;
  font-size: 1.125rem;
  line-height: 1;
  padding: 0 0 0 var(--e1);
  cursor: pointer;
}

.jeton__retirer:hover { color: var(--erreur); }

/* ---------------------------------------------------------------- alertes */

.alerte {
  display: flex;
  align-items: flex-start;
  gap: var(--e3);
  padding: var(--e3) var(--e4);
  border-radius: var(--rayon);
  border: 1px solid;
  margin-bottom: var(--e4);
  font-size: 0.9375rem;
}

.alerte__icone { width: 1.25rem; height: 1.25rem; flex-shrink: 0; margin-top: 0.125rem; }

.alerte--succes { background: var(--succes-fond); border-color: var(--succes); color: var(--succes); }
.alerte--erreur { background: var(--erreur-fond); border-color: var(--erreur); color: var(--erreur); }
.alerte--info   { background: var(--info-fond);   border-color: var(--info);   color: var(--info); }

/* ---------------------------------------------------------------- tableaux */

.tableau-defilant {
  /* Les tableaux larges défilent dans leur cadre, jamais la page entière. */
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

caption {
  padding: var(--e3) var(--e4);
  text-align: left;
  font-size: 0.875rem;
  color: var(--texte-tenu);
}

th {
  text-align: left;
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--texte-tenu);
  background: var(--surface-2);
  padding: var(--e3) var(--e4);
  border-bottom: 1px solid var(--bordure);
  white-space: nowrap;
}

td {
  padding: var(--e3) var(--e4);
  border-bottom: 1px solid var(--bordure);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--surface-2); }

/* --------------------------------------------------------------- étiquettes */

.etiquette {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  padding: 0.125rem var(--e2);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: var(--surface-2);
  color: var(--texte-doux);
  border: 1px solid var(--bordure);
  white-space: nowrap;
}

.etiquette--terre { background: var(--vert-clair); color: var(--vert-fonce); border-color: var(--vert); }
.etiquette--olive { background: var(--succes-fond); color: var(--succes); border-color: var(--succes); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .etiquette--terre { background: var(--surface-2); color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .etiquette--terre { background: var(--surface-2); color: var(--vert); }


/* -------------------------------------------------------------- compteurs */

/* Bandeau d'accueil : un aplat chaleureux qui donne le ton dès l'ouverture. */
.bandeau {
  display: grid;
  gap: var(--e5);
  padding: var(--e5);
  margin-bottom: var(--e6);
  border-radius: var(--rayon-lg);
  border: 1px solid var(--bordure);
  background:
    radial-gradient(circle at 12% 18%, color-mix(in srgb, var(--vert) 16%, transparent), transparent 55%),
    radial-gradient(circle at 88% 78%, color-mix(in srgb, var(--bleu) 18%, transparent), transparent 55%),
    var(--surface);
}

@media (min-width: 56rem) {
  .bandeau {
    /*
     * Trois colonnes : le titre prend ce qui reste, les compteurs et la photo
     * sont dimensionnés par leur contenu. La photo tombait sous le titre parce
     * que la grille n'en comptait que deux — elle passait donc à la ligne
     * suivante, en pleine largeur.
     */
    grid-template-columns: 1fr auto auto;
    align-items: center;
  }

  /* Dans le bandeau, les compteurs restent côte à côte : la colonne de
     droite est étroite et la règle auto-fit les empilerait. */
  .bandeau .compteurs {
    grid-template-columns: repeat(3, minmax(7rem, 1fr));
  }
}

.bandeau__titre { margin: 0 0 var(--e1); }

.bandeau__date {
  margin: 0;
  color: var(--texte-doux);
  font-size: 0.9375rem;
}

.compteurs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr));
  gap: var(--e3);
}

.compteur {
  display: block;
  padding: var(--e4);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-left: 4px solid var(--bordure-forte);
  border-radius: var(--rayon-lg);
  text-align: center;
  text-decoration: none;
  color: inherit;
  transition: border-color var(--transition), box-shadow var(--transition);
}

a.compteur:hover {
  box-shadow: var(--ombre-2);
  color: inherit;
}

/* Chaque compteur porte sa propre couleur : c'est ce qui redonne de la vie
   à la page, et le libellé reste le porteur du sens. */
/*
 * Les compteurs puisent dans les mêmes variables que les graphiques : une
 * page où les tuiles de tête et les courbes ne parlent pas la même langue
 * paraît assemblée de bric et de broc. Les valeurs des deux modes suivent
 * automatiquement.
 */
.compteur--personnes { border-left-color: var(--gr-bleu); }
.compteur--photos    { border-left-color: var(--gr-orange); }
.compteur--unions    { border-left-color: var(--gr-violet); }
.compteur--noms      { border-left-color: var(--gr-emeraude); }
.compteur--prenoms   { border-left-color: var(--gr-rouge); }
.compteur--age       { border-left-color: var(--gr-bleu); }

.compteur--personnes .compteur__valeur { color: var(--gr-bleu); }
.compteur--photos    .compteur__valeur { color: var(--gr-orange); }
.compteur--unions    .compteur__valeur { color: var(--gr-violet); }
.compteur--noms      .compteur__valeur { color: var(--gr-emeraude); }
.compteur--prenoms   .compteur__valeur { color: var(--gr-rouge); }
.compteur--age       .compteur__valeur { color: var(--gr-bleu); }


/* Rubriques du bloc « Aujourd'hui » : un liseré coloré par nature
   d'événement, doublé du libellé — la couleur n'est jamais seule porteuse. */
.evt {
  font-size: 0.9375rem;
  margin: var(--e4) 0 var(--e2);
  padding-left: var(--e3);
  border-left: 3px solid var(--bordure-forte);
}

.evt--fete    { border-left-color: #2e7d4f; }
.evt--anniv   { border-left-color: #b0561f; }
.evt--mariage { border-left-color: #d97b28; }
.evt--deces   { border-left-color: var(--bordure-forte); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .evt--fete { border-left-color: #519f6f; }
  :root:not([data-theme="light"]) .evt--anniv { border-left-color: #c8783a; }
  :root:not([data-theme="light"]) .evt--mariage { border-left-color: #e9a463; }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .evt--fete { border-left-color: #519f6f; }
  :root[data-theme="dark"] .evt--anniv { border-left-color: #c8783a; }
  :root[data-theme="dark"] .evt--mariage { border-left-color: #e9a463; }


.carte--jour { border-left: 4px solid var(--vert); }

.compteur__valeur {
  display: block;
  font-family: var(--serif);
  font-size: clamp(1.75rem, 1.4rem + 1.4vw, 2.25rem);
  font-weight: 600;
  line-height: 1.1;
  /*
   * Le vert n'est qu'un défaut, pour un compteur sans teinte propre. Les
   * surcharges de mode qui figuraient ici l'imposaient à tous : plus
   * spécifiques et plus tardives, elles écrasaient la couleur de chaque
   * compteur, si bien que les bordures se coloraient et pas les nombres.
   * Les variables --gr-… savent déjà s'adapter au mode ; il n'y a plus rien
   * à corriger après coup.
   */
  color: var(--vert-fonce);
  font-variant-numeric: tabular-nums;
}


.compteur__libelle {
  font-size: 0.8125rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--texte-tenu);
}

/* ------------------------------------------------------------- calendrier */

.calendrier { width: 100%; border-collapse: collapse; }

.calendrier th {
  padding: var(--e2) 0;
  text-align: center;
  font-size: 0.75rem;
  background: transparent;
  border: 0;
}

.calendrier td {
  padding: 0;
  border: 1px solid var(--bordure);
  text-align: center;
}

.calendrier__jour {
  display: grid;
  place-items: center;
  /* Cible tactile suffisante même sur la grille dense du calendrier. */
  min-height: 2.75rem;
  width: 100%;
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  color: var(--texte);
  text-decoration: none;
  cursor: pointer;
}

.calendrier__jour:hover { background: var(--surface-2); }
.calendrier__jour--hors-mois { color: var(--texte-tenu); opacity: 0.5; }

.calendrier__jour--aujourdhui {
  font-weight: 700;
  box-shadow: inset 0 0 0 2px var(--vert);
}

/* Un jour porteur d'événement est signalé par un point ET par son title. */
.calendrier__jour--evenement { background: var(--vert-clair); color: var(--vert-fonce); font-weight: 600; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .calendrier__jour--evenement { background: var(--surface-2); color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .calendrier__jour--evenement { background: var(--surface-2); color: var(--vert); }


.calendrier__point {
  display: block;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  margin-top: 1px;
}

/* --------------------------------------------------------------- forum */

.message {
  padding: var(--e5);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
}

.message__entete {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding-bottom: var(--e3);
  margin-bottom: var(--e3);
  border-bottom: 1px solid var(--bordure);
  flex-wrap: wrap;
}

.message__sujet { font-family: var(--serif); font-size: 1.125rem; font-weight: 600; }
.message__corps { color: var(--texte); overflow-wrap: anywhere; }
.message__corps p:last-child { margin-bottom: 0; }

/* ------------------------------------------------------- barres de mesure */

.mesure { display: grid; gap: var(--e2); }

.mesure__ligne {
  display: grid;
  grid-template-columns: minmax(6rem, 10rem) 1fr auto;
  align-items: center;
  gap: var(--e3);
  font-size: 0.875rem;
}

/* La barre est un SVG : sa largeur est une donnée, et la politique de
   sécurité du contenu interdit un style calculé côté serveur. Les attributs
   géométriques SVG ne sont pas du CSS et passent donc sans exception. */
.mesure__piste {
  display: block;
  width: 100%;
  height: 0.625rem;
  overflow: visible;
}

.mesure__piste .fond  { fill: var(--surface-2); }
.mesure__piste .barre { fill: var(--vert); }

.mesure__valeur { font-variant-numeric: tabular-nums; color: var(--texte-tenu); }

.mesure__ligne--active span:first-child { font-weight: 600; }

/* --------------------------------------------------------- graphiques */

.figure {
  margin: 0;
}

.figure__titre {
  font-size: 0.9375rem;
  font-weight: 600;
  margin-bottom: var(--e1);
}

.figure__note {
  font-size: 0.8125rem;
  color: var(--texte-tenu);
  margin: var(--e2) 0 0;
}

.graphe {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  /*
   * Le SVG suit la largeur de son cadre : dans une carte pleine largeur, un
   * repère de 640 × 150 donnait un graphique de trois cents pixels de haut
   * pour douze colonnes. Le plafond le ramène à une proportion lisible ; les
   * graphiques des colonnes étroites, eux, n'atteignent jamais cette limite.
   */
  max-height: 17rem;
}

/*
 * LES TEINTES DES GRAPHIQUES.
 *
 * Cinq couleurs, choisies par scripts/validate_palette.js et non à l'œil.
 * Chacune passe la bande de clarté de son mode, le plancher de chroma et le
 * contraste sur la surface — en clair comme en sombre, où les valeurs sont
 * choisies séparément et non éclaircies mécaniquement.
 *
 * Une distinction qui décide de tout : ces teintes n'identifient pas des
 * séries qu'on compare, elles distinguent des SECTIONS. Deux d'entre elles ne
 * se rencontrent jamais dans un même repère — sauf la pyramide des âges, seul
 * graphique à deux séries. C'est donc cette paire-là, et elle seule, qui a été
 * validée sur tous les critères de séparation : bleu contre orange, ΔE 21 en
 * protanopie, 25 en vision normale, et une légende par-dessus, car l'identité
 * ne se confie jamais à la couleur seule.
 *
 * Le contrôle « toutes paires » échouerait sur bleu/violet — ΔE 2,5 en
 * protanopie. C'est sans conséquence ici : ils sont à trois écrans l'un de
 * l'autre. Le mentionner plutôt que de le taire évite qu'on les rapproche un
 * jour dans un même graphique sans y penser.
 */

:root {
  --gr-bleu:     #2f62a8;
  --gr-orange:   #c25a1e;
  --gr-violet:   #7d4ea3;
  --gr-rouge:    #a4342f;
  --gr-emeraude: #0e7f5c;

  /* La teinte en service, qu'une section peut remplacer. */
  --gr-trait:  var(--gr-bleu);
  --gr-trait-2: var(--gr-orange);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --gr-bleu:     #4d8cc9;
    --gr-orange:   #cd7433;
    --gr-violet:   #a077cc;
    --gr-rouge:    #cc5f5a;
    --gr-emeraude: #3d9e7c;
  }
}

:root[data-theme="dark"] {
  --gr-bleu:     #4d8cc9;
  --gr-orange:   #cd7433;
  --gr-violet:   #a077cc;
  --gr-rouge:    #cc5f5a;
  --gr-emeraude: #3d9e7c;
}

/* Une section choisit sa teinte ; tout ce qu'elle contient suit. */
[data-teinte="bleu"]     { --gr-trait: var(--gr-bleu); }
[data-teinte="orange"]   { --gr-trait: var(--gr-orange); }
[data-teinte="violet"]   { --gr-trait: var(--gr-violet); }
[data-teinte="rouge"]    { --gr-trait: var(--gr-rouge); }
[data-teinte="emeraude"] { --gr-trait: var(--gr-emeraude); }

.graphe .marque    { fill: var(--gr-trait); }
.graphe .marque--f { fill: var(--gr-trait); }
.graphe .marque--h { fill: var(--gr-trait-2); }

/* --------------------------------------------------------- courbe */

.graphe .courbe__aire  { fill: var(--gr-trait); opacity: 0.14; }
.graphe .courbe__trait { fill: none; stroke: var(--gr-trait); stroke-width: 2; stroke-linejoin: round; }

/* Anneau de la couleur du fond : le point reste net là où la courbe passe. */
.graphe .courbe__point { fill: var(--gr-trait); stroke: var(--surface); stroke-width: 2; }

/* ---------------------------------------------------------- jauge */

.jauges {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--e5);
}

.jauge__entete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e3);
  margin-bottom: var(--e2);
}

.jauge__titre  { font-size: 0.9375rem; font-weight: 600; }
.jauge__valeur { font-size: 1.125rem; font-weight: 700; color: var(--gr-trait); font-variant-numeric: tabular-nums; }

.jauge__piste { display: block; width: 100%; height: 0.5rem; }
.jauge__fond  { fill: var(--surface-2); }
.jauge__part  { fill: var(--gr-trait); }

.jauge__note { margin: var(--e2) 0 0; font-size: 0.8125rem; color: var(--texte-tenu); }

/*
 * Les barres horizontales des palmarès suivent la teinte de leur carte.
 *
 * La règle est restreinte aux cartes qui déclarent une teinte : sans cela
 * elle repeignait aussi la barre d'avancement du formulaire de fiche, qui
 * n'a rien d'un graphique et doit rester verte comme le reste du site.
 */
[data-teinte] .mesure__piste .barre { fill: var(--gr-trait); }

.graphe .grille      { stroke: var(--bordure); stroke-width: 1; }
.graphe .axe-texte   { fill: var(--texte-tenu); font-size: 10px; }
.graphe .val-texte   { fill: var(--texte-doux); font-size: 10px; font-weight: 600; }

.legende {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e4);
  margin-top: var(--e3);
  font-size: 0.8125rem;
  color: var(--texte-doux);
}

.legende__item { display: inline-flex; align-items: center; gap: var(--e2); }

.legende__puce {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 3px;
  flex-shrink: 0;
}

/*
 * Les puces de la légende reprennent les variables des marques : une légende
 * qui ne s'accorde pas au graphique qu'elle explique est pire qu'aucune.
 */
.legende__puce--f { background: var(--gr-trait); }
.legende__puce--h { background: var(--gr-trait-2); }


/* Vue tableau : toute donnée d'un graphique reste accessible en texte. */
.figure details summary {
  cursor: pointer;
  font-size: 0.8125rem;
  color: var(--texte-doux);
  margin-top: var(--e3);
}

.figure details[open] summary { margin-bottom: var(--e3); }

/* --------------------------------------------------------------- divers */

.fil-ariane {
  font-size: 0.875rem;
  color: var(--texte-tenu);
  margin-bottom: var(--e4);
}

.fil-ariane a { color: var(--texte-doux); }

.vide {
  padding: var(--e7) var(--e4);
  text-align: center;
  color: var(--texte-tenu);
  border: 1px dashed var(--bordure-forte);
  border-radius: var(--rayon-lg);
}

.vide__titre { font-family: var(--serif); font-size: 1.125rem; color: var(--texte-doux); margin-bottom: var(--e2); }

.pagination {
  display: flex;
  gap: var(--e2);
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  margin-top: var(--e6);
}

.pagination__lien {
  display: inline-grid;
  place-items: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding-inline: var(--e2);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  color: var(--texte-doux);
  text-decoration: none;
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}

.pagination__lien:hover { background: var(--surface-2); border-color: var(--vert); }

.pagination__lien[aria-current="page"] {
  background: var(--vert);
  border-color: var(--vert);
  color: #fff;
  font-weight: 600;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pagination__lien[aria-current="page"] { color: #1a1510; }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .pagination__lien[aria-current="page"] { color: #1a1510; }


.pied {
  padding-block: var(--e6);
  margin-top: var(--e8);
  border-top: 1px solid var(--bordure);
  font-size: 0.875rem;
  color: var(--texte-tenu);
}

/* Écrans de connexion : mise en page centrée sans navigation */
.ecran-simple {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--e5) var(--e4);
}

.ecran-simple__boite {
  width: 100%;
  max-width: 24rem;
}

.ecran-simple__marque {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e2);
  margin-bottom: var(--e5);
  text-align: center;
}

.ecran-simple__marque svg { width: 3rem; height: 3rem; color: var(--vert); }

/*
 * Le logo était servi à sa taille naturelle : deux cent vingt pixels, soit un
 * tiers de la hauteur utile d'un téléphone, qui repoussaient hors de l'écran les
 * façons de se connecter autres que le mot de passe. Il reste reconnaissable
 * bien plus petit — et il ne sert qu'à dire où l'on est.
 */
.ecran-simple__marque img {
  width: min(7.5rem, 34vw);
  height: auto;
}

/* Sur un écran court — un téléphone couché, une petite fenêtre — on rogne
   encore : c'est là que la place manque le plus. */
@media (max-height: 40rem) {
  .ecran-simple { padding-block: var(--e3); }
  .ecran-simple__marque { margin-bottom: var(--e3); }
  .ecran-simple__marque img { width: min(4.5rem, 22vw); }
}

/* ------------------------------------------------------------ utilitaires

   Petit jeu de classes destiné à remplacer les attributs style= dans les
   gabarits. La politique de sécurité du contenu (style-src 'self') interdit
   les styles en ligne : sans ces classes, chaque style= serait silencieusement
   ignoré par le navigateur.
   ------------------------------------------------------------------------ */

.m0        { margin: 0; }
.mt0       { margin-top: 0; }
.mt1       { margin-top: var(--e1); }
.mb1       { margin-bottom: var(--e1); }
.mt7       { margin-top: var(--e7); }
.casse-normale { text-transform: none; }
.mb0       { margin-bottom: 0; }
.mt2       { margin-top: var(--e2); }
.mt3       { margin-top: var(--e3); }
.mt4       { margin-top: var(--e4); }
.mt5       { margin-top: var(--e5); }
.mb2       { margin-bottom: var(--e2); }
.mb3       { margin-bottom: var(--e3); }
.mb4       { margin-bottom: var(--e4); }
.mb5       { margin-bottom: var(--e5); }
.mb6       { margin-bottom: var(--e6); }
.mb7       { margin-bottom: var(--e7); }

.tenu      { color: var(--texte-tenu); }
.doux      { color: var(--texte-doux); }
.terre     { color: var(--vert-fonce); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .terre { color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .terre { color: var(--vert); }


.t-xxs     { font-size: 0.75rem; }
.t-xs      { font-size: 0.8125rem; }
.t-sm      { font-size: 0.875rem; }
.t-md      { font-size: 0.9375rem; }
.t-lg      { font-size: 1.0625rem; }
.t-xl      { font-size: 1.125rem; }

.serif     { font-family: var(--serif); }
.gras      { font-weight: 600; }
.normal    { font-weight: 400; }
.italique  { font-style: italic; }
.centre    { text-align: center; }
.droite    { text-align: right; }
.nowrap    { white-space: nowrap; }
.chiffres  { font-variant-numeric: tabular-nums; }
.mono      { font-family: var(--mono); }
.sans-deco { text-decoration: none; color: inherit; }

.pleine    { width: 100%; }
/*
 * Qualifiées par type : « input[type="search"] » pèse plus lourd qu'une
 * simple classe dans la cascade, et reprendrait la largeur pleine.
 */
.auto,
input.auto, select.auto, textarea.auto           { width: auto; }
.l-etroit,
input.l-etroit, select.l-etroit                  { width: 7rem; flex: none; }
.l-moyen,
input.l-moyen, select.l-moyen                    { min-width: 12rem; width: auto; flex: 1 1 12rem; }

.liste-nue { list-style: none; margin: 0; padding: 0; }

/* Galerie resserrée des colonnes latérales */
.galerie--mini {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 5.5rem), 1fr));
}

/* Bloc de commande à copier dans un terminal */
.commande {
  display: block;
  overflow-x: auto;
  padding: var(--e3);
  margin: var(--e3) 0;
  background: var(--surface-2);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--texte);
  white-space: pre;
}

/* Bouton de formulaire présenté comme un lien de navigation */
.nav__bouton-lien {
  border: 0;
  background: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
}

.separateur      { border-bottom: 1px solid var(--bordure); }
.separateur-haut { border-top: 1px solid var(--bordure); }
.pad-v2          { padding-block: var(--e2); }
.pad-v3          { padding-block: var(--e3); }
.pad5            { padding: var(--e5); }

.encadre-fort {
  border-color: var(--vert);
  border-width: 2px;
}

.pleine-hauteur-carte { grid-column: 1 / -1; }

/* Listes de définitions des fiches */
.defs {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--e2) var(--e4);
  margin: 0;
  font-size: 0.9375rem;
}

.defs dt { color: var(--texte-tenu); }
.defs dd { margin: 0; }

/* ------------------------------------------------------ mouvement réduit */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- impression */

@media print {
  .entete,
  .nav,
  .pied,
  .formulaire__actions,
  .bouton { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; }
  .carte, .personne { border: 1px solid #999; box-shadow: none; }
  a { color: #000; text-decoration: underline; }
  .arbre { overflow: visible; }
}

/* --------------------------------------------- chemin par alliance ------ */

.chemin { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--e2); }

.chemin__etape { position: relative; }

/* Le libellé de la relation s'intercale entre deux personnes. */
.chemin__relation {
  display: inline-block;
  margin: var(--e2) 0 var(--e2) var(--e5);
  padding: var(--e1) var(--e3);
  border-radius: 999px;
  background: var(--vert-clair);
  border: 1px solid var(--vert-bord);
  color: var(--vert-fonce);
  font-size: 0.8125rem;
  font-weight: 600;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chemin__relation { color: var(--vert); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .chemin__relation { color: var(--vert); }


/* ------------------------------------------------------------- cartes --- */

.carte-figure { margin: 0; }

/*
 * Le SVG des cartes géographiques porte « carte-dessin » et non « carte » :
 * ce dernier nom désigne déjà le bloc encadré du site, et le SVG héritait
 * donc de son fond, de sa bordure et de son rembourrage.
 */
.carte-dessin {
  display: block;
  width: 100%;
  height: auto;
  /* Les tracés sont fins : on les laisse déborder légèrement du cadre. */
  overflow: visible;
}

/* Rampe séquentielle : une seule teinte, du clair au foncé. La magnitude se
   lit dans la clarté, jamais dans la teinte. */
.carte__zone           { fill: var(--surface-2); stroke: var(--surface); stroke-width: 0.7; }
.carte__zone--n0       { fill: #eaf4ed; }
.carte__zone--n1       { fill: #c7e3d1; }
.carte__zone--n2       { fill: #9bceae; }
.carte__zone--n3       { fill: #66b287; }
.carte__zone--n4       { fill: #3d9463; }
.carte__zone--n5       { fill: #22713f; }

/* Pour la carte des régions, les frontières départementales s'effacent. */
.carte__zone--fondue   { stroke-width: 0.35; stroke: rgba(255,255,255,.45); }

.carte__lien .carte__zone { cursor: pointer; transition: fill 120ms; }
.carte__lien:hover .carte__zone { fill: var(--vert); }
.carte__lien:focus-visible .carte__zone { stroke: var(--texte); stroke-width: 2; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .carte__zone { fill: var(--surface-2); stroke: var(--surface); }
  :root:not([data-theme="light"]) .carte__zone--n0 { fill: #1f3227; }
  :root:not([data-theme="light"]) .carte__zone--n1 { fill: #26492f; }
  :root:not([data-theme="light"]) .carte__zone--n2 { fill: #2f6b41; }
  :root:not([data-theme="light"]) .carte__zone--n3 { fill: #3d8b55; }
  :root:not([data-theme="light"]) .carte__zone--n4 { fill: #55a473; }
  :root:not([data-theme="light"]) .carte__zone--n5 { fill: #77c093; }
  :root:not([data-theme="light"]) .carte__zone--fondue { stroke: rgba(0,0,0,.35); }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .carte__zone { fill: var(--surface-2); stroke: var(--surface); }
  :root[data-theme="dark"] .carte__zone--n0 { fill: #1f3227; }
  :root[data-theme="dark"] .carte__zone--n1 { fill: #26492f; }
  :root[data-theme="dark"] .carte__zone--n2 { fill: #2f6b41; }
  :root[data-theme="dark"] .carte__zone--n3 { fill: #3d8b55; }
  :root[data-theme="dark"] .carte__zone--n4 { fill: #55a473; }
  :root[data-theme="dark"] .carte__zone--n5 { fill: #77c093; }
  :root[data-theme="dark"] .carte__zone--fondue { stroke: rgba(0,0,0,.35); }


.carte__echelle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e3);
  margin-top: var(--e3);
  font-size: 0.75rem;
  color: var(--texte-tenu);
}

.carte__echelle-titre {
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.carte__palier { display: inline-flex; align-items: center; gap: var(--e1); }

.carte__puce {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 3px;
  border: 1px solid var(--bordure);
}

.carte__puce--n0 { background: #eaf4ed; }
.carte__puce--n1 { background: #c7e3d1; }
.carte__puce--n2 { background: #9bceae; }
.carte__puce--n3 { background: #66b287; }
.carte__puce--n4 { background: #3d9463; }
.carte__puce--n5 { background: #22713f; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .carte__puce--n0 { background: #1f3227; }
  :root:not([data-theme="light"]) .carte__puce--n1 { background: #26492f; }
  :root:not([data-theme="light"]) .carte__puce--n2 { background: #2f6b41; }
  :root:not([data-theme="light"]) .carte__puce--n3 { background: #3d8b55; }
  :root:not([data-theme="light"]) .carte__puce--n4 { background: #55a473; }
  :root:not([data-theme="light"]) .carte__puce--n5 { background: #77c093; }
}

/* Choix explicite du thème sombre par le visiteur */
:root[data-theme="dark"] .carte__puce--n0 { background: #1f3227; }
  :root[data-theme="dark"] .carte__puce--n1 { background: #26492f; }
  :root[data-theme="dark"] .carte__puce--n2 { background: #2f6b41; }
  :root[data-theme="dark"] .carte__puce--n3 { background: #3d8b55; }
  :root[data-theme="dark"] .carte__puce--n4 { background: #55a473; }
  :root[data-theme="dark"] .carte__puce--n5 { background: #77c093; }



/* ------------------------------------------------- sélecteur de thème --- */

.theme {
  margin-top: var(--e2);
  padding: var(--e3);
  border-top: 1px solid var(--bordure);
}

.theme__titre {
  display: block;
  margin-bottom: var(--e2);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--texte-tenu);
}

.theme__choix {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  padding: 2px;
  background: var(--surface-2);
  border-radius: var(--rayon);
}

.theme__bouton {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: var(--e2) var(--e1);
  border: 0;
  border-radius: calc(var(--rayon) - 2px);
  background: none;
  color: var(--texte-tenu);
  font: 500 0.6875rem/1.2 var(--sans);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.theme__bouton svg { width: 1rem; height: 1rem; }

.theme__bouton:hover { color: var(--texte); }

.theme__bouton[aria-pressed="true"] {
  background: var(--surface);
  color: var(--vert);
  box-shadow: var(--ombre-1);
}

/* ---------------------------------------------------------------------------
 * Formulaire de fiche : sections dépliables.
 *
 * Le marqueur natif de <summary> est retiré au profit d'un chevron placé à
 * droite, qui pivote. Deux règles sont nécessaires et non une : Firefox et
 * Chrome utilisent « list-style », Safari le pseudo-élément WebKit.
 * ------------------------------------------------------------------------ */

.section {
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  margin-bottom: var(--e3);
  /*
   * Pas de « overflow: hidden » ici, quoiqu'il arrondirait commodément le
   * fond de l'en-tête au survol : le calendrier des dates se déploie hors du
   * cadre de la section et s'en trouverait décapité. L'arrondi est donc porté
   * par l'en-tête lui-même, juste en dessous.
   */
}

.section[open] {
  border-color: var(--bordure-forte);
}

.section__tete {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e3) var(--e4);
  cursor: pointer;
  list-style: none;
  user-select: none;
  border-radius: calc(var(--rayon) - 1px);
}

/* Repliée, la section n'est qu'un en-tête : il porte l'arrondi des quatre
   coins. Dépliée, ses angles du bas rejoignent le corps. */
.section[open] .section__tete {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.section__tete::-webkit-details-marker { display: none; }

.section__tete:hover { background: var(--surface-2); }

.section__tete:focus-visible {
  outline: 2px solid var(--vert);
  outline-offset: -2px;
}

.section__icone {
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--vert);
}

.section__texte {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.section__titre {
  font-weight: 600;
  color: var(--texte);
}

.section__accroche {
  font-size: 0.8125rem;
  color: var(--texte-doux);
}

/*
 * Le compteur. Il reste discret tant que la section est incomplète : un
 * badge rouge sur « 0/3 » transformerait une fiche en devoir non rendu.
 */
.section__compte {
  flex: 0 0 auto;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: var(--texte-doux);
  background: var(--fond);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
}

.section__compte--plein {
  color: var(--vert);
  border-color: var(--vert);
}

.section__chevron {
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  color: var(--texte-doux);
  transition: transform 0.15s ease;
}

.section[open] .section__chevron { transform: rotate(180deg); }

.section__corps {
  padding: 0 var(--e4) var(--e4);
  border-top: 1px solid var(--bordure);
  padding-top: var(--e4);
}

.section__corps .champ:last-child { margin-bottom: 0; }

@media (prefers-reduced-motion: reduce) {
  .section__chevron { transition: none; }
}

/* ---------------------------------------- barre d'avancement de la fiche */

.avancement {
  padding: var(--e4);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.avancement__ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--e3);
  margin-bottom: var(--e2);
}

.avancement__libelle {
  font-size: 0.875rem;
  color: var(--texte-doux);
}

.avancement__valeur {
  font-size: 1.25rem;
  color: var(--vert);
  font-variant-numeric: tabular-nums;
}

.avancement .mesure__piste { height: 0.5rem; }

.avancement__note { margin: var(--e2) 0 0; }

/* ---------------------------------------------------------------------------
 * Le CTA du bandeau : « Ajouter une personne ».
 *
 * Il vient d'un menu latéral où il ne servait qu'à ceux qui étaient déjà dans
 * « Ma famille ». Créer une fiche est une action, et une action se propose
 * partout.
 * ------------------------------------------------------------------------ */

.cta-entete {
  flex: 0 0 auto;
  white-space: nowrap;
}

/*
 * Le SVG n'a ni largeur ni hauteur propres : dans les boutons du corps de page
 * il hérite d'une taille, mais le bandeau n'a pas cette règle et le
 * pictogramme se réduisait à zéro — un pavé vert sans rien dedans.
 */
.cta-entete svg {
  width: 1.125rem;
  height: 1.125rem;
  flex: 0 0 auto;
}

/*
 * Sous 68rem, le bandeau porte déjà la marque, la recherche, la photo du
 * hasard, la messagerie et le profil. Le libellé s'efface et le bouton se
 * réduit à sa croix — le geste reste, l'encombrement disparaît.
 */
@media (max-width: 68rem) {
  .cta-entete__texte { display: none; }
  .cta-entete { padding-inline: var(--e3); }
}

/* --------------------------------- le choix d'une recherche par lieu */

.choix-lieu {
  display: flex;
  flex-direction: column;
  gap: var(--e3);
  padding: var(--e4);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.choix-lieu:hover,
.choix-lieu:focus-visible {
  border-color: var(--vert);
  transform: translateY(-2px);
}

/*
 * L'illustration est la vraie carte du site, dessinée à vide. Elle est donc
 * un SVG de plein format : la hauteur est bornée ici, et le débordement
 * masqué, sans quoi la carte du monde imposerait sa proportion à la carte.
 */
.choix-lieu__dessin {
  display: block;
  max-height: 9rem;
  overflow: hidden;
  border-radius: var(--rayon);
  background: var(--surface-2);
  padding: var(--e2);
}

.choix-lieu__dessin svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: 8.5rem;
}


.choix-lieu__texte {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
}

.choix-lieu__titre {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--texte);
}

.choix-lieu__accroche {
  font-size: 0.9375rem;
  color: var(--texte-doux);
  line-height: 1.5;
}

.choix-lieu__compte {
  font-size: 0.8125rem;
  color: var(--vert);
}

@media (prefers-reduced-motion: reduce) {
  .choix-lieu { transition: none; }
  .choix-lieu:hover { transform: none; }
}

/* Ligne mise en avant dans un tableau (le pays choisi sur la carte du monde). */
.ligne--active { background: var(--vert-clair); }

/* ---------------------------------------------------------------------------
 * Les ancres et le bandeau collant.
 *
 * Le bandeau est en « position: sticky » et mesure environ 120 px. Un lien
 * vers « #photos » amenait donc le titre exactement dessous : on arrivait sur
 * une liste de photos décapitée, sans le nom du lieu — signalé sur
 * /agora?lieu=…#photos, mais le défaut valait pour toutes les ancres du site,
 * #resultats et #detail compris.
 *
 * « scroll-margin-top » ne coûte rien aux éléments qu'on n'atteint jamais par
 * une ancre : le navigateur ne s'en sert qu'au moment de faire défiler
 * jusqu'à eux. La règle peut donc rester large.
 * ------------------------------------------------------------------------ */

[id] {
  /*
   * Une seule valeur, sans exception pour les petits écrans : le bandeau y
   * reste collant et garde la même hauteur. J'avais d'abord réduit la marge
   * sous 48 rem en supposant le contraire — mesure faite, il fait 120 px des
   * deux côtés. Un peu de blanc au-dessus d'une ancre ne gêne personne ;
   * atterrir sous le bandeau, si.
   */
  scroll-margin-top: 8.5rem;
}

/* ---------------------------------------------------------------------------
 * Le bandeau sur un téléphone.
 *
 * À 375 px, ses sept éléments réclamaient 392 px : la page débordait de dix-sept
 * pixels vers la droite, l'avatar était rogné et tout le site défilait
 * latéralement. Mesuré, l'excédent tenait au nom du site — cent vingt pixels
 * à lui seul, à côté du logo qui dit déjà de quel site il s'agit.
 *
 * C'est donc lui qui cède, et rien d'autre : chacun des six éléments restants
 * est un geste (ouvrir le menu, chercher, ajouter, lire ses messages, son
 * profil), et un geste retiré est un geste perdu.
 * ------------------------------------------------------------------------ */

@media (max-width: 40rem) {
  .marque__nom { display: none; }

  /*
   * Les onglets débordent aussi, mais eux défilent — c'est voulu. Un dégradé
   * sur le bord droit le dit : sans lui, « Admin » semble ne pas exister.
   */
  .onglets {
    -webkit-mask-image: linear-gradient(to right, #000 85%, transparent);
    mask-image: linear-gradient(to right, #000 85%, transparent);
  }

  /* Le logo garde sa place de lien vers l'accueil, sans le texte à côté. */
  .marque { gap: 0; }

  .entete__interieur {
    gap: var(--e2);
    padding-inline: var(--e3);
  }
}

/*
 * Filet de sécurité. Le bandeau n'était pas seul en cause : n'importe quel
 * tableau ou titre trop large fait défiler la page entière sur le côté, et le
 * défaut ne se voit qu'au téléphone, là où personne ne teste. Les contenus
 * larges ont leur propre conteneur à défilement ; le corps de page, lui, ne
 * doit jamais bouger horizontalement.
 */
html, body { overflow-x: hidden; }

/* ------------------------------------------ choix du fournisseur de courriels */

.fournisseurs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--e3);
}

.fournisseur {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  padding: var(--e3) var(--e4);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  cursor: pointer;
}

/*
 * LE BOUTON RADIO RESTE VISIBLE, et ce n'est pas un choix esthétique.
 *
 * Je l'avais masqué, en confiant l'indication du choix à
 * « .fournisseur:has(input:checked) ». Sur un navigateur sans « :has() », il
 * ne restait alors AUCUN signe de ce qui était coché : trois cartes
 * identiques, dont une déjà sélectionnée à l'insu du visiteur. En production,
 * un administrateur a cru choisir Brevo, Mailjet est resté coché, et sa clé
 * Brevo est partie dans MAILJET_API_KEY.
 *
 * Le rond natif est toujours juste, sur tous les navigateurs, sans qu'on ait
 * à le réinventer. La mise en valeur de la carte vient par-dessus, comme
 * agrément — plus jamais comme seule indication.
 */
.fournisseur {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--e3);
}

.fournisseur input {
  flex: 0 0 auto;
  margin-top: 0.15rem;
}

.fournisseur__texte {
  display: flex;
  flex-direction: column;
  gap: var(--e1);
  min-width: 0;
}

.fournisseur:hover { border-color: var(--bordure-forte); }

/*
 * L'agrément passe par le frère du bouton : « input:checked + … » fonctionne
 * partout, là où « :has() » manque encore à l'appel sur les navigateurs un
 * peu anciens.
 */
.fournisseur input:checked + .fournisseur__texte .fournisseur__nom {
  color: var(--vert);
}

.fournisseur:focus-within {
  outline: 2px solid var(--vert);
  outline-offset: 2px;
}

.fournisseur__nom { font-weight: 600; color: var(--texte); }

.fournisseur__voie {
  font-size: 0.75rem;
  color: var(--texte-tenu);
  font-family: var(--mono);
}

/* ---------------------------------------------------------------------------
 * La boîte à idées, dans le bandeau.
 *
 * Elle voisine la messagerie : ce sont les deux façons de dire quelque chose
 * au reste de la famille, l'une adressée, l'autre ouverte. Elle en reprend
 * donc exactement l'allure — deux icônes côte à côte qui ne se ressemblent pas
 * se liraient comme deux fonctions sans rapport.
 * ------------------------------------------------------------------------ */

/*
 * LA MARGE AUTOMATIQUE EST ICI, ET NULLE PART AILLEURS.
 *
 * Elle était portée par la messagerie ET par le menu du compte : chacun
 * réclamant l'espace libre, le navigateur le partageait entre les deux. Ampoule
 * collée au champ de recherche, enveloppe au milieu de nulle part, compte à
 * droite — trois éléments d'un même groupe éparpillés sur toute la largeur.
 *
 * Posée sur le premier des trois, elle pousse le groupe entier à droite et les
 * laisse côte à côte, ce qu'ils n'auraient jamais dû cesser d'être.
 */
.idee-entete {
  flex: 0 0 auto;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  color: var(--texte-doux);
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}

.idee-entete:hover { background: var(--surface-2); color: var(--vert-fonce); }
.idee-entete svg { width: 1.35rem; height: 1.35rem; }

/* ------------------------------------------- le menu « Ajouter » du bandeau */

.ajout-entete { position: relative; flex: 0 0 auto; }

.ajout-entete__calque {
  display: none;
  position: absolute;
  left: 0;
  top: calc(100% + var(--e2));
  z-index: var(--z-menu);
  min-width: 12rem;
  padding: var(--e2);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
}

.ajout-entete__bascule:checked ~ .ajout-entete__calque { display: block; }

/*
 * Le focus clavier doit se voir sur l'étiquette, qui a pris le rôle du bouton.
 */
.ajout-entete__bascule:focus-visible + .cta-entete {
  outline: 2px solid var(--vert);
  outline-offset: 2px;
}

.ajout-entete__lien {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e3);
  border-radius: var(--rayon);
  color: var(--texte);
  text-decoration: none;
  font-size: 0.9375rem;
}

.ajout-entete__lien:hover { background: var(--surface-2); color: var(--vert-fonce); }
.ajout-entete__lien svg { width: 1.1rem; height: 1.1rem; flex: 0 0 auto; color: var(--vert); }

/* Sur un téléphone, le calque s'ancre à droite pour ne pas sortir de l'écran. */
@media (max-width: 40rem) {
  .ajout-entete__calque { left: auto; right: 0; }
}

/* ---------------------------------------------------------------------------
 * La visite guidée du premier passage.
 *
 * Le voile assombrit la page, le halo découpe l'élément dont on parle, la
 * bulle porte le texte. Les trois sont positionnés en JavaScript : la
 * politique de sécurité interdit les styles écrits dans le HTML, mais pas les
 * affectations à element.style — vérifié dans le navigateur avant d'écrire
 * ceci plutôt que supposé.
 * ------------------------------------------------------------------------ */

.visite { position: fixed; inset: 0; z-index: var(--z-modale, 9000); }

/*
 * UN SEUL MÉCANISME D'ASSOMBRISSEMENT, et c'est le halo.
 *
 * Son ombre portée de 9999 px couvre tout l'écran sauf son propre rectangle :
 * elle assombrit et découpe d'un même geste. J'avais d'abord ajouté un voile
 * séparé par-dessus, qu'il fallait masquer quand le halo paraissait — au
 * moyen de « :has() », c'est-à-dire du piège déjà rencontré sur le choix du
 * fournisseur de courriels. Deux mécanismes valaient une couche de trop et
 * une règle qui ne s'applique pas partout ; il n'en reste qu'un.
 *
 * Le cadre entoure l'élément plutôt que de le détourer : connaître la forme
 * exacte de chaque cible serait fragile, un rectangle lumineux désigne aussi
 * bien et ne se trompe jamais de contour.
 */
.visite__halo {
  position: absolute;
  border-radius: var(--rayon-lg);
  border: 2px solid var(--vert);
  box-shadow: 0 0 0 9999px rgb(0 0 0 / 0.55), 0 0 0 4px rgb(46 125 79 / 0.35);
  pointer-events: none;
  transition: top 0.25s ease, left 0.25s ease, width 0.25s ease, height 0.25s ease;
}

.visite__bulle {
  position: absolute;
  width: min(22rem, calc(100vw - 2rem));
  padding: var(--e5);
  background: var(--surface);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
}

.visite__compteur {
  margin: 0 0 var(--e2);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--texte-tenu);
}

.visite__titre {
  margin: 0 0 var(--e3);
  font-size: 1.125rem;
}

.visite__texte {
  margin: 0 0 var(--e4);
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--texte-doux);
}

.visite__actions {
  display: flex;
  align-items: center;
  gap: var(--e2);
}

.visite__espace { flex: 1 1 auto; }

@media (prefers-reduced-motion: reduce) {
  .visite__halo { transition: none; }
}

/* Sur un téléphone, la bulle occupe le bas de l'écran plutôt que de courir
   après une cible qui tient déjà toute la largeur. */
@media (max-width: 30rem) {
  .visite__bulle { padding: var(--e4); }
}

/* Un bouton qui vit parmi des liens en prend l'apparence. */
.moi__lien--bouton {
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
}

/* ------------------------------------------ l'appel à identifier les photos */

.appel-qui {
  display: flex;
  align-items: center;
  gap: var(--e4);
  padding: var(--e4);
  margin-bottom: var(--e5);
  background: var(--vert-clair);
  border: 1px solid var(--vert);
  border-radius: var(--rayon-lg);
  color: inherit;
  text-decoration: none;
}

.appel-qui:hover { box-shadow: var(--ombre-2); }

.appel-qui__dessin { flex: 0 0 auto; width: 4rem; height: 3rem; color: var(--vert-fonce); }

.appel-qui__texte { flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--e1); min-width: 0; }
.appel-qui__titre { font-weight: 700; color: var(--vert-fonce); }
.appel-qui__note  { font-size: 0.875rem; color: var(--texte-doux); line-height: 1.45; }

.appel-qui__action {
  flex: 0 0 auto;
  padding: var(--e2) var(--e4);
  border-radius: 999px;
  background: var(--vert);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
}

@media (max-width: 40rem) {
  .appel-qui { flex-wrap: wrap; }
  .appel-qui__action { width: 100%; text-align: center; }
}

/* ------------------------------------------------------- « Perdu de vue » */

.perdus { border-color: var(--vert); }

.perdus__dessin {
  display: block;
  width: 6rem;
  height: 4.5rem;
  margin-bottom: var(--e3);
  color: var(--vert);
}

.perdus__titre { margin-bottom: var(--e2); }

.perdus__phrase {
  margin: 0 0 var(--e4);
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--texte-doux);
}

.perdus__reste { margin: var(--e3) 0 0; }

/* --------------------------------------------------------- les documents */

.doc {
  display: flex;
  align-items: center;
  gap: var(--e4);
  padding: var(--e3) var(--e4);
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  text-decoration: none;
  color: inherit;
}

.doc:hover { border-color: var(--vert); }

/*
 * L'extension tient lieu de pictogramme. Un dessin par format serait plus
 * joli et moins juste : « PDF » et « TIF » ne se confondent pas, et le
 * visiteur sait déjà ce que chacun veut dire.
 */
.doc__icone {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--rayon);
  background: var(--surface-2);
  color: var(--texte-doux);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.03em;
}

.doc__texte { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.doc__titre { font-weight: 600; color: var(--texte); }
.doc__meta  { font-size: 0.8125rem; color: var(--texte-tenu); }

.doc--serre { padding: var(--e2) var(--e3); }
.doc--serre .doc__icone { width: 2.25rem; height: 2.25rem; font-size: 0.625rem; }

/* ------------------------------------ « ne s'est jamais connecté » */

.jamais__dessin {
  display: block;
  width: 4.5rem;
  height: 3rem;
  margin-bottom: var(--e3);
  color: var(--vert);
}

/* ------------------------------------ la photo au hasard, sur l'accueil */

.hasard {
  display: flex;
  align-items: stretch;
  gap: 0;
  flex: 0 1 22rem;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
}

.hasard:hover { border-color: var(--vert); }

.hasard__image {
  flex: 0 0 8rem;
  width: 8rem;
  height: 100%;
  object-fit: cover;
  background: var(--surface-2);
}

.hasard__texte {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  justify-content: center;
  padding: var(--e3) var(--e4);
  min-width: 0;
}

.hasard__surtitre {
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--vert);
  font-weight: 700;
}

.hasard__nom { font-weight: 600; color: var(--texte); }

.hasard__lien,
.hasard__legende {
  font-size: 0.8125rem;
  color: var(--texte-doux);
  /* Une légende peut être longue : deux lignes, puis on coupe. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.hasard__legende { color: var(--texte-tenu); font-style: italic; }

@media (max-width: 48rem) {
  .hasard { flex-basis: 100%; }
}

/* ------------------------------------- l'accueil de la visite guidée */

/*
 * LE VOILE DE L'ÉCRAN D'ACCUEIL, ET POURQUOI IL EST ICI ET NON SUR LA CARTE.
 *
 * Les étapes suivantes obtiennent leur assombrissement par l'ombre portée du
 * halo. L'accueil n'a pas de halo — il ne désigne rien — et se détachait donc
 * sur une page en pleine lumière, ce qui le faisait passer pour un encart
 * parmi d'autres plutôt que pour le début de quelque chose.
 *
 * Mon premier essai posait un pseudo-élément « position: fixed » sur la carte
 * elle-même. Il la recouvrait exactement au lieu de couvrir l'écran : la carte
 * porte un « transform » pour se centrer, et un transform fait qu'un
 * descendant « fixe » se cale sur LUI et non sur la fenêtre. En mode sombre le
 * défaut se remarquait à peine ; en clair, la carte devenait grise.
 *
 * Le voile est donc porté par la racine, qui ne subit aucune transformation.
 * La classe est retirée par le script au moment où la visite commence.
 */
.visite--accueil { background: rgb(0 0 0 / 0.55); }

.visite__accueil {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(30rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: var(--e6) var(--e5) var(--e5);
  text-align: center;
  background: var(--surface);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
}

/*
 * L'arbre est dessiné, pas photographié : il suit le thème, reste net à toute
 * taille et ne coûte aucun chargement. Ses feuilles portent des visages —
 * c'est de famille qu'il s'agit, pas de botanique.
 */
.visite__arbre {
  display: block;
  width: min(14rem, 60%);
  height: auto;
  margin: 0 auto var(--e4);
  color: var(--vert-fonce);
}

.visite__feuilles circle { fill: var(--vert-clair); stroke: var(--vert); stroke-width: 2; }
.visite__silhouettes path { fill: var(--vert-fonce); }

.visite__surtitre {
  margin: 0 0 var(--e2);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--vert);
  font-weight: 700;
}

.visite__bienvenue {
  margin: 0 0 var(--e4);
  font-family: var(--serif);
  font-size: 1.75rem;
  line-height: 1.15;
}

.visite__intro {
  margin: 0 0 var(--e3);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--texte-doux);
}

.visite__accueil .visite__actions { margin-top: var(--e5); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .visite__feuilles circle {
    fill: color-mix(in srgb, var(--vert) 25%, transparent);
  }
}

:root[data-theme="dark"] .visite__feuilles circle {
  fill: color-mix(in srgb, var(--vert) 25%, transparent);
}

/* Les deux actions du bas du calque, détachées des liens de navigation. */
.moi__actions {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  margin-top: var(--e3);
  padding-top: var(--e3);
  border-top: 1px solid var(--bordure);
}

/* ---------------------------------------------- la rangée d'outils */

.rang-outils {
  display: flex;
  align-items: center;
  gap: var(--e4);
  max-width: var(--largeur-max);
  margin-inline: auto;
  padding-inline: var(--e4);
}

/*
 * Les onglets prennent la place disponible et défilent seuls si besoin ; le
 * bouton reste collé au bord droit, sous le calque du profil.
 */
.rang-outils .onglets { flex: 1 1 auto; min-width: 0; padding-inline: 0; }
.rang-outils .ajout-entete { flex: 0 0 auto; margin-left: auto; }

/* Le calque de l'ajout s'ouvre vers la gauche : à droite, il sortirait. */
.rang-outils .ajout-entete__calque { left: auto; right: 0; }

@media (min-width: 62rem) {
  .rang-outils { padding-inline: var(--e5); }
}

/* ------------------------------------- aperçu d'un courriel, en admin */

.apercu-mail {
  padding: var(--e4);
  background: var(--surface-2);
  border-radius: var(--rayon);
  font-size: 0.875rem;
}

.apercu-mail__ligne { margin: 0 0 var(--e1); color: var(--texte-doux); }
.apercu-mail__filet { margin: var(--e3) 0; border: 0; border-top: 1px solid var(--bordure); }
.apercu-mail__salut { margin: 0 0 var(--e2); font-weight: 600; }

.apercu-mail__bouton {
  display: inline-block;
  margin: var(--e4) 0 0;
  padding: var(--e2) var(--e4);
  border-radius: var(--rayon);
  background: var(--vert);
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 600;
}

/* ------------------------------------------- les visages suggérés */

/*
 * Ils sont repérés au dépôt, côté serveur, et proposés — jamais nommés. Le
 * trait est discontinu pour qu'on les distingue au premier coup d'œil des
 * repères confirmés, qui sont pleins : l'un est une hypothèse, l'autre un fait.
 */
.visage-suggere {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--taille);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  padding: 0;
  background: none;
  border: 2px dashed rgb(255 255 255 / 0.85);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35);
  cursor: pointer;
  opacity: 0.75;
  transition: opacity 0.15s ease, border-color 0.15s ease;
}

.visage-suggere:hover,
.visage-suggere:focus-visible {
  opacity: 1;
  border-color: var(--vert);
  border-style: solid;
}

/* --------------------------------------------- fiches à compléter */

.a-completer {
  padding: var(--e2) 0;
  border-bottom: 1px solid var(--bordure);
}

.a-completer:last-child { border-bottom: 0; }

/*
 * Le nom et la jauge sur une ligne, la jauge poussée à droite. Elle dit d'un
 * coup d'œil ce qu'un pourcentage écrit ne dirait pas : que c'est presque fini.
 */
.a-completer__qui {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
}

/*
 * La jauge a un viewBox de mille unités et aucune largeur propre : laissée
 * libre dans une ligne flexible, elle réclamerait mille pixels. On la borne.
 */
.a-completer__qui svg {
  flex: 0 0 4.5rem;
  width: 4.5rem;
}

.a-completer__manque { margin-top: 0.15rem; }

/* ------------------------------------------ recettes et traditions */

/*
 * Une fiche de carnet plutôt qu'une ligne de liste. Une recette se choisit à
 * l'œil — « ah, la tarte » — et non en lisant une colonne de titres ; la carte
 * lui laisse la place de porter son nom en grand.
 */
.recette-carte {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
  padding: var(--e4);
  text-decoration: none;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-lg);
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.recette-carte:hover,
.recette-carte:focus-visible {
  border-color: var(--vert);
  transform: translateY(-2px);
}

.recette-carte__nature {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--vert);
}

.recette-carte__titre {
  font-family: var(--police-titre, inherit);
  font-size: 1.125rem;
  line-height: 1.25;
}

.recette-carte__meta { font-size: 0.8125rem; }

.recette-carte__origine {
  font-size: 0.875rem;
  font-style: italic;
  color: var(--texte-doux);
}

/* --- la recette elle-même */

/*
 * Les ingrédients à gauche, la marche à suivre à droite : on lit la liste une
 * fois, en faisant les courses, et les étapes vingt fois, les mains dans la
 * farine. Sur un téléphone posé sur le plan de travail, elles s'empilent.
 */
.recette-corps {
  display: grid;
  gap: var(--e5);
  grid-template-columns: 1fr;
}

@media (min-width: 52rem) {
  .recette-corps { grid-template-columns: minmax(0, 14rem) minmax(0, 1fr); }
}

.recette-liste {
  margin: 0;
  padding-left: 1.1rem;
}

.recette-liste li { margin-bottom: var(--e2); }

/* Les étapes sont numérotées et espacées : on y revient en cours de route et
   il faut retrouver où l'on en était. */
.recette-etapes { counter-reset: etape; list-style: none; margin: 0; padding: 0; }

.recette-etapes li {
  position: relative;
  padding-left: 2.25rem;
  margin-bottom: var(--e4);
}

.recette-etapes li::before {
  counter-increment: etape;
  content: counter(etape);
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  font-size: 0.8125rem;
  color: var(--vert);
  border: 1px solid var(--vert);
  border-radius: 50%;
}

/* ------------------------------------------ souvenirs enregistrés */

.enreg { display: flex; flex-direction: column; gap: var(--e3); }

.enreg__etat {
  display: flex;
  align-items: center;
  gap: var(--e3);
}

/* Un point rouge qui bat : le seul signe qui dise, sans le lire, que ça tourne. */
.enreg__pastille {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 50%;
  background: var(--bordure-forte);
  flex: none;
}

.enreg__pastille--active {
  background: #d94141;
  animation: enreg-battement 1.4s ease-in-out infinite;
}

@keyframes enreg-battement {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}

/* Le minuteur est le repère de celui qui parle : il doit se lire de loin. */
.enreg__minuteur {
  font-variant-numeric: tabular-nums;
  font-size: 1.5rem;
  line-height: 1;
}

.enreg__mode { font-size: 0.8125rem; }

.enreg__apercu,
.souvenir-lecteur {
  display: block;
  width: 100%;
  max-width: 100%;
  border-radius: var(--rayon);
}

.enreg__apercu { max-height: 22rem; background: #000; }

/* Le dépôt manuel s'efface d'un cran quand l'enregistrement est possible :
   il reste accessible, il n'est plus le chemin principal. */
.enreg__depot-replie { opacity: 0.72; }
.enreg__depot-replie:focus-within { opacity: 1; }

/* --- la liste de questions */

.questions { list-style: none; margin: 0; padding: 0; }

.questions__item {
  display: block;
  width: 100%;
  padding: var(--e2) var(--e3);
  margin-bottom: var(--e2);
  font-size: 0.9375rem;
  text-align: left;
  color: inherit;
  background: none;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  cursor: pointer;
}

.questions__item:hover,
.questions__item:focus-visible { border-color: var(--vert); }

.questions__item--choisi {
  border-color: var(--vert);
  background: var(--surface-2);
}

/*
 * La question posée, citée. Des années après, elle sera la seule à dire à quoi
 * la réponse répond — d'où la place qu'on lui donne, avant l'enregistrement.
 */
.souvenir-question {
  margin: 0 0 var(--e5);
  padding: var(--e3) var(--e4);
  font-family: var(--police-titre, inherit);
  font-size: 1.25rem;
  line-height: 1.35;
  border-left: 3px solid var(--vert);
}

/* ------------------------- suggestions du bandeau, et symboles de sexe */

/*
 * Mars et Vénus. Un caractère au lieu de cinq lettres : sur une carte, la place
 * gagnée revient aux dates et au lieu, qui apprennent quelque chose. La couleur
 * suit celle déjà employée pour distinguer les fiches.
 */
.sexe {
  font-size: 0.95em;
  line-height: 1;
  /*
   * Le symbole a besoin d'air à sa gauche. Le nom et les renseignements se
   * suivent sur la même ligne quand la place le permet, et « Taddei♂ » se
   * lisait comme un seul mot — le signe paraissait accroché au nom plutôt que
   * de commencer la ligne suivante.
   */
  margin-inline-start: 0.4em;
}

/* Les mêmes deux couleurs que le liseré des cartes : le site n'en connaît
   pas d'autres pour cela, et en inventer deux troublerait la lecture. */
.sexe--m { color: var(--bleu); }
.sexe--f { color: var(--vert); }

/*
 * La liste du bandeau montre des cartes, pas des lignes : on cherche quelqu'un
 * qu'on connaît, et un visage se reconnaît plus vite qu'un nom ne se lit.
 */
.suggestions-riches {
  position: absolute;
  z-index: var(--z-menu);
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 26rem;
  overflow-y: auto;
  padding: var(--e2);
  background: var(--surface);
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-lg);
  box-shadow: var(--ombre-3);
}

.suggestions-riches__item {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e2) var(--e3);
  border-radius: var(--rayon);
  text-decoration: none;
  color: inherit;
}

.suggestions-riches__item:hover,
.suggestions-riches__item--vise { background: var(--surface-2); }

.suggestions-riches__item .personne__portrait,
.suggestions-riches__item .personne__initiales {
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
}

/* La dernière ligne, qui mène à la recherche complète : elle doit se lire
   comme une action, pas comme un huitième résultat. */
.suggestions-riches__tous {
  display: block;
  width: 100%;
  margin-top: var(--e2);
  padding: var(--e2) var(--e3);
  font-size: 0.8125rem;
  text-align: left;
  color: var(--texte-doux);
  background: none;
  border: 0;
  border-top: 1px solid var(--bordure);
  border-radius: 0;
  cursor: pointer;
}

.suggestions-riches__tous:hover { color: var(--vert); }

/* ------------------------------------------------- la case « décédée » */

/*
 * Séparé du reste par un filet et de l'air : ce n'est pas une section de plus,
 * c'est une question qu'on pose une fois, à la fin, et dont la réponse est non
 * pour la plupart des fiches.
 */
.deces {
  margin-top: var(--e5);
  padding-top: var(--e4);
  border-top: 1px solid var(--bordure);
}

.deces__bascule { margin-bottom: 0; }

.deces__corps { margin-top: var(--e4); }

/* ==================================================== l'arbre dessiné */

/*
 * Une généalogie se lit dans l'espace : les aïeux tout en haut, le conjoint à
 * côté, les enfants en dessous.
 *
 * TOUT L'ALIGNEMENT VIENT DE LA GRILLE, et c'est ce qui rend le dessin fiable.
 * Chaque génération divise la précédente par deux : huit grands-parents sur
 * huit colonnes, quatre parents sur deux colonnes chacun, deux conjoints sur
 * quatre. Le centre d'un couple tombe donc exactement sur le centre de son
 * enfant, sans qu'on ait rien à mesurer, et un nom long ne décale rien.
 *
 * Dix colonnes en tout : les huit de l'ascendance, plus une de chaque côté pour
 * les fratries.
 */
.arbre3-defilant {
  /* Sous sa largeur minimale, le tableau défile plutôt que de se comprimer
     jusqu'à l'illisible. */
  overflow-x: auto;
  padding-bottom: var(--e3);
}

.arbre3 {
  display: grid;
  min-width: 64rem;
  grid-template-columns: minmax(6.5rem, 0.9fr) repeat(8, minmax(6rem, 1fr)) minmax(6.5rem, 0.9fr);
  grid-template-rows: auto var(--e4) auto var(--e4) auto var(--e4) auto;
  gap: 0 var(--e2);
  align-items: center;
  justify-items: stretch;
}

/* Sans conjoint, la moitié droite n'a pas lieu d'être : six colonnes. */
.arbre3--seul {
  min-width: 40rem;
  grid-template-columns: minmax(6.5rem, 0.9fr) repeat(4, minmax(6rem, 1fr)) minmax(6.5rem, 0.9fr);
}

/* Sans aucun aïeul connu, les deux premières rangées disparaissent. */
.arbre3--sans-aieux { grid-template-rows: auto var(--e4) auto var(--e4) auto; }

.arbre3-cell { position: relative; min-width: 0; height: 100%; display: flex; align-items: center; }

/* --- rangée 1 : les huit grands-parents */

.arbre3-gp1 { grid-area: 1 / 2; }
.arbre3-gp2 { grid-area: 1 / 3; }
.arbre3-gp3 { grid-area: 1 / 4; }
.arbre3-gp4 { grid-area: 1 / 5; }
.arbre3-gp5 { grid-area: 1 / 6; }
.arbre3-gp6 { grid-area: 1 / 7; }
.arbre3-gp7 { grid-area: 1 / 8; }
.arbre3-gp8 { grid-area: 1 / 9; }

/* Les traits joignant chaque couple d'aïeuls, dans l'écart entre leurs cases. */
.arbre3-ua1 { grid-area: 1 / 2 / 2 / 4; }
.arbre3-ua2 { grid-area: 1 / 4 / 2 / 6; }
.arbre3-ua3 { grid-area: 1 / 6 / 2 / 8; }
.arbre3-ua4 { grid-area: 1 / 8 / 2 / 10; }

/* --- rangée 2 : les descentes des aïeuls vers les parents */

.arbre3-da1 { grid-area: 2 / 2 / 3 / 4; }
.arbre3-da2 { grid-area: 2 / 4 / 3 / 6; }
.arbre3-da3 { grid-area: 2 / 6 / 3 / 8; }
.arbre3-da4 { grid-area: 2 / 8 / 3 / 10; }

/* --- rangée 3 : les quatre parents, deux colonnes chacun */

.arbre3-p1 { grid-area: 3 / 2 / 4 / 4; }
.arbre3-p2 { grid-area: 3 / 4 / 4 / 6; }
.arbre3-p3 { grid-area: 3 / 6 / 4 / 8; }
.arbre3-p4 { grid-area: 3 / 8 / 4 / 10; }

.arbre3-up1 { grid-area: 3 / 2 / 4 / 6; }
.arbre3-up2 { grid-area: 3 / 6 / 4 / 10; }

/* --- rangée 4 : les descentes des parents vers le couple */

.arbre3-dp1 { grid-area: 4 / 2 / 5 / 6; }
.arbre3-dp2 { grid-area: 4 / 6 / 5 / 10; }

/* --- rangée 5 : les fratries, le couple */

.arbre3-fa       { grid-area: 5 / 1; }
.arbre3-moi      { grid-area: 5 / 2 / 6 / 6; }
.arbre3-conjoint { grid-area: 5 / 6 / 6 / 10; }
.arbre3-fb       { grid-area: 5 / 10; }
.arbre3-uc       { grid-area: 5 / 2 / 6 / 10; }

/* --- rangées 6 et 7 : la descente et les enfants */

.arbre3-de      { grid-area: 6 / 2 / 7 / 10; }
.arbre3-enfants { grid-area: 7 / 2 / 8 / 10; }

/* La variante sans conjoint : tout tient dans les colonnes 2 à 5. */
.arbre3--seul .arbre3-p1  { grid-area: 3 / 2 / 4 / 4; }
.arbre3--seul .arbre3-p2  { grid-area: 3 / 4 / 4 / 6; }
.arbre3--seul .arbre3-moi { grid-area: 5 / 2 / 6 / 6; }
.arbre3--seul .arbre3-fa  { grid-area: 5 / 1; }
.arbre3--seul .arbre3-fb  { grid-area: 5 / 6; }
.arbre3--seul .arbre3-de      { grid-area: 6 / 2 / 7 / 6; }
.arbre3--seul .arbre3-enfants { grid-area: 7 / 2 / 8 / 6; }

/* Sans aïeux, tout remonte de deux rangées. */
.arbre3--sans-aieux .arbre3-p1  { grid-row: 1; }
.arbre3--sans-aieux .arbre3-p2  { grid-row: 1; }
.arbre3--sans-aieux .arbre3-p3  { grid-row: 1; }
.arbre3--sans-aieux .arbre3-p4  { grid-row: 1; }
.arbre3--sans-aieux .arbre3-up1 { grid-row: 1; }
.arbre3--sans-aieux .arbre3-up2 { grid-row: 1; }
.arbre3--sans-aieux .arbre3-dp1 { grid-row: 2; }
.arbre3--sans-aieux .arbre3-dp2 { grid-row: 2; }
.arbre3--sans-aieux .arbre3-fa       { grid-row: 3; }
.arbre3--sans-aieux .arbre3-moi      { grid-row: 3; }
.arbre3--sans-aieux .arbre3-conjoint { grid-row: 3; }
.arbre3--sans-aieux .arbre3-fb       { grid-row: 3; }
.arbre3--sans-aieux .arbre3-uc       { grid-row: 3; }
.arbre3--sans-aieux .arbre3-de       { grid-row: 4; }
.arbre3--sans-aieux .arbre3-enfants  { grid-row: 5; }

/* --- les traits */

/*
 * Le trait d'union est centré sur la zone qu'il couvre et large de l'écart
 * entre les deux cases : il relie donc leurs bords sans les recouvrir.
 */
.arbre3-union {
  justify-content: center;
  align-items: center;
  pointer-events: none;
}

.arbre3-union::before {
  content: "";
  width: calc(var(--e2) + 2px);
  border-top: 2px solid var(--bordure-forte);
}

/*
 * La mention posée au-dessus du trait — « Mariage · 12/03/1998 ». Elle flotte
 * sans occuper de place : la rangée est déjà dimensionnée par les cases, et
 * pousser le trait vers le bas désalignerait tout ce qui en descend.
 */
.arbre3-union__mention {
  position: absolute;
  left: 50%;
  bottom: 50%;
  transform: translate(-50%, -0.35rem);
  padding: 0 var(--e2);
  font-size: 0.68rem;
  white-space: nowrap;
  color: var(--texte-tenu);
  background: var(--surface);
  border-radius: var(--rayon);
}

.arbre3-descente {
  justify-content: center;
  align-items: stretch;
}

.arbre3-trait {
  width: 0;
  border-left: 2px solid var(--bordure-forte);
}

/* --- une case */

.arbre3-case {
  position: relative;
  width: 100%;
  padding: var(--e2);
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-top: 3px solid var(--bordure-forte);
  border-radius: var(--rayon);
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.arbre3-case--m { border-top-color: var(--bleu); }
.arbre3-case--f { border-top-color: var(--vert); }

.arbre3-case:hover { transform: translateY(-2px); border-color: var(--vert); }

.arbre3-case__vers {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  text-decoration: none;
  color: inherit;
}

.arbre3-case__portrait {
  width: 3rem;
  height: 3rem;
  border-radius: var(--rayon);
  object-fit: cover;
  background: var(--surface-2);
}

.arbre3-case__portrait--initiales {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--texte-doux);
}

.arbre3-case__nom {
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.arbre3-case__annees { font-size: 0.7rem; color: var(--texte-tenu); }

/*
 * Le lien vers la fiche ne se montre qu'au survol et au clavier : la case
 * entière mène déjà quelque part, et deux liens visibles côte à côte feraient
 * hésiter sur celui qu'il faut prendre.
 */
.arbre3-case__fiche {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.68rem;
  color: var(--texte-tenu);
  opacity: 0;
  transition: opacity 0.15s ease;
}

.arbre3-case:hover .arbre3-case__fiche,
.arbre3-case__fiche:focus-visible { opacity: 1; }

@media (hover: none) {
  /* Au doigt, il n'y a pas de survol : le lien reste visible. */
  .arbre3-case__fiche { opacity: 1; }
}

.arbre3-case--vide {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3.5rem;
  border-style: dashed;
  border-top-style: dashed;
  border-top-color: var(--bordure);
  background: none;
  color: var(--texte-tenu);
  font-size: 0.85rem;
}

.arbre3-case--vide:hover { transform: none; border-color: var(--bordure); }

/* --- la pastille des frères et sœurs */

.arbre3-boite {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  width: 100%;
  padding: var(--e2) var(--e3);
  font-size: 0.78rem;
  background: var(--surface-2);
  border-radius: var(--rayon-lg);
}

.arbre3-boite__titre {
  font-size: 0.66rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--texte-tenu);
  margin-bottom: 0.15rem;
}

.arbre3-boite__nom a { text-decoration: none; }
.arbre3-boite__nom a:hover { text-decoration: underline; }

/* --- les enfants, en ligne sous le couple */

.arbre3-enfants { justify-content: center; }

.arbre3-enfants__ligne {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--e3);
  width: 100%;
}

.arbre3-enfant { width: 8rem; flex: none; height: auto; }

/* La zone de survol d'une colonne : invisible, mais elle capte le pointeur sur
   toute la hauteur — un jour à zéro n'a pas de barre à viser. */
.graphe .survol { fill: transparent; }

/* ------------------------------------------- le conjoint qui manque */

/*
 * « Conjoint inconnu » n'appelait aucun geste, alors que c'est justement la
 * case où il y en a un à faire : ces enfants ont eu deux parents, et celui-là
 * manque. Le pointillé dit le vide, le plus dit quoi en faire.
 */
.conjoint-manquant {
  display: flex;
  align-items: center;
  gap: var(--e3);
  padding: var(--e3);
  text-decoration: none;
  color: var(--texte-doux);
  border: 1px dashed var(--bordure-forte);
  border-radius: var(--rayon);
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.conjoint-manquant:hover,
.conjoint-manquant:focus-visible {
  color: var(--vert-fonce);
  border-color: var(--vert);
  border-style: solid;
  background: var(--surface-2);
}

.conjoint-manquant__plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--vert);
  border: 2px solid currentColor;
  border-radius: 50%;
}

.conjoint-manquant__texte {
  display: flex;
  flex-direction: column;
  font-style: italic;
}

.conjoint-manquant__action {
  font-style: normal;
  font-size: 0.8125rem;
  color: var(--vert);
}

/* ------------------------------------- corriger ou retirer un message */

/*
 * Les deux actions vivent dans la ligne de date, en petit : elles ne servent
 * qu'à celui qui a écrit, et rarement. Les mettre en évidence donnerait à
 * chaque bulle deux boutons dont on n'a presque jamais besoin.
 */
.bulle__action {
  padding: 0;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  text-decoration: underline;
  cursor: pointer;
}

.bulle__action:hover { color: var(--vert); }

/* Un message retiré : la bulle demeure, le texte est en creux. */
.bulle__texte--retire {
  font-style: italic;
  opacity: 0.6;
}

.bulle__correction textarea {
  width: 100%;
  min-height: 4.5rem;
}
