/* ==================================================================
   KOMPTA — 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; }

.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. 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); }
}

/* 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. */
  width: 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-actions { width: 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) {
  .l-actions { width: 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;
}

/* ==================================================================
   7. 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;
}

/* ==================================================================
   8. LE TUNNEL DE SCAN (courses.php, consommer.php)

   L'ecran qu'on tient a bout de bras dans un rayon, souvent d'une
   seule main. Tout y est plus grand qu'ailleurs : les boutons se
   touchent avec le pouce, les chiffres se lisent sans se pencher, et
   le bandeau du total reste colle en haut pendant tout le parcours.

   Toutes les couleurs viennent des jetons : rien ici ne connait la
   couleur choisie dans la page Configuration.
   ================================================================== */

.tunnel { margin-bottom: 32px; }

/* --- Le bandeau du cout en temps reel ----------------------------- */

/* Colle en haut : c'est ce qu'on regarde en levant les yeux, et il ne
   doit pas falloir remonter la page pour le retrouver. */
.tunnel-bandeau {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  gap: 8px;
  justify-content: space-between;
  margin-bottom: 16px;
  padding: 12px 16px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
  box-shadow: var(--ombre);
}

.tunnel-chiffre {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  text-align: center;
}

.tunnel-valeur {
  font-family: var(--police-titre);
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.tunnel-chiffre-fort .tunnel-valeur {
  color: var(--accent-texte);
  font-size: 1.75rem;
}

.tunnel-libelle {
  color: var(--texte-doux);
  font-size: 0.75rem;
  line-height: 1.2;
}

/* --- La camera ---------------------------------------------------- */

.tunnel-camera {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--texte);
}

.tunnel-camera video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Le viseur : un cadre large et bas, a la forme d'un code-barres. Il ne
   sert a rien techniquement — le decodeur balaie toute l'image — mais
   il dit ou poser le code, et c'est ce qui fait la difference entre
   « ca n'accroche jamais » et « ca marche tout de suite ». */
.tunnel-viseur {
  position: absolute;
  top: 50%;
  left: 8%;
  width: 84%;
  /* PLUS HAUT QU'UN CODE-BARRES : le decodeur balaie une vingtaine de
     lignes reparties sur la moitie centrale de l'image, pas seulement
     celle du milieu. Un cadre trop bas laissait croire qu'il fallait
     viser au pixel pres — alors qu'il suffit que le code soit dans la
     zone. Plus haut, on l'attrape sans se contorsionner. */
  height: 42%;
  transform: translateY(-50%);
  border: 2px solid var(--texte-inverse);
  border-radius: var(--rayon-petit);
  box-shadow: 0 0 0 100vmax rgb(20 20 19 / 35%);
}

.tunnel-lampe {
  position: absolute;
  right: 12px;
  bottom: 12px;
  background: var(--surface);
}

.tunnel-lampe[aria-pressed="true"] {
  background: var(--accent);
  color: var(--accent-encre);
}

/* Pas de camera (refus, navigateur sans acces) : le cadre noir n'a plus
   rien a montrer, on le retire au lieu de laisser un trou. */
.sans-camera .tunnel-camera,
.sans-camera .tunnel-etat { display: none; }

.tunnel-etat {
  margin: 8px 0 16px;
  color: var(--texte-doux);
  font-size: 0.9rem;
  text-align: center;
}

/* --- La saisie du code a la main ---------------------------------- */

/* TOUJOURS VISIBLE, jamais repliee derriere un « je n'arrive pas a
   scanner » : un code-barres froisse sur un sachet de salade ne se lit
   pas, quel que soit le decodeur. C'est le chemin qui marche a tous
   les coups. */
.tunnel-saisie {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 16px;
}

.tunnel-saisie label {
  flex: 1 0 100%;
  color: var(--texte-doux);
  font-size: 0.85rem;
}

.tunnel-saisie input {
  flex: 1;
  min-width: 180px;
  padding: 10px 12px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: var(--police-corps);
  font-size: 1rem;
}

/* --- La fiche du produit scanne ----------------------------------- */

.tunnel-fiche { margin-bottom: 24px; }

.tunnel-fiche-tete {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 12px;
}

.tunnel-fiche-tete h2 { margin-bottom: 2px; }

.tunnel-vignette {
  flex: 0 0 auto;
  width: 80px;
  height: 60px;
  border-radius: var(--rayon-petit);
  object-fit: cover;
}

.tunnel-stock {
  margin-bottom: 8px;
  padding: 10px 14px;
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
  font-size: 0.95rem;
}

.tunnel-rappel {
  margin-bottom: 12px;
  padding: 10px 14px;
  border-radius: var(--rayon-petit);
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-size: 0.9rem;
}

/* --- Les deux photos ---------------------------------------------- */

.tunnel-photos {
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr 1fr;
  margin: 16px 0 8px;
}

.tunnel-photo {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: stretch;
}

.tunnel-photo img {
  width: 100%;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* La mention du service exterieur, a l'endroit et au moment ou il sert
   (regle 10d) : une ligne dans une politique de confidentialite ne
   remplace pas l'information au moment du geste. */
.tunnel-mention {
  margin-bottom: 16px;
  font-size: 0.8rem;
}

/* --- Quantite et prix --------------------------------------------- */

.tunnel-compte {
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr;
  margin: 16px 0;
}

.champ-quantite .compteur {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

/* Des boutons qu'on touche du pouce, sans viser : 48 px est la taille
   minimale d'une cible tactile sure. En dessous, on se trompe une fois
   sur cinq, et l'on ne s'en apercoit qu'au passage en caisse. */
.compteur-bouton {
  flex: 0 0 auto;
  justify-content: center;
  min-width: 52px;
  min-height: 48px;
  font-size: 1.3rem;
  line-height: 1;
}

.champ-quantite input,
.tunnel-compte input[type="text"] {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: var(--police-corps);
  font-size: 1.25rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

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

.bouton-large {
  flex: 1;
  justify-content: center;
  min-width: 200px;
  min-height: 52px;
  font-size: 1.05rem;
}

.tunnel-sansjs { margin-bottom: 24px; }

.tunnel-titre-liste { margin-top: 32px; }

/* --- Le passage en caisse ----------------------------------------- */

.tunnel-fin {
  display: grid;
  gap: 16px;
  grid-template-columns: 1fr;
  align-items: center;
  margin-top: 24px;
}

/* Une ligne prise disparait de l'ecran en s'estompant : on ne la
   supprime pas du DOM, pour qu'un « Remettre » reste possible. */
.est-prise {
  opacity: 0.45;
  text-decoration: line-through;
}

/* ==================================================================
   9. COMPLEMENTS DE TABLEAU ET DE FICHE
   ================================================================== */

/* Montants, quantites et dates : alignes a droite et en chiffres de
   meme largeur, sans quoi une colonne de prix ne se compare pas d'un
   coup d'oeil (regle 11f). */
table.donnees th.cellule-nombre,
table.donnees td.cellule-nombre {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

table.donnees td.cellule-vignette { padding: 4px 8px; }

.vignette {
  border-radius: 4px;
  object-fit: cover;
}

/* Un formulaire pose DANS une cellule : il ne doit pas casser la
   hauteur de ligne unique du tableau (regle 11f). */
.ligne-forme {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  margin: 0;
}

.ligne-forme input[type="text"],
.ligne-forme input[type="date"] {
  padding: 4px 8px;
  border: 1px solid var(--bordure-forte);
  border-radius: 6px;
  background: var(--surface);
  color: var(--texte);
  font-family: var(--police-corps);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

.outils-forme { margin: 0; }

.titre-section-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* Le chiffre qui repond a la question de la carte. Plus petit que
   .chiffre du tableau de bord : ici il accompagne un texte, il ne le
   remplace pas. */
.chiffre-fort {
  margin-bottom: 4px;
  color: var(--accent-texte);
  font-family: var(--police-titre);
  font-size: 1.9rem;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.chapo {
  margin-bottom: 24px;
  color: var(--texte-doux);
  font-size: 1.1rem;
  line-height: 1.7;
}

.photo-fiche {
  width: 100%;
  margin-bottom: 16px;
  border-radius: var(--rayon-petit);
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* Une fiche en deux colonnes : l'intitule a gauche, la valeur a droite,
   chaque paire sur sa ligne. */
.fiche-liste {
  display: grid;
  gap: 4px 16px;
  grid-template-columns: auto 1fr;
  margin: 0;
}

.fiche-liste dt {
  color: var(--texte-doux);
  font-size: 0.85rem;
}

.fiche-liste dd {
  margin: 0;
  font-size: 0.95rem;
}

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

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

.liste-simple li:last-child { border-bottom: 0; }

.lien-discret {
  margin-left: 8px;
  color: var(--texte-doux);
  font-size: 0.8rem;
}

/* ==================================================================
   10. RESPONSIVE DU TUNNEL
   Mobile d'abord : ce qui precede est la version telephone, c'est-a-dire
   celle qui sert vraiment. Au-dela, on etale.
   ================================================================== */

@media (width >= 720px) {
  .tunnel-compte { grid-template-columns: repeat(3, 1fr); }
  .tunnel-fin { grid-template-columns: 2fr 1fr; }
  .tunnel-valeur { font-size: 1.6rem; }
  .tunnel-chiffre-fort .tunnel-valeur { font-size: 2.1rem; }
  .tunnel-libelle { font-size: 0.85rem; }
}

@media (width >= 1024px) {
  /* Le cadre de la camera ne grandit plus indefiniment : au-dela d'une
     certaine taille, il ne montre rien de plus et repousse la fiche du
     produit hors de l'ecran. */
  .tunnel-camera { max-width: 560px; margin-inline: auto; }
}

/* --- LES TABLEAUX SUR TELEPHONE -----------------------------------
   Le gabarit de liste est en « table-layout: fixed » avec des largeurs
   en pourcentage : sur un ecran de 390 px, les six colonnes se
   compriment jusqu'a ce que les en-tetes se touchent — « PRODUITRAYON
   QU… » — et plus rien ne se lit.
   
   L'enveloppe sait pourtant defiler (overflow-x: auto) ; il lui
   manquait seulement une raison de le faire. Une largeur minimale sur
   la table la lui donne : elle deborde, elle defile, et chaque colonne
   garde une largeur ou son contenu tient (regle 11f).
   ------------------------------------------------------------------ */
@media (width < 900px) {
  .table-enveloppe-liste table.donnees { min-width: 720px; }
}

/* ==================================================================
   11. L'ECRAN DE COURSES AUTONOME

   « Je fais mes courses » n'a ni barre laterale ni menu de compte.
   Debout dans un rayon, l'ecran est petit et la main est prise :
   chaque pixel pris par une navigation est un pixel de moins pour le
   produit, et chaque lien est une facon de sortir du tunnel par
   erreur. Une seule sortie, nommee, en haut a droite.
   ================================================================== */

.tunnel-shell {
  min-height: 100vh;
  min-height: 100dvh;   /* la barre d'adresse d'un telephone se retracte */
  background: var(--fond);
}

.tunnel-entete {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding: 10px var(--gouttiere);
  border-bottom: 1px solid var(--bordure);
  background: var(--surface);
}

.tunnel-entete-titre {
  overflow: hidden;
  margin: 0;
  font-family: var(--police-titre);
  font-size: 1.05rem;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.tunnel-contenu {
  padding: 16px var(--gouttiere) 48px;
}

/* Le bandeau des totaux se colle SOUS l'en-tete, pas sous le haut de
   la fenetre : sinon il passerait dessous et deviendrait illisible. */
.tunnel-shell .tunnel-bandeau { top: 53px; }

/* --- Le choix du magasin ------------------------------------------
   En tete du tunnel : c'est en arrivant au magasin qu'on sait ou l'on
   est, pas la veille en faisant la liste. */
.tunnel-magasin {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 16px;
}

.tunnel-magasin label {
  color: var(--texte-doux);
  font-size: 0.9rem;
}

.tunnel-magasin select {
  flex: 1;
  min-width: 160px;
  padding: 8px 10px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: var(--police-corps);
  font-size: 0.95rem;
}

/* ==================================================================
   12. LA VISEE

   Le premier jet declenchait la photo au clic : on obtenait ce que la
   camera regardait a cet instant — le code-barres qu'on venait de
   scanner, ou le comptoir. Impossible de viser.

   Le bouton OUVRE maintenant la visee : la vue camera passe en grand,
   le cadre de scan s'efface, et deux boutons apparaissent. On cadre,
   on declenche, on voit l'image.
   ================================================================== */

.tunnel-visee-barre {
  position: sticky;
  bottom: 0;
  z-index: 25;
  padding: 12px 16px;
  border: 1px solid var(--accent);
  border-radius: var(--rayon);
  margin-bottom: 16px;
  background: var(--surface);
  box-shadow: var(--ombre-flottante);
}

.tunnel-visee-titre {
  margin-bottom: 10px;
  font-size: 0.95rem;
  text-align: center;
}

.tunnel-visee-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

/* Pendant la visee, la camera prend toute la place utile et le cadre
   du code-barres disparait : on ne cadre plus un code, on cadre un
   produit. */
.en-visee .tunnel-camera {
  aspect-ratio: 3 / 4;
  max-width: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-doux);
}

.en-visee .tunnel-viseur { display: none; }

/* Le reste de la fiche s'efface : pendant qu'on cadre, un formulaire
   de quantite ne sert a rien et pousse la camera hors de l'ecran. */
.en-visee .tunnel-fiche-tete,
.en-visee .tunnel-stock,
.en-visee .tunnel-rappel,
.en-visee .tunnel-photos,
.en-visee .tunnel-mention,
.en-visee .tunnel-compte,
.en-visee .tunnel-actions,
.en-visee .tunnel-magasin,
.en-visee .tunnel-saisie { display: none; }

@media (width >= 720px) {
  .en-visee .tunnel-camera { aspect-ratio: 4 / 3; max-width: 720px; margin-inline: auto; }
}

.tunnel-reprise { margin-top: 8px; }

/* --- Le repli « je n'ai pas de mot de passe » ---------------------
   Un <details> natif : il s'ouvre au clic et a la barre d'espace, sans
   une ligne de script. Visible, mais sans encombrer le geste courant. */
.repli-connexion {
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid var(--bordure);
}

.repli-connexion summary {
  cursor: pointer;
  color: var(--accent-texte);
  font-size: 0.95rem;
}

.repli-connexion summary:hover { color: var(--accent-fonce); }

.repli-connexion > *:not(summary) { margin-top: 16px; }

/* --- Le champ qui vient d'etre rempli tout seul -------------------
   Le prix lu sur l'etiquette apparait dans un champ que l'on ne
   regardait pas : sans ce signal d'une seconde, on croit que rien ne
   s'est passe et on le saisit a la main par-dessus.

   La couleur n'est pas seule a porter l'information (regle 10e) : le
   message au-dessus annonce « Prix lu sur l'etiquette : 2,45 € ». */
.vient-d-etre-rempli {
  border-color: var(--accent) !important;
  background: var(--accent-doux) !important;
  transition: background 400ms ease, border-color 400ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .vient-d-etre-rempli { transition: none; }
}

/* ==================================================================
   13. LES CHAMPS DU TUNNEL

   Ils ne peuvent pas reprendre le style « fiche » de la charte, ou le
   libelle occupe une pastille grise de 13 rem a gauche du champ. Ce
   style est juste pour un formulaire qu'on remplit assis, avec vingt
   libelles alignes sur la meme colonne. Il ne l'est pas du tout pour
   un compteur qu'on manipule au pouce, debout : la pastille mangeait
   la place et le champ de quantite se retrouvait ecrase a vingt
   pixels, illisible.

   Ici, le libelle passe AU-DESSUS et le controle prend toute la
   largeur.
   ================================================================== */

.tunnel-champ {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}

.tunnel-champ > label {
  color: var(--texte-doux);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.tunnel-champ > input,
.tunnel-champ > select {
  width: 100%;
  padding: 12px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: var(--police-corps);
  font-size: 1.05rem;
}

.tunnel-champ .aide {
  margin: 0;
  color: var(--texte-doux);
  font-size: 0.8rem;
}

/* --- Le compteur --------------------------------------------------
   Le champ garde une largeur MINIMALE : dans une grille a trois
   colonnes, « flex: 1 » le laissait se reduire jusqu'a disparaitre,
   et l'on voyait deux boutons encadrant un trait blanc. */
.tunnel-champ-quantite .compteur {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.tunnel-champ-quantite input {
  flex: 1;
  min-width: 4.5rem;
  padding: 12px 8px;
  border: 1px solid var(--bordure-forte);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  color: var(--texte);
  font-family: var(--police-corps);
  font-size: 1.35rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* --- LE LOGO PORTE LA COULEUR DE L'APPLICATION --------------------
   Il est trace en « currentColor » : sans cette regle il prendrait la
   couleur du texte de la marque, donc du noir. On lui donne l'accent,
   et il suit la couleur choisie dans la page Configuration — comme
   l'icone de l'onglet et celle de l'ecran d'accueil, dessinees a
   partir du meme trace. */
.marque .logo {
  flex: 0 0 auto;
  color: var(--accent);
}

/* ==================================================================
   14. LA LISTE PAR RAYON, DANS LE TUNNEL

   Un tableau par rayon, avec son titre. Dans une seule longue liste,
   on ne voit pas ou un rayon finit et ou le suivant commence — et
   c'est pourtant la seule chose qui compte quand on traverse le
   magasin.
   ================================================================== */

.tunnel-rayon { margin-bottom: 24px; }

.tunnel-rayon-titre {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: 8px;
  font-size: 1.15rem;
}

/* Le compte de ce qui reste dans ce rayon. Il descend a mesure qu'on
   coche, et tombe a zero quand le rayon est fait. */
.tunnel-rayon-compte {
  padding: 2px 10px;
  border-radius: var(--rayon-pilule);
  background: var(--accent-doux);
  color: var(--accent-texte);
  font-family: var(--police-corps);
  font-size: 0.8rem;
  font-weight: 600;
}

/* Un rayon entierement fait s'estompe : on sait d'un coup d'oeil ou
   l'on en est. Il ne disparait pas — il faut pouvoir y revenir. */
.tunnel-rayon.est-fini { opacity: 0.55; }

.tunnel-rayon.est-fini .tunnel-rayon-compte {
  background: var(--surface-2);
  color: var(--texte-doux);
}

/* Une ligne prise reste en place, barree. « Annuler » remplace « Pris »
   et « Pas trouve » : se tromper en rayon arrive, et une ligne disparue
   ne se corrige plus. */
table.donnees tr.est-prise td,
table.donnees tr.est-laissee td {
  opacity: 0.6;
}

table.donnees tr.est-prise td:first-child {
  text-decoration: line-through;
}

/* Les actions, elles, restent parfaitement lisibles : c'est par elles
   qu'on revient en arriere. */
table.donnees tr.est-prise td.col-actions,
table.donnees tr.est-laissee td.col-actions {
  opacity: 1;
}

/* --- LE CADDIE : ce qu'on y a mis, et de quoi l'en sortir ---------
   Un <details> replie : ce n'est pas ce qu'on regarde en faisant ses
   courses, c'est ce qu'on ouvre quand on s'est trompe. Le total, lui,
   reste en permanence dans le bandeau. */
.tunnel-caddie {
  margin-bottom: 16px;
  padding: 10px 14px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
  background: var(--surface);
}

.tunnel-caddie summary {
  display: flex;
  gap: 10px;
  align-items: center;
  cursor: pointer;
  color: var(--accent-texte);
  font-size: 0.95rem;
  font-weight: 600;
}

.tunnel-caddie-compte {
  padding: 2px 10px;
  border-radius: var(--rayon-pilule);
  background: var(--accent-doux);
  font-size: 0.8rem;
}

/* Le tableau du caddie defile dans son propre conteneur, comme tous
   les autres (regle 11f) : sans cela, les boutons « Retirer » le
   poussaient plus large que l'ecran et c'est la PAGE qui se mettait a
   defiler de travers. */
.tunnel-caddie-defilement {
  overflow-x: auto;
  margin-top: 12px;
}

/* Et en largeur AUTOMATIQUE, contrairement aux listes : quatre
   colonnes courtes n'ont pas besoin d'une grille fixe, et la grille
   fixe est justement ce qui ecrasait les libelles. */
.tunnel-caddie-table {
  width: 100%;
  min-width: 320px;
  table-layout: auto;
}

.tunnel-caddie-table td,
.tunnel-caddie-table th { white-space: nowrap; }

.tunnel-caddie-table td:first-child {
  overflow: hidden;
  max-width: 14rem;
  text-overflow: ellipsis;
}

/* ==================================================================
   15. LE TUNNEL SUR TÉLÉPHONE : LA LIGNE S'EMPILE

   Les pages-liste d'administration défilent horizontalement sous
   900 px (section 10) : on y consulte, et faire glisser un tableau
   pour lire une colonne de plus est acceptable.

   DANS LE TUNNEL, NON. « Pas trouvé » et « Pris » sont les deux
   gestes de l'écran ; les pousser hors du cadre, c'est obliger à
   faire glisser chaque ligne avant de pouvoir la cocher, debout, une
   main prise. C'est exactement ce qui se passait : le bouton « Pas
   trouvé » était coupé au bord droit de tous les rayons.

   Sous 700 px, le tableau cesse donc d'être un tableau : chaque
   produit devient un bloc de deux lignes — son nom et sa quantité
   au-dessus, ses boutons dessous, sur toute la largeur.
   ================================================================== */

@media (width < 700px) {

  /* On annule le défilement forcé des pages-liste : ici, rien ne doit
     sortir du cadre. */
  .tunnel-rayon .table-enveloppe-liste table.donnees,
  .tunnel-caddie-table {
    min-width: 0;
    table-layout: auto;
  }

  .tunnel-rayon .table-enveloppe-liste { overflow-x: visible; }

  /* Les en-têtes de colonnes n'ont plus de sens une fois la ligne
     empilée : le nom et le prix se lisent seuls. */
  .tunnel-rayon table.donnees thead,
  .tunnel-caddie-table thead { display: none; }

  .tunnel-rayon table.donnees,
  .tunnel-rayon table.donnees tbody,
  .tunnel-caddie-table,
  .tunnel-caddie-table tbody { display: block; width: 100%; }

  /* Chaque produit devient une carte : nom et quantité sur la première
     ligne, boutons sur la seconde. */
  .tunnel-rayon table.donnees tr,
  .tunnel-caddie-table tr {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 10px;
    align-items: center;
    padding: 12px 14px;
    border-bottom: 1px solid var(--bordure);
  }

  .tunnel-rayon table.donnees tr:last-child,
  .tunnel-caddie-table tr:last-child { border-bottom: 0; }

  .tunnel-rayon table.donnees td,
  .tunnel-caddie-table td {
    max-width: none;
    padding: 0;
    border: 0;
    white-space: normal;
  }

  /* Le nom prend la place qui reste, la quantité se colle à droite. */
  .tunnel-rayon table.donnees td:first-child,
  .tunnel-caddie-table td:first-child {
    overflow: visible;
    flex: 1 1 60%;
    font-weight: 500;
    text-overflow: clip;
  }

  .tunnel-rayon table.donnees td.cellule-nombre,
  .tunnel-caddie-table td.cellule-nombre {
    flex: 0 0 auto;
    color: var(--texte-doux);
    text-align: right;
  }

  /* Les actions passent à la ligne, sur toute la largeur : c'est là
     qu'on appuie, elles ne doivent jamais être à moitié coupées. */
  .tunnel-rayon table.donnees td.col-actions,
  .tunnel-caddie-table td.col-actions {
    flex: 1 1 100%;
    text-align: left;
  }

  .tunnel-rayon .actions-ligne,
  .tunnel-caddie-table .actions-ligne {
    flex-wrap: wrap;
    gap: 6px;
    justify-content: flex-start;
  }

  .tunnel-rayon .ligne-forme { flex-wrap: wrap; gap: 6px; }

  /* Le champ de prix garde une largeur utilisable : « 12,45 » doit
     tenir sans que le champ mange la ligne. */
  .tunnel-rayon .ligne-forme input[type="text"] { width: 5.5rem; }

  /* Des boutons qu'on touche du pouce sans viser. */
  .tunnel-rayon .bouton-petit,
  .tunnel-caddie-table .bouton-petit {
    min-height: 40px;
    padding-inline: 14px;
  }
}

/* ==================================================================
   16. KOMPTA — ce que le gabarit d'origine n'avait pas
   ==================================================================
   Quatre composants propres à un outil de facturation multi-entreprises.
   Rien ici n'écrit de couleur : tout passe par les jetons de
   charte-tokens.css, que _css/theme.php surcharge (règles 8 et 11b).
   ================================================================== */

/* --- L'encadré explicatif d'un régime -----------------------------
   Il n'est pas décoratif : il rappelle à quelles règles fiscales on est
   soumis pendant qu'on modifie le réglage qui les change. Le liseré
   d'accent le détache du formulaire sans en faire une alerte. */
.encadre {
  margin: 20px 0 0;
  padding: 20px;
  border-left: 3px solid var(--accent);
  border-radius: var(--rayon-petit);
  background: var(--surface-2);
}

.encadre h3 {
  margin: 20px 0 8px;
  font-size: 1rem;
}

.encadre > p:first-child { margin-bottom: 16px; }

/* --- Les paires libellé / valeur ----------------------------------
   Une <dl> mise en grille : le libellé à gauche, la valeur à droite,
   et l'ensemble s'empile sur téléphone plutôt que de comprimer les
   deux colonnes jusqu'à l'illisible. */
.paires { margin: 0; }

.paires > div {
  display: grid;
  gap: 4px 16px;
  padding: 8px 0;
  border-top: 1px solid var(--bordure);
}

.paires > div:first-child { border-top: 0; }

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

.paires dd { margin: 0; }

/* --- Listes de notes et de mentions -------------------------------
   Les mentions légales d'un document se lisent une par une : on les
   sépare d'un filet plutôt que d'une puce, pour qu'on les compte du
   regard comme elles apparaîtront en pied de facture. */
.notes,
.mentions-apercu {
  margin: 0 0 1em;
  padding: 0;
  list-style: none;
}

.notes > li,
.mentions-apercu > li {
  padding: 8px 0 8px 16px;
  border-top: 1px solid var(--bordure);
  border-left: 2px solid var(--bordure-forte);
  margin-bottom: 0;
  color: var(--texte-doux);
  font-size: 0.92rem;
}

.notes > li:first-child,
.mentions-apercu > li:first-child { border-top: 0; }

.mentions-apercu > li {
  border-left-color: var(--accent);
  color: var(--texte);
  font-size: 0.875rem;
}

/* --- Le nom de l'entreprise dans la barre du haut -----------------
   PROPRE AU MULTI-ENTREPRISES : quelqu'un peut avoir deux onglets
   ouverts sur deux organisations, et émettre une facture depuis la
   mauvaise. Le nom est donc affiché en permanence, pas rangé dans un
   menu qu'il faut ouvrir. */
.appli-entete-org {
  color: var(--texte);
  font-weight: 600;
}

.appli-entete-sep { color: var(--texte-tres-doux); }

/* Le rôle, en toutes lettres dans le menu de compte : un lecteur doit
   savoir qu'il est en lecture seule AVANT de chercher un bouton qui
   n'existe pas pour lui (règle 10e). */
.menu-compte-role {
  display: block;
  margin-top: 4px;
  color: var(--texte-tres-doux);
  font-size: 0.8rem;
}

@media (width >= 640px) {
  .paires > div { grid-template-columns: 220px 1fr; align-items: baseline; }
}

/* --- La ligne de document en cours d'édition ----------------------
   Chaque ligne d'un devis ou d'une facture est son propre formulaire
   (voir admin/document-modifier.php). Les champs se posent en grille
   souple : sur un grand écran la ligne se lit d'un trait, sur un
   téléphone elle s'empile, et dans les deux cas le total reste visible
   pendant qu'on saisit — c'est précisément ce qu'on vérifie en
   établissant une facture. */
.ligne-document {
  display: grid;
  gap: 0 16px;
  padding: 16px 0 8px;
  grid-template-columns: 1fr;
}

.ligne-document .barre-actions {
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
}

/* La ligne d'édition et son bouton de suppression sont deux formulaires
   distincts — un formulaire ne s'imbrique pas dans un autre — mais ils
   se lisent comme un seul bloc, d'où le filet qui les réunit. */
.ligne-document + .ligne-forme {
  padding-bottom: 20px;
  border-bottom: 1px solid var(--bordure);
}

@media (width >= 900px) {
  .ligne-document { grid-template-columns: repeat(4, 1fr); }
  .ligne-document .champ-large,
  .ligne-document .champ-zone,
  .ligne-document .barre-actions { grid-column: 1 / -1; }
}

/* --- La ligne d'assiette d'une déclaration ------------------------
   La conclusion du calcul : le chiffre qu'on recopiera sur le portail.
   Elle mérite d'être vue, pas d'être décorée — un fond d'accent très
   pâle et une graisse, rien de plus.

   Elle portait « est-prise », qui signifie « déjà pris » dans le
   squelette d'origine : grisée et barrée. Le seul chiffre qui compte
   s'affichait comme s'il ne comptait plus. */
table.donnees tr.ligne-assiette td {
  background: var(--accent-doux);
  font-weight: 600;
  color: var(--texte);
}

/* ==================================================================
   LES CASES A COCHER EXPLIQUEES

   Une case dont le libelle tient sur une ligne se pose n'importe ou.
   Celles-ci portent une explication en dessous — « ne cochez pas sur un
   ordinateur partage » — et cette explication doit se lire AVANT qu'on
   coche, pas apres.

   LA ZONE CLIQUABLE COUVRE TOUT LE BLOC, titre et explication comprises :
   viser une case de 16px au doigt, sur telephone, est une epreuve.
   ================================================================== */

.case {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 16px;
  margin: 0 0 20px;
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-petit);
  background: var(--surface);
  cursor: pointer;
  transition: var(--transition);
}

.case:hover {
  border-color: var(--accent);
}

/* Le focus se voit — jamais d'outline retire sans remplacement
   (regle 10e). Il porte sur la case, mais c'est le bloc entier qui
   s'entoure : autrement le liseré se perd dans un coin. */
.case:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-doux);
}

.case input[type="checkbox"] {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.case span {
  flex: 1 1 auto;
  line-height: 1.5;
}

.case small {
  display: block;
  margin-top: 4px;
  color: var(--texte-doux);
  font-size: 0.875rem;
  line-height: 1.45;
}

/* ==================================================================
   DEUX CHAMPS COTE A COTE

   Prenom/Nom, mot de passe/confirmation : des paires qui se lisent
   ensemble et qu'on separe sur deux lignes pour rien.

   MOBILE-FIRST : une seule colonne par defaut, deux au-dessus de 560px.
   L'inverse — deux colonnes qu'on effondre — laisse toujours un cas ou
   la media query ne s'applique pas et ou deux champs de 200px se
   marchent dessus.
   ================================================================== */

.champs-deux {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 16px;
}

@media (min-width: 560px) {
  .champs-deux { grid-template-columns: 1fr 1fr; }
}

/* Un formulaire qui ne porte qu'un bouton — « recommencer », « annuler ».
   Sans cela, il herite des marges de formulaire et ouvre un trou. */
.formulaire-en-ligne {
  display: inline;
  margin: 0;
}
