/* ==================================================================
   KONSEIL — feuille de style de l'application
   Toutes les couleurs viennent de charte-tokens.css : aucun hexa ici.
   ================================================================== */

/* ==================================================================
   1. GABARIT DE PAGE
   ================================================================== */
.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.contenu {
  flex: 1;
  width: 100%;
  max-width: var(--largeur-max);
  margin: 0 auto;
  padding: 32px var(--gouttiere) 64px;
}

/* Colonne de lecture centree : formulaire de connexion, page d'erreur. */
.contenu-etroit {
  max-width: 560px;
  margin-inline: auto;
}

/* --- En-tete public ---------------------------------------------- */
.entete {
  border-bottom: 1px solid var(--bordure);
  background: var(--surface);
}

.entete-interieur {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: var(--largeur-max);
  margin: 0 auto;
  padding: 16px var(--gouttiere);
}

.marque {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--texte);
  font-family: var(--police-titre);
  font-size: 1.25rem;
  font-weight: 600;
  text-decoration: none;
}

.marque img { width: 32px; height: 32px; border-radius: var(--rayon-petit); }

.nav-publique {
  display: flex;
  align-items: center;
  gap: 20px;
  font-size: 0.95rem;
}

.nav-publique a { color: var(--texte-doux); text-decoration: none; }
.nav-publique a:hover { color: var(--texte); }

/* --- Pied de page ------------------------------------------------ */
.pied {
  border-top: 1px solid var(--bordure);
  background: var(--surface-2);
  color: var(--texte-doux);
  font-size: 0.875rem;
}

.pied-interieur {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  justify-content: space-between;
  max-width: var(--largeur-max);
  margin: 0 auto;
  padding: 28px var(--gouttiere);
}

.pied a { color: var(--texte-doux); }
.pied a:hover { color: var(--texte); }
.pied-liens { display: flex; flex-wrap: wrap; gap: 20px; }

/* ==================================================================
   2. SHELL APPLICATIF (pages connectees)
   Sidebar a gauche, contenu a droite. Sur telephone la sidebar passe
   au-dessus, en barre horizontale defilante.
   ================================================================== */
.appli { display: flex; min-height: 100vh; }

.barre-laterale {
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  gap: 24px;
  padding: 20px 16px;
  border-right: 1px solid var(--bordure);
  background: var(--surface-2);
}

.barre-laterale .marque { font-size: 1.1rem; }

/* --- Bouton burger, pilote par une case a cocher masquee -----------
   Sans JavaScript : la case porte l'etat, le CSS lit :checked. Le menu
   reste donc utilisable si un script ne se charge pas, et rien n'est
   ecrit en ligne — la CSP l'interdirait. */
.bascule-menu { position: absolute; opacity: 0; pointer-events: none; }

.barre-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.burger { display: none; }

.nav-appli { display: flex; flex-direction: column; gap: 2px; }

.nav-appli a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--rayon-petit);
  color: var(--texte-doux);
  font-size: 0.95rem;
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}

.nav-appli a:hover { background: var(--surface-3); color: var(--texte); }

.nav-appli a[aria-current="page"] {
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-weight: 500;
}

.barre-laterale-pied {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--bordure);
  color: var(--texte-tres-doux);
  font-size: 0.8rem;
}

.appli-corps { flex: 1; min-width: 0; }

/* Pleine largeur : dans le shell applicatif, la barre laterale donne
   deja la marge de gauche. Brider le contenu a 1240px et le centrer
   laissait deux bandes vides sur un ecran large, alors que ce sont
   justement les tableaux de depenses et de comptes qui ont besoin de
   place. */
.appli-contenu {
  width: 100%;
  padding: 28px var(--gouttiere) 64px;
}

/* ==================================================================
   3. COMPOSANTS
   ================================================================== */

/* --- Titre de section -------------------------------------------- */
.titre-section {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 18px;
}

/* Le titre porte deja sa propre marge basse (regle h1-h4) : ajoutee a celle
   de .titre-section, elle creusait un trou entre le titre et le texte qui le
   suit. Le bloc gere son espacement, le titre ne gere plus le sien. */
.titre-section h1,
.titre-section h2 { margin-bottom: 0; }

.surtitre {
  margin: 0 0 6px;
  color: var(--accent-texte);
  font-family: var(--police-corps);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* --- Cartes ------------------------------------------------------ */
.grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

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

.carte h3 { margin-bottom: 6px; }
.carte p:last-child { margin-bottom: 0; }

/* DEUX CARTES EMPILEES NE SE TOUCHENT PAS.
   ------------------------------------------------------------------
   L'espacement ne venait que du « gap » des grilles. Une carte tire sa
   place de son conteneur, donc deux cartes posees l'une sous l'autre
   dans le flux normal — deux encadres d'avertissement, une fiche
   suivie d'un tableau — se collaient bord a bord, et leurs deux traits
   de 1px se lisaient comme une seule boite coupee en deux.

   La marge se pose sur la carte elle-meme, et se retire la ou une
   gouttiere fait deja le travail : dans une grille, et sur la
   derniere du lot. Corriger conteneur par conteneur aurait laisse
   ressortir le defaut au prochain endroit ou l'on empile deux cartes. */
/* 20px, et non var(--gouttiere) : celle-ci vaut 64px sur grand ecran,
   parce qu'elle espace la PAGE de ses bords. Entre deux cartes, ce
   serait un trou. */
.carte { margin-bottom: 20px; }

.carte:last-child { margin-bottom: 0; }

/* Dans une grille, c'est « gap » qui espace : une marge en plus
   creuserait deux fois entre les lignes. */
.grille > .carte,
.grille-1-1 > .carte,
.grille-1-2 > .carte,
.grille-2-1 > .carte,
.grille-3 > .carte { margin-bottom: 0; }

.carte-lien {
  color: inherit;
  text-decoration: none;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.carte-lien:hover {
  border-color: var(--bordure-forte);
  box-shadow: var(--ombre-flottante);
}

/* Chiffre-cle d'un tableau de bord. */
.chiffre {
  display: block;
  font-family: var(--police-titre);
  font-size: 2rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.chiffre-positif { color: var(--vert); }
.chiffre-negatif { color: var(--rouge); }

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

/* --- Pastilles de statut ----------------------------------------- */
.pastille {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--rayon-pilule);
  background: var(--surface-3);
  color: var(--texte-doux);
  font-size: 0.78rem;
  font-weight: 500;
  white-space: nowrap;
}

.pastille-ok { background: var(--vert-doux); color: var(--vert); }
.pastille-attente { background: var(--ambre-doux); color: var(--ambre); }
.pastille-retard { background: var(--rouge-doux); color: var(--rouge); }
.pastille-info { background: var(--bleu-doux); color: var(--bleu); }

/* --- Boutons ------------------------------------------------------ */
.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 20px;
  border: 1px solid transparent;
  border-radius: var(--rayon-petit);
  background: var(--accent);

  /* L'encre du bouton primaire est CALCULEE a partir de la couleur
     choisie (voir _php/config.php), pas figee en blanc. Sur un accent
     clair — terracotta, jaune, vert d'eau — un texte blanc tombe sous
     le contraste AA et devient penible a lire ; l'encre bascule alors
     au noir. Sur un accent sombre elle reste blanche. C'est la seule
     facon de laisser choisir n'importe quelle couleur sans produire un
     bouton illisible (regle 10e). */
  color: var(--accent-encre, var(--texte-inverse));
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}

.bouton:hover { background: var(--accent-fonce); color: var(--accent-encre, var(--texte-inverse)); }

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

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

.bouton-discret {
  padding: 6px 12px;
  border-color: transparent;
  background: none;
  color: var(--texte-doux);
  font-size: 0.9rem;
}

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

.bouton-bloc { width: 100%; }

/* --- Formulaires -------------------------------------------------- */
/* --- LE CHAMP : LIBELLE EN TETE, VALEUR A COTE ---------------------
   Le libelle au-dessus et l'aide en dessous, cela faisait trois lignes
   de hauteur par champ : une fiche de dix champs ne tenait plus dans un
   ecran, et il fallait defiler pour relire ce qu'on venait de saisir.

   Le libelle passe donc a GAUCHE, dans une pastille collee au champ —
   les deux forment un seul objet encadre — et l'aide devient le texte
   de substitution, visible tant que le champ est vide. Un champ = une
   ligne.

   L'aide reste accessible une fois le champ rempli : « title » au
   survol et paragraphe pour lecteur d'ecran (voir champ() dans
   _php/ui.php). Une information qui ne vivrait que dans un placeholder
   disparaitrait a la premiere frappe. */
.appli .champ {
  display: grid;
  /* TOUS LES LIBELLES A LA MEME LARGEUR, celle du plus long de
     l'application (« Surface habitable (m² ) », 22 signes). Une pastille
     qui s'ajuste a chaque libelle donne autant de bords gauches qu'il y
     a de champs : l'oeil ne trouve plus de colonne ou s'appuyer, et la
     fiche parait de travers. */
  grid-template-columns: 13rem minmax(0, 1fr);
  align-items: stretch;
  margin-bottom: 10px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  overflow: hidden;
  background: var(--surface);
  transition: border-color var(--transition);
}

.appli .champ > label {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 10px 12px;
  border-right: 1px solid var(--bordure);
  background: var(--surface-2);
  color: var(--texte-doux);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.25;
  text-transform: uppercase;
}

/* Le champ lui-meme perd son cadre : c'est l'enveloppe qui le porte
   desormais, sans quoi on verrait deux traits l'un contre l'autre. */
.appli .champ > input,
.appli .champ > select,
.appli .champ > textarea {
  border: 0;
  border-radius: 0;
  background: transparent;
  /* Sans cela, un champ de fichier garde sa largeur naturelle et
     deborde de sa colonne au lieu de s'y plier. */
  min-width: 0;
}

/* LE FOCUS RESTE VISIBLE, et il l'est meme davantage qu'avant : c'est
   tout l'encadre qui s'allume, pas seulement le rectangle de saisie
   (regle 10e — jamais d'outline supprime sans remplacement). */
.appli .champ:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-doux);
}

.appli .champ > input:focus,
.appli .champ > select:focus,
.appli .champ > textarea:focus {
  outline: none;
  border-color: transparent;
}

/* UNE CASE A COCHER NE SE MET PAS EN PASTILLE. La case et son libelle
   forment une phrase qu'on lit de gauche a droite — « Répartir entre les
   membres selon les quotes-parts » —, pas un intitule de colonne. Serree
   dans 9,5 rem, elle s'empilait sur cinq lignes. */
.appli .champ-case {
  display: block;
  padding: 10px 13px;
}

.appli .champ-case > label {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  color: var(--texte);
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
}

.appli .champ-case > .aide:not(.lecteur-seul) {
  grid-column: auto;
  padding: 6px 0 0;
}

/* Une zone de texte fait plusieurs lignes de haut : son libelle se cale
   en haut, sinon il flotte au milieu d'un bloc vide. */
.appli .champ-zone > label {
  align-items: flex-start;
  padding-top: 13px;
}

/* L'aide est rendue par champ() en « lecteur-seul » : elle vit dans le
   texte de substitution et dans le title. Cette regle ne sert plus qu'a
   une aide ecrite a la main dans une page. */
.champ .aide {
  margin: 6px 0 0;
  color: var(--texte-doux);
  font-size: 0.83rem;
}

/* HORS DE L'ADMIN, l'aide se lit sous le champ comme avant. champ() la
   marque « lecteur-seul » parce qu'elle part dans le texte de
   substitution — ce qui n'a de sens que la ou le libelle est passe a
   gauche, c'est-a-dire dans le shell applicatif. */
.page .champ .aide.lecteur-seul {
  position: static;
  width: auto;
  height: auto;
  clip-path: none;
  white-space: normal;
}

.appli .champ > .aide:not(.lecteur-seul) {
  grid-column: 2;
  margin: 0;
  padding: 0 13px 10px;
}

/* Dans une carte etroite — une colonne sur quatre —, une pastille de
   9,5 rem ne laisse plus rien au champ : le libelle repasse au-dessus.
   On mesure la CARTE et non la fenetre : c'est la largeur disponible
   qui compte, pas celle de l'ecran. */
.appli .carte,
.appli .carte-formulaire {
  container-type: inline-size;
}

/* Le seuil se mesure sur la BOITE DE CONTENU de la carte, padding
   deduit : une carte de 567 px n'offre que 519 px a ses champs. A 28 rem
   (448 px), la pastille de 12 rem laisse encore 256 px a la valeur ;
   en dessous, elle repasse au-dessus du champ. */
@container (width < 28rem) {
  .appli .champ { grid-template-columns: minmax(0, 1fr); }

  .appli .champ > label {
    border-right: 0;
    border-bottom: 1px solid var(--bordure);
    padding: 7px 12px;
  }

  .appli .champ-zone > label { padding-top: 7px; }

  /* Il n'y a plus qu'une colonne : renvoyer l'aide dans la seconde en
     creerait une fantome, et toute la grille se decalerait. */
  .appli .champ > .aide:not(.lecteur-seul) {
    grid-column: 1;
    padding: 0 12px 8px;
  }
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="number"],
input[type="search"],
select,
textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: inherit;
  font-size: 1rem;
  transition: border-color var(--transition);
}

input:hover,
select:hover,
textarea:hover { border-color: var(--texte-tres-doux); }

textarea { min-height: 120px; resize: vertical; }

/* Champ leurre anti-robot : invisible a l'oeil, present dans le DOM. */
.pot-de-miel {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --- Messages ----------------------------------------------------- */
.message {
  margin-bottom: 24px;
  padding: 14px 16px;
  border: 1px solid var(--bordure);
  border-left: 3px solid var(--texte-doux);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  font-size: 0.95rem;
}

.message-ok { border-left-color: var(--vert); background: var(--vert-doux); }
.message-erreur { border-left-color: var(--rouge); background: var(--rouge-doux); }
.message-info { border-left-color: var(--bleu); background: var(--bleu-doux); }

/* --- Tableaux ----------------------------------------------------- */
.table-enveloppe { overflow-x: auto; }

table.donnees {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.93rem;
}

table.donnees th,
table.donnees td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--bordure);
  text-align: left;
  vertical-align: top;
}

table.donnees th {
  color: var(--texte-doux);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

table.donnees td.nombre,
table.donnees th.nombre {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

table.donnees tbody tr:hover { background: var(--surface-2); }

/* Un montant ou une date ne se coupe jamais en deux : « 19 230,40 € »
   reparti sur trois lignes se lit comme trois nombres. */
table.donnees td.nombre,
table.donnees td.cellule-date { white-space: nowrap; }

/* --- Accueil public ----------------------------------------------- */
.accroche {
  padding: 56px 0 40px;
  border-bottom: 1px solid var(--bordure);
}

.accroche h1 { max-width: 18ch; }

.accroche .chapeau {
  max-width: 60ch;
  color: var(--texte-doux);
  font-size: 1.1rem;
}

.actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

/* --- Page hors ligne ---------------------------------------------- */
.hors-ligne {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: var(--gouttiere);
  text-align: center;
}

/* --- Contenu editorial (mentions legales, confidentialite) --------- */
.texte-long { max-width: 70ch; }
.texte-long h2 { margin-top: 2em; }
.texte-long ul { padding-left: 1.2em; }
.texte-long li { margin-bottom: 0.4em; }

/* ==================================================================
   4. RESPONSIVE — la sidebar ne devient verticale qu'a partir de 900px
   ================================================================== */
@media (width < 900px) {
  .appli { flex-direction: column; }

  .barre-laterale {
    gap: 0;
    padding: 12px var(--gouttiere);
    border-right: none;
    border-bottom: 1px solid var(--bordure);
  }

  /* Le bouton apparait, le menu se replie. Treize entrees en barre
     defilante, c'etait illisible au pouce : on ne voyait que les trois
     premieres et rien n'indiquait qu'il y en avait dix autres. */
  .burger {
    display: flex;
    flex-direction: column;
    gap: 5px;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 10px;
    border: 1px solid var(--bordure-forte);
    border-radius: var(--rayon-petit);
    background: var(--surface);
    cursor: pointer;
  }

  .burger-trait {
    display: block;
    height: 2px;
    border-radius: 2px;
    background: var(--texte);
    transition: transform var(--transition), opacity var(--transition);
  }

  .bascule-menu:focus-visible ~ .barre-tete .burger {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
  }

  /* Ouvert, le bouton devient une croix : l'etat se lit sans avoir a
     dérouler la page. */
  .bascule-menu:checked ~ .barre-tete .burger-trait:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .bascule-menu:checked ~ .barre-tete .burger-trait:nth-child(2) { opacity: 0; }
  .bascule-menu:checked ~ .barre-tete .burger-trait:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  .nav-appli,
  .barre-laterale-pied { display: none; }

  .bascule-menu:checked ~ .nav-appli,
  .bascule-menu:checked ~ .barre-laterale-pied { display: block; }

  .bascule-menu:checked ~ .nav-appli {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--bordure);
  }

  .nav-appli a {
    padding: 12px;          /* cible confortable au pouce */
    font-size: 1rem;
  }

  .barre-laterale-pied { margin-top: 12px; }
}

@media (width >= 900px) {
  /* Largeur pilotee par un jeton : le menu doit contenir son plus long
     libelle sur une seule ligne (regle 11i). */
  .barre-laterale { width: var(--barre-laterale); }
}

@media print {
  .barre-laterale,
  .entete,
  .pied,
  .actions { display: none; }

  body { background: none; }
}


/* ==================================================================
   5. FORMULAIRES DE SAISIE (lot L1)
   ================================================================== */

/* Respiration entre les blocs d'une page d'admin : sans elle, le titre
   d'une section colle aux cartes de la precedente et l'on ne voit plus
   ou l'une finit et l'autre commence. */
.appli-contenu > section { margin-top: 44px; }
.appli-contenu > .grille + section { margin-top: 40px; }
.appli-contenu > section:first-of-type { margin-top: 32px; }

/* Grille de champs : une colonne sur telephone, deux des qu'il y a la
   place. Les champs larges (adresse, notes) prennent toute la ligne. */
.grille-champs {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 20px;
}

.champ-large { grid-column: 1 / -1; }

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

.barre-actions-fin { margin-left: auto; }

/* Sous une fiche en colonnes, le bouton d'enregistrement n'appartient a
   aucune d'elles : il enregistre la fiche entiere. Il se pose donc au
   milieu, sous l'ensemble, et non calé a gauche sous la premiere. */
.barre-actions-centre {
  justify-content: center;
  margin-top: 0;
}

/* IL A SA PROPRE CARTE, sur toute la largeur du contenu. Pose a nu sous
   les colonnes, le bouton flottait sur le fond de page comme s'il
   appartenait a la carte du dessus ; dans sa bande, il se lit comme ce
   qu'il est : le pied de la fiche entiere. */
.carte-actions {
  padding: 16px 24px;
  margin-bottom: 32px;
}

/* Bloc de formulaire dans une carte. */
.carte-formulaire {
  padding: 24px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  margin-bottom: 32px;
}

.carte-formulaire h2 { margin-bottom: 20px; }

/* Ligne inactive d'un tableau : presente, mais visiblement retiree. */
tr.inactive td { color: var(--texte-tres-doux); }

/* Total d'une colonne de parts : vert s'il tombe juste, rouge sinon. */
.total-parts {
  font-family: var(--police-titre);
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
}

.total-juste { color: var(--vert); }
.total-faux  { color: var(--rouge); }

/* Barre de recherche et de filtres : les champs s'alignent et le bouton
   se cale sur leur ligne de base. */
.barre-recherche {
  display: flex;
  flex-wrap: wrap;
  gap: 0 16px;
  align-items: flex-end;
  margin-bottom: 24px;
}

.barre-recherche .champ { flex: 1 1 180px; }
.barre-recherche .champ:last-child { flex: 0 0 auto; }

/* Rangee de filtres cliquables. */
.filtres {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 24px;
}

.filtres a { text-decoration: none; }
.filtres a:hover { background: var(--surface-3); color: var(--texte); }

/* Un formulaire reduit a un bouton, glisse dans une ligne de tableau :
   il doit se comporter comme du texte, pas comme un bloc. */
.form-inline { display: inline; }

/* Actions en fin de ligne de tableau. */
td.actions {
  white-space: nowrap;
  text-align: right;
}

td.actions a { margin-left: 12px; font-size: 0.88rem; }

/* Galerie de photos : des vignettes de taille reguliere, sans etirer
   les images — un tirage en portrait et une facade en paysage doivent
   cohabiter sans deformation. */
.galerie {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}

.vignette {
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.vignette img {
  display: block;
  width: 100%;
  height: 180px;
  object-fit: cover;
  background: var(--surface-2);
}

.vignette figcaption {
  padding: 12px 14px;
  font-size: 0.85rem;
  line-height: 1.5;
}

.vignette figcaption .pastille { margin: 4px 4px 0 0; }

/* Etat vide : ni tableau fantome, ni fausses donnees. */
.vide {
  padding: 32px;
  border: 1px dashed var(--bordure-forte);
  border-radius: var(--rayon);
  color: var(--texte-doux);
  text-align: center;
}

.vide p:last-child { margin-bottom: 0; }

@media (width >= 720px) {
  .grille-champs { grid-template-columns: 1fr 1fr; }
}


/* ==================================================================
   6. CALENDRIER MENSUEL (lot L5)

   Une occupation est une PLAGE, pas un point : elle se dessine en barre
   continue, decoupee a la semaine. Les barres se placent avec
   grid-column, d'ou les classes .cal-cN (colonne de depart) et .cal-lN
   (nombre de jours) — la CSP interdit l'attribut style, et sept colonnes
   ne font que quatorze classes.
   ================================================================== */
.calendrier {
  overflow: hidden;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.cal-entetes {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-bottom: 1px solid var(--bordure);
  background: var(--surface-2);
}

.cal-entete {
  padding: 10px 6px;
  color: var(--texte-doux);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: uppercase;
}

/* Chaque semaine est sa propre grille : les barres s'empilent sous la
   ligne des numeros, et le placement automatique les serre. */
.cal-semaine {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px 2px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--bordure);
}

.cal-semaine:last-child { border-bottom: none; }

.cal-jour {
  grid-row: 1;
  min-height: 46px;
  padding: 6px 8px;
  border-right: 1px solid var(--bordure);
}

.cal-jour:nth-child(7n) { border-right: none; }
.cal-jour.hors-mois { background: var(--fond); }
.cal-jour.hors-mois .cal-numero { color: var(--texte-tres-doux); }

.cal-jour.aujourdhui { background: var(--accent-doux); }
.cal-jour.aujourdhui .cal-numero { color: var(--accent-texte); font-weight: 600; }

.cal-numero {
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  color: var(--texte-doux);
}

.cal-bande {
  overflow: hidden;
  min-width: 0;
  margin: 0 2px;
  padding: 3px 8px;
  border-left: 3px solid var(--texte-doux);
  border-radius: var(--rayon-petit);
  background: var(--surface-3);
  color: var(--texte);
  font-size: 0.78rem;
  line-height: 1.4;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cal-bande.annulee { opacity: 0.45; text-decoration: line-through; }
.cal-suite { color: var(--texte-doux); }

/* Colonne de depart et longueur, en jours. */
.cal-c1 { grid-column-start: 1; }
.cal-c2 { grid-column-start: 2; }
.cal-c3 { grid-column-start: 3; }
.cal-c4 { grid-column-start: 4; }
.cal-c5 { grid-column-start: 5; }
.cal-c6 { grid-column-start: 6; }
.cal-c7 { grid-column-start: 7; }

.cal-l1 { grid-column-end: span 1; }
.cal-l2 { grid-column-end: span 2; }
.cal-l3 { grid-column-end: span 3; }
.cal-l4 { grid-column-end: span 4; }
.cal-l5 { grid-column-end: span 5; }
.cal-l6 { grid-column-end: span 6; }
.cal-l7 { grid-column-end: span 7; }

/* Une teinte par membre, stable d'un mois sur l'autre ; le bleu est
   reserve aux locations, pour qu'on distingue au premier coup d'oeil
   « la famille » de « des inconnus qui paient ». */
.cal-loc { border-left-color: var(--bleu);   background: var(--bleu-doux); }
.cal-m0  { border-left-color: var(--accent); background: var(--accent-doux); }
.cal-m1  { border-left-color: var(--vert);   background: var(--vert-doux); }
.cal-m2  { border-left-color: var(--ambre);  background: var(--ambre-doux); }
.cal-m3  { border-left-color: var(--rouge);  background: var(--rouge-doux); }
.cal-m4  { border-left-color: var(--texte-doux); background: var(--surface-3); }
.cal-m5  { border-left-color: var(--accent-fonce); background: var(--accent-doux); }

.cal-legende {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.cal-legende .cal-bande { margin: 0; }

/* Sur telephone, sept colonnes de barres deviennent illisibles : on
   garde la grille mais on masque le texte des barres, la couleur et
   l'infobulle suffisent, et le tableau sous la grille reste la source
   detaillee. */
@media (width < 640px) {
  .cal-jour { min-height: 38px; padding: 4px; }
  .cal-bande { padding: 3px 4px; font-size: 0.68rem; }
}


/* ==================================================================
   7. CARNET DE BORD DU DOSSIER (lot L9)

   Une note se lit, elle ne se parcourt pas en tableau : d'ou le bloc
   plutot que la ligne. Ce qu'il y a A FAIRE se detache du reste, c'est
   la seule partie sur laquelle on agit.
   ================================================================== */
.note {
  margin-bottom: 12px;
  border: 1px solid var(--bordure);
  border-left: 3px solid var(--accent);
  border-radius: var(--rayon);
  background: var(--surface);
}

/* Le dossier se lit comme une FAQ : la liste des sujets d'abord, le
   detail au depliage. Un <details> natif, donc sans JavaScript — la
   CSP n'a rien a autoriser, et ca fonctionne meme script desactive. */
.note > summary {
  padding: 18px 22px;
  cursor: pointer;
  list-style: none;   /* Firefox */
}

.note > summary::-webkit-details-marker { display: none; }

.note > summary:hover { background: var(--surface-2); }

.note[open] > summary {
  border-bottom: 1px solid var(--bordure);
  background: var(--surface-2);
}

/* Le chevron dit ce qui va se passer, et tourne quand c'est fait. */
.note > summary::after {
  flex: 0 0 auto;
  align-self: center;
  color: var(--texte-doux);
  content: "⌄";
  font-size: 1.3rem;
  line-height: 1;
  transition: transform var(--transition);
}

.note[open] > summary::after { transform: rotate(180deg); }

.note-repere { flex: 1 1 260px; }
.note-repere .surtitre { display: block; margin-bottom: 4px; }

/* Le contenu deplie garde les marges qu'avait la fiche entiere. */
.note > *:not(summary) { margin-right: 22px; margin-left: 22px; }
.note > *:last-child { margin-bottom: 20px; }

.note.inactive {
  border-left-color: var(--bordure-forte);
  background: var(--fond);
}

.note.inactive h2 { color: var(--texte-doux); }

.note-tete {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-start;
  justify-content: space-between;
}

.note-tete h2 { margin-bottom: 0; font-size: 1.2rem; }
.note-tete .surtitre { margin-bottom: 4px; }
.note-tete { align-items: center; }

.note-etat {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.note-corps {
  margin-top: 16px;
  color: var(--texte-doux);
  line-height: 1.65;
}

/* Le bloc d'action : la seule partie sur laquelle on agit. */
.note-action {
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: var(--rayon-petit);
  background: var(--accent-doux);
  line-height: 1.6;
}

.note-action .surtitre { margin-bottom: 6px; }
.note-action .legende { margin: 8px 0 0; }

/* Un tableau glisse dans une note : chasse fixe, sinon les colonnes ne
   tombent plus en face. Il defile horizontalement plutot que de forcer
   la page a s'elargir. */
.note-tableau {
  overflow-x: auto;
  margin: 12px 0;
  padding: 12px 14px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--fond);
  color: var(--texte);
  font-family: ui-monospace, "sf mono", menlo, monospace;
  font-size: 0.78rem;
  line-height: 1.55;
  white-space: pre;
}

.note-corps p { margin: 0 0 0.9em; }
.note-corps p:last-child { margin-bottom: 0; }
.note-action p { margin: 0 0 0.7em; }
.note-action p:last-child { margin-bottom: 0; }

.note-pied {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--bordure);
}

.note .barre-actions { margin-top: 4px; }


/* ==================================================================
   8. CARTE CADASTRALE (lot L10)

   Dessinee en SVG dans la page, a partir de contours stockes en base :
   aucun fond de carte tiers, donc aucune fuite d'adresse IP.
   ================================================================== */
.carte-enveloppe {
  overflow-x: auto;
  padding: 12px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

/* Le plan lui-meme.
   Volontairement PAS nomme « .carte » : cette classe designe deja les
   cartes-fiches du tableau de bord. Les deux regles se seraient
   melangees — le SVG heritait du padding et du fond des fiches, et les
   fiches du detail se retrouvaient etirees. */
.carte-plan {
  display: block;
  width: 100%;
  height: auto;
  min-width: 520px;
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
}

/* Les contours se posent sur un fond de plan : liseré clair pour les
   detacher du bati, remplissage translucide pour laisser voir dessous.
   Un trait sombre se serait perdu dans les courbes de niveau. */
.parcelle {
  stroke: var(--surface);
  stroke-width: 1.5;
  stroke-linejoin: round;
  cursor: pointer;
  transition: fill-opacity var(--transition);
  fill-opacity: 0.5;
}

.parcelle:hover { fill-opacity: 0.8; }

a:focus-visible .parcelle {
  stroke: var(--texte);
  stroke-width: 3;
}

.p-oui     { fill: var(--vert); }
.p-partiel { fill: var(--ambre); }
.p-non     { fill: var(--rouge); }
.p-inconnu { fill: var(--texte-tres-doux); }

.p-choisie {
  fill: var(--accent);
  fill-opacity: 0.75;
  stroke: var(--texte);
  stroke-width: 4;
}

/* Survol d'un jeton : on montre ou est la parcelle avant meme le clic. */
.p-survol {
  fill-opacity: 0.9;
  stroke: var(--texte);
  stroke-width: 3;
}

.etiquette {
  fill: var(--texte);
  font-family: var(--police-corps);
  font-size: 13px;
  font-weight: 500;
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 3px;
  pointer-events: none;
}

.etiquette-choisie { font-size: 16px; font-weight: 700; }

.carte-legende {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}

.cl {
  padding: 4px 12px;
  border-left: 4px solid var(--texte-doux);
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
  font-size: 0.82rem;
}

.cl-oui     { border-left-color: var(--vert);   background: var(--vert-doux); }
.cl-partiel { border-left-color: var(--ambre);  background: var(--ambre-doux); }
.cl-non     { border-left-color: var(--rouge);  background: var(--rouge-doux); }
.cl-inconnu { border-left-color: var(--texte-tres-doux); }

.carte-detail { margin-top: 36px; }
.carte-detail .note-corps { max-width: 78ch; white-space: pre-wrap; }

/* --- Commandes de la carte -----------------------------------------
   Zoom, deplacement et choix du fond sont de simples liens : la vue
   est un centre et un zoom, le serveur recompose. Aucun JavaScript,
   donc rien a autoriser dans la CSP — et la carte reste pilotable si
   un script ne se charge pas. */
.carte-commandes {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 14px;
}

.carte-groupe {
  display: flex;
  overflow: hidden;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
}

.carte-bouton {
  padding: 8px 14px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte-doux);
  font-size: 0.85rem;
  line-height: 1.2;
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}

.carte-groupe .carte-bouton {
  border: 0;
  border-right: 1px solid var(--bordure);
  border-radius: 0;
}

.carte-groupe > :last-child { border-right: 0; }

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

.carte-bouton.est-actif {
  background: var(--accent);
  color: var(--texte-inverse);
}

/* Bouton en butee : on le garde visible, mais inerte — le faire
   disparaitre ferait sauter la rangee a chaque clic. */
.carte-bouton.est-inerte {
  color: var(--texte-tres-doux);
  cursor: default;
}

.carte-echelle {
  padding: 8px 12px;
  color: var(--texte-doux);
  font-size: 0.8rem;
  white-space: nowrap;
}

.carte-avis {
  padding: 10px 14px;
  border-left: 4px solid var(--ambre);
  border-radius: var(--rayon-petit);
  background: var(--ambre-doux);
}

/* --- Liste des parcelles ------------------------------------------
   Les parcelles sont dispersees sur plusieurs sections du cadastre :
   a l'echelle de l'ensemble, certaines font quelques pixels. Cette
   liste donne un acces direct au detail, sans viser au pixel. */
.titre-liste-parcelles { margin-top: 32px; margin-bottom: 12px; }

.liste-parcelles {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.jeton-parcelle {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 8px 14px;
  border: 1px solid var(--bordure);
  border-left: 4px solid var(--texte-tres-doux);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.jeton-parcelle:hover {
  border-color: var(--bordure-forte);
  box-shadow: var(--ombre-flottante);
}

.jeton-oui     { border-left-color: var(--vert); }
.jeton-partiel { border-left-color: var(--ambre); }
.jeton-non     { border-left-color: var(--rouge); }
.jeton-inconnu { border-left-color: var(--texte-tres-doux); }

.jeton-reference { font-weight: 600; }
.jeton-surface   { color: var(--texte-doux); font-size: 0.85rem; }

/* --- Fenetre modale du detail d'une parcelle -----------------------
   <dialog> gere seul le focus, la touche Echap et le fond grise : rien
   a reecrire en JavaScript. */
.modale {
  width: min(720px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  padding: 0;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  box-shadow: var(--ombre-flottante);
  color: var(--texte);
}

.modale::backdrop { background: rgb(0 0 0 / 45%); }

.modale-entete {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  justify-content: space-between;
  padding: 24px 24px 16px;
  border-bottom: 1px solid var(--bordure);
}

.modale-entete h2 { margin: 0; }

.modale-fermer {
  padding: 8px 16px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
  color: var(--texte);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
}

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

.modale-corps {
  overflow-y: auto;
  max-height: calc(100vh - 200px);
  padding: 24px;
}

.modale-corps .note-corps { max-width: none; white-space: pre-wrap; }

/* ==================================================================
   9. CHANTIERS DOCUMENTES (lot L11)

   Qui a fait le travail, les photos du chantier, et sa facture — avec
   le detail lu dans le document.
   ================================================================== */

/* Groupe de champs qui vont ensemble : « qui a realise le chantier »
   se lit comme UNE question a trois reponses possibles, pas comme
   trois champs sans rapport perdus dans la grille. */
.bloc-champs {
  margin: 0 0 24px;
  padding: 20px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface-2);
}

.bloc-champs legend {
  padding: 0 8px;
  font-size: 0.9rem;
  font-weight: 600;
}

.bloc-champs > .aide {
  margin: 0 0 16px;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

/* Case a cocher : le libelle reste sur la meme ligne que la case. La
   regle generale met les libelles en bloc, ce qui est juste pour un
   champ de saisie et faux pour une case. */
.champ label > input[type="checkbox"] {
  width: auto;
  margin-right: 8px;
  vertical-align: baseline;
}

input[type="file"] {
  width: 100%;
  padding: 10px 12px;
  border: 1px dashed var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
  font: inherit;
  font-size: 0.9rem;
}

/* Dans un champ encadre, le pointille ferait un second cadre a
   l'interieur du premier. */
.appli .champ > input[type="file"] {
  border: 0;
  border-radius: 0;
  background: transparent;
}

input[type="file"]:hover { border-color: var(--accent); }

/* --- Une facture de chantier --------------------------------------- */
.facture {
  margin-bottom: 24px;
  padding: 20px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.facture-tete {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 16px;
}

.facture-tete h3 { margin: 0 0 4px; }
.facture-tete .legende { margin: 0; }

.facture-montants { text-align: right; }
.facture-montants .chiffre { font-size: 1.6rem; }
.facture-montants .legende { margin: 2px 0 0; }

/* Le formulaire de creation de depense se distingue du reste de la
   fiche : c'est le seul endroit de la page qui touche a l'argent. */
.facture-depense {
  margin-top: 16px;
  padding: 16px;
  border-left: 4px solid var(--accent);
  border-radius: var(--rayon-petit);
  background: var(--accent-doux);
}

.facture-depense .grille-champs { margin-bottom: 0; }

@media (max-width: 640px) {
  .facture-tete { flex-direction: column; }
  .facture-montants { text-align: left; }
}

/* --- Cases a cocher en liste --------------------------------------
   Plusieurs personnes peuvent avoir fait le meme chantier : des cases
   a cocher, donc, et non des boutons radio qui obligeraient a n'en
   citer qu'une. */
.champ-libelle {
  display: block;
  margin-bottom: 6px;
  font-size: 0.9rem;
  font-weight: 500;
}

.cases {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.cases label {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 0;
  padding: 8px 12px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  font-weight: 400;
  cursor: pointer;
}

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

/* La case cochee doit se voir d'un coup d'oeil sur une liste de dix
   membres — sans :has, il faudrait un script pour ca. */
.cases label:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-doux);
}

.cases input[type="checkbox"] { width: auto; margin: 0; }

/* --- Vignette de chantier dans la liste ---------------------------- */
.miniature {
  display: block;
  width: 72px;
  height: 72px;
  border-radius: var(--rayon-petit);
  object-fit: cover;
}

.miniature-vide {
  border: 1px dashed var(--bordure-forte);
  background: var(--surface-2);
}

.cellule-photo { width: 88px; }

/* Un auteur par ligne : « SARL Casanova » et « Jean-Marc, Marie-Noëlle »
   ne doivent pas se lire comme une seule enfilade de noms. */
.auteur { display: block; }
.auteur + .auteur { margin-top: 4px; }
.auteur .legende { font-size: 0.78rem; }

/* La cellule reste une CELLULE : un <td> en display:flex quitte la mise
   en page du tableau, et la ligne deborde de son cadre. C'est le groupe
   a l'interieur qui porte la disposition. */
.cellule-actions { white-space: nowrap; }

.actions-groupe {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
}

.actions-groupe .bouton { padding: 7px 14px; font-size: 0.85rem; }

/* Bouton d'une action destructrice : la couleur previent, mais elle ne
   previent pas seule — le libelle dit « Supprimer » et une
   confirmation suit (regle 10e : jamais l'information par la couleur). */
.bouton-danger { color: var(--rouge); }
.bouton-danger:hover { border-color: var(--rouge); color: var(--rouge); }

/* ------------------------------------------------------------------
   Tableau qui devient une liste de cartes sur telephone.

   Un seul balisage pour les deux presentations : chaque cellule porte
   son libelle en data-libelle, et le CSS le reaffiche en tete de ligne
   quand l'en-tete du tableau disparait. Deux balisages separes
   auraient diverge des la premiere colonne ajoutee — l'un des deux
   aurait ete oublie.
   ------------------------------------------------------------------ */
@media (max-width: 760px) {
  .table-cartes thead { display: none; }

  .table-cartes,
  .table-cartes tbody,
  .table-cartes tr,
  .table-cartes td {
    display: block;
    width: 100%;
  }

  .table-cartes tr {
    margin-bottom: 16px;
    padding: 16px;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon);
    background: var(--surface);
    box-shadow: var(--ombre);
  }

  .table-cartes tbody tr:hover { background: var(--surface); }

  .table-cartes td {
    display: flex;
    gap: 16px;
    align-items: baseline;
    justify-content: space-between;
    padding: 7px 0;
    border-bottom: 1px solid var(--bordure);
    text-align: right;
  }

  .table-cartes td:last-child { border-bottom: 0; }

  .table-cartes td::before {
    flex: 0 0 auto;
    color: var(--texte-doux);
    content: attr(data-libelle);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-align: left;
    text-transform: uppercase;
  }

  /* La photo et le titre font l'en-tete de la carte : pleine largeur,
     sans libelle, comme sur une fiche. */
  .table-cartes .cellule-photo,
  .table-cartes td[data-libelle="Chantier"] {
    display: block;
    padding-top: 0;
    text-align: left;
  }

  .table-cartes .cellule-photo::before,
  .table-cartes td[data-libelle="Chantier"]::before { content: none; }

  .table-cartes .cellule-photo { width: 100%; padding-bottom: 12px; border-bottom: 0; }

  .table-cartes .miniature {
    width: 100%;
    height: 180px;
  }

  .table-cartes .chantier-titre { font-size: 1.05rem; }

  .table-cartes td[data-libelle="Réalisé par"] { display: block; text-align: left; }
  .table-cartes td[data-libelle="Réalisé par"]::before { display: block; margin-bottom: 4px; }

  /* Les actions passent en pleine largeur : sur un telephone, une cible
     de 44 px de haut est le minimum utilisable au pouce. */
  .table-cartes .cellule-actions { padding-top: 14px; }
  .table-cartes .cellule-actions::before { content: none; }

  .table-cartes .actions-groupe { flex-direction: column; }
  .table-cartes .actions-groupe .form-inline { width: 100%; }

  .table-cartes .actions-groupe .bouton {
    width: 100%;
    padding: 12px 16px;
    font-size: 0.95rem;
  }
}

/* --- Pagination -----------------------------------------------------
   Elle n'apparait qu'au-dela d'une page : tant que la maison a moins de
   vingt chantiers termines, rien n'encombre l'ecran. */
.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--bordure);
}

.pagination-etat {
  margin: 0;
  color: var(--texte-doux);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.pagination-etat .legende { display: block; font-size: 0.78rem; }

/* Bouton en butee : garde sa place plutot que de disparaitre, sinon la
   rangee saute d'un cote a l'autre a chaque changement de page. */
.pagination .est-inerte {
  color: var(--texte-tres-doux);
  cursor: default;
  opacity: 0.55;
}

/* Combien de chantiers dans la section, a cote de son titre. */
.compteur {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--texte-doux);
  font-family: var(--police-corps);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  vertical-align: middle;
}

/* La synthese ferme la page : on la consulte, on ne la cherche pas. */
.synthese { margin-top: 40px; padding-top: 8px; border-top: 1px solid var(--bordure); }

@media (max-width: 560px) {
  .pagination { flex-direction: column-reverse; }
  .pagination .bouton,
  .pagination .est-inerte { width: 100%; }
}

/* Navigation par mois du calendrier : sous le titre plutot que dedans,
   la ligne de titre portant deja les boutons d'ajout. */
/* La navigation par mois vit dans la barre d'outils : elle s'aligne sur
   les autres commandes plutot que de flotter au-dessus. */
.barre-mois {
  display: flex;
  gap: 6px;
  align-items: center;
}

/* --- Menu par thèmes ------------------------------------------------
   Quinze entrées d'affilée, on ne les lit plus : on cherche. Un filet
   et un intitulé discret suffisent à séparer les familles — pas besoin
   de replier quoi que ce soit, ce qui demanderait du JavaScript. */
.nav-groupe + .nav-groupe {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--bordure);
}

.nav-titre {
  margin: 0 0 6px;
  padding: 0 14px;
  color: var(--texte-tres-doux);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* --- Carte et liste cote a cote -------------------------------------
   La liste sous la carte obligeait a faire defiler pour choisir une
   parcelle, puis a remonter pour la regarder. Cote a cote, on voit les
   deux. */
.carte-zone {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}

.carte-zone .carte-enveloppe {
  flex: 1 1 auto;
  min-width: 0;
}

.carte-panneau {
  display: flex;
  flex: 0 0 232px;
  flex-direction: column;
  overflow-y: auto;
  /* La liste ne depasse jamais la hauteur de la carte : sans plafond,
     dix-neuf parcelles allongeaient la page autant qu'avant. */
  max-height: 640px;
  padding: 16px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.titre-panneau {
  margin: 0 0 12px;
  font-size: 1rem;
}

/* Dans le panneau, les jetons s'empilent au lieu de s'aligner. */
.carte-panneau .liste-parcelles {
  display: block;
  margin: 0;
  padding: 0;
  list-style: none;
}

.carte-panneau .liste-parcelles li + li { margin-top: 6px; }

.carte-panneau .jeton-parcelle {
  justify-content: space-between;
  width: 100%;
  padding: 8px 12px;
}

/* La parcelle choisie se repere dans la liste comme sur le plan. */
.jeton-parcelle.est-choisie {
  border-color: var(--accent);
  border-left-color: var(--accent);
  background: var(--accent-doux);
  font-weight: 500;
}

@media (max-width: 900px) {
  /* Sous cette largeur, cote a cote ne tient plus : on empile, et la
     liste reprend sa disposition en jetons. */
  .carte-zone { flex-direction: column; }

  .carte-panneau {
    flex: 1 1 auto;
    max-height: none;
    width: 100%;
  }

  .carte-panneau .liste-parcelles {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  .carte-panneau .liste-parcelles li + li { margin-top: 0; }
  .carte-panneau .jeton-parcelle { width: auto; }
}

/* Changer l'etat d'un sujet du dossier : les quatre etats cote a cote,
   l'actuel affiche en pastille et les trois autres en boutons. Un
   menu deroulant aurait demande un clic de plus pour la meme chose. */
.note-etats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--bordure);
}

.note-etats-libelle {
  margin-right: 4px;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

.note-etats .bouton { padding: 6px 14px; font-size: 0.85rem; }

/* Bouton d'un selecteur (annee d'exercice, par exemple) : l'actif se
   distingue comme dans les commandes de la carte. */
.bouton.est-actif {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-encre, var(--texte-inverse));
}

.bouton.est-actif:hover { border-color: var(--accent-fonce); background: var(--accent-fonce); }

/* --- L'ardoise : qui doit quoi, tous appels confondus ---------------
   Une ligne par personne, depliable sur le detail. Meme mecanique que
   le dossier : un <details> natif, sans JavaScript. */
.ardoise-ligne {
  margin-bottom: 8px;
  border: 1px solid var(--bordure);
  border-left: 4px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
}

.ardoise-ligne > summary {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  cursor: pointer;
  list-style: none;
}

.ardoise-ligne > summary::-webkit-details-marker { display: none; }
.ardoise-ligne > summary:hover { background: var(--surface-2); }
.ardoise-ligne[open] > summary { border-bottom: 1px solid var(--bordure); }

/* L'etat se lit d'abord au mot, la couleur ne fait que confirmer. */
.ardoise-ligne.est-en-retard { border-left-color: var(--rouge); }
.ardoise-ligne.est-du        { border-left-color: var(--ambre); }
.ardoise-ligne.est-a-jour    { border-left-color: var(--vert); }

.ardoise-qui { flex: 1 1 200px; font-weight: 500; }

.ardoise-chiffres {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: flex-end;
}

.ardoise-detail {
  color: var(--texte-doux);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.ardoise-reste { font-variant-numeric: tabular-nums; }
.ardoise-ligne.est-en-retard .ardoise-reste { color: var(--rouge); }

.ardoise-ligne .table-enveloppe { padding: 4px 18px 16px; }

@media (max-width: 640px) {
  .ardoise-chiffres { justify-content: flex-start; width: 100%; }
}

/* Tableau des soldes annee par annee : les colonnes d'annees sont
   etroites et nombreuses, la colonne de cumul porte la conclusion. */
.table-cumul .cumul-total {
  border-left: 1px solid var(--bordure);
  background: var(--surface-2);
  white-space: nowrap;
}

.table-cumul .cumul-total .legende { font-size: 0.72rem; }
.table-cumul td.nombre { white-space: nowrap; }

/* ==================================================================
   11. GABARIT D'ADMINISTRATION (regle 11 du CLAUDE.md global)

   Barre de compte en haut a droite, gamme de tons pour les boutons,
   grilles de cartes, et la page-liste type : texte d'introduction,
   barre d'outils, tableau triable d'une ligne de haut, pagination.

   Tout est branche sur les jetons : rien ici ne connait la couleur
   choisie dans la page Configuration.
   ================================================================== */

/* --- Barre laterale : un libelle par ligne, jamais coupe ----------
   Le lien est une boite flex : l'icone d'abord, le libelle ensuite.
   La coupure au besoin se pose sur le LIBELLE et non sur le lien —
   text-overflow ne mord pas sur le texte anonyme d'un conteneur flex,
   et surtout on ne veut jamais rogner l'icone. La largeur du menu est
   calculee pour que rien ne soit coupe (regle 11i) : cette ellipse est
   un filet de securite, pas le fonctionnement normal. */
.nav-appli a { white-space: nowrap; }

.nav-libelle {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* L'icone ne retrecit jamais, meme si le libelle est long, et se tient
   un ton en retrait : c'est le mot qu'on lit, l'icone ne fait que
   reperer. Elle passe au plein contraste sur la rubrique ouverte et au
   survol. Tracee en currentColor, elle suit l'accent de la page
   Configuration sans qu'aucune couleur ne soit ecrite ici. */
.nav-appli a .icone {
  flex: 0 0 auto;
  opacity: 0.62;
  transition: opacity var(--transition);
}

.nav-appli a:hover .icone,
.nav-appli a:focus-visible .icone,
.nav-appli a[aria-current="page"] .icone { opacity: 1; }

/* --- Barre du haut : le compte, et rien d'autre -------------------
   Le compte quitte le pied du menu pour le coin haut droit, ou tout le
   monde va le chercher. La barre reste collee en haut : sur une longue
   liste, on ne remonte pas 200 lignes pour se deconnecter. */
.appli-entete {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: flex-end;
  padding: 10px var(--gouttiere);
  border-bottom: 1px solid var(--bordure);
  background: var(--fond);
}

.appli-entete-fil {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  color: var(--texte-tres-doux);
  font-size: 0.85rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Menu de compte : un <details> natif. Il s'ouvre au clic et au
   clavier sans une ligne de script — le script ne fait qu'ajouter le
   confort (fermeture au clic exterieur et a Echap). */
.menu-compte { position: relative; }

.menu-compte > summary {
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 7px 12px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-pilule);
  background: var(--surface);
  color: var(--texte);
  font-size: 0.9rem;
  cursor: pointer;
  list-style: none;
}

.menu-compte > summary::-webkit-details-marker { display: none; }
.menu-compte > summary:hover { background: var(--surface-2); }
.menu-compte[open] > summary { border-color: var(--texte-doux); }

.menu-compte-pastille {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-size: 0.75rem;
  font-weight: 600;
}

.menu-compte-panneau {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  min-width: 232px;
  padding: 8px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  box-shadow: var(--ombre-flottante);
}

.menu-compte-qui {
  padding: 8px 10px 12px;
  border-bottom: 1px solid var(--bordure);
  margin-bottom: 6px;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

.menu-compte-qui strong { display: block; color: var(--texte); font-size: 0.95rem; }

.menu-compte-panneau a,
.menu-compte-panneau button {
  display: block;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: var(--rayon-petit);
  background: none;
  color: var(--texte);
  font-family: inherit;
  font-size: 0.92rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.menu-compte-panneau a:hover,
.menu-compte-panneau button:hover { background: var(--surface-3); color: var(--texte); }

/* --- Gamme de tons (regle 11c) ------------------------------------
   Une seule regle de bouton, six jeux de variables. Ajouter un ton, ce
   n'est pas ecrire une regle de plus : c'est declarer trois variables.
   L'encre est calculee cote serveur pour rester lisible quelle que soit
   la couleur choisie — c'est ce qui evite le bouton jaune a texte blanc. */
.bouton-rouge  { --ton: var(--ton-rouge);  --ton-survol: var(--ton-rouge-fonce);  --ton-encre: var(--ton-rouge-encre); }
.bouton-orange { --ton: var(--ton-orange); --ton-survol: var(--ton-orange-fonce); --ton-encre: var(--ton-orange-encre); }
.bouton-jaune  { --ton: var(--ton-jaune);  --ton-survol: var(--ton-jaune-fonce);  --ton-encre: var(--ton-jaune-encre); }
.bouton-vert   { --ton: var(--ton-vert);   --ton-survol: var(--ton-vert-fonce);   --ton-encre: var(--ton-vert-encre); }
.bouton-bleu   { --ton: var(--ton-bleu);   --ton-survol: var(--ton-bleu-fonce);   --ton-encre: var(--ton-bleu-encre); }
.bouton-gris   { --ton: var(--ton-gris);   --ton-survol: var(--ton-gris-fonce);   --ton-encre: var(--ton-gris-encre); }

.bouton-rouge,
.bouton-orange,
.bouton-jaune,
.bouton-vert,
.bouton-bleu,
.bouton-gris {
  background: var(--ton);
  color: var(--ton-encre);
}

.bouton-rouge:hover,
.bouton-orange:hover,
.bouton-jaune:hover,
.bouton-vert:hover,
.bouton-bleu:hover,
.bouton-gris:hover {
  background: var(--ton-survol);
  color: var(--ton-encre);
}

/* Meme ton, en contour : pour une action coloree qui ne doit pas peser
   autant qu'un aplat (un « Supprimer » de fin de ligne, par exemple). */
.bouton-contour {
  border-color: var(--ton, var(--bordure-forte));
  background: none;
  color: var(--ton-texte, var(--texte));
}

.bouton-contour:hover { background: var(--ton-doux, var(--surface-3)); color: var(--ton-texte, var(--texte)); }

.bouton-rouge.bouton-contour  { --ton-texte: var(--ton-rouge-texte);  --ton-doux: var(--ton-rouge-doux); }
.bouton-orange.bouton-contour { --ton-texte: var(--ton-orange-texte); --ton-doux: var(--ton-orange-doux); }
.bouton-jaune.bouton-contour  { --ton-texte: var(--ton-jaune-texte);  --ton-doux: var(--ton-jaune-doux); }
.bouton-vert.bouton-contour   { --ton-texte: var(--ton-vert-texte);   --ton-doux: var(--ton-vert-doux); }
.bouton-bleu.bouton-contour   { --ton-texte: var(--ton-bleu-texte);   --ton-doux: var(--ton-bleu-doux); }
.bouton-gris.bouton-contour   { --ton-texte: var(--ton-gris-texte);   --ton-doux: var(--ton-gris-doux); }

.bouton-petit { padding: 6px 12px; font-size: 0.85rem; }

/* --- Grilles de cartes (regle 11d) --------------------------------
   Les proportions demandees, nommees par ce qu'elles font. Tout
   s'effondre en une colonne sur telephone : deux tiers d'un ecran de
   375px ne sont pas deux tiers, ce sont deux colonnes illisibles. */
.grille-1-1,
.grille-1-2,
.grille-2-1,
.grille-3 {
  display: grid;
  gap: 20px;
  align-items: start;
  margin-bottom: 24px;
}

@media (width >= 900px) {
  .grille-1-1 { grid-template-columns: 1fr 1fr; }
  .grille-1-2 { grid-template-columns: 1fr 2fr; }
  .grille-2-1 { grid-template-columns: 2fr 1fr; }
  .grille-3   { grid-template-columns: repeat(3, 1fr); }
}

/* DEUX CARTES EMPILEES DANS LA MEME COLONNE.
   `gap` ne separe que les CELLULES de la grille. Des qu'une colonne en
   contient plusieurs — la fiche client en aligne six a droite —, les
   cartes se touchent : `.carte` ne porte aucune marge verticale, et
   c'est voulu, sinon chaque cellule qui n'en contient qu'une aurait a
   l'annuler.

   L'ecart se pose donc ENTRE DEUX CARTES VOISINES, et nulle part
   ailleurs. Passer la colonne en `flex` avec un `gap` reglerait le
   meme cas, mais l'ecart s'ajouterait a la marge basse des grilles
   imbriquees qu'une colonne peut contenir, et les eloignerait de 44px
   sans qu'on l'ait demande.

   Le `> div >` est ce qui rend la regle sure : il ne vise que les
   cartes rangees dans une enveloppe de colonne. Deux cartes posees
   dans deux CELLULES voisines sont aussi des soeurs — un `.carte +
   .carte` nu decalerait la carte de droite de 20px vers le bas. */
.grille-1-1 > div > .carte + .carte,
.grille-1-2 > div > .carte + .carte,
.grille-2-1 > div > .carte + .carte,
.grille-3   > div > .carte + .carte {
  margin-top: 20px;
}

/* Photo a gauche, plans a droite (regle 11d, lot L19). Une photo de
   facade se reconnait en petit ; les plans, eux, se comparent — c'est
   a eux qu'il faut la place. */
.grille-1-3 {
  display: grid;
  gap: 20px;
  align-items: start;
  margin-bottom: 24px;
}

@media (width >= 900px) {
  .grille-1-3 { grid-template-columns: 1fr 3fr; }
}

/* Trois colonnes : la saisie, la photo, le plan. Une fiche se remplit
   en regardant ce qu'on decrit — renvoyer la photo et le plan sous le
   formulaire obligeait a faire defiler la page pour verifier qu'on
   parlait bien de la meme piece. */
.grille-2-1-1 {
  display: grid;
  gap: 20px;
  /* LES CARTES D'UNE MEME LIGNE ONT LA MEME HAUTEUR. Calees en haut,
     elles finissaient chacune ou son contenu s'arretait : trois bas de
     cartes a trois hauteurs differentes, et la page semblait inachevee. */
  align-items: stretch;
  margin-bottom: 20px;
}

@media (width >= 900px) {
  /* Entre 900 et 1280px, trois colonnes rendraient le formulaire
     illisible : il passe sur toute la largeur, et la photo et le plan
     se partagent la ligne suivante. */
  .grille-2-1-1 { grid-template-columns: 1fr 1fr; }
  .grille-2-1-1 > :first-child { grid-column: 1 / -1; }
}

/* Trois colonnes seulement quand il y a vraiment la place. A 1100 px de
   fenetre, la barre laterale prise, chaque carte tombait a 183 px : le
   libelle « Choisir une photo » y passait sur deux lignes et le champ
   n'avait plus de quoi montrer son contenu. Deux colonnes valent mieux
   que trois trop etroites. */
@media (width >= 1400px) {
  .grille-2-1-1 { grid-template-columns: 2fr 1fr 1fr; }
  .grille-2-1-1 > :first-child { grid-column: auto; }
  /* Dans une colonne de moitie de page, deux champs cote a cote
     laissent quatre caracteres visibles chacun. */
  .grille-2-1-1 .grille-champs { grid-template-columns: 1fr; }
}

/* Dans une grille, la carte de saisie ne porte plus sa marge basse : les
   trois colonnes doivent finir sur la meme ligne, et la barre de boutons
   se poser juste dessous. */
.grille-2-1-1 .carte-formulaire { margin-bottom: 0; }

/* --- Introduction de rubrique (regle 11e) -------------------------
   Deux ou trois phrases avant le tableau. Ce n'est pas de l'ornement :
   une liste sans phrase d'accroche oblige chacun a deduire du contenu
   des colonnes ce que la rubrique contient et a quoi elle sert. */
.liste-intro {
  /* Toute la largeur du contenu, comme le tableau qui suit. Brider le
     texte a 78ch le laissait flotter au-dessus d'un tableau deux fois
     plus large : deux blocs de largeurs differentes ne se lisent pas
     comme une meme page. */
  margin-bottom: 24px;
  color: var(--texte-doux);
}

/* Deux ou trois phrases d'explication forment UN bloc, pas une suite de
   paragraphes aeres : l'interligne de lecture longue et la pleine marge
   entre paragraphes donnaient a trois lignes l'encombrement d'un article. */
.liste-intro p {
  margin-bottom: 0.4em;
  line-height: 1.55;
}

.liste-intro p:last-child { margin-bottom: 0; }

/* --- Barre d'outils ----------------------------------------------- */
.barre-outils {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-start;
  justify-content: space-between;

  /* Un filet AU-DESSUS et un filet EN DESSOUS : la barre d'outils est
     une bande, pas un empilement de boutons posés entre deux blocs. Le
     trait du haut la detache du texte d'introduction, celui du bas
     l'attache au tableau qu'elle commande. */
  padding-top: 16px;
  padding-bottom: 16px;
  border-top: 1px solid var(--bordure);
  border-bottom: 1px solid var(--bordure);
  margin-bottom: 4px;
}

.barre-outils-gauche,
.barre-outils-droite {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

.barre-outils-droite { justify-content: flex-end; }

.outils-recherche {
  display: flex;
  gap: 8px;
  align-items: center;
}

.outils-recherche input[type="search"] {
  width: min(320px, 60vw);
  padding: 9px 12px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: inherit;
  font-size: 0.92rem;
}

.outils-taille {
  display: flex;
  gap: 8px;
  align-items: center;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

/* L'intitule d'une commande ne se coupe jamais en deux : « Trier par »
   passait a la ligne des que la barre se serrait, et deux mots empiles
   devant un menu deroulant se lisent comme une erreur d'affichage. */
.outils-taille label { white-space: nowrap; }

.outils-taille select {
  padding: 7px 10px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: inherit;
  font-size: 0.9rem;
}

/* Le bouton de repli du selecteur : inutile des que le script tourne. */
.js .sans-js { display: none; }

.outils-aide > summary {
  list-style: none;
  cursor: pointer;
}

.outils-aide > summary::-webkit-details-marker { display: none; }

.outils-aide-contenu {
  position: absolute;
  right: var(--gouttiere);
  z-index: 15;
  max-width: 460px;
  padding: 18px 20px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  margin-top: 10px;
  background: var(--surface);
  box-shadow: var(--ombre-flottante);
  color: var(--texte-doux);
  font-size: 0.9rem;
}

.outils-aide-contenu p:last-child { margin-bottom: 0; }

/* --- Tableau de liste (regle 11 e/f) ------------------------------ */
.table-enveloppe-liste {
  overflow-x: auto;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  margin-top: 20px;
  background: var(--surface);
}

table.donnees th a.tri {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  color: inherit;
  text-decoration: none;
}

table.donnees th a.tri:hover { color: var(--texte); }
table.donnees th a.tri.est-actif { color: var(--accent-texte); }
.tri-fleche { font-size: 0.9em; opacity: 0.55; }
table.donnees th a.tri.est-actif .tri-fleche { opacity: 1; }

/* Une ligne tient sur UNE ligne (regle 11f). Le texte trop long est
   coupe par des points de suspension, pas replie : c'est ce qui permet
   de balayer verticalement une liste de 20 lignes sans que la hauteur
   de chacune depende de son contenu. Le titre complet reste accessible
   au survol et au lecteur d'ecran par l'attribut title. */
table.donnees.donnees-lignes td,
table.donnees.donnees-lignes th {
  /* Un peu plus serre que le tableau editorial : une liste de 20 lignes
     doit tenir sous les yeux sans defiler, et chaque ligne fait la meme
     hauteur puisque rien ne se replie. */
  padding: 10px 12px;
  vertical-align: middle;
  white-space: nowrap;
}

table.donnees.donnees-lignes td {
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
}

table.donnees.donnees-lignes td.cellule-large { max-width: 460px; }
table.donnees.donnees-lignes td.cellule-etroite { max-width: 150px; }

/* La colonne Actions reste collee a droite pendant que le tableau
   defile. Sur une liste large — un chantier a huit colonnes — les
   boutons sortaient de l'ecran, et il fallait faire defiler
   horizontalement pour atteindre « Modifier ». Ce sont justement les
   trois choses qu'on vient faire sur une ligne : elles ne doivent
   jamais disparaitre. */
table.donnees th.col-actions,
table.donnees td.col-actions {
  position: sticky;
  right: 0;
  z-index: 2;

  /* La MEME largeur que la classe .l-actions du <colgroup>, et surtout
     pas « 1% » : en table-layout: fixed, un pourcentage est pris au pied
     de la lettre. La colonne devenait large de quelques pixels, les
     trois boutons débordaient de leur cellule, et c'est tout le tableau
     qui sortait du cadre. Les tableaux écrits à la main — les documents
     rattachés d'une parcelle, les factures d'un chantier — n'ont pas de
     colgroup : c'est cette règle qui leur donne leur largeur.

     Le jeton --largeur-actions est posé sur table.donnees : les deux
     endroits lisent la même valeur, et une page qui porte quatre boutons
     la relève d'une classe sur son tableau. Écrites en dur des deux
     côtés, les deux largeurs finissaient par diverger — c'est ce qui
     rognait « Comptes rendus » sur la liste des formulaires. */
  width: var(--largeur-actions, 232px);
  background: var(--surface);
  text-align: right;
  white-space: nowrap;
}

/* Un filet marque la separation quand le tableau defile dessous, et le
   survol de ligne doit repeindre la cellule collee comme les autres. */
table.donnees td.col-actions { box-shadow: -1px 0 0 var(--bordure); }
table.donnees th.col-actions { box-shadow: -1px 0 0 var(--bordure); }
table.donnees tbody tr:hover td.col-actions { background: var(--surface-2); }

.actions-ligne {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  justify-content: flex-end;
}

.actions-ligne .bouton { padding: 4px 10px; font-size: 0.8rem; }

/* La colonne de vignette n'a pas besoin d'un intitule visible : l'image
   se presente toute seule. Le mot reste pour le lecteur d'ecran. */
table.donnees th.col-photo {
  overflow: hidden;
  width: 1%;
  text-indent: -9999px;
}

/* --- Pagination (regle 11e) --------------------------------------- */
.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin: 18px 0 8px;
}

.pagination-compte {
  margin: 0;
  color: var(--texte-doux);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.pagination-pages {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  padding: 0;
  margin: 0;
  list-style: none;
}

.pagination-lien {
  display: inline-block;
  min-width: 36px;
  padding: 7px 10px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte-doux);
  font-size: 0.88rem;
  text-align: center;
  text-decoration: none;
}

.pagination-lien:hover { background: var(--surface-3); color: var(--texte); }

.pagination-lien.est-actif {
  border-color: var(--accent);
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-weight: 600;
}

.pagination-lien.est-inerte {
  border-color: var(--bordure);
  background: none;
  color: var(--texte-tres-doux);
  cursor: default;
}

.pagination-saut { padding: 0 4px; color: var(--texte-tres-doux); }

/* --- Modal de confirmation de suppression (regle 11h) -------------
   Un <dialog> natif : le navigateur se charge du piege a focus, de la
   touche Echap et du fond inerte. Le script ne fait que l'ouvrir et
   recopier le libelle de la ligne visee. */
dialog.modal {
  width: min(460px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  color: var(--texte);
}

dialog.modal::backdrop { background: rgb(20 20 19 / 45%); }

.modal-corps { padding: 26px 26px 20px; }
.modal-corps h2 { margin-bottom: 10px; font-size: 1.25rem; }
.modal-corps p { color: var(--texte-doux); }
.modal-cible { color: var(--texte); font-weight: 600; }

.modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: flex-end;
  padding: 16px 26px 22px;
  border-top: 1px solid var(--bordure);
  background: var(--surface-2);
}

/* --- Fiche de detail (bouton « Voir ») ---------------------------- */
.fiche-champs {
  display: grid;
  gap: 2px 24px;
  margin: 0;
}

.fiche-champs dt {
  color: var(--texte-tres-doux);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fiche-champs dd { margin: 0 0 16px; }

@media (width >= 640px) {
  .fiche-champs { grid-template-columns: 200px 1fr; }
  .fiche-champs dt { padding-top: 2px; }
}

@media (width < 900px) {
  .barre-outils-gauche,
  .barre-outils-droite { width: 100%; }

  .barre-outils-droite { justify-content: flex-start; }
  .outils-recherche { flex: 1 1 100%; }
  .outils-recherche input[type="search"] { width: 100%; }
  .outils-aide-contenu { right: 0; left: 0; max-width: none; }
}

/* --- Page Configuration : echantillons de la gamme (regle 11k) -----
   Les pastilles de couleur ne peuvent pas porter un style en ligne :
   la CSP bloque l'attribut style comme elle bloque une balise <style>
   (regle 7). Elles lisent donc les jetons, exactement comme le reste de
   l'interface — ce qui a un avantage : l'apercu ne peut pas mentir, il
   affiche ce que l'application affichera. */
.gamme {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 12px;
}

.echantillon {
  padding: 14px 10px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  font-size: 0.78rem;
  text-align: center;
}

.echantillon-accent { background: var(--accent);     color: var(--accent-encre); }
.echantillon-rouge  { background: var(--ton-rouge);  color: var(--ton-rouge-encre); }
.echantillon-orange { background: var(--ton-orange); color: var(--ton-orange-encre); }
.echantillon-jaune  { background: var(--ton-jaune);  color: var(--ton-jaune-encre); }
.echantillon-vert   { background: var(--ton-vert);   color: var(--ton-vert-encre); }
.echantillon-bleu   { background: var(--ton-bleu);   color: var(--ton-bleu-encre); }
.echantillon-gris   { background: var(--ton-gris);   color: var(--ton-gris-encre); }

.appli .champ-couleur input[type="color"] {
  width: 100%;
  /* Dans l'encadre du champ, le selecteur ne porte plus son propre
     cadre : l'enveloppe le porte pour lui. */
  height: 44px;
  padding: 6px 12px;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.mesure {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  padding: 14px 16px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  margin-top: 16px;
  background: var(--surface-2);
  color: var(--texte-doux);
  font-size: 0.85rem;
}

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

/* --- Vignette dans une ligne de liste ------------------------------
   36px : assez pour reconnaitre un chantier d'un coup d'oeil, assez
   petit pour que la ligne garde la meme hauteur que les autres. */
.col-photo { width: 1%; }

.miniature-liste {
  display: block;
  width: 36px;
  height: 36px;
  border-radius: var(--rayon-petit);
  object-fit: cover;
  background: var(--surface-2);
}

.miniature-vide { border: 1px dashed var(--bordure-forte); background: none; }

table.donnees.donnees-lignes td .legende { font-size: 0.78rem; }
table.donnees.donnees-lignes td .pastille { margin-left: 6px; }

/* --- Largeurs de colonnes des listes (regle 11e) -------------------
   Le tableau d'une liste passe en table-layout: fixed : la largeur des
   colonnes est DECLAREE, elle ne depend plus du contenu du jour. Sans
   cela, un intitule un peu long poussait les dernieres colonnes sous
   les boutons d'action colles a droite, et la meme page changeait
   d'allure d'une semaine a l'autre.

   Les largeurs sont des classes et non des styles en ligne : la CSP
   bloque l'attribut style au meme titre qu'une balise <style>. */
table.donnees.donnees-lignes { table-layout: fixed; }

.l-min  { width: 56px; }
.l-4    { width: 4%; }
.l-6    { width: 6%; }
.l-8    { width: 8%; }
.l-10   { width: 10%; }
.l-12   { width: 12%; }
.l-14   { width: 14%; }
.l-16   { width: 16%; }
.l-20   { width: 20%; }
.l-24   { width: 24%; }
.l-30   { width: 30%; }
.l-40   { width: 40%; }
/* LA LARGEUR DE LA COLONNE D'ACTIONS SE DECLARE UNE SEULE FOIS.
   Elle etait ecrite en dur a DEUX endroits — ici, pour le <col> du
   colgroup, et sur td.col-actions, qui est colle a droite. Les deux
   doivent valoir la meme chose, sans quoi la cellule et sa colonne se
   contredisent ; un jeton porte par le tableau les tient d'accord.

   Le nombre de boutons varie de un a six selon la rubrique. En
   table-layout: fixed, UNE COLONNE TROP ETROITE NE S'ELARGIT PAS : son
   contenu deborde et se fait rogner par l'overflow: hidden des
   cellules. C'est ce qui coupait « Comptes rendus » sur la liste des
   formulaires. La page declare donc ce qu'elle porte, sur le tableau :
   <table class="donnees donnees-lignes actions-4"> */
table.donnees            { --largeur-actions: 232px; }
table.donnees.actions-3  { --largeur-actions: 340px; }
table.donnees.actions-4  { --largeur-actions: 450px; }
table.donnees.actions-6  { --largeur-actions: 640px; }

.l-actions { width: var(--largeur-actions, 232px); }

/* Le tableau ne se comprime plus indefiniment : sous cette largeur, il
   DEFILE DANS SON ENVELOPPE (regle 11f) au lieu de rogner ses colonnes.
   La colonne d'actions restant collee a droite, les boutons demeurent
   atteignables pendant le defilement — c'est tout l'interet du sticky. */
table.donnees.donnees-lignes { min-width: calc(560px + var(--largeur-actions, 232px)); }

/* Sans place pour trois boutons, la colonne d'actions se met a defiler
   avec le reste plutot que de recouvrir la derniere colonne. */
@media (width < 720px) {
  table.donnees { --largeur-actions: 200px; }
}

/* --- Marges du contenu applicatif ---------------------------------
   La gouttiere de 64px vaut pour les pages publiques et editoriales,
   ou une ligne trop longue se lit mal. Une page d'admin, elle, porte
   des tableaux : ces 128px de marge etaient pris sur les colonnes de
   donnees, et c'est la derniere colonne qui payait. On les rend au
   contenu (regle 11d : les pages d'admin occupent toute la largeur). */
@media (width >= 1024px) {
  .appli-contenu { padding-right: 32px; padding-left: 32px; }
}

/* --- Jauge de quote-part -------------------------------------------
   Une barre pour comparer six parts d'un coup d'oeil. Le chiffre en
   milliemes reste dans la colonne d'a cote : l'information n'est jamais
   portee par la seule representation graphique (regle 10e).

   Les largeurs sont des classes par pas de 5 % et non un style en
   ligne : la CSP bloque l'attribut style (regle 7). */
.jauge-part {
  display: block;
  overflow: hidden;
  width: 100%;
  height: 8px;
  border-radius: var(--rayon-pilule);
  background: var(--surface-3);
}

.jauge-part-remplie {
  display: block;
  height: 100%;
  border-radius: var(--rayon-pilule);
  background: var(--accent);
}

.jauge-0   { width: 0; }
.jauge-5   { width: 5%; }
.jauge-10  { width: 10%; }
.jauge-15  { width: 15%; }
.jauge-20  { width: 20%; }
.jauge-25  { width: 25%; }
.jauge-30  { width: 30%; }
.jauge-35  { width: 35%; }
.jauge-40  { width: 40%; }
.jauge-45  { width: 45%; }
.jauge-50  { width: 50%; }
.jauge-55  { width: 55%; }
.jauge-60  { width: 60%; }
.jauge-65  { width: 65%; }
.jauge-70  { width: 70%; }
.jauge-75  { width: 75%; }
.jauge-80  { width: 80%; }
.jauge-85  { width: 85%; }
.jauge-90  { width: 90%; }
.jauge-95  { width: 95%; }
.jauge-100 { width: 100%; }

/* Un champ de saisie dans une cellule de tableau reste lisible et
   assez large pour trois chiffres, sans etirer la colonne. */
table.donnees td input[type="number"] {
  width: 6.5em;
  padding: 6px 8px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: inherit;
  font-size: 0.92rem;
  text-align: right;
}

/* ==================================================================
   12. VISITE GUIDÉE ET GRANDES LIGNES (règle 12)

   L'application compte quinze rubriques et se consulte trois fois par
   an. Au bout de six mois, personne ne sait plus où se saisit une
   dépense : la visite se lance seule la première fois, et le tableau de
   bord garde en clair les mêmes explications pour ceux qui l'ont passée.
   ================================================================== */

/* --- Le halo : un trou dans un voile ------------------------------
   L'ombre portée de 9999px fait le voile ; la boîte, elle, reste
   transparente et encadre la cible. */
.visite-halo {
  position: fixed;
  z-index: 900;
  border-radius: var(--rayon-petit);
  box-shadow: 0 0 0 9999px rgb(20 20 19 / 62%);

  /* AUCUN ÉVÉNEMENT : le halo couvre l'écran entier par son ombre. Sans
     cette ligne, il avalerait tous les clics — y compris ceux des
     boutons de la bulle, pourtant au-dessus. */
  pointer-events: none;
  transition: top 180ms ease, left 180ms ease, width 180ms ease, height 180ms ease;
}

/* Étape sans cible visible : on garde le voile, on retire le cadre. */
.visite-halo-vide {
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
}

.visite-bulle {
  position: fixed;
  z-index: 901;
  width: min(340px, calc(100vw - 32px));
  padding: 18px 20px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  box-shadow: var(--ombre-flottante);
}

.visite-bulle h2 {
  margin-bottom: 8px;
  font-size: 1.05rem;
}

.visite-texte {
  margin-bottom: 0;
  color: var(--texte-doux);
  font-size: 0.9rem;
  line-height: 1.6;
}

.visite-texte strong { color: var(--texte); }

/* La flèche : un carré tourné de 45°, bordé sur deux côtés seulement —
   les deux qui restent visibles une fois la moitié du carré glissée
   sous la bulle. */
.visite-fleche {
  position: absolute;
  width: 12px;
  height: 12px;
  border-top: 1px solid var(--bordure);
  border-left: 1px solid var(--bordure);
  background: var(--surface);
  transform: rotate(45deg);
}

.visite-fleche-gauche { top: 22px; left: -7px; }
.visite-fleche-droite { top: 22px; right: -7px; transform: rotate(225deg); }
.visite-fleche-haut   { top: -7px; left: 26px; }
.visite-fleche-bas    { bottom: -7px; left: 26px; transform: rotate(225deg); }

.visite-pied {
  display: flex;
  gap: 8px;
  align-items: center;
  padding-top: 14px;
  border-top: 1px solid var(--bordure);
  margin-top: 16px;
}

.visite-compteur {
  /* Sans cette réserve, la largeur du compteur change entre « 1 / 9 » et
     « 10 / 9 » et les deux boutons sautent d'un pixel à chaque étape. */
  min-width: 44px;
  margin-right: auto;
  color: var(--texte-tres-doux);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
}

/* « Passer » est en retrait : on ne pousse pas quelqu'un dehors, mais
   la porte doit rester visible à chaque étape. */
.visite-passer {
  position: absolute;
  top: 10px;
  right: 12px;
  padding: 4px 6px;
  border: 0;
  background: none;
  color: var(--texte-tres-doux);
  font-family: inherit;
  font-size: 0.78rem;
  text-decoration: underline;
  cursor: pointer;
}

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

/* La cible mise en avant passe AU-DESSUS du voile. Sans cela, la barre
   latérale — qui a son propre empilement — resterait sous l'ombre et
   l'on encadrerait une zone sombre. */
.visite-cible {
  position: relative;
  z-index: 899;
}

/* Le scénario est de la donnée, pas de l'affichage : rien ne doit lui
   rendre un display. */
[data-visite-scenario][hidden],
[data-visite-auto][hidden] { display: none; }

/* --- Les grandes lignes, en clair sur le tableau de bord -----------
   La même chose que la visite, mais écrite : elle reste lisible quand
   le script ne se charge pas, et se relit sans relancer huit écrans. */
.guide-etapes {
  padding: 0;
  margin: 0;
  list-style: none;
  counter-reset: guide;
}

.guide-etapes > li {
  display: grid;
  grid-template-columns: 44px 1fr;
  gap: 16px;
  padding: 20px 0;
  border-top: 1px solid var(--bordure);
}

.guide-etapes > li:first-child { border-top: 0; padding-top: 4px; }

.guide-num {
  font-family: var(--police-titre);
  font-size: 1.6rem;
  font-weight: 600;
  line-height: 1;
  color: var(--accent-texte);
}

.guide-etapes h3 { margin-bottom: 6px; font-size: 1.05rem; }
.guide-etapes p { margin-bottom: 8px; color: var(--texte-doux); font-size: 0.92rem; }
.guide-etapes p:last-child { margin-bottom: 0; }

.guide-liens {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 0.88rem;
}

/* --- L'étape suivante : une seule proposition ---------------------
   Proposer les cinq d'un coup, c'est ne rien proposer du tout. */
.etape-suivante {
  border-left: 4px solid var(--accent);
  margin-bottom: 24px;
}

.etape-tag {
  margin-bottom: 6px;
  color: var(--accent-texte);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

@media (width < 640px) {
  /* SUR TÉLÉPHONE, LA BULLE NE SUIT PLUS LA CIBLE : la barre latérale
     est un tiroir refermé, la moitié des cibles n'existe pas à l'écran,
     et une bulle de 340px qui cherche à se poser à côté d'un élément de
     40px sort de la fenêtre une fois sur deux. Elle se pose en bas,
     pleine largeur, et le halo continue d'indiquer ce dont on parle
     quand la cible est visible. */
  .visite-bulle {
    top: auto !important;
    right: 12px;
    bottom: 12px;
    left: 12px !important;
    width: auto;
  }

  .visite-fleche { display: none; }

  .guide-etapes > li { grid-template-columns: 32px 1fr; gap: 12px; }
}

/* --- Formulaire en deux colonnes de hauteurs égales ----------------
   Un formulaire d'une quinzaine de champs empilés sur une colonne
   oblige à faire défiler pour voir la fin de ce qu'on remplit. Deux
   colonnes le tiennent sous les yeux — encore faut-il qu'elles se
   terminent à la même hauteur, sinon l'une pend sous l'autre et le
   bouton d'enregistrement se retrouve dans le vide. */
.form-colonnes {
  display: grid;
  gap: 0 32px;
}

@media (width >= 900px) {
  .form-colonnes { grid-template-columns: 1fr 1fr; }
}

.form-colonne {
  display: flex;
  flex-direction: column;
}

/* Le champ qui porte cette classe absorbe la hauteur restante de sa
   colonne : c'est lui qui égalise les deux. En pratique, la zone de
   notes — la seule qui peut grandir sans nuire. */
.champ-etire {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.champ-etire textarea {
  flex: 1;
  min-height: 200px;
  resize: vertical;
}

/* Deux champs courts côte à côte à l'intérieur d'une colonne — code
   postal et commune, latitude et longitude. */
.paire {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 16px;
}


/* --- Photo et plan du bien ----------------------------------------- */
.media-bien {
  margin: 0 0 16px;
  overflow: hidden;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface-2);
}

.media-bien img {
  display: block;
  width: 100%;
  height: auto;
}

/* --- Dialogue de recadrage ------------------------------------------
   Plus large que le modal de confirmation : on y regarde une image, pas
   une phrase. */
dialog.modal-large { width: min(880px, calc(100vw - 32px)); }

/* Cropper.js a besoin d'une hauteur bornee : sans elle, une photo de
   4000px de haut pousse les boutons du dialogue hors de l'ecran. */
.cadreur {
  max-height: min(60vh, 520px);
  margin-top: 16px;
  background: var(--surface-2);
}

.cadreur img {
  display: block;
  max-width: 100%;
}

/* Aperçu du cadrage, sous le champ : on montre ce qui partira, pas le
   fichier d'origine. */
.apercu-recadrage {
  display: block;
  width: 240px;
  max-width: 100%;
  margin-top: 10px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
}

/* Tant qu'aucun cadrage n'a ete fait, l'image n'a pas de source : sans
   cette ligne, le « display: block » ci-dessus l'emporte sur l'attribut
   « hidden » (qui n'est qu'un display:none de la feuille du navigateur)
   et la page affiche une icone d'image cassee avec son texte de
   remplacement. */
.apercu-recadrage[hidden] { display: none; }

/* Un plan depose en JPG ou en PNG s'affiche directement dans sa carte :
   ouvrir un onglet pour verifier qu'on a bien televerse le bon fichier
   est un detour. Les formats que le navigateur ne sait pas peindre
   (SVG, DWG, DXF, AI) gardent le simple lien d'ouverture. */
.media-plan {
  display: block;
  margin: 0 0 12px;
}

.media-plan img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  /* Un plan est souvent un trait noir sur fond transparent : sans
     surface derriere, il disparaitrait sur un fond sombre. */
  background: var(--surface);
}

/* --- Les plans du bien, cote a cote (lot L19) ----------------------
   Une maison a des niveaux. Les plans se REGARDENT ENSEMBLE — on suit
   une cloison du rez-de-chaussee a l'etage — donc en grille, a hauteur
   egale, et non empiles en pleine largeur. */
.galerie-plans {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 18px;
  margin: 0 0 20px;
  padding: 0;
  list-style: none;
}

.plan-vignette {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
}

.plan-image {
  display: block;
  overflow: hidden;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface);
}

.plan-image:hover,
.plan-image:focus-visible { border-color: var(--bordure-forte); }

/* Hauteur imposee, image entiere a l'interieur : un plan de facade tres
   large et un plan de cave presque carre doivent donner deux vignettes
   de meme taille, sinon la grille ondule. « contain » et non « cover » :
   un plan rogne ne se lit plus. */
.plan-image img {
  display: block;
  width: 100%;
  height: 160px;
  object-fit: contain;
  /* Un plan est souvent un trait noir sur fond transparent : sans
     surface derriere, il disparaitrait sur un fond sombre. */
  background: var(--surface);
}

/* Ce qu'aucun navigateur ne sait peindre — PDF, AI, DWG, DXF — garde sa
   place dans la grille, mais annonce franchement son format plutot que
   d'afficher une icone de fichier casse. */
.plan-fichier {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  justify-content: center;
  height: 160px;
  padding: 12px;
  border: 1px dashed var(--bordure-forte);
  border-radius: var(--rayon-petit);
  color: var(--texte-doux);
  text-align: center;
  /* C'est une TUILE, pas un lien dans une phrase : soulignee, elle
     jurait a cote des vignettes d'images qui l'entourent. */
  text-decoration: none;
}

.plan-fichier:hover { border-color: var(--accent); color: var(--accent-texte); }

.plan-format {
  font-family: var(--police-titre);
  font-size: 1.15rem;
  letter-spacing: 1px;
}

.plan-titre {
  font-weight: 600;
  line-height: 1.3;
}

.plan-vignette .legende { display: block; }

/* Le retrait d'un plan : discret, sous sa vignette, jamais un bouton
   plein qui pese autant que « Enregistrer ». */
.plan-vignette form { margin: 0; }

/* Sous chaque vignette, de quoi corriger l'intitule et le rang sans
   quitter la page — et le retrait, en bouton discret. */
.plan-edition {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.plan-edition input[type="text"] { width: 100%; }

.plan-edition-bas {
  display: flex;
  gap: 8px;
  align-items: center;
}

.plan-edition-bas label {
  margin: 0;
  color: var(--texte-doux);
  font-size: 0.82rem;
}

.plan-edition-bas input[type="number"] {
  width: 4.5rem;
  padding: 6px 8px;
}

/* Le retrait se pousse a droite : ce n'est pas dans le meme geste que
   le reglage de l'ordre. */
.plan-edition-bas button { margin-left: auto; }

.plan-edition .legende {
  overflow: hidden;
  margin: 0;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- Le plan en grand (lot L19) ------------------------------------
   Plus large que les autres dialogues : on y regarde un document, pas
   une phrase. */
.modale-plan { width: min(1100px, calc(100vw - 32px)); }

.modale-corps-plan {
  display: flex;
  justify-content: center;
  padding: 16px;
  background: var(--surface-2);
}

.modale-corps-plan img {
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 260px);
  border-radius: var(--rayon-petit);
  background: var(--surface);
}

/* Tant qu'aucun plan n'a ete clique, l'image n'a pas de source : sans
   cette ligne, le « display: block » ci-dessus l'emporterait sur
   l'attribut hidden et la page afficherait une icone cassee. */
.modale-corps-plan img[hidden] { display: none; }

.modale-plan .modal-actions {
  align-items: center;
  justify-content: space-between;
}

.modale-plan .modal-actions .legende { margin: 0; }

/* --- Emplacement de l'apercu de cadrage ----------------------------
   La page ne declare qu'un emplacement ; _js/recadrage.js y depose
   l'image une fois le cadre valide. Vide, il ne prend pas de place —
   c'est ce qui evite l'icone de fichier casse sous le champ. */
.apercu-zone:empty { display: none; }
.apercu-zone { margin-top: 10px; }

/* --- « Il y a un plan » dans une liste (lot L19) -------------------
   La colonne dit d'un coup d'oeil quelles pieces ont leur plan et
   lesquelles n'en ont pas. Le format non peignable montre une icone,
   jamais une image cassee — et jamais la couleur seule pour porter
   l'information (regle 10e) : le title et l'aria-label l'ecrivent. */
.col-plan { width: 1%; }

.marque-plan {
  display: flex;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
  color: var(--texte-doux);
}

.marque-plan svg { display: block; }

/* --- Alerte d'échéance dans une ligne (règle 11f) ------------------
   Une icône à côté de ce qu'elle concerne, plutôt qu'un bandeau en tête
   de page qui pousse le tableau vers le bas et oblige à faire le lien
   de tête entre sa ligne et celle du tableau. */
.alerte {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: var(--rayon-petit);
  margin-right: 4px;
  background: none;
  cursor: pointer;
  vertical-align: -6px;
}

.alerte:hover { background: var(--surface-3); }

/* Deux niveaux seulement : c'est dépassé, ou ça va l'être. Le mot et la
   date restent dans la pastille de la ligne — la couleur ne porte
   jamais l'information seule (règle 10e). */
.alerte-expire { color: var(--ton-rouge-texte); }
.alerte-proche { color: var(--ton-jaune-texte); }

.alerte svg { display: block; }

/* Dans une cellule qui coupe son texte, l'icône ne doit pas être
   rognée : elle garde sa place quoi qu'il arrive. */
table.donnees.donnees-lignes td .alerte { flex: 0 0 auto; }

/* --- Trace d'une conversation SMTP ---------------------------------
   Chaque échange sur sa ligne, en chasse fixe, avec un liseré qui dit
   d'un coup d'œil où ça s'est arrêté. Le but est qu'on puisse copier
   la ligne fautive et la coller telle quelle dans une recherche. */
.trace-smtp {
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: ui-monospace, "sf mono", menlo, consolas, monospace;
  font-size: 0.8rem;
  line-height: 1.5;
}

.trace-smtp li {
  margin-bottom: 2px;
  padding: 6px 10px;
  border-left: 3px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
  overflow-wrap: anywhere;
}

.trace-smtp .trace-ok   { border-left-color: var(--vert);  background: var(--vert-doux); }
.trace-smtp .trace-ko   { border-left-color: var(--rouge); background: var(--rouge-doux); }
.trace-smtp .trace-info { border-left-color: var(--bleu);  background: var(--bleu-doux); font-family: var(--police-corps); }

/* --- Photos d'un chantier : légende par photo (règle 11m) -----------
   Une vignette n'est plus une image avec un mot dessous : c'est une
   fiche. Elle porte sa légende, son moment, sa date, et deux vrais
   boutons. « Supprimer » était du texte gris qu'on prenait pour une
   légende ; c'est maintenant un bouton de la même famille que ceux des
   lignes du tableau. */
.vignette-fiche {
  display: grid;
  gap: 8px;
  margin-top: 10px;
}

.vignette-fiche .champ { margin: 0; }

.vignette-fiche label {
  display: block;
  margin-bottom: 2px;
  color: var(--texte-doux);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.vignette-fiche input,
.vignette-fiche select {
  width: 100%;
  padding: 6px 8px;
  font-size: 0.85rem;
}

/* Les deux boutons sur une ligne, et qui restent lisibles si la
   vignette se retrouve seule sur un téléphone. */
.vignette-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
}

.vignette-actions .bouton { flex: 1 1 auto; justify-content: center; }

/* --- Photos cadrées, en attente d'envoi ----------------------------
   Elles se distinguent de celles qui sont déjà enregistrées : un liseré
   d'accent en pointillé dit « ceci n'est pas encore parti ». Sans ce
   signal, on ferme la page en croyant avoir enregistré. La couleur ne
   porte pas l'information à elle seule (règle 10e) : le compteur, juste
   au-dessus, le dit en toutes lettres. */
.galerie-attente:empty { display: none; }

.galerie-attente { margin-top: 12px; }

.vignette-attente {
  border-style: dashed;
  border-color: var(--accent);
  background: var(--surface-2);
}

.vignette-attente figcaption {
  display: grid;
  gap: 8px;
}

.vignette-attente label {
  display: block;
  margin-bottom: 2px;
  color: var(--texte-doux);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.vignette-attente input,
.vignette-attente select {
  width: 100%;
  padding: 6px 8px;
  font-size: 0.85rem;
}

/* --- Portrait d'un membre (lot L24) --------------------------------
   Un rond, parce qu'un portrait carre au milieu d'un tableau se lit
   comme une vignette de produit. Sans photo, ce sont les INITIALES et
   non des pointillets vides : dans une liste ou la moitie des lignes
   n'ont pas encore de portrait, une colonne de cadres vides ne dit
   rien, alors que « MF » distingue deja deux lignes.

   Les tailles sont deux classes et non un style en ligne : la CSP
   interdit l'attribut style (regle 7). */
.portrait {
  display: block;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--surface-3);
  object-fit: cover;
}

.portrait-36 { width: 36px; height: 36px; }

.portrait-160 { width: 160px; height: 160px; }

/* Les initiales : centrees, dans la couleur du texte doux, jamais
   assez contrastees pour se faire passer pour une donnee. */
.portrait-vide {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--bordure);
  color: var(--texte-tres-doux);
  font-weight: 500;
  letter-spacing: 0.04em;
}

.portrait-36.portrait-vide { font-size: 0.78rem; }

.portrait-160.portrait-vide { font-size: 2.4rem; }

/* Dans la carte du formulaire et sur la fiche : centre, et de l'air
   avant le champ de depot. */
.portrait-fiche {
  display: flex;
  justify-content: center;
  margin: 0 0 16px;
}

/* ==================================================================
   MENU DE COMPTE — la sortie est un bouton dans un formulaire
   ==================================================================
   La deconnexion passe en POST avec jeton (regle 9a) : c'est donc un
   <button> dans un <form>. Le bouton est deja habille plus haut avec
   les liens du panneau ; il ne manque que ceci — UN FORMULAIRE EST UN
   ELEMENT DE BLOC, et celui-ci doit se comporter comme une simple
   ligne du panneau, sans marge propre. */
.menu-compte-sortie { display: block; margin: 0; }

/* ==================================================================
   KONSEIL — CE QUE LE PROJET AJOUTE A LA FEUILLE DE FUCONE
   ==================================================================
   Ecrit APRES tout le reste, et volontairement a un seul endroit :
   ces composants n'existent pas chez Fucone (la vitrine publique, le
   portail d'acces, la lecture des reponses), ou bien nommaient la
   meme chose autrement.

   TOUT EST EN var(--…). Aucune couleur ne s'ecrit ici : la charte vit
   dans charte-tokens.css et theme.php, et nulle part ailleurs (regle 8).
   ================================================================== */

/* --- Titres de page ---------------------------------------------- */
.page-titre { margin: 0 0 8px; }

.page-chapo {
  max-width: 68ch;
  margin: 0 0 28px;
  color: var(--texte-doux);
  font-size: 1.05rem;
}

/* Le fil d'Ariane dit OU l'on est, pas seulement d'ou l'on vient : sur
   une fiche atteinte par un lien direct, c'est la seule chose qui
   raccroche la page a son client. */
.fil-ariane {
  margin: 0 0 16px;
  color: var(--texte-tres-doux);
  font-size: 0.86rem;
}

.fil-ariane a { color: var(--texte-doux); }
.fil-ariane span { margin: 0 6px; }

/* --- La fiche : un bloc de champs -------------------------------- */
/* CE SONT LES CHAMPS QU'ON BORNE, JAMAIS LA PAGE (regle 11d). Un
   formulaire de 1600 px de large ne se remplit pas mieux ; une page
   bornee, elle, laisse la moitie droite de l'ecran vide pendant qu'un
   tableau se replie a gauche. */
.fiche {
  max-width: 62rem;
  margin: 0 0 24px;
  padding: 24px 26px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.fiche > h2:first-child { margin-top: 0; }

.fiche-question { padding: 16px 18px; margin-bottom: 12px; }

.fiche-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin: 20px 0 0;
}

.fiche-note {
  max-width: 62rem;
  margin: 8px 0 0;
  color: var(--texte-doux);
  font-size: 0.88rem;
  line-height: 1.55;
}

.fiche-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 0 0 10px;
  color: var(--texte-doux);
  font-size: 0.88rem;
}

/* Une liste de definitions : le libelle a gauche, la valeur a droite,
   et une colonne unique sous 640px — deux colonnes serrees a 300px
   coupent chaque valeur en trois lignes. */
.fiche-liste { margin: 0; }

.fiche-liste > div {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  padding: 10px 0;
  border-bottom: 1px solid var(--bordure);
}

.fiche-liste > div:last-child { border-bottom: 0; }

.fiche-liste dt {
  color: var(--texte-tres-doux);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fiche-liste dd { margin: 0; }

@media (min-width: 640px) {
  .fiche-liste > div { grid-template-columns: 11rem 1fr; gap: 12px; align-items: baseline; }
}

.facultatif { color: var(--texte-tres-doux); font-weight: 400; }

/* Un formulaire est un ELEMENT DE BLOC : pose entre deux boutons, il
   jette a la ligne tout ce qui suit, et aucun white-space n'y peut
   quoi que ce soit (regle 11f). */
.ligne-forme { display: inline-block; margin: 0 0 0 8px; }

/* --- Cartes ------------------------------------------------------- */
.carte-attention {
  border-left: 3px solid var(--ambre);
  background: var(--ambre-doux);
}

.carte-attention > h2:first-child { margin-top: 0; }

/* La carte « a faire maintenant » : elle porte l'accent, parce
   qu'elle ne propose jamais qu'UNE chose (regle 12a). */
.carte-action { border-left: 3px solid var(--accent); }

.carte-surtitre {
  margin: 0 0 6px;
  color: var(--texte-tres-doux);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.carte-chiffre { text-align: center; }

.carte-nombre {
  margin: 0;
  font-family: var(--police-titre);
  font-size: 2.4rem;
  font-weight: 600;
  line-height: 1.1;
}

.carte-legende {
  margin: 2px 0 0;
  color: var(--texte-doux);
  font-size: 0.86rem;
}

/* Une grille de cartes qui s'effondre en une colonne sous 900px
   (regle 11d). */
.cartes {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  margin: 0 0 24px;
}

@media (min-width: 900px) {
  .cartes { grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr)); }
}

.carte-v {
  padding: 22px 24px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.carte-v > h2:first-child,
.carte-v > h3:first-child { margin-top: 0; }

/* --- Pastilles ---------------------------------------------------- */
/* Neutre : une mention de service, pas un etat. Sans fond, une
   pastille ne se lit pas comme une pastille. */
.pastille-neutre { background: var(--surface-2); color: var(--texte-doux); }

/* --- Listes simples ----------------------------------------------- */
.liste-simple { margin: 0; padding: 0; list-style: none; }

.liste-simple > li {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
  padding: 9px 0;
  border-bottom: 1px solid var(--bordure);
}

.liste-simple > li:last-child { border-bottom: 0; }
.liste-simple > li.courant { font-weight: 500; }

.liste-titre,
.liste-simple > li.liste-titre {
  display: block;
  margin-top: 14px;
  border-bottom: 0;
  color: var(--texte-tres-doux);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* --- Étapes numérotées -------------------------------------------- */
/* Le compteur est en CSS et non dans le HTML : reordonner ou retirer
   une etape ne demande alors pas de renumeroter a la main, donc pas
   d'occasion de se tromper. */
.etapes {
  max-width: 62rem;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
  counter-reset: etape;
}

.etapes > li {
  counter-increment: etape;
  position: relative;
  margin: 0 0 4px;
  padding: 0 0 22px 52px;
  border-left: 1px solid var(--bordure);
  margin-left: 16px;
}

.etapes > li::before {
  content: counter(etape, decimal-leading-zero);
  position: absolute;
  top: 0;
  left: -16px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--texte-doux);
  font-family: var(--police-titre);
  font-size: 0.82rem;
  font-weight: 600;
}

.etapes > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.etapes > li > h3 { margin-top: 0; }

/* --- Question / réponse (lecture d'un entretien) ------------------ */
.qr { margin: 0 0 18px; }

.qr-question {
  margin: 0 0 4px;
  color: var(--texte-doux);
  font-size: 0.9rem;
}

/* La reponse est la matiere : elle se lit en grand, sur toute la
   largeur, et garde ses retours a la ligne. */
.qr-reponse {
  margin: 0;
  padding: 0 0 0 14px;
  border-left: 2px solid var(--bordure-forte);
  white-space: pre-wrap;
}

.question-lue { margin: 0 0 10px; }
.question-lue .legende { display: block; }

/* ==================================================================
   LE PORTAIL — connexion, code, secours, demande d'accès (règle 16f)
   ==================================================================
   LA CARTE D'ACTION VIENT EN PREMIER DANS LE DOCUMENT. La grille la
   place a droite sur grand ecran ; sur telephone elle doit se trouver
   AVANT le texte de presentation, pas derriere 400 px d'explications.
   C'est l'ordre du HTML qui le garantit, pas cette feuille. */
.portail {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
  max-width: 62rem;
  margin: 0 auto;
  padding: 8px 0 40px;
}

.portail-carte {
  padding: 28px 30px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.portail-carte > h1:first-child { margin-top: 0; }
.portail-carte hr { margin: 26px 0; border: 0; border-top: 1px solid var(--bordure); }

.portail-texte { color: var(--texte-doux); }
.portail-texte h2:first-child { margin-top: 0; }

.portail-aide {
  margin: 14px 0 0;
  color: var(--texte-doux);
  font-size: 0.88rem;
}

.portail-renvoi { margin: 10px 0 0; }

@media (min-width: 860px) {
  /* Le texte a gauche, la carte a droite — alors qu'elle est ecrite en
     premier dans le document. `order` ne change que l'ordre visuel :
     la tabulation et le lecteur d'ecran suivent toujours le HTML. */
  .portail-duo { grid-template-columns: 1fr 1fr; align-items: start; }
  .portail-duo .portail-carte { order: 2; }
  .portail-duo .portail-texte { order: 1; }
}

/* ==================================================================
   LA VITRINE PUBLIQUE (règle 16b)
   ================================================================== */
.vitrine-hero { max-width: 54rem; padding: 24px 0 40px; }

.vitrine-hero h1 {
  font-size: clamp(1.9rem, 4.5vw, 2.9rem);
  line-height: 1.12;
}

.vitrine-hero h1 em { color: var(--accent-texte); font-style: italic; }

.vitrine-chapo {
  max-width: 44rem;
  color: var(--texte-doux);
  font-size: 1.08rem;
  line-height: 1.65;
}

.vitrine-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 26px 0 10px;
}

.vitrine-mention { color: var(--texte-tres-doux); font-size: 0.88rem; }

.vitrine-section {
  max-width: 62rem;
  padding: 34px 0;
  border-top: 1px solid var(--bordure);
}

.vitrine-section > h2:first-child { margin-top: 0; }

.vitrine-etapes {
  margin: 20px 0 0;
  padding: 0 0 0 1.2em;
}

.vitrine-etapes > li { margin: 0 0 20px; padding-left: 6px; }
.vitrine-etapes > li > h3 { margin: 0 0 4px; }
.vitrine-etapes > li > p { margin: 0; color: var(--texte-doux); }

/* Un <details> natif : il s'ouvre au clic et au clavier, sans une
   ligne de script — et la CSP interdit le script en ligne. */
.vitrine-faq {
  padding: 14px 0;
  border-bottom: 1px solid var(--bordure);
}

.vitrine-faq > summary {
  cursor: pointer;
  font-weight: 500;
  list-style-position: outside;
}

.vitrine-faq > p { margin: 10px 0 0; color: var(--texte-doux); max-width: 62ch; }

/* Un compte rendu est un texte long : il se lit en colonne étroite.
   Une ligne de 140 caractères oblige l'œil à chercher le début de la
   suivante, et on relit deux fois la même. */
.texte-long { max-width: 68ch; white-space: pre-wrap; line-height: 1.7; }

/* ==================================================================
   L'ORGANIGRAMME (lot L4)
   ==================================================================
   Le SVG est rendu DANS la page, jamais servi comme fichier : un SVG
   servi est du XML exécutable. Rendu ici, il hérite des jetons de la
   charte — aucune couleur ne s'écrit dans le PHP qui le dessine. */
/* LE DESSIN GARDE SA TAILLE, LE CADRE DÉFILE.
   Il portait `width: 100%` : le cadre avait beau avoir `overflow-x:
   auto` depuis le début, il ne pouvait jamais défiler puisque le dessin
   ne dépassait jamais. Résultat mesuré sur ECSplicite : 2734px ramenés
   à 1159, soit 42% — un texte de 13px tombé à 5px. Un organigramme
   illisible n'est pas un organigramme.

   Sa taille vient maintenant des attributs width/height posés par
   organigramme_svg(). L'impression, elle, le ramène à la feuille. */
.organigramme {
  display: block;
  max-width: none;
  margin: 8px 0 4px;
  font-family: var(--police-corps);
}

.organigramme rect {
  fill: var(--surface);
  stroke: var(--bordure-forte);
  stroke-width: 1;
}

.organigramme .og-entreprise rect { fill: var(--accent-doux); stroke: var(--accent); }
.organigramme .og-direction rect  { fill: var(--surface-2); }

/* Un service sous le seuil est signalé DEUX FOIS : par le trait et
   par le mot « sous le seuil » écrit dans la boîte. Un organigramme
   s'imprime souvent en noir et blanc (règle 10e). */
.organigramme .og-maigre rect { stroke: var(--ambre); stroke-dasharray: 4 3; }

.organigramme .og-titre { fill: var(--texte); font-size: 13px; font-weight: 500; }
.organigramme .og-sous  { fill: var(--texte-doux); font-size: 11px; }
.organigramme .og-maigre .og-sous { fill: var(--ambre); }

.organigramme .og-trait {
  fill: none;
  stroke: var(--bordure-forte);
  stroke-width: 1.5;
}

/* L'organigramme déborde en largeur dès qu'il y a beaucoup de
   services : il défile dans son propre conteneur, et la page ne
   défile jamais latéralement (règle 10a). */
.organigramme-cadre { overflow-x: auto; }

/* min-width: 0 : un enfant de grille vaut « min-width: auto » et
   grossit au lieu de se replier — la page déborderait alors sur le
   côté, et le défilement du cadre ne servirait à rien. */
.organigramme-cadre { min-width: 0; }

@media print {
  /* À l'impression, on retire le fond des boîtes : une aplat de
     couleur imprimée en niveaux de gris rend le texte illisible. */
  .organigramme rect { fill: none !important; }
}

/* ==================================================================
   LA FRISE (lot L5)
   ==================================================================
   Une liste, pas un dessin. Une frise en SVG serait plus jolie et
   moins lisible : on vient y chercher « qu'est-ce qui s'est passé le
   12 », et une liste répond à cela mieux qu'une ligne du temps. */
/* UNE FRISE, PAS UNE LISTE.
   Elle était trois colonnes de texte séparées par un filet coupé à
   chaque intervalle : rien n'y reliait les événements, et l'œil lisait
   un tableau sans en-têtes. Ici un FIL CONTINU les traverse, et chaque
   événement s'y accroche par une pastille. Le fil est dessiné par
   chaque ligne plutôt que par la liste entière : les intitulés de mois
   l'interrompent alors d'eux-mêmes, ce qui est exactement ce qu'on
   veut — un mois est une rupture, pas un événement. */
.frise { margin: 24px 0 0; padding: 0; list-style: none; max-width: 62rem; }

.frise-mois {
  margin: 28px 0 10px;
  color: var(--texte-tres-doux);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.frise-mois:first-child { margin-top: 0; }

.frise-item {
  position: relative;
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: 0 26px;
  padding: 9px 0;
}

/* Le fil. Il court sur toute la hauteur de la ligne, si bien que deux
   lignes voisines le prolongent sans raccord visible. */
.frise-item::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 5.4rem;
  width: 1px;
  background: var(--bordure);
}

/* La pastille, posée SUR le fil. Le halo de la couleur de fond creuse
   le trait autour d'elle : sans lui, la pastille paraît enfilée sur une
   ficelle au lieu de marquer un point d'arrêt. */
.frise-item::after {
  content: "";
  position: absolute;
  top: 1rem;
  left: calc(5.4rem - 3px);
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--frise-puce, var(--bordure-forte));
  box-shadow: 0 0 0 3px var(--fond);
}

.frise-jour {
  padding-top: 1px;
  color: var(--texte-doux);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.frise-titre { margin: 0; }

/* Le genre devant le titre, en pastille. La couleur reprend celle du
   point sur le fil : on relie l'un à l'autre sans avoir à l'expliquer. */
.frise-genre {
  display: inline-block;
  margin-right: 8px;
  padding: 1px 8px;
  border-radius: var(--rayon-pilule);
  background: var(--frise-fond, var(--surface-2));
  color: var(--frise-texte, var(--texte-doux));
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: 1px;
}

.frise-detail {
  margin: 2px 0 0;
  color: var(--texte-doux);
  font-size: 0.86rem;
}

/* Chaque genre a sa couleur — le point sur le fil et le fond de la
   pastille la partagent, ce qui relie l'un à l'autre sans un mot.

   Elle ne porte JAMAIS l'information seule (règle 10e) : le genre est
   écrit en toutes lettres dans la pastille, et c'est le texte qui le
   dit. Le texte reste foncé sur toutes les teintes — il n'existe pas de
   jetons `--vert-texte` / `--ambre-texte` / `--bleu-texte`, et poser la
   couleur vive sur son propre fond pâle aurait donné des contrastes
   qu'on n'a pas mesurés. La teinte de fond suffit à distinguer. */
.frise-jalon       { --frise-puce: var(--ambre);  --frise-fond: var(--ambre-doux);  --frise-texte: var(--texte); }
.frise-jalon-fait  { --frise-puce: var(--vert);   --frise-fond: var(--vert-doux);   --frise-texte: var(--texte); }
.frise-formulaire  { --frise-puce: var(--accent); --frise-fond: var(--accent-doux); --frise-texte: var(--accent-texte); }
.frise-analyse     { --frise-puce: var(--accent); --frise-fond: var(--accent-doux); --frise-texte: var(--accent-texte); }
.frise-etude       { --frise-puce: var(--ambre);  --frise-fond: var(--ambre-doux);  --frise-texte: var(--texte); }
.frise-proposition { --frise-puce: var(--vert);   --frise-fond: var(--vert-doux);   --frise-texte: var(--texte); }
.frise-document    { --frise-puce: var(--bleu);   --frise-fond: var(--bleu-doux);   --frise-texte: var(--texte); }
.frise-reponse     { --frise-puce: var(--bordure-forte); }
.frise-courriel    { --frise-puce: var(--bordure-forte); }

/* min-width: 0 sur la colonne large : sans lui, un titre long la fait
   grossir au lieu de se replier, et la page déborde latéralement — le
   défaut se mesure, il ne se voit pas sur un grand écran. */
.frise-quoi { min-width: 0; }

/* Sur téléphone, le fil et sa pastille disparaissent : à 4,5rem de la
   gauche, ils mangeraient la moitié de la largeur utile. La date passe
   au-dessus du titre, alignée à gauche comme le reste. */
@media (width < 620px) {
  .frise-item { grid-template-columns: 1fr; gap: 2px; padding-left: 12px; border-left: 2px solid var(--frise-puce, var(--bordure)); }
  .frise-item::before,
  .frise-item::after { display: none; }
  .frise-jour { text-align: left; }
}

/* ==================================================================
   14. LA PAGE NUE — 404, ET RIEN D'AUTRE
   ==================================================================
   client_introuvable() écrit son HTML à la main : elle est appelée
   depuis le socle, avant que le shell ne soit chargé, et parfois
   parce que le shell lui-même ne peut pas se construire. Elle n'a
   donc que la feuille, et il lui faut sa règle — sans elle, la page
   d'erreur sort collée au bord gauche, en 16 px, et ressemble à une
   panne du serveur plutôt qu'à une réponse de l'application. */
.page-simple {
  max-width: 34rem;
  margin: 12vh auto;
  padding: 0 var(--gouttiere);
}

.page-simple h1 {
  font-family: var(--police-titre);
  font-size: clamp(1.6rem, 4vw, 2.2rem);
  margin-bottom: 16px;
}

.page-simple p { color: var(--texte-doux); margin-bottom: 16px; }

/* Un titre de section à l'intérieur d'une page, quand une même page
   porte deux tableaux qui ne parlent pas de la même chose. Sans lui,
   les deux listes se suivent sans que rien ne dise où l'une finit. */
.titre-section-simple {
  font-family: var(--police-titre);
  font-size: 1.25rem;
  margin: 32px 0 12px;
  padding-top: 20px;
  border-top: 1px solid var(--bordure);
}

/* ==================================================================
   15. LES DIAPOSITIVES — L'ÉTUDE D'UN SITE (lot L7)
   ==================================================================
   Empilées par défaut, et lisibles ainsi : c'est le rendu qui reste
   si _js/slides.js ne se charge pas. Le mode « présenter » n'ajoute
   qu'une classe sur le conteneur. */
.deck { display: flex; flex-direction: column; gap: var(--gouttiere); }

.diapo {
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-left: 4px solid var(--bordure-forte);
  border-radius: var(--rayon);
  padding: 28px 24px;
}

.diapo-num {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--texte-tres-doux);
  font-variant-numeric: tabular-nums;
  margin-bottom: 4px;
}

.diapo-genre {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--texte-doux);
  margin-bottom: 8px;
}

.diapo-titre {
  font-family: var(--police-titre);
  font-size: clamp(1.3rem, 3vw, 1.9rem);
  line-height: 1.2;
  margin-bottom: 12px;
}

.diapo-accroche { color: var(--texte-doux); max-width: 62ch; margin-bottom: 16px; }

.diapo-points { list-style: none; display: flex; flex-direction: column; gap: 12px; }
.diapo-points li { max-width: 70ch; padding-left: 16px; border-left: 2px solid var(--bordure); }
.diapo-points strong { display: block; }

.diapo-citation {
  margin-top: 20px;
  padding: 14px 18px;
  background: var(--surface-2);
  border-radius: var(--rayon-petit);
  max-width: 62ch;
}

.diapo-citation p { font-style: italic; }
.diapo-citation footer { font-size: 0.78rem; color: var(--texte-tres-doux); margin-top: 6px; }

/* La couleur du filet double un mot écrit en clair (règle 10e) : le
   genre figure toujours dans .diapo-genre. */
.diapo-couverture   { border-left-color: var(--accent); background: var(--surface-2); }
.diapo-constat      { border-left-color: var(--bordure-forte); }
.diapo-force        { border-left-color: var(--vert); }
.diapo-faiblesse    { border-left-color: var(--rouge); }
.diapo-question     { border-left-color: var(--bleu); }
.diapo-recommandation { border-left-color: var(--accent); }

/* --- Mode « présenter » : une page à la fois ---------------------- */
.deck-presente .diapo { display: none; min-height: 62vh; }
.deck-presente .diapo-active { display: block; }

.deck-barre {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 0;
  border-top: 1px solid var(--bordure);
  border-bottom: 1px solid var(--bordure);
  margin-bottom: var(--gouttiere);
}

.deck-position { font-variant-numeric: tabular-nums; color: var(--texte-doux); }

/* ==================================================================
   16. LA PROPOSITION — UN DOCUMENT, PAS UN ÉCRAN (lot L8)
   ==================================================================
   Elle se relit souvent sur papier : mesure de ligne bornée, sections
   numérotées, pas de fond coloré qui coûterait une cartouche. */
.proposition {
  background: var(--surface);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  padding: 32px 28px;
}

.proposition-titre {
  font-family: var(--police-titre);
  font-size: clamp(1.4rem, 3.4vw, 2rem);
  line-height: 1.2;
  margin-bottom: 14px;
}

.proposition-chapo {
  color: var(--texte-doux);
  max-width: 68ch;
  margin-bottom: 28px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--bordure);
}

.proposition-section { margin-bottom: 26px; max-width: 72ch; }

.proposition-section h3 {
  font-family: var(--police-titre);
  font-size: 1.15rem;
  margin-bottom: 8px;
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.proposition-num {
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
  color: var(--accent-texte);
  letter-spacing: 0.06em;
}

.proposition-verifier { margin-top: 32px; }

/* ==================================================================
   17. LE BILAN — TROIS OU QUATRE CHIFFRES, PAS DOUZE (lot L9)
   ================================================================== */
.chiffres {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin-bottom: 16px;
}

.chiffres > li { min-width: 8rem; }

.chiffre-libelle {
  display: block;
  font-size: 0.85rem;
  color: var(--texte-doux);
}

/* --- Sélecteur de client (barre latérale, back-office) --------------
   Le menu de gauche est au périmètre d'un client ; ce sélecteur le
   commande, et se place donc EN TÊTE de la colonne qu'il pilote — pas
   dans le menu du compte, qui rassemble ce qui ne dépend d'aucun
   client.

   Même ressort que le menu du compte : un <details> natif. La CSP
   interdit le JavaScript en ligne et referme la porte sans un mot
   (règle 7) ; un menu qui tient sans script ne tombe jamais.

   Aucune couleur en dur : tout vient des jetons de charte-tokens.css
   et de theme.php, si bien que le sélecteur suit l'accent choisi par
   le client sans qu'on y touche. */
/* IL NE SE REPLIE PAS AVEC LE MENU, sur téléphone.
   La barre latérale se referme sous 900px, mais le sélecteur reste :
   savoir de QUEL client on regarde les données est plus important que
   les rubriques elles-mêmes. Replié avec le reste, on lirait un
   calendrier sans savoir à qui il appartient — et il faudrait ouvrir le
   menu pour le vérifier. Mesuré à 720px : 46px de haut, la page ne
   déborde pas. */
.choix-client {
  position: relative;
  margin: 0 4px 18px;
}

.choix-client > summary {
  display: flex;
  gap: 8px;
  align-items: baseline;
  padding: 9px 12px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon);
  background: var(--surface);
  cursor: pointer;
  list-style: none;
}

.choix-client > summary::-webkit-details-marker { display: none; }
.choix-client > summary:hover { background: var(--surface-2); }
.choix-client[open] > summary { border-color: var(--texte-doux); }

/* L'étiquette dit ce que le nom EST : sans elle, « ECSplicite » posé
   en haut d'un menu se lit comme le nom du produit. */
.choix-client-etiquette {
  color: var(--texte-doux);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.choix-client-nom {
  flex: 1;
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.choix-client-panneau {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  width: 100%;
  min-width: 208px;
  max-height: 320px;
  padding: 6px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  box-shadow: var(--ombre-flottante);
  overflow-y: auto;
}

.choix-client-panneau a {
  display: block;
  padding: 8px 10px;
  border-radius: var(--rayon-petit);
  color: var(--texte);
  font-size: 0.9rem;
  text-decoration: none;
}

.choix-client-panneau a:hover { background: var(--surface-2); }

/* Le client courant est marqué, et pas seulement par la couleur
   (règle 10e) : aria-current le dit aux lecteurs d'écran, et la
   graisse le dit à l'œil. */
.choix-client-panneau a[aria-current] {
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-weight: 600;
}

.choix-client-tous {
  border-top: 1px solid var(--bordure);
  margin-top: 6px;
  padding-top: 10px;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

/* --- Le calendrier, en grille de mois -------------------------------
   Mécanique reprise du calendrier de propaganews : sept colonnes, des
   cases à hauteur minimale, les jours des mois voisins estompés, le
   jour courant marqué, les événements tronqués dans leur case.

   LE STYLE N'EN VIENT PAS. propaganews est écrit en Bootstrap — d-flex,
   card, gap-2 — et Konseil s'interdit Bootstrap (règle 11). On reprend
   le mécanisme, on rhabille au vocabulaire maison, et aucune couleur
   n'est écrite en dur : tout vient des jetons, donc la grille suit
   l'accent choisi par le client.

   C'est un <table> et non une grille CSS : un lecteur d'écran doit
   pouvoir annoncer « mercredi 16 », ce qu'une suite de <div> ne permet
   pas. */
.cal-barre {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin: 24px 0 14px;
}

.cal-navigation {
  display: flex;
  gap: 12px;
  align-items: center;
}

.cal-mois-titre {
  min-width: 11rem;
  margin: 0;
  font-family: var(--police-titre);
  font-size: 1.25rem;
  text-align: center;
  text-transform: capitalize;
}

.cal-grille {
  width: 100%;
  min-width: 44rem;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
}

.cal-grille th {
  padding: 8px 6px;
  border-bottom: 1px solid var(--bordure);
  color: var(--texte-doux);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
}

/* L'abréviation garde le jour entier dans son title : « mer » seul ne
   se lit pas à voix haute, et ne s'imprime pas mieux. */
.cal-grille th abbr { text-decoration: none; }

/* `height` SUR UNE CELLULE DE TABLEAU EST UN MINIMUM, pas un plafond :
   une journée chargée fait grandir sa semaine et rien n'est masqué.
   Mesuré avec sept jalons le même jour — la case passe à 215px, les
   autres semaines restent à 120px, aucun jalon ne sort de sa case.
   Ne pas y ajouter `overflow: hidden` : ce serait cacher une échéance,
   et une échéance cachée est une échéance manquée. */
.cal-case {
  height: 7.5rem;
  padding: 6px;
  border-right: 1px solid var(--bordure);
  border-bottom: 1px solid var(--bordure);
  background: var(--surface);
  vertical-align: top;
}

.cal-grille tr > .cal-case:first-child { border-left: 1px solid var(--bordure); }

/* Les jours du mois voisin restent visibles — une semaine amputée se
   lit mal — mais reculent d'un ton : on voit qu'ils ne comptent pas. */
.cal-hors { background: var(--fond); }
.cal-hors .cal-numero { color: var(--texte-tres-doux); }

/* Le jour courant : un liseré, pas un aplat. Un fond coloré entrerait
   en concurrence avec les jalons qu'il contient. */
.cal-auj { box-shadow: inset 0 0 0 2px var(--accent); }
.cal-auj .cal-numero { color: var(--accent-texte); font-weight: 700; }

.cal-numero {
  display: block;
  margin-bottom: 4px;
  color: var(--texte-doux);
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* UN JALON DANS SA CASE. Il tient sur une ligne et se coupe : une case
   qui grandit avec son contenu ferait des semaines de hauteurs
   différentes, et la grille cesserait d'être une grille. Le titre
   complet est dans le title, et la page du jalon est à un clic. */
.cal-jalon {
  display: block;
  overflow: hidden;
  margin-top: 3px;
  padding: 3px 7px;
  border-left: 3px solid var(--cal-teinte, var(--bordure-forte));
  border-radius: var(--rayon-petit);
  background: var(--cal-fond, var(--surface-2));
  color: var(--texte);
  font-size: 0.78rem;
  line-height: 1.35;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cal-jalon:hover,
.cal-jalon:focus-visible { background: var(--surface-2); text-decoration: none; }

/* LA MARQUE, ET NON LE MOT. « EN RETARD » écrit dans la case mangeait
   la moitié de ses 174px : mesuré, sept jalons sur huit étaient
   tronqués et plus aucun titre ne se lisait. Un signe tient en une
   lettre.

   Ce n'est pas retomber sur la couleur seule (règle 10e) : un signe
   n'est pas une teinte, il survit au noir et blanc. Le mot entier reste
   dans le `title`, dans la légende, et dans un texte réservé au lecteur
   d'écran — qui l'annonce avant le titre. */
.cal-marque {
  display: inline-block;
  width: 1em;
  margin-right: 3px;
  color: var(--cal-teinte, var(--texte-doux));
  font-weight: 700;
  text-align: center;
}

.cal-prevu  { --cal-teinte: var(--accent); --cal-fond: var(--accent-doux); }
.cal-retard { --cal-teinte: var(--rouge);  --cal-fond: var(--rouge-doux); }
.cal-fait   { --cal-teinte: var(--vert);   --cal-fond: var(--vert-doux); }

.cal-legende {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
  color: var(--texte-doux);
  font-size: 0.82rem;
}

.cal-legende .cal-jalon { display: inline-block; margin-top: 0; }

/* Sous 720px, les mots « Précédent » et « Suivant » disparaissent : les
   chevrons suffisent, et la barre tient alors sur une ligne. Les mots
   restent dans l'aria-label du lien — c'est lui que le lecteur d'écran
   annonce. */
@media (width < 720px) {
  .cal-nav-mot { display: none; }
  .cal-mois-titre { min-width: 8rem; font-size: 1.1rem; }
  .cal-case { height: 5.5rem; }
}

/* --- L'organigramme, en page de consultation ------------------------
   La page d'édition porte le dessin ET les listes qui le remanient :
   c'est un établi. Cette page-ci ne porte que le dessin — c'est ce
   qu'on projette en réunion et ce qu'on imprime.

   Ni carte ni cadre autour : un encadrement dans un encadrement rogne
   la seule chose dont un organigramme a besoin, la place. La page EST
   le cadre. */
.organigramme-vue {
  margin-top: 24px;
  padding: 20px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

/* Le dessin est un SVG à viewBox : il se met à la largeur disponible et
   ne se coupe jamais. Sur un écran étroit, c'est l'enveloppe qui défile
   — un organigramme réduit à 320px ne se lit plus, le rétrécir serait
   l'effacer. */
.organigramme-vue .organigramme-cadre { min-width: 0; overflow-x: auto; }

.organigramme-note {
  max-width: 62rem;
  margin-top: 14px;
  color: var(--texte-doux);
  font-size: 0.9rem;
}

/* À L'IMPRESSION, IL NE RESTE QUE LE DESSIN.
   C'est la raison d'être de cette page : on la remet au client. La
   barre latérale, le menu du compte et le fil d'Ariane n'ont rien à
   faire sur une feuille, et le cadre non plus — le papier est déjà un
   cadre. */
@media print {
  .barre-laterale,
  .appli-entete,
  .fil-ariane,
  .titre-section .actions-ligne { display: none; }

  .organigramme-vue {
    padding: 0;
    border: 0;
    background: transparent;
  }

  /* Sur le papier, le dessin se ramène à la largeur de la feuille : à
     sa taille d'écran, il sortirait de la page. C'est le seul endroit
     où on le rétrécit, et c'est le seul où l'on n'a pas le choix. */
  .organigramme { width: 100%; height: auto; }
  .organigramme-cadre { overflow: visible; }

  .appli-contenu { padding: 0; }
}

/* --- La trame d'un formulaire, en lecture ---------------------------
   Cinquante-huit questions à la file, sans numéro ni relief, ne se
   parcourent pas : on ne sait ni où l'on en est, ni comment désigner
   une question au téléphone. Trois choses y remédient — un numéro
   continu, une section qui annonce son compte, et le type de réponse
   rejeté en bout de ligne parce qu'on le consulte rarement. */
.trame { margin-top: 8px; }

.trame-section {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: baseline;
  justify-content: space-between;
  margin: 28px 0 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--bordure);
}

.trame-section:first-child { margin-top: 0; }
.trame-section h3 { margin: 0; }

.trame-compte {
  margin: 0;
  color: var(--texte-doux);
  font-size: 0.8rem;
  white-space: nowrap;
}

.trame-questions {
  margin: 0;
  padding: 0;
  list-style: none;
}

.trame-question {
  display: grid;
  grid-template-columns: 2.25rem 1fr auto;
  gap: 0 14px;
  align-items: baseline;
  padding: 9px 0;
}

.trame-question + .trame-question { border-top: 1px solid var(--bordure); }

/* Le numéro est en aria-hidden : la liste ordonnée le dit déjà au
   lecteur d'écran, qui annoncerait sinon « 34, 34 ». Il reste à l'œil,
   pour qui parcourt une trame de cinquante-huit lignes. */
.trame-numero {
  color: var(--texte-tres-doux);
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.trame-corps { min-width: 0; }
.trame-libelle { margin: 0; }

.trame-aide {
  margin: 3px 0 0;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

.trame-type {
  color: var(--texte-doux);
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Sous 620px, le type passe à la ligne sous le libellé : gardé en bout
   de ligne, il volerait au titre la moitié d'un écran de téléphone. */
@media (width < 620px) {
  .trame-question { grid-template-columns: 2rem 1fr; }
  .trame-type { grid-column: 2; margin-top: 3px; }
}

/* --- L'organigramme -------------------------------------------------
   LE FORMAT VIENT DE L'INTRANET D'ECSPLICITE : une bande de
   gouvernance, le président, puis UNE COLONNE PAR DIRECTION dans
   laquelle les gens se lisent les uns sous les autres.

   C'est ce dernier point qui fait tout tenir. Un arbre classique aligne
   les services côte à côte : douze services faisaient 3 000px de large
   et un ascenseur horizontal permanent. Ici la largeur ne dépend que du
   NOMBRE DE DIRECTIONS, et la hauteur absorbe le reste — une page se lit
   de haut en bas, c'est le sens dans lequel on a de la place.

   On reprend la STRUCTURE d'ECSplicite, pas ses dégradés roses : ivoire,
   vert, serif éditoriale, et aucune couleur écrite ici. */
.orga { margin-top: 20px; }

/* --- La bande de gouvernance ---------------------------------------
   Une bande et non une boîte de plus : c'est une instance collective,
   distincte de la ligne hiérarchique. Lui donner une case dans l'arbre
   la ferait lire comme un échelon, ce qu'elle n'est pas. */
.orga-gouvernance {
  padding: 16px 20px;
  border: 1px solid var(--accent);
  border-radius: var(--rayon);
  background: var(--accent-doux);
}

.orga-gouvernance-titre {
  margin: 0 0 10px;
  color: var(--accent-texte);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.orga-pastilles {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.orga-pastilles li {
  display: flex;
  gap: 7px;
  align-items: center;
  padding: 4px 12px 4px 5px;
  border-radius: var(--rayon-pilule);
  background: var(--surface);
  font-size: 0.88rem;
  font-weight: 600;
}

.orga-gouvernance-note {
  margin: 10px 0 0;
  color: var(--accent-texte);
  font-size: 0.82rem;
}

/* --- Les initiales, à la place d'un portrait ------------------------
   Konseil ne stocke aucune photo de salarié de client, et il n'en
   stockera pas : deux lettres suffisent à reconnaître quelqu'un dans
   une liste. Décoratives, donc aria-hidden côté HTML — le nom est
   écrit juste à côté. */
.orga-initiales {
  display: grid;
  flex: 0 0 auto;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-size: 0.72rem;
  font-weight: 700;
}

/* --- Le président, et les têtes de direction ------------------------ */
.orga-tete {
  position: relative;
  display: flex;
  justify-content: center;
  padding-top: 26px;
}

/* La descente du président vers la rangée des directions. */
.orga-tete::before,
.orga-colonnes::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 0;
  height: 26px;
  border-left: 2px solid var(--bordure);
}

.orga-carte {
  width: 15rem;
  padding: 14px;
  border: 1px solid var(--bordure);
  border-top: 3px solid var(--accent);
  border-radius: var(--rayon);
  background: var(--surface);
  text-align: center;
}

.orga-carte .orga-initiales {
  width: 42px;
  height: 42px;
  margin: 0 auto 8px;
  font-size: 0.85rem;
}

.orga-carte-tete {
  border-color: var(--accent);
  background: var(--accent-doux);
}
.orga-carte-tete .orga-initiales { background: var(--surface); }

.orga-carte-nom { margin: 0; font-weight: 700; line-height: 1.25; }

.orga-carte-role {
  margin: 3px 0 0;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

.orga-carte-tag {
  margin: 8px 0 0;
  color: var(--accent-texte);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.orga-carte-sans { border-top-style: dashed; }

/* --- Les colonnes ---------------------------------------------------
   flex-wrap, et c'est délibéré : au-delà de ce que l'écran tient, les
   colonnes passent à la ligne au lieu d'exiger un ascenseur horizontal.
   Un organigramme qu'il faut faire défiler de côté ne se lit pas. */
.orga-colonnes {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  justify-content: center;
  padding-top: 26px;
}

.orga-colonne {
  display: flex;
  flex: 0 1 15rem;
  flex-direction: column;
  gap: 10px;
}

/* --- Les gens, en lignes compactes ---------------------------------- */
.orga-gens {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  list-style: none;
  overflow: hidden;
}

.orga-ligne {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 9px 11px;
}

.orga-ligne + .orga-ligne { border-top: 1px solid var(--bordure); }

.orga-ligne-corps { min-width: 0; }
.orga-ligne-nom { margin: 0; font-size: 0.88rem; font-weight: 600; line-height: 1.3; }

.orga-ligne-fonction {
  margin: 1px 0 0;
  color: var(--texte-doux);
  font-size: 0.8rem;
}

.orga-ligne-tag {
  margin: 3px 0 0;
  color: var(--accent-texte);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Sous le seuil d'anonymat : les mots « sous le seuil » sont ÉCRITS
   dans l'étiquette, la couleur ne fait que confirmer (règle 10e) — un
   organigramme s'imprime souvent en noir et blanc. */
.orga-ligne-tag.orga-maigre { color: var(--ambre); }

.orga-vide {
  margin: 0;
  padding: 10px 11px;
  border: 1px dashed var(--bordure);
  border-radius: var(--rayon);
  color: var(--texte-doux);
  font-size: 0.82rem;
  text-align: center;
}

@media (width < 720px) {
  .orga-carte { width: 100%; }
  .orga-colonne { flex: 1 1 100%; }
  .orga-tete::before,
  .orga-colonnes::before { display: none; }
  .orga-tete, .orga-colonnes { padding-top: 16px; }
}

/* ==================================================================
   19. LA SALLE D'ATTENTE D'UN TRAVAIL LONG
   ==================================================================
   La carte ne « tourne » pas : pas d'animation, pas de barre qui
   avance sans rien mesurer. Une barre de progression qui n'est reliee
   a aucune progression reelle ment, et elle ment justement pendant
   les secondes ou l'on se demande si quelque chose se passe.

   Ce qui rassure ici, c'est le TEXTE — il dit que la page bascule
   seule et qu'on peut la fermer — et la pastille qui bat doucement
   pour dire que la page est vivante. Elle s'arrete pour qui a demande
   moins de mouvement (prefers-reduced-motion), sans rien retirer de
   l'information, qui est ecrite. */
.attente { max-width: 44rem; }

.attente [data-travail-message] {
  position: relative;
  padding-left: 22px;
  font-weight: 500;
}

.attente [data-travail-message]::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
  animation: attente-bat 1.6s ease-in-out infinite;
}

@keyframes attente-bat {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.7); }
}

@media (prefers-reduced-motion: reduce) {
  .attente [data-travail-message]::before { animation: none; }
}

/* ==================================================================
   20. LES DOSSIERS DE DOCUMENTS
   ==================================================================
   Des tuiles, pas une arborescence en colonne : on est DANS un
   dossier, et ce qu'on voit est ce qu'il contient. Le fil d'Ariane
   dit ou l'on est, les tuiles disent ou l'on peut aller. Un arbre
   deplie a gauche aurait redit la meme chose une seconde fois, et
   pris le tiers de la largeur pour le faire. */
.classeurs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}

.classeur {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  transition: border-color 0.12s, background 0.12s;
}

.classeur-lien,
a.classeur { text-decoration: none; color: inherit; }

.classeur-lien { display: block; min-width: 0; flex: 1; }

.classeur-nom {
  display: block;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.classeur-compte {
  display: block;
  font-size: 0.82rem;
  color: var(--texte-doux);
}

.classeur:hover,
.classeur:focus-within { border-color: var(--accent); }

/* LA CIBLE DE DEPOT SE VOIT, et pas seulement par la couleur
   (regle 10e) : le trait passe en plein et s'epaissit, le fond
   change. Un daltonien voit le cadre changer. */
.classeur.est-survolee {
  border-color: var(--accent);
  border-width: 2px;
  background: var(--accent-doux);
  padding: 11px 13px;   /* compense les 2px de bordure */
}

.classeur-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.classeur-remonter { color: var(--texte-doux); }

/* ==================================================================
   21. COCHER ET DEPLACER PAR LOT
   ================================================================== */
.col-case { text-align: center; }
.col-case input { cursor: pointer; }

/* La ligne cochee se distingue par un FILET A GAUCHE autant que par
   son fond : sur un ecran mal regle, un fond a peine teinte ne se
   voit pas, un trait de 3px se voit toujours. */
tr.est-cochee > td { background: var(--accent-doux); }
tr.est-cochee > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

tr.est-tiree { opacity: 0.45; }

.table-lot tbody tr { cursor: grab; }

.barre-lot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 10px 14px;
  margin-bottom: -1px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon) var(--rayon) 0 0;
  background: var(--surface-2);
}

.barre-lot-compte { margin: 0; font-weight: 600; }

/* TOUT SUR UNE LIGNE, ET LA CAUSE N'EST PAS LE STYLE DE LA BARRE.
   ------------------------------------------------------------------
   « select » porte width: 100% dans toute l'application — c'est ce
   qu'on veut d'un champ dans une fiche. Dans une barre en flex avec
   flex-wrap: wrap, cette largeur de base de 100% lui reserve une
   ligne entiere, et les boutons tombent dessous.

   C'est le meme piege que le <form> en element de bloc de la regle
   11f : le coupable n'est pas la ou l'on regarde. La barre
   « lignes par page » ne l'avait pas parce qu'elle est en nowrap —
   ses elements se serrent au lieu de passer a la ligne.

   Deux corrections, et il faut les deux : la largeur du select
   redevient celle de son contenu, et la barre cesse de renvoyer a la
   ligne sur grand ecran. */
.barre-lot-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: nowrap;
}

.barre-lot-actions select {
  width: auto;
  max-width: 20rem;
  padding: 7px 10px;
  font-size: 0.9rem;
}

.barre-lot-actions .bouton { white-space: nowrap; }

/* ==================================================================
   22. LA CELLULE A DEUX LIGNES, ET LA VIGNETTE DE TYPE
   ==================================================================
   EXCEPTION ASSUMEE A « une ligne par ligne » (regle 11f). Le nom du
   fichier d'origine est ce qui permet de retrouver un document dont
   on a oublie le titre — « 2. base-de-donnees.html » dit ce que
   « Base de donnees — Dossier technique » ne dit pas. Colle derriere
   le titre, il etait illisible ; dessous, il se lit sans genre la
   lecture du titre.

   Les deux lignes restent BORNEES chacune a une ligne : la hauteur de
   ligne du tableau reste donc constante, ce qui etait le vrai but de
   la regle. */
.cellule-double { line-height: 1.3; }

.cellule-titre,
.cellule-sous {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cellule-sous {
  font-size: 0.8rem;
  color: var(--texte-doux);
}

/* L'ETIQUETTE DE TYPE EST ECRITE — « PDF », « DOCX ». Trois lettres se
   lisent ; une pastille de couleur ne dit rien a qui ne connait pas le
   code, et rien du tout a qui ne distingue pas les couleurs. */
.etiquette-type {
  display: inline-block;
  padding: 2px 6px;
  border: 1px solid var(--bordure-forte);
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--texte-doux);
  background: var(--surface-2);
}

.outils-dossier {
  display: flex;
  align-items: center;
  gap: 6px;
}

.outils-dossier input[type="text"] { width: 12rem; }

.liste-simple {
  margin: 12px 0;
  padding-left: 20px;
  max-height: 18rem;
  overflow-y: auto;
}

.liste-simple li { margin-bottom: 4px; }

@media (max-width: 900px) {
  .classeurs { grid-template-columns: 1fr; }
  .outils-dossier input[type="text"] { width: 100%; }

  /* Sur telephone, la barre A LE DROIT de se replier : la garder sur
     une ligne ferait deborder l'ecran, ce qui est pire que deux
     lignes. */
  .barre-lot-actions { flex-wrap: wrap; }
  .barre-lot-actions select { max-width: 100%; }
}

/* ==================================================================
   23. MODIFIER SUR PLACE, DANS LA LIGNE DU TABLEAU
   ==================================================================
   Un champ de saisie dans une cellule ne doit pas ressembler a un
   champ de formulaire : il doit ressembler a la ligne, et ne se
   reveler qu'au survol et au focus. Sinon un tableau de douze services
   devient un mur de boites blanches, et l'on ne lit plus rien.

   Le focus, lui, reste FRANCHEMENT visible (regle 10e) : on doit voir
   ou l'on est en naviguant au clavier. */
.champ-ligne {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid transparent;
  border-radius: var(--rayon-petit);
  background: transparent;
  font: inherit;
  color: inherit;
}

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

.champ-ligne:focus {
  border-color: var(--accent);
  background: var(--surface);
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

select.champ-ligne { cursor: pointer; }

/* Le formulaire d'ajout tient sur UNE ligne sous le tableau : c'est un
   geste court, il n'a pas besoin d'une fiche a lui. */
.forme-ajout {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--bordure);
}

.forme-ajout input[type="text"] { flex: 1 1 14rem; min-width: 0; }

/* Meme raison que ci-dessus : sans width auto, le select « dans quelle
   direction » prendrait toute la ligne et rejetterait le bouton
   dessous. */
.forme-ajout select { width: auto; max-width: 18rem; }

.forme-ajout label { white-space: nowrap; }

/* LES INITIALES REMPLACENT LE PORTRAIT QU'ON N'A PAS. Konseil ne
   stocke aucune photo de salarie de client : deux lettres suffisent a
   reconnaitre quelqu'un dans une liste, et elles ne creent aucune
   donnee personnelle a proteger, a transferer ni a effacer. */
.jeton-initiales {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.03em;
}

@media (max-width: 900px) {
  .forme-ajout input[type="text"] { flex: 1 1 100%; }
}
