:root {
  /* Le site est clair, et seulement clair.
     `color-scheme` ne colore rien ici : il dit au navigateur de dessiner
     SES elements en clair -- la liste deroulante d'un <select>, la case a
     cocher, l'ascenseur, le remplissage automatique. Sans cette ligne, un
     systeme regle en sombre les rendrait sombres par-dessus une page
     claire, et la liste des hebergements deviendrait illisible.
     Il n'y a donc plus de bloc `prefers-color-scheme` : en ajouter un
     reintroduirait un theme a moitie, celui du navigateur restant clair. */
  color-scheme: light;

  --fond: #f7f7f5;
  --carte: #ffffff;
  --trait: #dcdcd6;
  --texte: #23241f;
  --doux: #6b6b63;
  --accent: #2f5597;
  --ok: #2f7a4f;
  --erreur: #b3261e;
  --survol: #eaeae4;
  --bandeau: #e7eaf0;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 24px 16px 64px;
  background: var(--fond);
  color: var(--texte);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
}

main { max-width: 900px; margin: 0 auto; }

/* ---------- Menu principal ---------- */

/* Les trois pages sont trois etapes d'une meme decision -- ou, quand, qui --
   et elles se prennent dans cet ordre. Le menu les montre ainsi, et remplit
   celle qu'on regarde.
   Meme forme que les pastilles de personnes : la famille connait deja ce
   vocabulaire, une pastille pleine veut dire « c'est celle-la ».
   `admin.html` n'y figure pas : elle ne s'ouvre pas avec le code famille,
   et l'annoncer ici ne ferait qu'inviter a la pousser. */
.menu {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 22px;
}
.menu a {
  padding: 7px 15px;
  border: 1px solid var(--trait);
  border-radius: 999px;
  background: var(--carte);
  color: var(--doux);
  font-size: 0.93rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.menu a:hover {
  background: var(--survol);
  color: var(--texte);
  border-color: var(--doux);
}
/* `aria-current` porte l'information, et le style s'y accroche : un seul
   endroit a tenir a jour, et les lecteurs d'ecran annoncent la page
   courante sans qu'on ait rien a ajouter. */
.menu a[aria-current="page"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* ---------- Onglets de la page organisateur ---------- */

/* Meme forme que les pastilles et que le menu principal : la page
   n'introduit pas un troisieme vocabulaire pour dire « c'est celui-la ».
   Ce qui change, c'est le rattachement -- un trait continu sous la rangee,
   que l'onglet ouvert interrompt, pour qu'on voie qu'il tient au volet
   d'en dessous et non a la page. */
.onglets {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 20px;
  border-bottom: 1px solid var(--trait);
  padding-bottom: 0;
}
.onglets [role="tab"] {
  background: transparent;
  color: var(--doux);
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: 8px 8px 0 0;
  padding: 9px 16px;
  font-size: 0.93rem;
  font-weight: 500;
  margin-bottom: -1px;
}
.onglets [role="tab"]:hover {
  background: var(--survol);
  color: var(--texte);
}
/* L'etat vit dans `aria-selected`, et le style s'y accroche : un seul
   endroit a tenir a jour, et le lecteur d'ecran dit la meme chose que
   l'oeil. */
.onglets [role="tab"][aria-selected="true"] {
  background: var(--carte);
  color: var(--texte);
  border-color: var(--trait);
  border-bottom: 1px solid var(--carte);
  font-weight: 600;
}

/* Le volet ne porte aucun cadre : ce sont les fieldsets qu'il contient qui
   en ont un. Deux cadres imbriques feraient une boite dans une boite pour
   ne rien ajouter. */
.volet:focus { outline: none; }

h1 { font-size: 1.6rem; margin: 0 0 4px; }
h2 { font-size: 1.05rem; margin: 0 0 12px; }
.sous-titre { color: var(--doux); margin: 0 0 28px; }

fieldset {
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 20px;
  margin: 0 0 20px;
}
legend { font-weight: 600; padding: 0 8px; }

/* Un panneau qui se plie. Meme boite que `fieldset`, et son resume tient
   lieu de legende -- a ceci pres qu'il se clique, ce que le curseur et le
   triangle natif disent tous les deux. */
details.panneau-pliable {
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 14px 20px;
  margin: 0 0 20px;
}
details.panneau-pliable > summary {
  font-weight: 600;
  cursor: pointer;
  /* Le pointille du focus suit le resume, pas la boite entiere. */
  border-radius: 6px;
}
details.panneau-pliable > summary:hover { color: var(--accent); }
/* Une fois ouvert, le resume respire comme une legende : sans cela le
   premier element du panneau lui colle dessous. */
details.panneau-pliable[open] > summary { margin-bottom: 14px; }

label { display: block; font-size: 0.9rem; color: var(--doux); margin-bottom: 4px; }

input[type="text"], input[type="date"], input[type="number"], select {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--trait);
  border-radius: 6px;
  background: #fff;
  font: inherit;
  color: inherit;
}

.grille { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
th, td { padding: 8px 6px; border-bottom: 1px solid var(--trait); text-align: center; }
th:first-child, td:first-child { text-align: left; white-space: nowrap; }
thead th { color: var(--doux); font-weight: 600; }
td select { width: auto; min-width: 104px; }

/* La grille des tarifs : un tableau par type de couchage, et des nombres
   courts alignes sous leur colonne. Le titre du tableau porte le nom du
   couchage -- sans lui, huit tableaux de chiffres se ressemblent tous. */
table.tarifs { margin-bottom: 18px; }
table.tarifs caption {
  text-align: left;
  font-weight: 600;
  padding: 10px 0 8px;
}
table.tarifs th[scope="row"] { color: var(--doux); font-weight: 500; }
table.tarifs input[type="number"] { min-width: 4.5em; text-align: right; }

/* Un bouton pose a cote d'un champ : il s'aligne sur la ligne de
   saisie, et non sur l'etiquette qui la surmonte. */
.bouton-en-bas { display: flex; align-items: flex-end; }

/* Recopier la premiere valeur sur toute la ligne. Discret : c'est une
   commodite qu'on trouve en remplissant, pas une action qu'on cherche. */
button.etendre {
  background: transparent;
  border: 1px solid var(--trait);
  color: var(--doux);
  border-radius: 6px;
  padding: 1px 7px;
  margin-left: 8px;
  font-size: 0.85rem;
  font-weight: 600;
}
button.etendre:hover {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
}

/* Le bouton qui recopie un tableau sur ses voisins se range sous lui, et
   respire moins que les boutons de tete. */
.recopier { margin: -8px 0 20px; }

/* La remise n'est pas un prix : elle se retranche de ceux du dessus. Le
   trait dit la difference, et l'empeche de se perdre au milieu des
   douze cases d'une chambre. */
table.tarifs tr.a-part th, table.tarifs tr.a-part td {
  border-top: 2px solid var(--trait);
}

/* La colonne des totaux porte le chiffre qu'on vient chercher : elle se
   lit avant les autres. */
td.total-personne { font-weight: 700; }
tfoot th, tfoot td { border-top: 2px solid var(--trait); font-weight: 700; }

/* Cinq nuits font huit colonnes, quinze repas en font seize : au-dela
   d'une certaine largeur, un tableau se fait defiler plutot que de se
   tasser jusqu'a l'illisible. */
.tableau-large { overflow-x: auto; }
.tableau-large table { min-width: 100%; width: auto; }
.tableau-large th, .tableau-large td { white-space: nowrap; }

/* Les tableaux d'argent et de l'hotel (facture, comptes, onglets Facture
   et Hotel) gardent leur EN-TETE et leur PREMIERE COLONNE sous les yeux :
   soixante lignes et seize colonnes, et l'on ne sait plus quelle case
   est a qui ni de quelle nuit elle parle.

   `sticky` se colle au premier ancetre qui defile. Le cadre doit donc
   defiler dans les deux sens, lui : sans hauteur maximale, il grandirait
   avec le tableau, ne defilerait jamais en hauteur, et l'en-tete partirait
   avec la page.

   Les cases figees ont un fond plein -- sinon on lirait a travers -- et
   leur trait est une ombre : avec `border-collapse`, une bordure reste
   au tableau et ne suit pas la case qui se fige. */
.tableau-fige { max-height: 75vh; overflow: auto; }
.tableau-fige thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--carte);
  box-shadow: inset 0 -1px 0 var(--trait);
}
.tableau-fige tr > :first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--carte);
  box-shadow: inset -1px 0 0 var(--trait);
}
/* Le coin, fige dans les deux sens, passe au-dessus des deux. */
.tableau-fige thead tr > :first-child {
  z-index: 3;
  box-shadow: inset -1px -1px 0 var(--trait);
}

/* Chaque famille ferme sur sa somme : c'est la ligne qu'on cherche quand
   on prepare un virement. */
tr.sous-total th, tr.sous-total td {
  background: var(--carte);
  font-weight: 700;
  border-bottom: 2px solid var(--trait);
}

/* Une case a zero se marque d'un tiret : dans un tableau de seize
   colonnes, « 0,00 € » repete partout noie les vrais montants. */
td.rien { color: var(--doux); }

/* ---------- A table ---------- */
/* Une personne, quatre cases. Le nom au-dessus, les cases en dessous :
   sur un telephone elles tiennent sur deux lignes, sur un ecran sur
   une seule, et dans les deux cas on voit a qui elles appartiennent. */
.personne-regime {
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
}
.nom-regime { display: flex; align-items: center; gap: 8px; }
.cases-regime { display: flex; flex-wrap: wrap; gap: 4px 22px; }
.cases-regime .interrupteur { margin: 6px 0 0; }

/* Une page fermee par l'organisateur. En haut, pleine largeur, et avant
   tout le reste : le message qui vivait sous le bouton d'enregistrement
   arrivait apres qu'on avait rempli la grille. */
.bandeau-ferme {
  margin: 0 0 20px;
  padding: 12px 16px;
  border: 1px solid var(--erreur);
  border-left: 4px solid var(--erreur);
  border-radius: 8px;
  background: #fff;
}

/* ---------- L'historique ---------- */
/* Une ligne par geste, du plus recent au plus ancien, et le detail sous le
   pli. Les lignes se suivent de pres : c'est une liste qu'on parcourt, pas
   un formulaire qu'on remplit. */
details.geste {
  border: 1px solid var(--trait);
  border-radius: 8px;
  padding: 8px 12px;
  margin-bottom: 6px;
}
details.geste > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  cursor: pointer;
  border-radius: 6px;
}
details.geste > summary:hover { color: var(--accent); }
details.geste .quand { color: var(--doux); font-size: 0.82rem; }
details.geste .quoi { font-weight: 600; }
/* Un geste deja annule se lit encore -- c'est l'historique -- mais il ne
   se repropose pas. */
details.geste.annule > summary .quoi { text-decoration: line-through; opacity: 0.6; }

/* Un jalon n'est pas un geste : c'est un socle. Le trait plein le detache
   de la liste qu'il ferme. */
.jalon {
  border: 1px solid var(--trait);
  border-left: 4px solid var(--accent);
  border-radius: 8px;
  padding: 8px 12px;
  margin-bottom: 6px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
}
/* La date, le motif et les compteurs sur une ligne, et les boutons au
   bout de la meme : sans cette part flexible, le bloc de gauche prenait
   toute la largeur et renvoyait les boutons a la ligne suivante. */
.jalon-quoi {
  flex: 1 1 16em;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
}

/* Le detail d'un geste : « diner : non -> oui », une ligne par champ. */
.changement { font-size: 0.86rem; margin: 4px 0 0; }
.changement .champ { color: var(--doux); }
.changement .fleche { color: var(--doux); margin: 0 4px; }

/* Un bouton qui doit s'aligner sur le bas d'un champ voisin, et non sur
   le haut de son etiquette. */
.aligne-bas { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; }

/* ---------- Comment un type se facture ---------- */
/* Les trois questions, juste au-dessus du tableau de prix dont elles
   commandent les colonnes. Une bande discrete : c'est un reglage qu'on
   pose une fois, pas la saisie du jour. */
.facturation {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px 18px;
  padding: 10px 12px;
  margin-bottom: 6px;
  border: 1px dashed var(--trait);
  border-radius: 8px;
  background: var(--carte);
}
.facturation .reglage {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  font-size: 0.82rem;
  color: var(--doux);
}
.facturation select { width: auto; min-width: 12em; }
/* Les trois cases tiennent sur une ligne, et se replient sur un
   telephone plutot que de pousser le panneau en largeur. */
.facturation .repas-compris { flex-direction: column; }
.facturation .repas-compris .interrupteur { margin: 0; font-size: 0.88rem; }

/* ---------- Les activites ---------- */
/* Une idee, une reponse. L'intitule et la liste deroulante sur la meme
   ligne : c'est la paire qu'on lit, et sur un telephone elle se replie
   l'une sous l'autre plutot que de se tasser. */
.activite {
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
}
.activite-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 14px;
}
/* La liste deroulante prend toute la largeur par defaut, comme les autres
   champs. Ici elle ne porte que trois mots : elle se serre. */
.activite-tete select { width: auto; min-width: 9.5em; }
.activite .note { margin: 6px 0 0; }
.activite-bas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  margin-top: 8px;
}
.activite-bas .etiquettes { margin-left: 0; }

/* Les noms, derriere un pli. Depliee, la liste des « non » fait soixante
   prenoms sous chaque idee, et la page ne montre plus les idees. */
details.qui-a-dit { margin-top: 8px; }
details.qui-a-dit > summary {
  font-size: 0.83rem;
  color: var(--doux);
  cursor: pointer;
  border-radius: 6px;
}
details.qui-a-dit > summary:hover { color: var(--accent); }
details.qui-a-dit .note { margin: 6px 0 0; }

/* Dans le tableau de l'organisateur, la case se centre sous sa colonne
   comme un chiffre le ferait. */
td .interrupteur { margin: 0; justify-content: center; }
input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--accent); }

button {
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 6px;
  padding: 12px 24px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
button:disabled { opacity: 0.5; cursor: default; }

/* Tous les paragraphes d'etat, et non le seul `#message`.
   Chaque panneau a fini par avoir le sien -- `#message-sejour`,
   `#message-lieux`, `#message-couchages`... -- et aucun n'heritait de ces
   trois lignes : un refus s'affichait dans la couleur du texte courant,
   c'est-a-dire comme une phrase ordinaire. Le selecteur les prend tous,
   et un panneau ajoute demain sera colore sans qu'on y pense. */
[id^="message"] { margin-top: 14px; font-size: 0.93rem; min-height: 1.5em; }
[id^="message"].ok { color: var(--ok); }
[id^="message"].erreur { color: var(--erreur); }

.note {
  font-size: 0.85rem;
  color: var(--doux);
  background: #efefea;
  border-left: 3px solid var(--trait);
  padding: 10px 12px;
  border-radius: 0 6px 6px 0;
  margin-top: 16px;
}

/* Un avertissement reste une note : meme boite, meme place, meme ton. Seuls
   le lisere et la couleur du texte changent. Ce n'est pas une erreur --
   l'action reste permise, et parfois voulue -- c'est une action dont la
   portee depasse ce qu'on croit cliquer. */
.note.alerte {
  border-left-color: var(--erreur);
  color: var(--texte);
}

.defilement { overflow-x: auto; }

/* Hors de l'ecran, mais dans le document. `display:none` serait plus court
   -- et c'est justement pour cela que LastPass, 1Password et les autres
   ignorent les champs qui le portent : un champ cache ainsi est le motif
   classique du piege. Reste la mise hors ecran, qu'ils lisent. */
.hors-ecran {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  border: 0;
}

/* ---------- Champ + bouton sur une ligne ---------- */
.ligne-champ { display: flex; gap: 10px; align-items: stretch; }
.ligne-champ input { flex: 1; }
.ligne-champ button { padding: 9px 20px; white-space: nowrap; }

/* ---------- Autocomplétion ---------- */
.auto { position: relative; }

#suggestions {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}
#suggestions:empty { display: none; }

#suggestions li {
  padding: 11px 12px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--trait);
}
#suggestions li:last-child { border-bottom: 0; }
#suggestions li:hover, #suggestions li:focus {
  background: var(--accent);
  color: #fff;
  outline: none;
}
#suggestions span { color: var(--doux); font-size: 0.87rem; }
#suggestions li:hover span, #suggestions li:focus span { color: #fff; opacity: 0.85; }

/* ---------- Sélecteur de personne ---------- */
.pastilles { display: flex; flex-wrap: wrap; gap: 8px; }

.pastille {
  background: transparent;
  color: var(--texte);
  border: 1px solid var(--trait);
  border-radius: 999px;
  padding: 8px 15px;
  font-size: 0.93rem;
  font-weight: 500;
}
.pastille.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.pastille .moi { opacity: 0.7; font-weight: 400; }
.pastille .vide { color: var(--accent); font-weight: 700; }
.pastille.active .vide { color: #fff; }

/* ---------- Grille ---------- */
/* Plus de monde que de places cette nuit-la. Ce n'est pas une erreur --
   la saisie reste ouverte, et c'est a l'organisateur de trancher -- mais
   ca doit sauter aux yeux dans un tableau de chiffres. La couleur ne porte
   pas seule : la cellule a aussi un `title` qui dit l'ecart. */
/* Une case qui s'explique au survol : un supplement, une reduction. Le
   souligne pointille dit qu'il y a quelque chose a lire. */
td.explique {
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  cursor: help;
}

td.trop {
  color: var(--erreur);
  font-weight: 700;
}

tr.absente td:first-child { color: var(--doux); }
tr.absente select { color: var(--doux); }

.actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }

button.discret {
  background: transparent;
  color: var(--doux);
  border: 1px solid var(--trait);
  font-weight: 500;
}
/* Le texte passe en pleine couleur sur un fond a peine marque. Un survol
   doit toujours ajouter du contraste : sans fond pose ici, une couleur de
   texte claire ou sombre finit forcement par se confondre avec l'un des
   deux themes. */
button.discret:hover {
  background: var(--survol);
  color: var(--texte);
  border-color: var(--doux);
}

/* ---------- Page d'administration ---------- */
.titre-groupe { margin-top: 18px; }
.discret-inline { color: var(--doux); font-weight: 400; font-size: 0.85rem; }

.titre-famille {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--doux);
  margin: 18px 0 6px;
}
.titre-famille:first-child { margin-top: 0; }

.personne {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--trait);
}
.personne > div { flex: 1; min-width: 0; }
.personne .lien {
  display: block;
  font-size: 0.83rem;
  color: var(--doux);
}

.etiquettes { display: inline-flex; gap: 5px; margin-left: 8px; }
.etiquette {
  font-size: 0.72rem;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--trait);
  color: var(--doux);
}
.etiquette.ok { color: var(--ok); border-color: var(--ok); }

/* Ce que la date de naissance dirait, quand la categorie posee dit autre
   chose. Ce n'est pas une erreur -- l'hotel compte parfois autrement -- mais
   ca doit se voir dans une liste de soixante lignes. */
.etiquette.alerte { color: var(--erreur); border-color: var(--erreur); }

button.retirer {
  background: transparent;
  color: var(--doux);
  border: 1px solid var(--trait);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 0.9rem;
  line-height: 1.2;
  flex: none;
}
button.retirer:hover { color: #fff; background: var(--erreur); border-color: var(--erreur); }

/* Vider un plan n'est pas le reporter. Meme forme que ses voisins --
   la rangee doit rester lisible -- mais le survol passe au rouge :
   c'est la seule des trois actions qui efface. */
#couchages-vider:hover {
  color: #fff;
  background: var(--erreur);
  border-color: var(--erreur);
}

/* Meme forme que le bouton de retrait, autre intention : corriger n'est
   pas supprimer, et le survol ne doit pas passer au rouge. */
button.modifier {
  background: transparent;
  color: var(--doux);
  border: 1px solid var(--trait);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 0.9rem;
  line-height: 1.2;
  flex: none;
}
button.modifier:hover {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
}

/* Le prenom se corrige la ou il se lit : le champ prend la place du nom,
   pas celle de la page. */
.renommage { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.renommage input { flex: 1; min-width: 120px; }
.renommage button { padding: 7px 14px; font-size: 0.9rem; }

/* Meme geste pour une ligne d'inventaire, trois champs au lieu d'un. Un
   nombre n'a pas besoin de s'etirer comme un prenom : seul le type garde
   de quoi se lire en entier. */
.renommage select { flex: 0 1 auto; width: auto; min-width: 9.5em; }
.renommage input[type="number"] { flex: 0 0 4.5em; min-width: 0; }
/* Une date a une largeur qu'elle connait : le navigateur y dessine trois
   champs et un calendrier, et l'etirer ne la rend pas plus lisible. */
.renommage input[type="date"] { flex: 0 0 auto; width: auto; min-width: 0; }

/* Un de plus, un de moins : le geste le plus frequent de l'inventaire, et
   celui qui ne merite pas d'ouvrir un formulaire. Le nombre au milieu n'est
   pas un champ -- il ne se saisit pas, il se compte. */
.pas-a-pas { display: flex; align-items: center; gap: 6px; flex: none; }
.pas-a-pas .valeur {
  min-width: 1.7em;
  text-align: center;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

button.pas {
  background: transparent;
  color: var(--texte);
  border: 1px solid var(--trait);
  border-radius: 6px;
  padding: 2px 11px;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.35;
  flex: none;
}
button.pas:hover {
  background: var(--survol);
  border-color: var(--doux);
}

/* ---------- Le fil des étapes ---------- */

/* Code famille puis prénom : deux champs de texte, au même endroit, dans
   un cadre identique. On tape le code, la page répond… et rien ne semble
   avoir bougé. Le fil apparaît à l'acceptation et ne repart plus : il y a
   désormais quelque chose qui n'y était pas. */
.fil {
  margin: 0 0 18px;
  padding: 10px 14px;
  border-left: 4px solid var(--ok);
  border-radius: 0 6px 6px 0;
  background: #eaf3ed;
  color: var(--texte);
  font-size: 0.92rem;
}
.fil strong { color: var(--ok); }

/* Et le panneau qui arrive se signale une fois, brièvement. Sous
   `prefers-reduced-motion`, rien ne bouge : l'animation est un renfort,
   jamais le seul message. */
@media (prefers-reduced-motion: no-preference) {
  .surgit { animation: surgit 0.3s ease-out; }
}
@keyframes surgit {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Les deux panneaux de la page des dates ---------- */

/* L'un se remplit, l'autre se lit -- et ca doit se voir de loin. Deux
   variantes du meme cadre ne suffisent pas : on cherche encore ou cliquer
   dans le second.

   La saisie reste une CARTE posee sur la page : fond plein, coins arrondis,
   bord accentue du cote ou le regard arrive, ombre qui la souleve.

   Le resultat devient un BANDEAU : un aplat qui n'est ni la page ni la
   carte, aucun cadre, des angles droits, une barre accentuee en tete et un
   titre en capitales. Deux objets differents, pas deux nuances du meme. */
fieldset.panneau-saisie {
  border-left: 4px solid var(--accent);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.07);
}

/* Le bandeau des resultats. C'est un `details` depuis qu'il se plie : le
   `summary` remplace le `legend`, et le `float` qui empechait ce dernier de
   mordre la bordure n'a plus lieu d'etre. */
details.panneau-resultat {
  background: var(--bandeau);
  border: 0;
  border-top: 4px solid var(--accent);
  border-radius: 0;
  margin: 28px 0 20px;
  padding: 16px 20px 20px;
}
details.panneau-resultat > summary {
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--doux);
  cursor: pointer;
  border-radius: 6px;
}
details.panneau-resultat > summary:hover { color: var(--accent); }
details.panneau-resultat[open] > summary { margin-bottom: 12px; }
/* Le decompte reste une phrase : les capitales du titre ne l'atteignent pas. */
details.panneau-resultat > summary .discret-inline {
  text-transform: none;
  letter-spacing: 0;
}
/* Sur l'aplat du bandeau, une note grise sur gris se brouille : on lui
   retire son fond et on ne garde que le lisere. */
details.panneau-resultat .note {
  background: transparent;
}

/* ---------- Rapport du sondage ---------- */

.classement {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
}
.classement li {
  padding: 10px 0;
  border-bottom: 1px solid var(--trait);
}
.classement li:last-child { border-bottom: 0; }

.rang-titre { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }
.rang-titre .lien { color: var(--doux); font-size: 0.83rem; }

/* Les memes couleurs que les boutons de reponse : vert pour oui, rouge pour
   non, et le gris du fond pour ceux qui n'ont rien dit. La barre se lit donc
   sans legende, comme la carte. */
.barre {
  display: flex;
  height: 9px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--trait);
  margin: 7px 0 5px;
}
.barre span { display: block; }
.b-oui { background: var(--ok); }
.b-non { background: var(--erreur); }
.b-muet { background: var(--trait); }

/* Le verdict n'est ni une alerte ni une note de bas de page : c'est la
   reponse a la question que la page pose. Le lisere le dit sans crier --
   d'ou l'accent, la ou `.alerte` prend le rouge. */
.note.resultat {
  border-left-color: var(--accent);
  color: var(--texte);
}

.rang-chiffres {
  font-size: 0.82rem;
  color: var(--doux);
  font-variant-numeric: tabular-nums;
}

/* ---------- Différences avec une sauvegarde ---------- */

/* Une difference se lit en deux temps : ce qui s'est passe, puis a qui.
   L'etiquette porte le verbe, le texte porte le nom et les deux nombres. */
.diff {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 3px 0;
  font-size: 0.9rem;
}
.diff .diff-texte { color: var(--texte); }
.diff .etiquette { flex: none; }

/* ---------- Portée des droits ---------- */
.portee {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 5px;
  font-size: 0.8rem;
  color: var(--doux);
}
.portee select {
  width: auto;
  padding: 2px 6px;
  font-size: 0.8rem;
  border-radius: 5px;
}
.portee .compte {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---------- Sondage sur la date ---------- */
.option {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--trait);
}
.option:last-child { border-bottom: 0; }
.option-titre { flex: 1; min-width: 190px; }
.option-titre .lien { display: block; font-size: 0.82rem; color: var(--doux); }

.choix { display: flex; gap: 6px; flex: none; }
.choix button {
  background: transparent;
  color: var(--doux);
  border: 1px solid var(--trait);
  border-radius: 6px;
  padding: 7px 13px;
  font-size: 0.88rem;
  font-weight: 500;
}
.choix button.actif { color: #fff; border-color: transparent; }
.choix button.choix-oui.actif { background: var(--ok); }
.choix button.choix-non.actif { background: var(--erreur); }

.interrupteur {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 8px 0 0;
  color: var(--texte);
  cursor: pointer;
}

/* Une touche du clavier, citee dans une note. Le navigateur lui donne une
   fonte a chasse fixe et rien d'autre ; sans ce cadre, « Suppr » se lit
   comme un mot ordinaire au milieu d'une phrase. */
kbd {
  font: inherit;
  font-size: 0.82em;
  padding: 1px 6px;
  border: 1px solid var(--trait);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--carte);
  color: var(--texte);
  white-space: nowrap;
}

/* ---------- Plan de couchage ---------- */

/* Les nuits du sejour. Pas des onglets ARIA -- la page en a deja une rangee
   en tete -- mais des boutons a deux etages : la date, et combien de gens
   dorment sur place ce soir-la. Le second chiffre evite d'ouvrir une nuit
   vide pour s'en apercevoir. */
.nuits {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 16px;
}
.nuits .nuit {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  background: transparent;
  color: var(--doux);
  border: 1px solid var(--trait);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 0.86rem;
  font-weight: 500;
}
.nuits .nuit:hover { background: var(--survol); color: var(--texte); }
.nuits .nuit .combien {
  font-size: 0.74rem;
  font-variant-numeric: tabular-nums;
  opacity: 0.8;
}
.nuits .nuit[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Un rectangle par couchage. Ils se rangent tout seuls : l'inventaire en
   compte quatre une annee et onze la suivante, et aucune largeur fixe ne
   tiendrait les deux. */
.plan-grille {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}

.unite {
  border: 1px solid var(--trait);
  border-radius: 10px;
  background: var(--carte);
  padding: 10px 12px 12px;
}
.unite h4 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin: 0 0 8px;
  font-size: 0.92rem;
}
.unite .compte-unite {
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--doux);
  font-variant-numeric: tabular-nums;
}
.unite .compte-unite.trop { color: var(--erreur); font-weight: 700; }
.unite.debordee { border-color: var(--erreur); }

/* Le tas de ceux qui restent a placer n'est pas une unite : c'est lui qu'on
   regarde, et c'est lui qui doit se vider. Il prend donc toute la largeur,
   au-dessus, et un aplat qui le distingue des chambres. */
.unite.tas {
  background: var(--bandeau);
  border: 0;
  border-left: 4px solid var(--accent);
  border-radius: 0 10px 10px 0;
  margin-bottom: 14px;
}

/* La boite entiere recoit le depot, pas la seule bande des jetons : viser
   trois pixels de haut dans un rectangle vide serait un jeu d'adresse. */
.unite .places {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-height: 38px;
  align-content: flex-start;
}
.unite .places .vide {
  color: var(--doux);
  font-size: 0.82rem;
  font-style: italic;
  align-self: center;
}
.unite.visee {
  border-color: var(--accent);
  background: var(--survol);
}

/* Un jeton est un vrai bouton : il prend le focus, il s'active a la barre
   d'espace, et un lecteur d'ecran l'annonce -- ce qu'un <div draggable> ne
   fait pas. Le glisser-deposer ne repond ni au doigt ni au clavier ; le
   clic, si. */
.jeton {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  background: var(--carte);
  color: var(--texte);
  border: 1px solid var(--trait);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 0.88rem;
  font-weight: 500;
  cursor: grab;
  /* Rien a selectionner sur un jeton : le prenom n'est pas du texte a
     copier, c'est une poignee. Et une selection en cours ferait concurrence
     au glisser. */
  user-select: none;
  -webkit-user-select: none;
  /* Le glisser est suivi par la page elle-meme, au pointeur. Sans cette
     ligne, le doigt ferait defiler la page au lieu de deplacer le jeton --
     c'est le navigateur qui prendrait le geste, et il ne le rend pas. */
  touch-action: none;
}

/* Le sosie qui suit le curseur pendant le deplacement.
   `pointer-events: none` n'est pas un detail : c'est ce qui permet a
   `elementFromPoint` de voir le rectangle SOUS le fantome. Sans cela, le
   fantome se designerait lui-meme et aucune boite ne serait jamais visee. */
.jeton.fantome {
  position: fixed;
  z-index: 50;
  pointer-events: none;
  margin: 0;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.22);
  opacity: 0.92;
  transform: rotate(-1.5deg);
}
.jeton:hover { background: var(--survol); border-color: var(--doux); }
.jeton .etiquette { font-size: 0.68rem; padding: 0 6px; }

/* Ce qui distingue deux « Marie ». Nettement plus discret que le prenom :
   on cherche le prenom, on ne lit la precision que si l'on hesite. */
.jeton .precision {
  font-size: 0.76rem;
  font-weight: 400;
  color: var(--doux);
}
.jeton.saisi .precision { color: rgba(255, 255, 255, 0.85); }

/* Ceux dont on a la charge, et ceux qu'on ne fait que regarder.
   Le cercle vert n'est pas une decoration : c'est la seule chose qui dise,
   avant le premier clic, ce que la page laissera faire. Et le grise dit
   l'inverse sans avoir a l'ecrire soixante fois.
   Les deux tiennent aussi sans la couleur -- le trait est plus epais d'un
   cote, le jeton est en retrait de l'autre -- et le `title` de chaque jeton
   verrouille le dit en toutes lettres. */
.jeton.mien {
  border-width: 2px;
  border-color: var(--ok);
}
.jeton.mien:hover { border-color: var(--ok); background: #eaf3ed; }

.jeton.verrouille {
  background: transparent;
  color: var(--doux);
  border-style: dotted;
  cursor: default;
  /* Pas d'`opacity` : elle delaverait aussi le texte. Mesure faite, le gris
     a 75 % tombe a 3.2 contre le blanc -- sous le seuil, pour un prenom
     qu'on doit pouvoir lire meme quand on ne peut pas le deplacer. Le trait
     pointille et la couleur douce suffisent a dire « pas a toi ». */
}
.jeton.verrouille .precision,
.jeton.verrouille .etiquette { color: var(--doux); }

/* La note qui explique le cercle vert le montre plutot que de le decrire. */
.exemple-mien {
  border: 2px solid var(--ok);
  border-radius: 999px;
  padding: 0 8px;
  font-weight: 500;
  color: var(--texte);
}

/* Saisi : il attend qu'on designe une arrivee. L'etat se voit de loin,
   parce qu'entre-temps le prochain clic n'importe ou le deplacera. */
.jeton.saisi {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  cursor: grabbing;
}
.jeton.saisi .etiquette { color: #fff; border-color: rgba(255, 255, 255, 0.6); }

/* Pose ailleurs que ce qu'il avait demande. Ce n'est pas une erreur --
   l'organisateur arbitre -- mais l'ecart doit se lire sur le jeton, la ou
   il est, et non dans un message a part. Le pointille le dit sans crier,
   et le `title` donne le detail. */
.jeton.ecart {
  border-style: dashed;
  border-color: var(--erreur);
}

/* ---------- La porte d'entree ---------- */
/* Quatre choix, en cartes plutot qu'en liste de liens : on vient ici pour
   choisir, et une carte se vise du pouce. Le titre dit ou l'on va, la
   ligne du dessous ce qu'on y fera -- sans quoi « Le lieu » et « La date »
   se ressemblent trop pour qu'on sache lequel ouvrir. */
.choix { display: grid; gap: 12px; margin: 0 0 20px; }
.carte-choix {
  display: block;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 16px 18px;
  text-decoration: none;
  color: var(--texte);
}
.carte-choix:hover, .carte-choix:focus-visible { border-color: var(--accent); }
.carte-choix strong { display: block; margin-bottom: 4px; }
.carte-choix span { color: var(--doux); font-size: 0.93rem; }

/* ---------- Carte des départements ---------- */
.carte-cadre {
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 8px;
  margin: 12px 0 10px;
  /* L'infobulle des noms se pose dans le cadre, relativement a lui. */
  position: relative;
}

.carte-svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: 68vh;
  /* Sans cela, le glissé du doigt fait défiler la page au lieu de peindre. */
  touch-action: none;
  cursor: crosshair;
}
/* `carte-svg` et non `#carte` : admin.html montre la meme carte, en lecture
   seule, sous un autre identifiant. */
.carte-svg.lecture { cursor: default; }

/* Vert pour « on peut y aller », rouge pour « pas là » : le couple se lit
   sans légende, et c'est ce qui compte sur une carte qu'on parcourt du
   regard avant de la comprendre. */
.dep {
  fill: #6aab84;
  stroke: var(--carte);
  stroke-width: calc(1.2px / var(--zoom, 1));
  transition: fill 0.08s linear;
}
.carte-svg:not(.lecture) .dep:hover { fill: #5b9b75; }
/* En lecture, la teinte porte le nombre de refus : on ne la change pas sous
   la souris, on l'assombrit a peine -- assez pour voir quel departement la
   bulle decrit, pas assez pour se lire comme un autre nombre. */
.carte-svg.lecture .dep:hover { filter: brightness(0.9); }

.dep.refuse { fill: #c0392b; }

/* Du vert au rouge en passant par l'ambre : le nombre de refus se lit
   comme une température. La teinte de la vue famille est posee par
   `resultats.js`, en ligne : elle depend du plus grand nombre de refus,
   qu'une feuille de style ne connait pas. */

.carte-legende {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  font-size: 0.84rem;
  color: var(--doux);
  margin: 0 0 8px;
}
.pastille-legende {
  display: inline-block;
  width: 13px;
  height: 13px;
  border-radius: 3px;
  vertical-align: -2px;
  margin-right: 3px;
}
.pastille-legende.vert { background: #6aab84; }
.pastille-legende.rouge { background: #c0392b; }

/* Le degrade de la legende : de un refus au plus grand nombre observe. */
.legende-echelle { display: inline-flex; align-items: center; gap: 6px; }
.degrade-legende {
  display: inline-block;
  width: 110px;
  height: 13px;
  border-radius: 3px;
}

/* ---------- Pinceau et villes ---------- */

#pinceau {
  fill: rgba(217, 83, 79, 0.18);
  stroke: #d9534f;
  stroke-width: calc(1.5px / var(--zoom, 1));
  /* Sans cela, le disque du pinceau masquerait ce qu'il doit peindre. */
  pointer-events: none;
}

/* La couche entière est inerte : un nom de ville ne doit jamais interposer
   un trou dans lequel le pinceau ne peindrait pas. */
#couche-villes { pointer-events: none; }
#couche-villes.masquee, #pinceau.masquee { display: none; }

/* Blanc cerne de noir, et non l'inverse : c'est la seule combinaison qui
   tienne aussi bien sur le vert moyen que sur le rouge sature. Le cerne est
   trace SOUS le remplissage (`paint-order`), sinon il rongerait les lettres. */
.ville-point {
  fill: #ffffff;
  stroke: rgba(0, 0, 0, 0.7);
  stroke-width: calc(2px / var(--zoom, 1));
  r: calc(6.5px / var(--zoom, 1));
}
.ville-nom {
  font-size: calc(27px / var(--zoom, 1));
  font-weight: 600;
  fill: #ffffff;
  font-family: system-ui, sans-serif;
  paint-order: stroke;
  stroke: rgba(0, 0, 0, 0.72);
  stroke-width: calc(5.5px / var(--zoom, 1));
  stroke-linejoin: round;
}

/* ---------- Tutoriel sous la carte ---------- */
.tutoriel {
  margin: 4px 0 16px;
  padding-left: 22px;
  font-size: 0.89rem;
  color: var(--doux);
  line-height: 1.7;
}
.tutoriel strong { color: var(--texte); }

/* ---------- Qui est pour, qui est contre : la bulle de la carte ---------- */

/* Elle suit la souris sans jamais la gener : `pointer-events: none`, sans
   quoi elle s'interposerait entre le curseur et le departement, et
   s'eteindrait d'elle-meme en s'ouvrant. */
.infobulle-carte {
  position: absolute;
  z-index: 5;
  max-width: min(320px, 90%);
  padding: 9px 12px;
  background: var(--carte);
  color: var(--texte);
  border: 1px solid var(--trait);
  border-left: 4px solid var(--accent);
  border-radius: 6px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.18);
  font-size: 0.85rem;
  line-height: 1.4;
  pointer-events: none;
}
.infobulle-carte[hidden] { display: none; }
.infobulle-carte p { margin: 0 0 4px; }
.infobulle-carte .infobulle-titre { margin-bottom: 6px; }
/* Le rouge et le vert des boutons de reponse : on lit « non » et « oui »
   avant de lire le mot. */
.infobulle-non strong { color: var(--erreur); }
.infobulle-oui strong { color: var(--ok); }
.infobulle-muets { color: var(--doux); }

/* ---------- Zoom et pan de la carte ---------- */

/* Sur le cadre, en haut a droite, hors du chemin du pinceau. Le bouton de
   retour n'apparait que si l'on a zoome : sur une carte entiere il ne
   servirait a rien. */
.carte-zoom {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 4;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.carte-zoom button {
  width: 32px;
  height: 32px;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
  background: var(--carte);
  color: var(--texte);
  border: 1px solid var(--trait);
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
  cursor: pointer;
}
.carte-zoom button:hover { border-color: var(--accent); color: var(--accent); }
.carte-zoom button[hidden] { display: none; }

/* La carte zoomee se deplace a la molette enfoncee. */
.carte-svg.deplace, .carte-svg.deplace .dep { cursor: grabbing; }

/* La derniere ligne du classement des departements : ce qui est a egalite
   hors de la liste. Une mention, pas un rang. */
.classement li.rang-reste {
  color: var(--doux);
  font-size: 0.85rem;
  border-bottom: 0;
}
