/*
 * Palette et constantes visuelles, centralisées en variables CSS pour
 * pouvoir ajuster tout le theme d'un seul endroit (ex. un futur mode
 * sombre n'aurait qu'a redefinir ce bloc dans un @media
 * (prefers-color-scheme: dark) { :root { ... } }).
 */
:root {
  /* Multiplicateur de la taille du texte, réglable par utilisateur dans
     les Préférences (séparément pour le tableau et l'arbre, et pour les
     grands et petits écrans). Surchargé par un <style> émis en tête de
     page ; 1 = taille de référence, donc aucun changement par défaut. */
  --echelle-texte: 1;

  --police: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --couleur-fond: #f4f6f8;
  --couleur-texte: #2b2f36;
  --couleur-bordure: #d7dde3;

  --couleur-accent: #3d7a8c;       /* bleu-vert discret : liens, boutons, contexte actif */
  --couleur-accent-clair: #c6e9f3;

  --couleur-priorite0: #eef1f4;    /* pas de priorite */
  --couleur-priorite1: #fde68a;    /* ! */
  --couleur-priorite2: #fb923c;    /* !! */
  --couleur-priorite3: #ef4444;    /* !!! */

  --rayon: 8px;
  --ombre-legere: 0 1px 2px rgba(20, 20, 30, 0.08), 0 1px 1px rgba(20, 20, 30, 0.06);
  --ombre-moyenne: 0 2px 6px rgba(20, 20, 30, 0.12);
  --transition-rapide: 120ms ease;
  --default-bg: rgb(203, 191, 231);
}

body {
  font-family: var(--police);
  color: var(--couleur-texte);
  background-color: var(--couleur-fond);
}

h1 {
  display: inline;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.hover:hover {
  background-color: var(--couleur-priorite3);
}

.bctx {
  width: 100px;
  margin: 2px 0;
  background-color: #fff;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  padding: 4px 6px;
  transition: border-color var(--transition-rapide), box-shadow var(--transition-rapide);
}
.bctx:hover, .bctx:focus {
  border-color: var(--couleur-accent);
  outline: none;
}

.logo-titre{
  vertical-align:-8%;
  margin-left:8px;
}

.default_bg{
  background-color:var(--default-bg); 
}

.form-admin{
  width:200px;
  margin-left:100px;
}

.admin {
border:1px solid black;
}

.admin td{
  border:1px solid black;
  padding:4px;
}
/* utilsé par agenda et résultat de recherche */

.resultat-colonnes { columns: 4; column-gap: 12px; }
.resultat-colonnes .resultat-recherche { display: block; break-inside: avoid; margin-bottom: 10px; }


/* ==========
================================================================
   BOUTONS — règle unique, qu'il s'agisse d'un <button> ou d'un <a
   class="bouton"> (les deux sont utilisés dans la barre d'outils selon que
   l'action déclenche du JS ou navigue vers une autre page). Les deux
   éléments ont des styles par défaut différents selon les navigateurs
   (bordure "enfoncée" native sur <button>, aucune bordure sur <a>) :
   `all: unset` les efface d'abord tous les deux, PUIS les propriétés
   suivantes (dans cette même règle, donc sans risque de conflit de
   priorité CSS) redéfinissent l'apparence, identique pour les deux.
   ========================================================================== */
.bouton {
  all: unset;
  box-sizing: border-box;
  font-family: var(--police);
  vertical-align: middle;
  text-decoration: none;
  display: inline-block;
  /*background-color: #fff;*/
  color: var(--couleur-texte, #222);
  /*border: 1px solid var(--couleur-bordure);*/
  border-radius: var(--rayon);
  /*padding: 2px 2px;*/
  cursor: pointer;
  text-align: center;
  transition: background-color var(--transition-rapide), box-shadow var(--transition-rapide), transform var(--transition-rapide);
}
/* Fond blanc par défaut : sans lui, les boutons se fondaient dans le fond
   de la page et seul le filet les délimitait. Le blanc les détache
   nettement, et laisse la couleur au contenu — priorités, contextes. */
.bouton {
  background-color: #fff;
}
.bouton:hover {
  background-color: var(--couleur-accent-clair);
  box-shadow: var(--ombre-legere);
}
/* Plus d'agrandissement au survol ni au clic.
   Sur écran tactile il n'y a pas de survol : le navigateur applique :hover
   APRÈS la touche et le garde jusqu'au geste suivant, si bien qu'un bouton
   restait grossi de 20 % et débordait sur ses voisins. Le retour visuel
   passe désormais par le fond et l'ombre seuls, qui ne déplacent rien. */
.bouton:active {
  background-color: var(--couleur-accent);
}
.bouton:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.bouton:disabled:hover {
  background-color: #fff;
  box-shadow: none;
}

/* « form { font-size: 11px } » a été retiré d'ici. C'était une règle GLOBALE,
   en pixels ABSOLUS, qui s'appliquait aux formulaires de neuf pages :
   préférences, amis, outils, accueil, première connexion, mes accès... Tout
   texte s'y trouvant était réduit à 11 px, quelle que soit l'échelle de texte
   choisie par l'utilisateur — l'un des réglages d'accessibilité de Toddo
   était donc sans effet sur une bonne partie de l'application.
   C'était aussi la vraie cause du « texte trop petit » signalé sur la page
   de première connexion et sur les deux premiers pavés de « Mes accès » :
   ceux-là sont dans un <form>, le troisième non — d'où la différence.
   Les rares endroits qui veulent un texte compact le demandent désormais
   explicitement, et en unités relatives. */
.chat-formulaire { font-size: calc(0.95rem * var(--echelle-texte)); }
.contexte-actuel-affiche {
  align-self: stretch; /* le fond occupe toute la largeur disponible, plutôt que de se resserrer sur le texte */
  text-align: center;
  background-color: lightgreen; /* même couleur que la pastille active dans la liste de contextes */
  border-radius: var(--rayon);
  padding: 4px 12px;
  font-weight: 600;
  margin-bottom: 2px;
  font-size:120%;
  box-sizing: border-box;
}
.mode-sombre .contexte-actuel-affiche {
  background-color: #29433a !important; /* même équivalent sombre que les pastilles actives */
  color: var(--couleur-texte);
}

/* Barre d'outils : une GRILLE de cases identiques, sur deux lignes.
   La version précédente était un flex sans gap, où chaque bouton prenait la
   largeur de son emoji : les icônes se touchaient, de largeurs inégales, et
   viser au doigt relevait de la chance. Une grille à colonnes de largeur
   fixe (auto-fill) donne à tous la même surface, aligne les deux lignes, et
   s'adapte seule à la largeur disponible — deux lignes sur une colonne
   étroite, une seule si la place le permet. */
.barre-outils {
  /* FLEX sur une seule ligne, et non une grille.
     La grille répartissait les boutons en colonnes d'au moins 40 px : dès
     qu'ils étaient plus nombreux que la largeur ne le permettait, les
     derniers — la corbeille en tête — passaient à la ligne suivante.
     En flex avec « flex-wrap: nowrap », ils se PARTAGENT la largeur
     disponible et rétrécissent ensemble : ils restent sur une ligne et
     gardent tous la même taille, quel que soit leur nombre. */
  display: flex;
  flex-wrap: nowrap;
  /* Écart resserré (4px auparavant) : depuis que chaque bouton porte son
     propre filet, c'est le trait qui dit où il finit — l'espace n'a plus
     à s'en charger, comme pour les pastilles de contexte. */
  gap: 2px;
  align-items: center;
  padding-right: 5px;
  margin-bottom: 4px;
}
/* Tous les boutons à la même taille, quel que soit le glyphe. aspect-ratio
   plutôt qu'une hauteur fixe : les cases restent carrées même quand la
   grille les étire un peu pour remplir la ligne. */
.barre-outils .bouton {
  padding: 0;
  /* Même filet arrondi que les pastilles de contexte, et pour la même
     raison : il délimite la cible cliquable, ce qu'un simple écart faisait
     mal — surtout au doigt, où l'on ne voit pas où finit un bouton.
     rgba plutôt que --couleur-bordure : ce gris très pâle disparaît sur
     les fonds clairs de l'application. */
  border: 1px solid rgba(0, 0, 0, 0.28);
  font-size: 1.5em;
  padding:4px;
  white-space: nowrap;
  /* Tous de la même taille et tous sur la même ligne :
     - flex: 1 1 0 leur donne à chacun la MÊME part de la largeur, quelle
       que soit la largeur de leur glyphe (un « ? » et un 🗓️ n'ont pas la
       même chasse) ;
     - min-width: 0 est indispensable, sans quoi la largeur minimale d'un
       élément flex est celle de son contenu : les boutons refuseraient de
       rétrécir et déborderaient au lieu de se partager la place ;
     - aspect-ratio les garde carrés. */
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}
/* TAILLE UNIQUE pour tous les éléments cliquables de la barre.
   Trois réglages s'y disputaient jusqu'ici : « width: 10% » sur .bouton,
   « width/height: 36px » sur les boutons géants, et la taille propre de
   l'enveloppe du menu « ⋯ ». D'où trois hauteurs différentes (46, 38 et
   22 px) sur une même ligne.
   Une seule déclaration décide désormais, et elle vise l'enveloppe du menu
   au même titre que les boutons : chacun reçoit la même part de largeur
   (flex: 1 1 0), la même hauteur, et refuse de déborder (min-width: 0).
   Le sélecteur « > » limite la règle aux enfants DIRECTS : les boutons du
   panneau déroulant, qui sont des entrées de menu à libellé, gardent leur
   forme rectangulaire. */
/* Le sélecteur vise TOUS les enfants de la barre plutôt qu'une liste de
   classes : le bouton de déconnexion vient du système d'authentification
   externe, on ne maîtrise ni son identifiant ni ses classes. Seul
   l'indicateur d'enregistrement est exclu — c'est une pastille flottante,
   pas un bouton. */
.barre-outils > *:not(#etat-sauvegarde):not(.barre-outils-plus-panneau),
.barre-outils > .bouton,
.barre-outils > .barre-outils-plus,
.barre-outils > .bouton.bouton-geant {
/* Taille FIXE par défaut : sur un grand écran, « flex: 1 1 0 » étirait
     chaque bouton pour remplir la barre — 123 px de large pour une icône,
     mesuré sur 1400 px. Les boutons gardent donc leur taille naturelle, et
     la place en trop reste vide.
     C'est en portrait, où la barre est trop étroite pour onze boutons,
     qu'ils se partagent la largeur (cf. le bloc portrait). */
  flex: 0 0 auto;
  min-width: 0;
  width: 40px;
  height: 38px;
  aspect-ratio: auto;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* La corbeille reste à l'extrémité DROITE : la marge automatique absorbe
   toute la place disponible avant elle. C'est le seul bouton destructeur,
   l'éloigner réduit le risque de le toucher par mégarde — et sur grand
   écran il y a justement de la place pour le faire. */

/* (la règle grid-column ci-dessous n'a plus d'effet depuis le passage en
   flex ; l'écart et le trait de séparation, eux, s'appliquent toujours) */
/* La corbeille est repoussée à l'extrémité DROITE de la barre.
   « -2 / -1 » désigne la dernière colonne, quel que soit le nombre de
   colonnes que auto-fill aura calculé — on ne peut donc pas l'écrire en
   dur. L'espace éventuellement laissé avant elle est voulu : la corbeille
   est destructrice, l'éloigner des boutons de navigation réduit le risque
   de la toucher par mégarde, au doigt en particulier. */
/* La corbeille reste dans le flux — « grid-column: -2 / -1 » la forçait
   dans la dernière colonne de la grille et la rejetait hors de la barre
   dès que celle-ci était pleine — mais elle s'en DÉTACHE visiblement :
   c'est le seul bouton destructeur, et le toucher par mégarde coûte cher.
   Un écart et un trait de séparation, plutôt qu'un éloignement en bout de
   ligne qui la faisait disparaître. */
/* La corbeille : même largeur que les autres, l'écart de séparation étant
   porté par une MARGE et non par un rembourrage. Le padding-left de 14 px
   s'ajoutait à sa largeur (43 px contre 32) puisqu'il est intérieur ; la
   marge, elle, reste extérieure et ne la déforme pas.
   Le trait de séparation se pose sur la marge, via un pseudo-élément, pour
   la même raison. */
/* margin-left: auto — la marge automatique absorbe toute la place libre et
   pousse la corbeille à l'extrémité DROITE. C'est le seul bouton
   destructeur : l'éloigner réduit le risque de le toucher par mégarde, et
   sur grand écran la place ne manque pas.
   Une valeur fixe (24 px) ne créait qu'un écart de cette largeur, laissant
   la corbeille collée au groupe au milieu de la barre. */
.barre-outils #btn-corbeille {
  margin-left: auto;
  position: relative;
}
/* Plus de trait de séparation avant la corbeille : il datait de l'époque où
   elle était collée aux autres boutons. Depuis qu'une marge automatique la
   repousse à l'extrémité droite, l'écart parle de lui-même — et le trait
   flottait au milieu du vide. */
/* L'enveloppe du menu « ⋯ » reçoit le même rembourrage et la même bordure
   que les boutons — même transparents. Avec « flex-basis: 0 » et
   « box-sizing: border-box », la base d'un élément flexible ne peut pas
   descendre sous son rembourrage plus sa bordure : les boutons partaient
   donc de 10 px (4+4+1+1) et l'enveloppe de 0, et l'écart de 8 px se
   retrouvait tel quel après répartition de l'espace libre. Mesuré : 32 px
   contre 24. */
.barre-outils > .barre-outils-plus {
  border: 1px solid transparent;
  padding: 4px;
}

/* Le bouton de déconnexion, fourni par le système d'authentification
   externe, n'a pas la classe .bouton : il échappait donc au dimensionnement
   commun et restait plus petit que ses voisins. On le vise par son
   identifiant, et par la classe qu'il porte le cas échéant. */
.barre-outils > #btn-logout,
.barre-outils > #btn-deconnexion,
.barre-outils > .bouton-logout,
.barre-outils > a[href*="logout"] {
  flex: 0 0 auto;
  width: 40px;
  height: 38px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border: 1px solid rgba(0, 0, 0, 0.28);
  border-radius: var(--rayon);
  background-color: #fff;
  text-decoration: none;
}

/* Le panneau « ⋯ » contient des boutons à libellé, qui eux doivent rester
   larges et rectangulaires : la règle ci-dessus ne les concerne pas. */
.barre-outils .barre-outils-plus-panneau .bouton {
  width: auto;
  aspect-ratio: auto;
  display: block;
  font-size: 1em;
  padding: 6px 10px;
  /* Pas de filet ici : dans un menu déroulant, les entrées sont déjà
     séparées par leur survol et le cadre du panneau. Les encadrer une à
     une donnerait une grille de boutons là où l'on attend une liste. */
  border: none;
}
/* Indicateur d'enregistrement de la vue arbre : une pastille FLOTTANTE,
   hors du flux.
   Il vivait auparavant comme cellule de la grille de la barre d'outils.
   Quel que soit le réglage, cela posait un problème : cellule normale, il
   rejetait la corbeille à la ligne ; cellule pleine largeur masquée quand
   vide, il faisait apparaître puis disparaître une ligne entière à chaque
   enregistrement — la barre d'outils grandissait, toute la page se
   décalait, puis revenait deux secondes plus tard. Cocher une case
   provoquait donc un sursaut de l'interface entière.
   En position fixed, il n'occupe plus aucune place : rien ne bouge. Il est
   posé en bas à droite, loin des zones de dépôt, pour ne pas gêner un
   glisser-déposer en cours. */
#etat-sauvegarde {
  position: fixed;
  bottom: 12px;
  right: 12px;
  z-index: 60;
  max-width: 60vw;
  padding: 6px 12px;
  border-radius: var(--rayon);
  background-color: var(--couleur-accent-clair);
  color: var(--couleur-texte);
  border: 1px solid var(--couleur-bordure);
  box-shadow: var(--ombre-moyenne);
  font-size: 0.85em;
  font-weight: 600;
  /* pointer-events:none — la pastille ne doit jamais intercepter un clic
     ni un relâchement de glisser-déposer qui passerait au-dessus d'elle. */
  pointer-events: none;
}
#etat-sauvegarde:empty { display: none; }
#btn-ajouter-tache.bouton-geant,
#btn-corbeille.bouton-geant {
  /* Aucune dimension propre : c'est la règle « .barre-outils > .bouton »
     qui décide, pour tous les boutons ensemble. Le 2em et les 36 px carrés
     d'origine les faisaient dépasser et poussaient leurs voisins ; leur
     importance se joue sur leur POSITION — le « + » en tête, la corbeille
     détachée en fin — pas sur leur encombrement. */
  font-weight: bold;
  line-height: 36px; /* centre verticalement le "+" (un <button> n'a pas de comportement d'alignement vertical natif pour du texte seul) */
  text-align: center;
}
.barre-outils-espace {
  /* Supprimé : cet espaceur servait, en flex, à repousser la corbeille à
     l'extrémité. Dans une grille de cases identiques il n'a plus d'objet —
     la corbeille occupe simplement la case suivante, ce qui est justement
     ce qu'on veut (tous les boutons de même taille, alignés). */
  display: none;
}
/* Enveloppe du bouton « ⋯ ». Ses dimensions viennent de la règle commune
   « .barre-outils > … » ; ici, seul l'ancrage du panneau déroulant. */
.barre-outils-plus {
  position: relative;
}
/* Le bouton à l'intérieur remplit son enveloppe : c'est elle qui porte la
   part de largeur, lui n'a qu'à l'occuper. */
.barre-outils .barre-outils-plus > .bouton {
  flex: 1 1 auto;
  width: 38px;
  /*height: 100%;*/
  aspect-ratio: auto;
  min-width: 0;
}

/* L'indicateur d'enregistrement ne doit pas prendre de part de largeur :
   il est en position fixe (pastille flottante) et n'a rien à faire dans
   le partage. */
.barre-outils > #etat-sauvegarde { flex: 0 0 0; }
/* ABSOLUTE et non RELATIVE : un élément en position relative reste dans le
   flux — il occupait donc sa place dans la barre, poussant le bouton « ⋯ »
   sur le côté à chaque ouverture, et se plaçait par rapport à un point de
   départ qui bougeait avec lui.
   En absolu il est retiré du flux et ancré sur .barre-outils-plus (qui est
   en position relative) : le bouton ne bouge plus, et le panneau s'ouvre
   juste en dessous, aligné à droite pour ne pas déborder de l'écran quand
   le bouton est près du bord. */
.barre-outils-plus-panneau {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  left: auto;
  background: #fff;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-moyenne);
  padding: 6px;
  flex-direction: column;
  gap: 4px;
  z-index: 10000;
  min-width: 160px;
}
.barre-outils-plus-panneau.ouvert {
  display: flex;
}
.barre-outils-plus-panneau .bouton {
  text-align: left;
  white-space: nowrap;
}
/* Sur écran étroit, le panneau était calé 180 px à gauche de son bouton et
   sortait de l'écran par la droite ou la gauche selon la place. On le
   centre dans la fenêtre : c'est la seule position qui tienne quelle que
   soit la largeur, et quel que soit l'endroit où se trouve le bouton. */
/* Le panneau suit le MÊME seuil que la mise en page portrait
   (max-aspect-ratio: 13/9), et non plus « max-width: 700px ».
   Les deux se contredisaient : sur un écran de 741 px de large en
   portrait, la disposition mobile s'appliquait — onglets, colonne
   ancrée — mais pas le positionnement du panneau, qui gardait celui du
   grand écran (« left: -180px », calé sur son bouton) et sortait donc de
   l'écran par la gauche.
   Un seul seuil pour un seul concept : soit on est en portrait, soit on
   ne l'est pas. La largeur est ajoutée en second critère pour couvrir un
   téléphone tenu à l'horizontale, étroit mais en « paysage ». */
@media screen and (max-aspect-ratio: 13/9), screen and (max-width: 700px) {
  /* Le panneau doit passer DEVANT la colonne des contextes.
     Son z-index (100000) ne suffisait pas : .bandeau-commun, son ancêtre,
     porte « position: sticky » ET un z-index, ce qui crée un CONTEXTE
     D'EMPILEMENT — les z-index des descendants n'y sont comparés qu'entre
     eux, et c'est le 40 du bandeau qui affronte le 50 de la colonne. Le
     panneau restait donc dessous, quelle que soit sa valeur.
     On sort le panneau de ce piège en le sortant du bandeau : « fixed »
     ne suffit pas (un ancêtre à z-index le contient quand même), il faut
     que le bandeau cesse de créer un contexte pendant l'ouverture — c'est
     ce que fait la règle .barre-outils-ouverte plus bas. */
  .barre-outils-plus-panneau {
    position: fixed;
    /* Centré horizontalement, juste sous les barres : c'est la seule
       position qui tienne quelle que soit la largeur de l'écran et quel
       que soit l'endroit où se trouve le bouton « ⋯ » — lequel se déplace
       selon le nombre de boutons et le repli de la barre d'outils. */
    top: calc(var(--hauteur-barres, 96px) + 8px);
    left: 50%;
    transform: translateX(-50%);
    width: min(88vw, 320px);
    max-height: 70vh;
    overflow-y: auto;
    z-index: 100000;
    box-shadow: var(--ombre-moyenne);
  }
}

/* Mode sombre : le panneau a un fond sombre, son texte doit suivre —
   il restait noir sur noir, donc illisible. */
.mode-sombre .barre-outils-plus-panneau,
.mode-sombre .barre-outils-plus-panneau .bouton,
.mode-sombre .menu-contexte,
.mode-sombre .menu-contexte button {
  color: var(--couleur-texte) !important;
}
.mode-sombre .menu-contexte {
  background-color: #262b30 !important;
  border-color: #3a3f44 !important;
}
.mode-sombre .menu-contexte button:hover {
  background-color: #31373d !important;
}

.mode-sombre .barre-outils-plus-panneau {
  background-color: #262b30 !important;
}

.cercle1, .cercle2, .cercle3 {
  display: inline-block;
  vertical-align: middle;
  margin-left: 4px;
  border-radius: 50%;
  width: 10px;
  height: 10px;
  z-index: 2000;
}
.cercle3 { background: var(--couleur-priorite3); }
.cercle2 { background: var(--couleur-priorite2); }
.cercle1 { background: var(--couleur-priorite1); }

.zone table td:first-child::after {
  content: "";
  display: inline-block;
  vertical-align: top;
  min-height: 60px;
}

.entete table, .entete tr, .entete td {
  padding: 0;
  border: none;
}

.arrondi, .arrondi2 {
  border-radius: var(--rayon);
}

.context {
  box-shadow: var(--ombre-moyenne);
}

#info {
  color: var(--couleur-priorite3);
  font-size: 0.85em;
  min-height: 0;
}
#info:empty { display: none; }

/* .item est la zone editable d'une tache : white-space:pre-wrap est ESSENTIEL
   pour que les espaces d'indentation tapes par l'utilisateur restent visibles
   et soient renvoyes tels quels par innerText au moment de la sauvegarde. */
.item {
  text-align: left;
  display: block;
  margin-left: 0px;
  margin-right:1px;
  /*white-space: pre-wrap;*/
  /* Interligne DÉGRESSIF : 1,5 est confortable à taille normale, mais un
     interligne proportionnel devient excessif quand l'utilisateur agrandit
     le texte — l'espace entre deux lignes grandit alors autant que les
     caractères, alors que l'œil n'en a pas besoin. On le resserre à mesure
     que l'échelle monte, sans jamais descendre sous 1,2 où les lignes
     commenceraient à se toucher.
     À 100 % : 1,35. À 135 % : 1,21. À 200 % : 1,15 (plancher). */
  line-height: max(1.15, calc(1.35 - (var(--echelle-texte) - 1) * 0.4));
  /* "anywhere" (et non break-word) : seul lui réduit AUSSI la largeur
     minimale de l'élément — indispensable dans une cellule de tableau,
     sinon un mot insécable (URL...) impose sa longueur à toute la colonne,
     qui s'élargit et passe sous l'ascenseur maison. */
  overflow-wrap: anywhere;
  text-overflow: hidden;
  overflow: hidden;
  max-width: 100%;
}
/* Les zones posent leurs tâches dans <table class="colonne"> : sans
   table-layout fixed, la largeur mini d'une cellule = son mot le plus
   long — même cause, même effet que ci-dessus. */
table.colonne { table-layout: fixed; width: 100%; }

.item2 {
  position: relative; /* conservé au cas où un futur élément aurait besoin d'un ancrage ; le trombone est maintenant dans le flux flex normal */
  margin: 4px;
  margin-right: 22px; /* laisse la place à l'ascenseur maison (18px) sans chevauchement, cf. .ascenseur-piste */
  border-radius: var(--rayon);
  box-shadow: var(--ombre-legere);
  transition: box-shadow var(--transition-rapide), transform var(--transition-rapide);
  /* essentiel sur tactile : sans ça, dragdroptouch.js (qui simule le
     glisser-déposer sur mobile) intercepte le geste de défilement vertical
     dès que le doigt part d'une tâche (donc quasiment tout l'écran) —
     touch-action:pan-y dit au navigateur de garder la main sur le
     défilement vertical natif, et de ne laisser le polyfill agir que pour
     un vrai geste de glissement. */
  touch-action: pan-y;
}
.item2:hover {
  box-shadow: var(--ombre-moyenne);
}
/* Idem pour les cartes : un changement d'échelle au toucher donne
   l'impression que la tâche bouge alors qu'on voulait seulement la lire. */
.item2[draggable="true"]:active {
  box-shadow: var(--ombre-moyenne);
}

/* carte de résultat cliquable (page de recherche, vue transversale des tags) :
   toute la carte navigue, pas juste un petit lien en dessous */
a.resultat-recherche {
  display: block;
  text-decoration: none;
  color: inherit;
  margin-bottom: 8px;
  margin-right: 19px;
}
a.resultat-recherche:hover .item2 {
  box-shadow: var(--ombre-moyenne);
  transform: translateY(-1px);
}

@keyframes pulsation-mise-en-evidence {
  0%, 100% { box-shadow: var(--ombre-legere); }
  50% { box-shadow: 0 0 0 4px var(--couleur-priorite3); }
}
.tache-mise-en-evidence {
  animation: pulsation-mise-en-evidence 0.6s ease-in-out 2;
}

/* ---------- mode sombre ---------- */
/* Une vraie palette plutôt qu'un simple filtre d'inversion vidéo : une
   inversion abîmerait les icônes SVG (elles redeviendraient illisibles ou
   changeraient de sens visuel) et rendrait les couleurs de priorité
   incohérentes (le rouge "urgent" pourrait devenir vert). Comme tout le
   CSS s'appuie déjà sur des variables, redéfinir juste ce bloc suffit à
   adapter toute l'application. */
.mode-sombre {
  --couleur-fond: #1b1f24;
  --couleur-texte: #e8eaed;
  --couleur-bordure: #3a3f44;
  --couleur-accent: #6fb3c7;
  --couleur-accent-clair: #24343a;
  --couleur-priorite0: #2a2e33;
  --couleur-priorite1: #6b5a1f;
  --couleur-priorite2: #7a441c;
  --couleur-priorite3: #7a2e2e;
}
.mode-sombre body { background-color: var(--couleur-fond); color: var(--couleur-texte); }
.mode-sombre .bouton,
.mode-sombre .bctx,
.mode-sombre .menu-contexte,
.mode-sombre .box {
  background-color: #262b30 !important;
  color: var(--couleur-texte);
}
.mode-sombre .contexte-pastille[style*="ivory"] { background-color: #262b30 !important; }
.mode-sombre .contexte-pastille[style*="lightgreen"] { background-color: #29433a !important; }

/* Le rond (copie de la tâche) : ancré dans le coin de SA PROPRE carte de
   tâche (.item2, en position:relative ci-dessus), plutôt que poussé vers le
   bord de la zone défilante par un float + marge négative comme avant —
   cette ancienne technique le faisait atterrir sous l'ascenseur de la zone,
   le rendant à moitié caché et difficile à cliquer en mode PC (où
   l'ascenseur réserve en permanence de la place), alors qu'en mode tactile
   l'ascenseur n'est qu'une fine surcouche qui laisse un peu de place. */
.trombone {
  position: relative; /* seul le badge (nombre) a besoin d'un positionnement, cf. .trombone-badge */
  font-size: 12px;
  cursor: pointer;
  line-height: 1;
  flex-shrink: 0; /* ne doit jamais être écrasé/caché par le texte de la tâche qui prend le plus de place */
  align-self: flex-start;
  padding: 2px;
}
.trombone-badge {
  position: absolute;
  top: -6px;
  right: -8px;
  background: var(--couleur-accent);
  color: white;
  border-radius: 999px;
  font-size: 0.7em;
  padding: 0 4px;
  font-weight: 700;
}

/* La case mère est SUPERPOSÉE au bloc de texte, pas placée à côté.
 *
 * En flex, elle occupait une colonne et poussait tout le texte vers la
 * droite — décalage qui s'ajoutait à CHAQUE ligne, y compris les
 * sous-lignes indentées. D'où l'écart mesuré : 46 px entre le titre et le
 * premier niveau, puis 21 px seulement entre les niveaux suivants. Les
 * quatre espaces par niveau étaient pourtant réguliers ; c'est la mise en
 * page qui ne l'était pas.
 *
 * En position absolue, elle ne prend plus de place dans le flux : toutes
 * les lignes partent du même bord, et l'indentation redevient l'unique
 * source de décalage. La première ligne réserve la largeur de la case par
 * un retrait qui ne vaut QUE pour elle (text-indent), ce qui laisse les
 * sous-lignes à leur juste place.
 */
.ligne-titre {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  position: relative;
}
.ligne-titre > .case-mere {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
}
.ligne-titre .item {
  flex: 1 1 auto;
  min-width: 0; /* essentiel pour qu'un enfant flex contenant du texte
                   pre-wrap se redimensionne correctement au lieu de
                   déborder de son conteneur */
}
/* Retrait de la PREMIÈRE ligne seulement, pour contourner la case mère
   désormais superposée. 1.6em ≈ sa largeur plus l'espace qui la suivait. */
.ligne-titre:has(> .case-mere) .item { text-indent: 1em; }
.case, .case-mere {
  cursor: pointer;
  transition: transform var(--transition-rapide);
  display: inline-block;
  user-select: none; /* évite de sélectionner le glyphe au double-clic */
  margin-left:-.5cm;
}
.case:hover, .case-mere:hover {
  transform: scale(1.15);
}
.case-mere {
  font-weight: bold;
  flex-shrink: 0; /* la case ne doit jamais se comprimer si le texte est long */
  margin-left:0;
}

.link {
  color: var(--couleur-accent);
}

.badge-echeance {
  font-size: 0.75em;
  padding: 1px 6px;
  border-radius: 999px;
  white-space: nowrap;
  /* Le badge vit DANS le span de texte (.item) et flotte à droite : la
     première ligne du texte s'écrit à sa gauche, les suivantes passent
     dessous sur toute la largeur — le texte n'est plus décalé d'un bloc.
     Un float ne fonctionne que dans le même flux que le texte, d'où le
     déplacement du badge à l'intérieur du span (render_task_block & co). */
  float: right;
  margin-left: 8px;
  margin-bottom: 2px;
}
/* Clearfix : si le texte est plus court que le badge (tâche d'un mot), le
   float ne doit pas déborder du span sur ce qui suit. */
.item::after {
  content: "";
  display: table;
  clear: both;
}
.echeance-retard   { background-color: var(--couleur-priorite3); color: white; font-weight: 600; }
.echeance-proche   { background-color: var(--couleur-priorite2); color: var(--couleur-texte); font-weight: 600; }
.echeance-normale  { background-color: var(--couleur-accent-clair); color: var(--couleur-accent); }

.badge-delegation {
  font-size: 0.75em;
  padding: 1px 6px;
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
  align-self: flex-start;
  background-color: var(--couleur-accent);
  color: white;
}

.tag {
  color: var(--couleur-accent);
  background-color: var(--couleur-accent-clair);
  border-radius: 4px;
  padding: 0 4px;
  cursor: pointer;
  text-decoration: none;
  font-size: 0.95em;
  transition: background-color var(--transition-rapide);
}
.tag:hover {
  background-color: var(--couleur-priorite1);
}

.menu-contexte {
  position: fixed;
  z-index: 3000;
  background: #fff;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-moyenne);
  display: flex;
  flex-direction: column;
  /*overflow: auto;*/
  min-width: 160px;
}
.menu-contexte button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  border: none;
  background: none;
  font-family: var(--police);
  font-size: 0.95em;
  cursor: pointer;
}
.menu-contexte button:hover {
  background-color: var(--couleur-accent-clair);
}

.boite-dialogue-fond {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 4000;
}
.boite-dialogue {
  background: #fff;
  border-radius: var(--rayon);
  box-shadow: var(--ombre-moyenne);
  padding: 20px;
  min-width: 260px;
  max-width: 90vw;
}
.mode-sombre .boite-dialogue {
  background-color: #262b30 !important;
  color: var(--couleur-texte);
}
.boite-dialogue p {
  margin: 0 0 10px;
}
.boite-dialogue-champ {
  width: 100%;
  box-sizing: border-box;
  padding: 6px 8px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  font-family: var(--police);
  font-size: 1em;
}
.boite-dialogue-boutons {
  display: flex;
  /* CENTRÉS et non alignés à droite : sur mobile, la pastille de discussion
     est ancrée en bas à droite de l'écran et recouvrait le bouton OK dès
     que le clavier virtuel remontait la boîte. Le centre est la seule
     position qui n'entre en concurrence avec aucun élément flottant — ils
     sont tous dans un coin. */
  justify-content: center;
  gap: 12px;
  margin-top: 14px;
}
/* Cibles confortables au doigt : 44 px est le minimum recommandé par les
   guides d'accessibilité tactile, et « Annuler » suivi d'« OK » à 8 px
   l'un de l'autre invitait à se tromper. */
.boite-dialogue-boutons .bouton {
  min-width: 96px;
  min-height: 44px;
}

/* ---------- boutons de priorité de la fenêtre de saisie ----------
   Taper « ! » demande deux appuis sur un clavier virtuel (bascule vers les
   symboles, puis la touche) : ces boutons évitent ce détour. Ils basculent
   la priorité plutôt que de l'ajouter — rappuyer sur le même niveau le
   retire, ce qui évite d'avoir à effacer des « ! » à la main. */
.palette-priorite {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
  flex-wrap: wrap;
}
.palette-priorite button {
  all: unset;
  box-sizing: border-box;
  min-width: 44px;
  min-height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(0, 0, 0, 0.28);
  border-radius: var(--rayon);
  background-color: #fff;
  color: #2b2f36;
  font-weight: 700;
  cursor: pointer;
}
.palette-priorite button[data-niveau="1"] { border-left: 6px solid var(--couleur-priorite1); }
.palette-priorite button[data-niveau="2"] { border-left: 6px solid var(--couleur-priorite2); }
.palette-priorite button[data-niveau="3"] { border-left: 6px solid var(--couleur-priorite3); }
/* aria-pressed porte l'état actif : c'est ce qu'annonce un lecteur d'écran
   pour un bouton à deux états, et le CSS s'y accroche aussi bien. */
.palette-priorite button[aria-pressed="true"] {
  background-color: var(--couleur-accent-clair);
  box-shadow: 0 0 0 2px var(--couleur-accent);
}

.input { padding: 10px; }

.scrollable {
  overflow-y: auto;
  overflow-x: hidden;
  /* Sur tactile, le glisser-déposer (dragdroptouch.js) fonctionne très bien
     par ailleurs, mais rend ambigu un geste de défilement démarré SUR une
     tâche (le système ne sait pas si on veut la faire glisser ou juste
     défiler). L'ascenseur "maison" ci-dessous (js/app.js) donne une zone de
     préhension dédiée, à côté des tâches plutôt que dessus. touch-action:
     pan-y (sur .item2) reste utile en complément pour les gestes qui
     démarrent malgré tout sur une tâche. */
  /* L'ascenseur NATIF est entièrement masqué : sur desktop (Firefox/Chrome),
     le personnaliser en plus de l'ascenseur "maison" créait DEUX ascenseurs
     visibles en même temps (confusion, et un comportement visuel erratique
     au relâchement en bas). Un seul ascenseur, le nôtre, partout. */
  scrollbar-width: none;      /* Firefox */
}
.colonne-contextes { scrollbar-width: none; } /* remplacé par l'ascenseur maison, comme .scrollable */
.colonne-contextes::-webkit-scrollbar { display: none; }

.scrollable::-webkit-scrollbar {
  display: none; /* Chrome/Safari/Edge */
}

/* Enveloppe créée par js/app.js autour de chaque zone défilante : ELLE ne
   défile jamais, contrairement à .scrollable qu'elle contient — c'est
   essentiel pour que l'ascenseur (posé à côté, pas dedans) reste fixe à
   l'écran pendant qu'on fait défiler le contenu, au lieu de défiler avec
   lui (le bug initial : le pouce restait "en haut" du contenu et sortait
   de l'écran dès qu'on descendait, puisqu'il faisait partie du contenu
   scrollable au lieu d'être un vrai overlay). */
.ascenseur-enveloppe {
  position: relative;
}

/* Ascenseur "maison" (js/app.js) : garanti visible même là où le CSS natif
   ci-dessus aurait été ignoré (iOS Safari, notamment, qui ne personnalise
   jamais ses ascenseurs natifs). Superposé au-dessus du contenu, ne gêne
   pas le défilement natif qui continue de fonctionner normalement en
   dessous — c'est UNIQUEMENT un habillage visuel + une poignée saisissable,
   le défilement réel reste géré par le navigateur. */
.ascenseur-piste {
  position: absolute;
  top: 0;
  right: 2px;
  width: 18px;
  height: 100%;
  pointer-events: none; /* seul le pouce doit intercepter le clic/toucher, pas toute la piste */
  z-index: 10;
}
/* Zones à ascenseur permanent (data-ascenseur-permanent) : quand rien ne
   déborde, le pouce reste affiché pleine hauteur mais inerte et atténué —
   le comportement des ascenseurs de bureau classiques. La piste seule ne
   suffirait pas : elle n'a volontairement aucun fond (invisible). */
.ascenseur-pouce-inerte {
  opacity: 0.25;
  pointer-events: none;
}

.ascenseur-pouce {
  position: absolute;
  right: 0;
  width: 100%;
  min-height: 30px;
  background-color: var(--couleur-accent);
  border-radius: 8px;
  opacity: 0.6;
  pointer-events: auto;
  touch-action: none; /* pour pouvoir le faire glisser sans que la page scrolle en même temps */
}
.ascenseur-pouce:hover,
.ascenseur-pouce:active {
  opacity: 0.9;
}

/* ---------- couleurs de contexte ----------
   Le fond pastel est posé en style inline (il vient de la base, il ne peut
   donc pas vivre ici) ; ce bloc ne s'occupe que de ce qui en découle.
   Le texte est FORCÉ en sombre : les 8 pastels sont clairs, et en mode
   sombre la couleur de texte héritée (claire) serait illisible dessus.
   Le "!important" est nécessaire pour battre .colorN du mode sombre, qui
   fixe lui aussi la couleur du texte. */
.item2[data-ctx-couleur],
.item2[data-ctx-couleur] .item,
.item2[data-ctx-couleur] .case,
.item2[data-ctx-couleur] p {
  color: #2b2f36 !important;
}
/* Les liens dans une tâche colorée gardent un contraste suffisant. */
.item2[data-ctx-couleur] a.link { color: #1b4b58 !important; }

/* Sélecteur de couleur (création d'un contexte, entrée "Couleur…") */
.palette-couleurs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 10px 0;
  max-width: 320px;
}
.palette-couleurs button {
  all: unset;
  box-sizing: border-box;
  width: 34px;
  height: 34px;
  border-radius: var(--rayon);
  border: 2px solid var(--couleur-bordure);
  cursor: pointer;
  transition: transform var(--transition-rapide), border-color var(--transition-rapide);
}
.palette-couleurs button:hover { transform: scale(1.15); }
.palette-couleurs button[aria-pressed="true"] {
  border-color: var(--couleur-accent);
  box-shadow: 0 0 0 2px var(--couleur-accent);
}
/* "Aucune couleur" : une case barrée, plutôt qu'un carré blanc qu'on
   confondrait avec un pastel très pâle. */
.palette-couleurs button.palette-aucune {
  background:
    linear-gradient(to top right,
      transparent calc(50% - 1px), var(--couleur-priorite3) 50%,
      transparent calc(50% + 1px)),
    #fff;
}

/* ---------- accessibilité : police et espacement ----------
   Réglages par compte (page Préférences), posés en classes sur <body> par
   classes_accessibilite() (utils.php).

   L'ESPACEMENT est séparé de la POLICE à dessein, parce que les deux n'ont
   pas le même statut : l'effet de l'espacement des lettres sur la lecture
   des personnes dyslexiques est solidement établi (Zorzi et coll., PNAS
   2012 — environ 50 % d'erreurs en moins chez 74 enfants dyslexiques
   italiens et français, par réduction de l'encombrement visuel), tandis
   que le bénéfice des polices « dys » n'est pas démontré et relève surtout
   de la préférence personnelle. Les combiner en un seul réglage aurait
   caché ce fait à l'utilisateur ; séparés, chacun compose ce qui lui va.

   Le sélecteur descend explicitement aux champs de saisie : input, textarea
   et button n'héritent PAS de la police du body (comportement historique
   des navigateurs), la zone d'édition d'une tâche serait donc restée dans
   une autre police que la tâche elle-même. */
/* Trois familles au choix (page Préférences). Les sélecteurs descendent
   explicitement aux champs de saisie : input, textarea, button et select
   n'héritent PAS de la police du body — comportement historique des
   navigateurs — et la zone d'édition d'une tâche serait sinon restée dans
   une autre police que la tâche elle-même.
   Sans "body" devant : les mêmes classes servent à l'aperçu de la page
   Préférences, posé sur un simple <p>. */
.police-sans,
.police-sans input, .police-sans textarea, .police-sans button, .police-sans select {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
.police-serif,
.police-serif input, .police-serif textarea, .police-serif button, .police-serif select {
  font-family: Georgia, "Times New Roman", "Liberation Serif", serif;
}
.police-opendyslexic,
.police-opendyslexic input,
.police-opendyslexic textarea,
.police-opendyslexic button,
.police-opendyslexic select {
  font-family: 'OpenDyslexic', var(--police-base, sans-serif);
}

/* Valeurs en "em" et non en pixels : l'espacement suit la taille du texte,
   y compris là où la mise en page réduit la police (badges, calendrier).
   L'interlignage accompagne l'interlettrage — sans lui, des lignes plus
   larges finissent par se toucher. */

.espacement-large {
  letter-spacing: 0.06em;
  word-spacing: 0.12em;
  line-height: 1.6;
}
.espacement-xlarge {
  letter-spacing: 0.12em;
  word-spacing: 0.24em;
  line-height: 1.8;
}
/* Les glyphes de case à cocher (□/☑) sont des caractères isolés : l'espace
   ajouté après eux décalerait le texte de la sous-tâche sans rien
   apporter, la case n'ayant pas de voisine dont il faille la distinguer. */
.espacement-large .case,
.espacement-xlarge .case {
  letter-spacing: normal;
  word-spacing: normal;
}

/* pastilles de contexte : legere transition au survol/a la selection */
.contexte-pastille {
  transition: background-color var(--transition-rapide), box-shadow var(--transition-rapide);
  border-radius: var(--rayon);
  white-space: nowrap; /* le badge de priorité (span imbriqué) ne doit jamais passer à la ligne */
  /* Filet arrondi autour de chaque contexte. Il remplace l'écart comme
     séparateur : c'est le trait qui dit où finit une pastille, on peut
     donc les rapprocher franchement sans qu'elles se confondent.
     Posé ici, hors des media queries, il vaut pour les deux orientations.
     box-sizing : le filet ne doit pas élargir la pastille au-delà de la
     colonne, qui a une largeur fixe en mode paysage. */
  /* Teinte propre, et non --couleur-bordure (#d7dde3) : ce gris très pâle
     est prévu pour séparer des blocs sur fond blanc ; posé sur l'ivoire ou
     le vert clair d'une pastille, il ne se distinguait pas. */
  border: 1px solid rgba(0, 0, 0, 0.28);
  box-sizing: border-box;
}
/* Couleur du contexte : en bande verticale à gauche, plutôt qu'en fond —
   le fond de la pastille sert déjà à indiquer le contexte ACTIF (vert
   clair), les deux informations ne peuvent pas partager la même surface
   sans que l'une masque l'autre.
   Cette bande remplace le filet sur le bord gauche : son sélecteur porte
   un attribut, donc une spécificité supérieure. Écrit juste après le filet
   pour que l'ordre saute aux yeux — la règle existait auparavant cent
   lignes plus haut, où rien ne signalait qu'elle en surchargeait une
   autre. */
.contexte-pastille[data-couleur] {
  border-left: 6px solid var(--couleur-contexte);
}
.contexte-pastille:hover {
  box-shadow: var(--ombre-legere);
}

@media screen and (max-aspect-ratio: 13/9) { /* portrait */

  /* Priorités en BANDE VERTICALE à gauche du bloc (au lieu de colorer
     fond et texte) : lisibilité identique dans les deux thèmes — ce qui
     règle au passage le texte noir de la priorité 2 en mode sombre — et
     le fond du bloc reste libre (futures couleurs de contexte). La bande
     transparente de la priorité 0 garde tous les blocs alignés. */
  .color0, .color1, .color2, .color3 { padding: 2px; font-weight: normal; color: var(--couleur-texte); background-color: transparent; }
  .item2.color0 { border-left: 9px solid transparent; }
  .item2.color1 { border-left: 9px solid var(--couleur-priorite1); }
  .item2.color2 { border-left: 9px solid var(--couleur-priorite2); }
  .item2.color3 { border-left: 9px solid var(--couleur-priorite3); }

  body { margin:0px;background-color: var(--couleur-accent-clair);};

  body, textarea, button { font-size: calc(4vmin * var(--echelle-texte)); font-family: var(--police); }

  /* Les conteneurs des six autres zones ne sont plus masqués en bloc :
     ils portent maintenant les zones que les onglets rendent accessibles.
     Seuls restent cachés les éléments qui n'ont pas de place en portrait. */
  #howto, .container1, .colonne-contextes { display: none; }

  /* Une seule zone à l'écran. Les conteneurs (.bl, .pb, .ec) perdent leur
     mise en page de bureau et se contentent d'exister : c'est la règle
     ci-dessous, sur les zones elles-mêmes, qui décide de ce qui s'affiche.
     Sans « display: contents », leurs hauteurs (33 %, 70 %) écraseraient
     la zone visible. */
  .bl, .pb, .ec { display: contents; }

  /* Une seule zone visible à la fois.
     js/app.js pose la classe « zone-cachee » sur les zones inactives et
     sur leur entête — plutôt qu'un sélecteur par numéro dans le CSS, qui
     obligerait à toucher la feuille de style à chaque zone ajoutée.
     La classe est portée par l'ENVELOPPE d'ascenseur quand elle existe
     (js/ascenseur.js enveloppe les zones défilantes à l'exécution) : sans
     cela, une piste d'ascenseur orpheline resterait à l'écran. */
  .zone-cachee { display: none !important; }

  /* Le titre de la zone reste en place pendant qu'on fait défiler ses
     tâches : il indique OÙ l'on se trouve, information qui ne doit pas
     disparaître au premier mouvement de doigt — d'autant qu'une seule
     zone est visible et que rien d'autre ne le rappelle.
     Il se colle sous le bandeau et les onglets, dont la hauteur est
     mesurée à l'exécution (cf. --hauteur-barres dans js/app.js). */
  /* UNE SEULE surface défile : la zone. .liste portait aussi
     « overflow-y: auto » (classe .sc), ce qui en faisait un second
     conteneur défilant — et c'est LUI qui servait de référence au titre
     collant, dont le décalage « top » se comptait alors depuis le haut de
     .liste et non depuis celui de l'écran. Le titre se retrouvait poussé
     de cent pixels vers le bas, par-dessus les premières tâches.
     Sans ce défilement parasite, le titre reste en place de lui-même : il
     est SIBLING de la zone, hors du conteneur qui défile. Aucun « sticky »
     n'est nécessaire, et il faut donc l'ôter — il ne pouvait que nuire. */
  /* UNE SEULE surface défile : la page. .liste portait « overflow-y: auto »
     (classe .sc), ce qui en faisait un second conteneur défilant et
     faussait le calcul des éléments collants — leur décalage se comptait
     depuis le haut de .liste, pas depuis celui de l'écran. */
  /* « .liste.sc » et non « .liste » : la classe .sc pose « overflow-y: auto »
     dans ce même bloc, et à spécificité égale c'est la dernière déclarée qui
     gagne. .liste restait donc un conteneur défilant — et c'est LUI qui
     servait de référence au titre collant : le décalage de 135 px se
     comptait depuis le haut de .liste (140 px) et non depuis celui de
     l'écran, plaçant le titre à 275 px, par-dessus les tâches. Mesuré dans
     un navigateur réel, la valeur correspondait au pixel près.
     Deux classes sur le même élément l'emportent quel que soit l'ordre. */
  .liste.sc { overflow: visible; }

  /* Le titre de zone se colle sous le bandeau ET les onglets, en troisième
     étage : il indique OÙ l'on se trouve, information qui ne doit pas
     disparaître au premier tour de molette — d'autant qu'une seule zone est
     visible et que rien d'autre ne le rappelle. */
  .ContextManagment {
    position: sticky;
    top: var(--hauteur-barres, 96px);
    z-index: 30;
  }

  /* Le bandeau commun (contexte + barre d'outils) précède les onglets :
     il est extérieur aux zones, donc toujours visible quelle que soit
     celle qu'on consulte. */
  /* Bandeau FIXE en haut : il ne défile pas avec la liste.
     Le contenu de la zone défile sous lui ; sans cette fixation, un
     défilement un peu vif de la liste entraînait le bandeau et les
     boutons sortaient de l'écran — d'autant plus facilement que la zone
     occupe désormais toute la hauteur disponible. */
  /* ---------- panneau « ⋯ » ouvert : tout le reste s'efface ----------
     Ces empilements sont pénibles parce que le z-index d'un élément n'a de
     sens QUE dans le contexte où il se trouve. Le panneau vit dans
     .bandeau-commun (z-index 40) : quelle que soit sa propre valeur, il ne
     dépassera jamais 40 face au reste de la page. Il faut donc agir sur
     les VOISINS, pas sur lui.
     Plutôt que de traquer un à un les éléments qui le recouvrent — la
     colonne d'abord, puis les onglets et le « + », et demain un autre — on
     les abaisse TOUS pendant l'ouverture. La liste est courte et ils ont
     tous la même raison d'être empilés : rester au-dessus des tâches qui
     défilent. Face à un panneau ouvert, aucun n'a de raison de rester
     devant.
     Les classes sont posées sur <body> et sur le bandeau par le JS des
     deux vues. */
  .bandeau-commun.panneau-ouvert { z-index: auto; }
  body.panneau-ouvert .coin,
  body.panneau-ouvert .colonne-contextes,
  body.panneau-ouvert .onglets-zones,
  body.panneau-ouvert .ContextManagment { z-index: auto; }
  /* Le « + » de la colonne est empilé DANS .coin : abaisser .coin ne
     suffit pas, l'entête garde son propre niveau à l'intérieur. */
  body.panneau-ouvert .contextes-entete { z-index: auto; }

  /* La barre d'outils perd sa marge basse à l'intérieur du bandeau.
     Cette marge de 4 px n'est pas comptée dans offsetHeight : la mesure
     donnait 61 px alors que les onglets commençaient à 65. Ils sautaient
     donc de 4 px au premier tour de molette, en se calant sur la valeur
     mesurée — le « petit mouvement » observé. Sans marge, position
     naturelle et position collée coïncident. */
  .bandeau-commun .barre-outils { margin-bottom: 0; }

  /* En portrait, la barre est trop étroite pour onze boutons à taille fixe :
     ils se PARTAGENT la largeur et rétrécissent ensemble, plutôt que de
     déborder ou de passer à la ligne. */
  .barre-outils > .bouton,
  .barre-outils > .barre-outils-plus,
  .barre-outils > .bouton.bouton-geant,
  .barre-outils > #btn-logout,
  .barre-outils > #btn-deconnexion,
  .barre-outils > .bouton-logout,
  .barre-outils > a[href*="logout"] {
    flex: 1 1 0;
    width: auto;
  }
  /* L'écart de séparation de la corbeille est réduit : chaque pixel compte. */
  .barre-outils > #btn-corbeille { margin-left: 16px; }

  /* Aucun espace entre les onglets et le contenu : .colonne est un <table>,
     dont l'espacement de cellules par défaut (border-spacing) ajoutait un
     pixel. Ce pixel séparait la position naturelle du titre de sa position
     collée — d'où un saut d'un pixel au premier défilement, visible parce
     que le titre est large et contrasté. */
  .colonne { border-spacing: 0; border-collapse: collapse; }
  .disposition-generale { margin-top: 0; }

  /* ---------- une seule surface défilante ----------
     La zone débordait sous la fenêtre : il fallait faire défiler la zone
     PUIS la page pour atteindre les dernières tâches — et une fois la zone
     à son terme, le doigt n'entraînait plus rien, la page ne prenant pas le
     relais. Les deux dernières lignes restaient donc hors d'atteinte.

     Cause : la hauteur de .colonne (100dvh) ne descendait pas jusqu'à la
     zone. .colonne est un <table> ; ses tbody/tr/td restent des boîtes de
     tableau, qui n'héritent pas du dimensionnement en flex — la chaîne se
     rompait là, et .liste grandissait avec son contenu.
     On force donc chaque maillon à transmettre la hauteur. min-height: 0
     partout : sans lui, la taille minimale d'un enfant flexible est celle
     de son CONTENU, et il repousse son conteneur au lieu de se limiter à la
     place disponible. */
  .colonne > tbody,
  .colonne > tbody > tr,
  .colonne > tbody > tr > td {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
  }

  /* La chaîne des hauteurs part du <body> lui-même, qui mesurait 762 px
     pour une fenêtre de 660 : la page débordait donc, et il fallait faire
     défiler la zone PUIS la page. Une fois la zone à son terme, le doigt
     n'entraînait plus rien — les dernières lignes restaient hors
     d'atteinte.
     body à la hauteur exacte de la fenêtre et sans débordement : la page ne
     défile plus du tout, la zone est la SEULE surface défilante, et son
     ascenseur mène jusqu'à la dernière tâche. Les barres collantes n'ont
     dès lors plus rien à faire, mais elles ne gênent pas. */
  /* CES RÈGLES NE VALENT QUE POUR LE TABLEAU ET L'ARBRE.
     Elles enferment la page dans la hauteur de la fenêtre pour qu'une seule
     surface défile — la zone de tâches. Appliquées à toutes les pages, elles
     rendaient les PRÉFÉRENCES, l'aide ou les nouveautés impossibles à faire
     défiler : leur contenu dépasse l'écran et n'avait plus aucun moyen de
     remonter.
     La classe est posée par index.php et arbre.php ; les pages
     transversales défilent normalement, comme n'importe quelle page web. */
  body.page-tableau,
  html:has(body.page-tableau) {
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
  }
  body.page-tableau {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  .bandeau-commun, .onglets-zones { flex: 0 0 auto; }
  .disposition-generale { flex: 1 1 auto; min-height: 0; }
  /* Le conteneur intermédiaire doit lui aussi transmettre la hauteur : il
     est en « display: block », si bien que le « flex: 1 1 auto » de .liste
     ne s'y appliquait pas — .liste prenait la hauteur de son contenu
     (679 px pour 579 disponibles) et débordait par le bas.
     .bl, .pb et .ec sont exclus : ils sont en « display: contents », qui
     les efface de la mise en page ; leur rendre une boîte rétablirait
     leurs hauteurs de grand écran (33 %, 70 %). */
  .disposition-generale > * { min-height: 0; }
  .disposition-generale > div:not(.bl):not(.pb):not(.ec) {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .bandeau-commun {
    background-color: var(--couleur-accent-clair);
    position: sticky;
    top: 0;
    z-index: 40;
    /* Pleine largeur également : la colonne des contextes commence
       désormais SOUS lui, plus rien ne recouvre ses derniers boutons. */
    box-sizing: border-box;
  }
  /* Les onglets restent collés sous le bandeau, pour la même raison :
     changer de zone doit rester possible sans remonter la liste. */
  /* Les onglets se collent SOUS le bandeau, et non à « top: 0 » comme lui.
     Deux éléments collants au même décalage se recouvrent : le second
     glissait sous le premier et disparaissait dès qu'on faisait défiler.
     La hauteur du bandeau seul est mesurée à l'exécution
     (--hauteur-bandeau), pour la même raison que --hauteur-barres : elle
     dépend de la taille du texte et du repli de la barre d'outils. */
  .onglets-zones {
    position: sticky;
    top: var(--hauteur-bandeau, 56px);
    z-index: 39;
  }

  /* « Next » est masqué en portrait par js/app.js, qui lui pose la même
     classe qu'aux zones inactives.
     Il vivait dans .bl / .pb, que la règle « display: none » d'origine
     escamotait avec les six zones ; en libérant ces conteneurs pour rendre
     les zones accessibles, on l'a fait RÉAPPARAÎTRE — occupant dès lors
     tout le haut de l'écran, au-dessus de la zone choisie.
     C'est un aperçu inter-contextes en lecture seule : utile sur grand
     écran où il ne coûte rien, superflu sur un téléphone où chaque ligne
     compte, et absent de la barre d'onglets. */

  /* ---------- barre d'onglets des zones ---------- */
  .onglets-zones {
    display: flex;
    gap: 2px;
    overflow-x: auto;
    overflow-y: hidden;
    /* Pleine largeur : la barre passe SOUS la colonne des contextes (qui
       démarre plus bas, cf. .coin) au lieu de s'arrêter avant elle. On
       gagne ainsi près d'un tiers de largeur pour les onglets — de quoi en
       montrer un de plus sans faire défiler.
       Le dernier onglet reste atteignable : la barre défile
       horizontalement, et rien ne la recouvre à cette hauteur. */
    padding: 0px 0px;
    margin-left:2px;
    background: var(--couleur-accent-clair);
    border-bottom: 1px solid var(--couleur-bordure);
    /* Défilement horizontal net : la barre s'arrête sur un onglet plutôt
       qu'entre deux, ce qui évite d'en laisser un à moitié coupé. */
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .onglets-zones::-webkit-scrollbar { display: none; }
  .onglet-zone {
    all: unset;
    width:13.6%;
    box-sizing: border-box;
    flex: 0 0 auto;
    scroll-snap-align: start;
    padding: 4px 4px;
    /*min-height: 36px;*/
    /*display: flex;*/
    align-items: center;
    gap: 4px;
    border-radius: 4px;
    border: 1px solid rgba(0, 0, 0, 0.28);
    background-color: #fff;
    color: #2b2f36;
    font-size: 0.5em;
    white-space: nowrap;
    cursor: pointer;
    overflow:hidden;
    text-overflow:clip;
  }
  .onglet-zone.actif {
    background-color: var(--couleur-accent);
    border-color: var(--couleur-accent);
    color: #fff;
    font-weight: 600;
  }
  .onglet-compteur {
    font-size: 0.75em;
    opacity: 0.75;
    font-weight: 400;
  }
  /* Onglet survolé pendant un glisser-déposer : il doit être évident que
     lâcher ici enverra la tâche dans cette zone. Le contour plutôt qu'un
     changement de fond, qui se confondrait avec l'onglet actif. */
  /* Onglet survolé pendant un glissement : VIDÉO INVERSÉE plutôt qu'un
     contour. Au doigt, un liseré de quelques pixels se voit mal — surtout
     sous le doigt qui le recouvre à moitié. L'inversion change toute la
     surface : impossible de se tromper sur l'endroit où l'on lâche. */
  .onglet-zone.onglet-survole,
  .onglet-zone.onglet-recu {
    background-color: var(--couleur-texte);
    color: var(--couleur-fond);
    border-color: var(--couleur-texte);
    transform: scale(1.06);
  }
  /* « onglet-recu » : posée une demi-seconde après un dépôt réussi. La tâche
     déposée disparaît de l'écran — sans ce clignotement, rien ne dirait où
     elle est allée. La transition adoucit le retour à l'état normal, pour
     que le signal se lise comme une confirmation et non comme un défaut
     d'affichage. */
  .onglet-zone { transition: background-color .25s, color .25s, transform .25s; }

  .cercle1, .cercle2, .cercle3 {
    width: 16px; height: 16px; border: 1px solid var(--couleur-bordure);
  }
  /* .trombone est défini une seule fois, hors media query, en
     position:absolute ancré dans .item2 — voir plus haut. */

  .z { 
    border: 0px solid black; margin: 0px;f
  }
  .t { float: top; }
  .pb { width: 70%; height: 33%; }
  .sc { height: 70%; overflow-y: auto; overflow-x: hidden;
  }
  /* La colonne visible occupe EXACTEMENT l'écran, et se partage en
     hauteur : l'entête (contexte, barre d'outils) prend ce qu'il lui faut,
     la liste prend le reste.

     Auparavant .liste valait 110vh et la zone défilante portait une hauteur
     de 99vh écrite en style inline : l'ensemble dépassait donc l'écran de
     la hauteur de l'entête, la dernière tâche restait hors champ, et
     l'ascenseur — dimensionné sur une zone plus haute que la surface
     visible — n'y menait pas.

     min-height:0 est indispensable sur un enfant flexible qui doit
     défiler : sans lui, sa taille minimale est celle de son CONTENU, et il
     repousse le conteneur au lieu de se limiter à la place disponible.
     Le !important est nécessaire pour battre le style inline. */
  .colonne { display: flex; flex-direction: column; }
  .liste {
    background-color: var(--couleur-fond);
    margin-bottom: 1px;
    flex: 1 1 auto;
    min-height: 0;
    height: auto;
    display: flex;
    flex-direction: column;
  }
  /* TOUTES les zones prennent la hauteur disponible, pas seulement celle
     de .liste. Chaque zone porte une hauteur en style INLINE (99vh pour
     « À faire » et « En cours », 29vh pour les autres) calibrée pour la
     disposition en colonnes du grand écran. En portrait, où l'on n'en
     affiche qu'une, ces valeurs faisaient sauter la mise en page à chaque
     changement d'onglet : une zone à 29vh laissait les deux tiers de
     l'écran vides et remontait la barre d'outils, une autre à 99vh
     débordait et la poussait hors champ.
     Le sélecteur vise la zone où qu'elle soit — dans .liste, dans .pb,
     dans .bl — puisque toutes se valent une fois seules à l'écran. */
  /* DEUX RÈGLES SÉPARÉES, et non une liste de sélecteurs.
     Un sélecteur inconnu dans une liste invalide la RÈGLE ENTIÈRE : sur un
     navigateur sans « :has() », la zone perdait aussi son dimensionnement
     alors que son sélecteur, lui, est valide partout. Elle gardait donc sa
     hauteur en style inline (99vh ou 29vh), ne débordait plus, et
     l'ascenseur — qui ne s'affiche que s'il y a de quoi faire défiler —
     disparaissait. Séparées, chaque règle vit sa vie. */
  .zone.scrollable[data-zone] {
    flex: 1 1 auto;
    min-height: 0;
    height: auto !important;
  }
  /* La classe « enveloppe-de-zone » est posée par js/ascenseur.js quand il
     enveloppe une zone : elle rend la règle indépendante de « :has() »,
     dont la prise en charge varie encore selon les navigateurs. Le
     sélecteur « :has() » est conservé en second recours, pour le cas où le
     JavaScript n'aurait pas tourné. */
  .ascenseur-enveloppe.enveloppe-de-zone {
    flex: 1 1 auto;
    min-height: 0;
    height: auto !important;
  }
  .ascenseur-enveloppe:has(.zone.scrollable[data-zone]) {
    flex: 1 1 auto;
    min-height: 0;
    height: auto !important;
  }
  .ascenseur-enveloppe > .zone.scrollable[data-zone] { height: 100% !important; }

  /* Le conteneur de la zone visible doit lui-même occuper la place restante,
     quelle que soit la colonne d'origine — .bl et .pb sont en
     « display: contents », leurs enfants deviennent donc enfants directs
     de la grille de .disposition-generale. */
  .disposition-generale { display: flex; flex-direction: column; min-height: 0; }
  .disposition-generale > .liste { flex: 1 1 auto; min-height: 0; }
  /* 100dvh et non 100vh : sur mobile, « vh » est calculé sur la fenêtre
     BARRES D'ADRESSE MASQUÉES, une hauteur que l'on n'a jamais tant qu'on
     n'a pas fait défiler. La colonne dépassait donc de la hauteur de ces
     barres — le bas de la liste « À faire » restait hors de l'écran et
     l'ascenseur, dimensionné sur une zone plus haute que la surface
     visible, n'atteignait jamais les dernières tâches.
     « dvh » (dynamic viewport height) suit la hauteur RÉELLEMENT visible.
     Le 100vh est conservé en repli pour les navigateurs antérieurs à 2022,
     qui ignorent la ligne suivante. */
  .colonne {
    background-color: var(--couleur-accent-clair);
    height: 100vh;
    height: 100dvh;
  }
  .todo { vertical-align: top;}
  /* Les 97 % laissaient les tâches passer SOUS l'ascenseur maison (18 px,
     posé à droite de la zone). On réserve sa place explicitement plutôt
     que de deviner un pourcentage : calc() reste juste quelle que soit la
     largeur de l'écran, un pourcentage non. box-sizing pour que la marge
     et la bordure ne s'ajoutent pas à la largeur calculée. */
  .item2 {
    margin: 3px;
    width: calc(100% - 28px);
    box-sizing: border-box;
  }
  #contextesportraits { width: 15vw; background-color: var(--couleur-accent-clair); vertical-align: top; }
  /* Pastilles resserrées : la colonne en compte souvent une vingtaine, et
     chaque pixel gagné en hauteur est une pastille de plus visible sans
     faire défiler. Le filet arrondi (posé hors media query) sépare
     suffisamment pour qu'on puisse coller davantage. */
  .box, lightgreen { width: 99%; display: block; margin: 1px 2px; padding: 0 4px; background-color: var(--couleur-accent); }
  .coin .contexte-pastille { min-height: 1.4em; line-height: 1.2; }
  /* Colonne de contextes pleine hauteur, plutôt qu'un petit encart dans le
     coin (où le contexte actif restait quasi invisible) : même largeur
     qu'avant (25vw), mais sur toute la hauteur de l'écran. #kanban prend
     une marge à droite équivalente pour ne jamais passer dessous. */
  
  .resultat-colonnes { columns: 2; column-gap: 4px; }
  
  .contexte-actuel-affiche {
  align-self: stretch; /* le fond occupe toute la largeur disponible, plutôt que de se resserrer sur le texte */
  text-align: center;
  background-color: lightgreen; /* même couleur que la pastille active dans la liste de contextes */
  border-radius: var(--rayon);
  padding: 0px 0px;
  font-weight: 600;
  margin-bottom: 0px;
  box-sizing: border-box;
}

  .box {
      white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .coin {
    /* La colonne démarre SOUS le bandeau et les onglets, pour que ceux-ci
       courent sur toute la largeur.
       La hauteur de ces deux barres n'est pas connue à l'avance : elle
       dépend de la taille du texte choisie par l'utilisateur, du nombre de
       boutons et de la largeur de l'écran (la barre d'outils se replie sur
       deux lignes ou non). js/app.js la MESURE au chargement et la publie
       dans --hauteur-barres ; les 96 px ne servent que de valeur de repli
       avant cette mesure. Une valeur figée était forcément fausse pour une
       partie des réglages — d'où le chevauchement observé. */
    position: fixed;
    top: var(--hauteur-barres, 96px);
    right: 0;
    width: 25vw;
    height: calc(100dvh - var(--hauteur-barres, 96px));
    /* Parenthèse en trop corrigée : « var(--x)); » rendait la déclaration
       invalide, et un analyseur CSS qui rencontre une erreur consomme
       jusqu'au prochain « ; » — emportant ici la position, la largeur et
       le z-index. La colonne des contextes perdait donc son ancrage en
       portrait, ce qui rendait le dépôt d'une tâche dessus impraticable. */
    background-color: var(--couleur-accent-clair);
    overflow-x: hidden; overflow-y: auto;
    /* Au-dessus du bandeau fixe (z-index 40) et des onglets (39) : la
       colonne est ancrée à droite sur toute la hauteur, et ces deux
       éléments s'étendent sur toute la LARGEUR. Sans cette priorité, ils
       recouvraient les premières pastilles — INBOX en tête — qui
       devenaient inatteignables.
       Le débordement horizontal du bandeau sous la colonne est voulu : il
       reste lisible, seule la zone couverte par la colonne lui échappe. */
    z-index: 50;
    width:27%;
    padding: 4px;
    box-sizing: border-box;
  }
  #kanban { margin-right: 26vw; }
}

@media screen and (min-aspect-ratio: 13/9) { /* paysage */
  /* En paysage la feuille ne fixait aucune taille et laissait le défaut du
     navigateur. On l'exprime maintenant explicitement, pour que l'échelle
     choisie par l'utilisateur ait prise dessus. */
  body, textarea, button { font-size: calc(1rem * var(--echelle-texte)); }
  .coin { display: none; }
  .colonne, .zone { width: 100%; }

  body { background-color: var(--couleur-fond); margin: 0; }
  .bl { clear: left; height: 100vh; width: 25%; background-color: var(--couleur-accent-clair); }
  .br { clear: right; height: 100vh; width: 25%; background-color: var(--couleur-accent-clair); }
  .z { display: inline-block; border: 0px solid black; margin: 0px; }
  .l { float: left; }
  .r { float: right; }
  .t { float: top; }
  .pb { width: 100%; height: 32%; }
  .liste { width: 25%; background-color: #fff; }
  /* Priorités en BANDE VERTICALE à gauche du bloc (au lieu de colorer
     fond et texte) : lisibilité identique dans les deux thèmes — ce qui
     règle au passage le texte noir de la priorité 2 en mode sombre — et
     le fond du bloc reste libre (futures couleurs de contexte). La bande
     transparente de la priorité 0 garde tous les blocs alignés. */
  .color0, .color1, .color2, .color3 { padding: 2px; font-weight: normal; color: var(--couleur-texte); background-color: transparent; }
  .item2.color0 { border-left: 9px solid transparent; }
  .item2.color1 { border-left: 9px solid var(--couleur-priorite1); }
  .item2.color2 { border-left: 9px solid var(--couleur-priorite2); }
  .item2.color3 { border-left: 9px solid var(--couleur-priorite3); }

  *[contenteditable] { -webkit-user-select: auto !important; }

  /* .trombone est défini une seule fois, hors media query, en
     position:absolute ancré dans .item2 — voir plus haut. */

  table { margin: auto; border-collapse: collapse;}
  table th, table td { border-collapse: collapse; text-align: center; }
  .zone table td { vertical-align: top; padding-bottom: 23vh; height: auto; }
  /* (l'ancienne règle "table span" de la v1 a été retirée : elle ciblait
     .item quand c'était le seul span dans le tableau, mais s'applique
     maintenant aussi par erreur aux cases à cocher et au rond, en plus de
     forcer une largeur fixe qui casse le dimensionnement flex de
     .ligne-titre — voir README) */

  /* Disposition générale : le kanban prend l'espace disponible, la colonne
     de contextes une largeur fixe sur toute la hauteur — juste à côté,
     plutôt que dans une rangée à part en haut de l'écran (où le contexte
     actif restait difficile à repérer). */
  .disposition-generale { display: flex; align-items: stretch; gap: 8px; }
  #kanban { flex: 1 1 auto; min-width: 0; }
  .colonne-contextes {
    flex: 0 0 200px;
    display: flex;
    flex-direction: column;
    margin-left:-8px;
    /* Écart resserré (4px auparavant) : depuis que chaque pastille porte
       son propre filet, l'espace n'a plus à faire office de séparateur. */
    gap: 2px;
    height: 100vh;
    overflow-y: auto;
    background-color: var(--couleur-accent-clair);
    border-radius: var(--rayon);
    padding: 4px;
    box-sizing: border-box;
  }

  /* L'ascenseur maison (js/app.js) enveloppe la colonne de contextes dans
     .ascenseur-enveloppe : c'est donc l'enveloppe qui devient l'enfant flex
     de .disposition-generale et doit porter la largeur fixe. */
  .disposition-generale > .ascenseur-enveloppe { flex: 0 0 200px; display: flex; }
  .disposition-generale > .ascenseur-enveloppe > .colonne-contextes { flex: 1 1 auto; }
  /* place pour le pouce (18px + marge), sinon il recouvre les pastilles */
  .colonne-contextes { padding-right: 24px; }

  /* ---- Zones calées en bas de l'écran -------------------------------
     Les hauteurs fixes en vh (29vh par zone, 99vh pour "À faire" et
     "En cours", posées en inline par afficher_zone) rendaient les bas de
     colonnes incapables de s'aligner : ce qui se trouve AU-DESSUS d'une
     zone (bandeau d'outils, zone Next...) varie d'une colonne à l'autre.
     Chaque colonne devient une pile flex de 100vh : les en-têtes et
     bandeaux gardent leur hauteur naturelle, et chaque zone défilante
     absorbe l'espace RESTANT (le !important est nécessaire pour vaincre
     la hauteur inline). Les zones se terminent donc toutes exactement en
     bas de l'écran, quel que soit leur contenu. */
  .bl { display: flex; flex-direction: column; }
  .bl > .pb { flex: 1 1 0; min-height: 0; height: auto; display: flex; flex-direction: column; }
  .liste { height: 100vh; display: flex; flex-direction: column; box-sizing: border-box; }
  /* le conteneur défilant remplit le reste de sa pile — qu'il soit encore
     nu (avant l'initialisation JS) ou déjà enveloppé par l'ascenseur */
  .pb > .zone, .liste > .zone,
  .pb > .ascenseur-enveloppe, .liste > .ascenseur-enveloppe {
    flex: 1 1 auto; min-height: 0;
  }
  .pb > .ascenseur-enveloppe, .liste > .ascenseur-enveloppe { display: flex; flex-direction: column; }
  .pb .zone, .liste .zone { height: auto !important; }

  .box {
    /* Hauteur RELATIVE et non fixe (20px auparavant).
       Ces 20 px étaient calibrés pour la taille de texte d'origine et ne
       bougeaient plus ensuite : dès que l'échelle montait — typiquement en
       vue arbre — les pastilles se chevauchaient, et quand elle baissait —
       typiquement en vue tableau — elles flottaient dans du vide. En « em »
       la colonne suit d'elle-même le réglage de chaque vue, sans qu'on ait
       à la régler deux fois. */
    position: relative; height: auto; min-height: 1.5em; line-height: 1.25;
    min-width: 50px; padding: 2px 8px; margin: 0;
    place-items: center; text-align: left; border-radius: var(--rayon);
    /* pas de bordure/fond individuel ici : la couleur ivoire/vert clair de
       chaque pastille vient d'un style inline (contexte actif ou non), et le
       fond partagé de .colonne-contextes suffit à les regrouper
       visuellement comme un seul ensemble plutôt que des boîtes séparées. */
  }
  .box > * { flex: 1 1 100px; }

  .link { text-decoration: none; font-weight: 600; }
}

/* ---------- fenêtre de chat flottante ---------- */

.chat-flottant {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 5000;
}
/* Gros rond "+" pour créer un nouveau contexte, en tête de la liste de
   contextes — même traitement visuel que le rond du chat (.chat-bouton-
   ouvrir), pour que ce soit immédiatement reconnaissable comme LE bouton
   d'action principal de cette liste (l'ancien petit "+" en bas de liste
   passait facilement inaperçu). */
.btn-nouveau-contexte {
  /*display: flex;*/
  position: relative;
  z-index: 1000;
  /*text-align:center;*/
  width: 36px;
  height: 36px;
  margin: 0px;
  /*border-radius: 50%;*/
  border: none;
  color: var(--couleur-accent);
  font-size: 3em;
  font-weight: bold;
  text-decoration: none;
  /*box-shadow: var(--ombre-moyenne);*/
  cursor: pointer;
  /*flex-shrink: 0;*/
}
.plus{
  /*position:relative;*/
  margin-top:-20px;
  margin-bottom:-15px;
}
.chat-bouton-ouvrir {
  position: relative;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: var(--couleur-accent);
  color: white;
  font-size: 1.4em;
  box-shadow: var(--ombre-moyenne);
  cursor: pointer;
}
.chat-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  background: var(--couleur-priorite3);
  color: white;
  border-radius: 999px;
  font-size: 0.6em;
  padding: 2px 6px;
  font-weight: 700;
}
.chat-panneau {
  position: absolute;
  bottom: 58px;
  right: 0;
  width: 300px;
  height: 400px;
  max-height: 70vh;
  background: #fff;
  border-radius: var(--rayon);
  box-shadow: var(--ombre-moyenne);
  display: flex;
  flex-direction: column;
  overflow-x:hidden ;overflow-y: auto;
}
.mode-sombre .chat-panneau { background-color: #262b30 !important; color: var(--couleur-texte); }
.chat-entete {
  padding: 8px 12px;
  background: var(--couleur-accent);
  color: white;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
}
.chat-bouton-retour {
  background: none;
  border: none;
  color: white;
  font-size: 1.1em;
  cursor: pointer;
  padding: 0;
}
#chat-vue-liste, #chat-vue-conversation {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
#chat-liste-amis {
  overflow-y: auto;overflow-x: hidden;
  flex: 1 1 auto;
}
.chat-ami {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  cursor: pointer;
  border-bottom: 1px solid var(--couleur-bordure);
}
.chat-ami:hover { background-color: var(--couleur-accent-clair); }
.chat-point-presence {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #bbb;
  flex-shrink: 0;
}
.chat-point-presence.en-ligne { background: #4caf50; }
.chat-ami-badge {
  margin-left: auto;
  background: var(--couleur-priorite3);
  color: white;
  border-radius: 999px;
  font-size: 0.75em;
  padding: 1px 7px;
}
.chat-messages {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.chat-bulle {
  max-width: 80%;
  padding: 6px 10px;
  border-radius: 12px;
  font-size: 0.9em;
  word-wrap: break-word;
}
.chat-bulle-moi {
  align-self: flex-end;
  background: var(--couleur-accent);
  color: white;
}
.chat-bulle-autre {
  align-self: flex-start;
  background: var(--couleur-accent-clair);
}
.chat-formulaire {
  display: flex;
  gap: 4px;
  padding: 8px;
  border-top: 1px solid var(--couleur-bordure);
}
.chat-formulaire input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  font-family: var(--police);
}

/* ---------- panneau de pièces jointes ---------- */

.boite-attachments {
  min-width: 320px;
  max-width: 90vw;
}
.attachments-liste {
  max-height: 40vh;
  overflow-y: auto;
  overflow-x: auto;
  margin: 8px 0;
}
.attachment-ligne {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid var(--couleur-bordure);
}
.attachment-infos {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.attachment-taille {
  font-size: 0.8em;
  color: var(--couleur-bordure);
}
.attachment-actions {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}
.attachment-actions .bouton {
  padding: 3px 8px;
  font-size: 0.85em;
}
.attachment-bouton-fichier {
  cursor: pointer;
  display: inline-block;
}
.attachment-edition {
  padding: 6px 0;
  border-bottom: 1px solid var(--couleur-bordure);
}
.attachment-edition textarea {
  width: 100%;
  box-sizing: border-box;
  min-height: 100px;
  font-family: var(--police);
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  padding: 6px;
  margin-bottom: 4px;
}
.attachments-ajout {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 8px;
}
.attachments-ajout input[type="file"] {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.85em;
}

/* ---------- popup d'édition/ajout de tâche ---------- */
/* Fond neutre volontairement : contrairement à l'ancienne édition en
   place (dans la carte elle-même), le texte reste toujours lisible quelle
   que soit la couleur de priorité de la tâche (le texte en priorité 3
   devenait invisible avec l'ancien "color: inherit"). */

.boite-edition-tache {
  width: 560px;
  max-width: 92vw;
  /* Grille : la zone de saisie et la palette d'émoticônes côte à côte, le
     reste (bouton retour, pièces jointes, boutons) sur toute la largeur.
     Une grille plutôt qu'un flex parce que seuls DEUX des enfants doivent
     se partager une ligne — les autres gardent leur pleine largeur sans
     qu'on ait à les envelopper. */
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 8px;
}
.boite-edition-tache > *:not(.textarea-edition-tache):not(.palette-smileys) {
  grid-column: 1 / -1;
}

/* Colonne d'émoticônes, à droite de la zone de saisie. Verticale et
   défilante : la liste vient de $smileys (config.php) et peut être
   allongée par l'administrateur sans que la boîte grandisse. */
.palette-smileys {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 40vh;
  overflow-y: auto;
  padding-right: 2px;
}
.palette-smileys button {
  all: unset;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 6px;
  border-radius: var(--rayon);
  cursor: pointer;
  white-space: nowrap;
}
.palette-smileys button:hover,
.palette-smileys button:focus-visible {
  background-color: var(--couleur-accent-clair);
}
.palette-smileys-emoji { font-size: 1.2em; line-height: 1; }
/* Le code en petit et en chasse fixe : c'est ce qu'on tape, il doit se
   lire sans ambiguïté (un « l » ne doit pas passer pour un « 1 »). */
.palette-smileys-code {
  font-family: ui-monospace, monospace;
  font-size: 0.75em;
  opacity: 0.75;
}
/* Sur écran étroit, la palette passe SOUS la zone de saisie et s'étale en
   lignes : une colonne de plus rognerait une largeur déjà comptée. */
@media screen and (max-width: 560px) {
  .boite-edition-tache { grid-template-columns: 1fr; }
  .palette-smileys {
    flex-direction: row;
    flex-wrap: wrap;
    max-height: 22vh;
  }
}
.bouton-retour-popup {
  display: block;
  background: none;
  border: none;
  font-size: 1.4em;
  cursor: pointer;
  padding: 0 0 8px 0;
  color: var(--couleur-accent);
  line-height: 1;
}
.textarea-edition-tache {
  width: 100%;
  box-sizing: border-box;
  min-height: 40vh;
  font-family: var(--police);
  font-size: 1em;
  color: var(--couleur-texte, #222);
  background-color: #fff;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  padding: 8px;
  resize: vertical;
  white-space: pre-wrap;
}
.mode-sombre .textarea-edition-tache {
  background-color: #1b1f24 !important;
  color: var(--couleur-texte) !important;
}
.bouton-attachments-popup {
  display: block;
  margin-top: 8px;
  font-size: 0.85em;
}

/* Bouton "Archiver" dans l'en-tête de la colonne Terminé */
.bouton-archiver-terminees {
  position: absolute;
  top: 2px;
  right: 4px;
  background: none;
  border: none;
  font-size: 1em;
  cursor: pointer;
  padding: 0;
  line-height: 1;
}

/* PAGE D'ACCUEIL. Réécrite en même temps que accueil.php : les anciennes
   règles supposaient un grand écran et des puces d'une seule ligne
   (« width:50% », « margin-left:2cm », « line-height:10px » — cette dernière
   faisait se chevaucher les lignes dès qu'un item en occupait deux). */
.accueil {
  max-width: 46rem;   /* en rem : la page suit l'échelle de texte du lecteur */
  margin: auto;
  padding: 1rem;
}

.accueil-entete { text-align: center; }
.accueil-entete h1 { margin-bottom: 0.2em; }

.accueil-image {
  max-width: 100%;    /* sans quoi l'image déborde sur un téléphone */
  height: auto;
}

/* L'inscription est encadrée : c'est le seul endroit de la page où l'on agit,
   tout le reste se lit. */
.accueil-inscription {
  margin: 1.5rem 0;
  padding: 1rem;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
}

/* flex-wrap : sur un écran étroit, le bouton passe sous le champ au lieu de
   le comprimer jusqu'à l'illisible. */
.accueil-formulaire {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.accueil-formulaire input[type="email"] {
  flex: 1 1 18rem;
  min-width: 0;       /* autorise le champ à rétrécir dans un conteneur flex */
  padding: 8px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
}
.accueil-formulaire .bouton { min-height: 44px; }

.accueil-recuperation { margin-top: 1rem; }
.accueil-recuperation summary { cursor: pointer; }

.accueil-presentation ul { padding-left: 1.3em; }
.accueil-presentation li { margin-bottom: 0.4em; }



/* ---------- page Préférences ---------- */
/* La page tenait sur une seule colonne étroite et demandait de dérouler
   pour voir quatre réglages. Elle passe en grille : les groupes se
   répartissent sur la largeur disponible et retombent sur une colonne
   quand l'écran est étroit. */
.pref-formulaire {
  max-width: 900px;
  /* Marge des DEUX côtés : un margin-left seul collait la page au bord
     droit et laissait un vide à gauche. */
  margin: 0 auto;
  padding: 0 24px;
  box-sizing: border-box;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
  align-items: start;
}
/* Le groupe « Confort de lecture » contient deux réglages plus un aperçu :
   il prend toute la largeur, sinon son aperçu se retrouve à l'étroit. */
.pref-groupe-large { grid-column: 1 / -1; }
/* Le bouton et l'indicateur d'état passent sous les groupes. */
.pref-formulaire > p { grid-column: 1 / -1; margin: 4px 0 0; }
.pref-groupe {
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  padding: 6px 10px 8px;
  margin: 0;
  background-color: var(--couleur-accent-clair);
}
/* Même correction que sur « Mes accès » : un <legend> se place PAR DÉFAUT
   SUR la bordure haute du <fieldset>. Invisible sur fond blanc, criant ici
   où chaque pavé a un fond coloré — le titre se retrouvait à moitié dedans,
   à moitié dehors. Le float le sort de ce mécanisme et en fait un titre
   ordinaire posé à l'intérieur du pavé ; display:block laisserait un espace
   fantôme dans certains navigateurs.
   La taille passe de 0,95 em à 1,05 em : un titre de section n'a aucune
   raison d'être plus petit que le texte qu'il annonce. */
.pref-groupe legend {
  float: left;
  width: 100%;
  margin: 0 0 8px;
  padding: 0;
  font-weight: 600;
  font-size: 1.05em;
}
/* Un flottant ne pousse pas son parent : sans ce clear, le pavé se
   refermerait sur son propre titre. */
.pref-groupe legend + * { clear: left; }
/* Le titre étant désormais À L'INTÉRIEUR, il lui faut de la place. */
.pref-groupe { padding: 12px 14px 14px 16px; }
.pref-sous-titre { font-weight: 600; margin: 8px 0 2px; font-size: 0.9em; }
/* Les choix s'empilent verticalement : une cible de clic pleine largeur
   est nettement plus facile à viser au doigt que le seul petit rond. On
   réduit le rembourrage sans descendre sous une hauteur confortable. */
.pref-choix {
  display: block;
  padding: 3px 4px;
  cursor: pointer;
  border-radius: var(--rayon);
  line-height: 1.4;
}
.pref-choix:hover { background-color: rgba(0, 0, 0, 0.05); }
.pref-aide { font-size: 0.8em; opacity: 0.8; margin: 3px 0 0; line-height: 1.35; }
.pref-confirmation { max-width: 900px; margin: 0 auto; padding: 0 24px; font-weight: 600; }
.pref-apercu {
  margin-top: 8px;
  border-top: 1px dashed var(--couleur-bordure);
  padding-top: 8px;
}
.pref-apercu-ligne {
  background-color: #fff;
  color: #2b2f36;
  border-radius: var(--rayon);
  padding: 10px;
  margin: 0;
}
.pref-valider { margin-left: 0; }


/* ---------- vue arbre : cibles de dépôt ----------
   Les cibles (corbeille et pastilles de contexte) ne portent AUCUN style
   propre au repos : ce sont les mêmes éléments que sur le tableau, et les
   distinguer visuellement irait contre le but recherché, qui est que les
   deux vues se ressemblent. Seul le survol pendant un glissement se
   signale.

   zTree ne se sert pas du glisser-déposer HTML5 : ces éléments ne
   reçoivent aucun événement "drop", c'est js/arbre.js qui les retrouve
   sous le pointeur au relâchement (cf. cibleSousLePointeur). */
.arbre-cible-survolee {
  outline: 3px solid var(--couleur-accent);
  outline-offset: 2px;
  box-shadow: var(--ombre-moyenne);
}
/* La corbeille de la vue arbre est un <span> et non un <button> (elle ne
   se clique pas, on y dépose) : il lui faut le curseur et l'alignement que
   le navigateur donnait gratuitement au bouton. */
#btn-corbeille.arbre-cible {
  cursor: default;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Indicateur d'enregistrement des préférences. Il occupe une place fixe
   même vide (min-height) : sans ça, son apparition décalerait le bouton
   sous le curseur au moment précis où l'on vient de cliquer. */
.pref-etat {
  margin-left: 10px;
  font-size: 0.9em;
  font-weight: 600;
  display: inline-block;
  min-height: 1.2em;
}
.pref-etat-echec { color: var(--couleur-priorite3); }

/* Résultat de recherche dans la vue arbre. Contour plutôt que fond coloré :
   le fond du nœud n'est pas libre (zTree l'utilise pour la sélection), et
   un contour reste visible quelle que soit la couleur de contexte. */
.ztree a.arbre-trouve {
  outline: 2px solid var(--couleur-accent);
  outline-offset: 1px;
  border-radius: 3px;
  font-weight: 600;
}

/* ---------- mode sombre : vue arbre, archives, nouveautés ----------
   zTreeStyle.css fixe « color:#333 » en dur sur .ztree et .ztree li a.
   En mode sombre, le texte des tâches devenait donc gris foncé sur fond
   foncé — illisible, c'est-à-dire quasiment invisible. On ne modifie pas
   la feuille de zTree (elle est remplacée à chaque mise à jour de la
   bibliothèque : la retouche serait perdue) : on la surcharge ici.
   Le « !important » est nécessaire, zTreeStyle.css étant chargée après
   style.css sur arbre.php. */
.mode-sombre .ztree,
.mode-sombre .ztree li a,
.mode-sombre .ztree li span {
  color: var(--couleur-texte) !important;
}
/* Le nœud sélectionné de zTree a un fond ambre clair prévu pour du texte
   noir : on lui rend un texte sombre plutôt que de changer son fond, qui
   sert de repère visuel familier. */
.mode-sombre .ztree li a.curSelectedNode,
.mode-sombre .ztree li a.curSelectedNode_Edit {
  color: #1a1d21 !important;
}
/* Les archives fixaient un fond « lightblue » et un texte noir : la page
   entière restait claire au milieu d'un thème sombre. */
.mode-sombre { --couleur-fond-archive: var(--couleur-fond); }
.mode-sombre .archive-carte {
  background: #262b30 !important;
  color: var(--couleur-texte);
}

/* ---------- page de résultats de recherche ----------
   Quatre colonnes sur écran large, deux sur mobile. Les résultats étaient
   auparavant empilés sur une seule colonne bridée à 600 px : sur un écran
   de bureau, quatre-vingts pour cent de la largeur restaient vides et il
   fallait dérouler longuement pour voir une dizaine de tâches.

   Disposition en COLONNES et non en grille.
   En grille, la hauteur d'une rangée est celle de sa carte la plus haute :
   une tâche de trois lignes creusait un vide sous chacune des trois autres
   cartes de sa rangée, d'où les blancs observés. Les colonnes CSS
   empilent au contraire les cartes bout à bout, sans trou.
   Contrepartie assumée : la lecture se fait de haut en bas colonne par
   colonne, et non de gauche à droite. Les résultats étant triés par
   priorité, les plus urgents se retrouvent groupés en tête de première
   colonne — ce qui reste lisible. */
.resultats-grille {
  display: block;
  column-count: 4;
  column-gap: 10px;
}
.resultats-grille .resultat-recherche {
  display: block;
  min-width: 0;
  /* Une carte ne doit jamais être coupée en deux par un saut de colonne. */
  break-inside: avoid;
  page-break-inside: avoid; /* repli pour les moteurs plus anciens */
  margin-bottom: 10px;
}
.resultats-grille .item2 {
  max-width: none;
  margin: 0;
  overflow-wrap: anywhere; /* une URL sans espace ne doit pas élargir la colonne */
}
@media screen and (max-width: 900px) {
  .resultats-grille { column-count: 2; }
}
@media screen and (max-width: 900px) {
  .resultats-grille { grid-template-columns: repeat(2, 1fr); }
}

/* Le lien de retour, défini une seule fois (navigation.php) : modifier son
   apparence ici la change sur toutes les pages qui l'affichent. */
/* Le lien de retour est posé À CÔTÉ du <h1>, qui est en display:inline — les
   deux sont donc sur la même ligne, et une marge verticale sur un élément en
   ligne reste sans effet (c'est ce qui rendait ma première correction
   inopérante). Il faut inline-block pour que les marges prennent, et
   l'essentiel de l'air doit être HORIZONTAL, entre le titre et le bouton. */
.ligne-retour {
  display: inline-block;
  margin: 0.4em 0 1em 1.4em;
}

/* ---------- vue arbre : nœuds sans enfant ----------
   zTree place un bouton « switch » devant CHAQUE nœud, y compris les
   feuilles, où il affiche un [-] qui ne déplie rien. On le masque en
   gardant sa place (visibility, pas display) : sinon les feuilles se
   décaleraient vers la gauche et l'alignement de l'arbre partirait.
   Les classes en _docu sont celles que zTree donne aux nœuds sans fils. */
.ztree li span.button.switch[class*="_docu"] { visibility: hidden; }
/* Filet de sécurité indépendant du nommage interne de zTree : un <li> qui
   ne contient pas de <ul> n'a pas d'enfants, son switch ne déplie donc
   rien. visibility et non display, pour ne pas décaler l'alignement. */
/* Cette règle est SEULE dans sa déclaration, et c'est voulu : si
   « :has() » n'est pas reconnu, elle est ignorée sans emporter de voisine.
   Elle n'est de toute façon qu'un filet de sécurité — le masquage
   principal passe par la classe noline_docu de zTree, juste au-dessus. */
.ztree li:not(:has(ul)) > span.button.switch { visibility: hidden; }

/* ---------- mode sombre : séparation des tâches ----------
   Les cartes .item2 n'avaient pas de fond propre : en mode sombre elles se
   confondaient avec le fond général et l'on ne voyait plus où finissait
   une tâche et où commençait la suivante. On leur donne un fond légèrement
   plus clair que la page, plus une bordure discrète.
   Les tâches d'un contexte COLORÉ sont exclues : leur fond pastel est posé
   en style inline et doit rester intact. */
.mode-sombre .item2:not([data-ctx-couleur]) {
  background-color: #262b30;
  /* Trois côtés seulement, JAMAIS le raccourci « border ».
     Le bord GAUCHE porte le bandeau de priorité (.item2.colorN, dans les
     media queries) : un raccourci le réinitialise, et les bandeaux
     rouge/orange/vert disparaissaient purement et simplement en mode
     sombre. */
  border-top: 1px solid #363c43;
  border-right: 1px solid #363c43;
  border-bottom: 1px solid #363c43;
}
.mode-sombre .zone .item2:not([data-ctx-couleur]) { margin-bottom: 4px; }

/* Le bouton « + » (nouveau contexte) touchait la première pastille : on
   visait INBOX et l'on ouvrait la création d'un contexte. Un écart net,
   plus un trait de séparation, lèvent l'ambiguïté. */
/* Entête de la colonne des contextes : le logo et le bouton d'ajout, côte
   à côte au-dessus des pastilles. Le « + » y est visible d'emblée — en fin
   de liste il fallait dérouler une vingtaine de contextes pour l'atteindre,
   et en tête il se confondait avec la première pastille. */
/* L'entête ne défile pas avec les pastilles : le bouton d'ajout doit
   rester atteignable quelle que soit la position dans une liste qui compte
   souvent une vingtaine de contextes. Les pastilles passent dessous.
   Le fond est indispensable — sans lui, on verrait les pastilles défiler
   au travers. */
.contextes-entete {
  position: sticky;
  /* top: -4px et non 0.
     Un élément collant se cale sur la BOÎTE DE REMBOURRAGE du conteneur
     défilant. La colonne ayant 4 px de rembourrage, « top: 0 » plaçait
     l'entête 4 px SOUS le bord de la colonne, et les pastilles défilaient
     dans cette bande — la « petite fenêtre » observée. La marge négative
     seule ne suffisait pas : elle déplace la position naturelle, mais la
     contrainte « top: 0 » la ramenait aussitôt vers le bas.
     -4px aligne la ligne de calage sur le bord de la colonne, et la marge
     négative fait de même pour la position naturelle : l'entête ne bouge
     donc plus du tout, collé ou non. */
  top: -4px;
  z-index: 2;
  background-color: var(--couleur-accent-clair);
  /* L'entête déborde du rembourrage de la colonne, DES QUATRE CÔTÉS.
     La colonne a 4 px de rembourrage. En haut, c'est ce qui créait la
     « petite fenêtre » : un élément collant se cale sur la BOÎTE DE
     REMBOURRAGE du conteneur défilant, donc 4 px plus haut que là où
     commence son contenu. Les pastilles traversaient cette bande de 4 px
     entre le bord de la colonne et le sommet de l'entête, et l'on voyait
     un fragment de liste y défiler.
     La marge haute négative comble exactement cette bande — trouvaille de
     l'utilisateur, et l'explication vaut d'être notée : « top: 0 » ne
     pouvait rien y faire, puisque l'entête y était DÉJÀ collé. Le décalage
     ne venait pas du positionnement mais du rembourrage du parent.
     Les marges latérales suivent la même logique, avec un rembourrage
     compensatoire pour que le contenu ne se déplace pas. */
  margin-top: -4px;
  margin-left: -4px;
  margin-right: -4px;
  padding-left: 6px;
  padding-right: 6px;
  padding-top: 4px;
  /* Un fond translucide laisserait voir les pastilles au travers : la
     couleur doit être pleinement opaque. */
  opacity: 1;
  display: flex;
  align-items: center;
  /* Le logo retiré, le « + » se retrouve seul : on le pousse à droite,
     là où l'œil le cherche depuis qu'il y était avec le logo. */
  justify-content: flex-end;
  gap: 8px;
  /* Compact, mais assez détaché de la première pastille pour qu'on ne
     confonde pas le « + » avec elle — c'est précisément ce qui l'avait
     fait chasser de la liste. */
  padding: 0 2px 6px;
  margin-bottom: 8px;
  border-bottom: 2px solid var(--couleur-bordure);
}
.contextes-logo {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
}
.btn-nouveau-contexte {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  border: none;
  /* Cible confortable au doigt, sans les 36 px carrés d'origine qui
     débordaient de l'entête. */
  min-width: 40px;
  min-height: 34px;
}

/* ---------- police choisie à l'intérieur des arbres ----------
   zTreeStyle.css contient « .ztree * { font-family: Verdana, ... } » — un
   sélecteur universel, et la feuille est chargée APRÈS style.css sur
   arbre.php. À spécificité égale, c'est elle qui l'emportait : le serif et
   OpenDyslexic n'atteignaient donc jamais le texte des tâches, alors même
   que la classe était bien posée sur <body>.
   On préfixe par body pour passer devant (0,2,1 contre 0,1,0) plutôt que
   de modifier zTreeStyle.css, qui serait écrasée à la prochaine mise à
   jour de la bibliothèque. */
body.police-sans .ztree, body.police-sans .ztree * {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
body.police-serif .ztree, body.police-serif .ztree * {
  font-family: Georgia, "Times New Roman", "Liberation Serif", serif;
}
body.police-opendyslexic .ztree, body.police-opendyslexic .ztree * {
  font-family: 'OpenDyslexic', sans-serif;
}
/* zTree fixe aussi font-size:12px sur tout son contenu, ce qui rend les
   tâches nettement plus petites que sur le tableau : on rend la main à la
   taille du thème. L'espacement des caractères étant exprimé en em, il
   suit automatiquement. */
body .ztree, body .ztree * { font-size: calc(0.95rem * var(--echelle-texte)); }

/* zTreeStyle.css fixe des hauteurs et des interlignes en PIXELS :
   line-height:14px sur li, height:17px sur a, line-height:16px sur span.
   Prévus pour du texte de 12 px, ils ne bougent pas quand la taille
   augmente : les lignes se chevauchaient dès qu'on dépassait 100 %.
   On repasse en unités relatives, qui suivent la taille choisie.
   Les span.button sont EXCLUS : ce sont les cases à cocher et les boutons
   de dépliage, dessinés depuis une image-sprite dont les coordonnées sont
   en pixels — les redimensionner casserait le découpage. */
/* L'arbre est une vue de STRUCTURE : on y cherche à embrasser beaucoup de
   lignes d'un coup d'œil, bien plus que sur le tableau. Son interligne est
   donc nettement plus serré — assez toutefois pour que les descendantes
   des lettres (p, g, j) ne touchent pas la ligne suivante. */
body .ztree li { line-height: 1.15; }
body .ztree li a {
  height: auto;
  min-height: 1.2em;
  line-height: 1.15;
  padding: 0 3px 0 0;
}
body .ztree li span:not(.button) { line-height: 1.15; }
body .ztree li a span.node_name { white-space: normal; }

/* Tableau des tailles de texte (page Préférences) : une ligne par vue,
   une colonne par type d'écran. Une grille de quatre champs isolés aurait
   obligé à répéter « tableau / grand écran » dans chaque étiquette. */
.pref-tableau-tailles { border-collapse: collapse; margin-top: 4px; }
.pref-tableau-tailles th,
.pref-tableau-tailles td { padding: 3px 10px 3px 0; text-align: left; font-weight: normal; }
.pref-tableau-tailles tr:first-child th { font-size: 0.85em; opacity: 0.8; }
.pref-tableau-tailles tr > th:first-child { font-weight: 600; }
.pref-pourcentage input {
  width: 4.5em;
  padding: 2px 4px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  /* La police du champ suit celle choisie par l'utilisateur (cf. les
     sélecteurs .police-* qui descendent jusqu'aux input). */
}

/* ---------- vue arbre : état « partiellement coché » ----------
   zTree distingue quatre états de case, dont deux « partiels ». Quand on
   coche un seul petit-enfant, tous ses ascendants passent en
   checkbox_true_part — une case qui porte la coche, et que l'on lit
   naturellement comme « fait ».
   Or Toddo n'a que deux états : une ligne est cochée si et seulement si
   TOUTES ses sous-lignes le sont (cf. render_task). Un ascendant dont une
   seule descendante reste décochée n'est PAS fait, et ne doit pas en avoir
   l'air. On lui donne donc l'apparence de l'état partiel NON coché
   (background-position 0 -28px au lieu de -14px -28px), qui reste
   distinct de la case vide : le repère « il y a du travail en cours
   là-dedans » est conservé, sans le faux message « c'est terminé ». */
/* « body » en tête : sans lui, ce sélecteur est le SOSIE exact de celui de
   zTreeStyle.css, qui est chargée APRÈS style.css sur arbre.php — à
   spécificité égale, la dernière déclarée gagne, et la règle ci-dessous
   n'avait donc aucun effet. Le même piège que pour la police. */
body .ztree li span.button.chk.checkbox_true_part { background-position: 0 -28px; }
body .ztree li span.button.chk.checkbox_true_part_focus { background-position: 0 -42px; }

/* ---------- vue arbre : couleur de fond du contexte ----------
   Toutes les tâches de l'arbre appartiennent au contexte affiché : sa
   couleur est posée une seule fois sur <body> (--couleur-taches) et
   reprise ici sur chaque nœud, plutôt que répétée sur chacun.
   On teinte le LIEN (le texte de la tâche) et non le <li> entier : c'est
   la surface qui correspond à la carte du tableau, et cela laisse les
   cases à cocher sur le fond de la page, où elles restent lisibles. */
/* On teinte le <li> DE PREMIER NIVEAU — c'est-à-dire la tâche entière,
   sous-lignes comprises — et non le lien seul.
   Teinter le lien ne colorait qu'un ruban de la largeur du texte, laissant
   des trous partout ailleurs ; le bloc, lui, correspond exactement à la
   carte du tableau. Le sélecteur enfant direct (« > ») est ce qui limite
   la règle aux tâches : les sous-lignes sont des <li> imbriqués et
   héritent de la couleur de leur tâche, sans se redessiner par-dessus. */
/* Bandeau de priorité des tâches de l'arbre, posé par onNodeCreated
   (js/arbre.js). Mêmes largeur et couleurs que sur le tableau, pour que les
   deux vues se lisent de la même façon. Le bandeau est indépendant de la
   couleur de contexte : une tâche non colorée en a un aussi. */
body .ztree > li.arbre-prio0 { border-left: 9px solid transparent; }
body .ztree > li.arbre-prio1 { border-left: 9px solid var(--couleur-priorite1); }
body .ztree > li.arbre-prio2 { border-left: 9px solid var(--couleur-priorite2); }
body .ztree > li.arbre-prio3 { border-left: 9px solid var(--couleur-priorite3); }

/* Les tâches passaient SOUS l'ascenseur : la liste occupait toute la
   largeur de la zone, sans réserver les 18 px de la piste. C'est la même
   marge que sur le tableau (cf. .item2 { margin-right: 22px }). */
body .ztree { margin-right: 22px; }

body[data-ctx-couleur] .ztree > li {
  background-color: var(--couleur-taches);
  border-radius: var(--rayon);
  /* Sans marge, les tâches successives formeraient un unique aplat de
     couleur où l'on ne verrait plus où l'une finit et l'autre commence.
     Écrite en RACCOURCI (margin) et non en margin-bottom : zTreeStyle.css
     pose « margin: 0 » sur .ztree li, et un raccourci réinitialise les
     quatre côtés — mieux vaut lui répondre sur le même terrain que de
     compter sur l'ordre de résolution entre raccourci et propriété
     détaillée. */
  margin: 0 0 2px 0;
  /* Resserré en même temps que l'interligne : sans cela, le gain obtenu
     sur les lignes aurait été repris par les marges entre les blocs. */
  padding: 1px 4px;
  box-sizing: border-box;
}
/* Même règle que pour les cartes du tableau : les huit pastels sont
   clairs, un texte clair (mode sombre) y serait illisible. */
body[data-ctx-couleur] .ztree > li,
body[data-ctx-couleur] .ztree > li a,
body[data-ctx-couleur] .ztree > li span:not(.button) { color: #2b2f36 !important; }
/* Le nœud sélectionné garde son fond ambre, repère familier de zTree. */
body[data-ctx-couleur] .ztree li a.curSelectedNode { background-color: #FFE6B0; }

/* Case mère « en cours » : au moins une sous-tâche cochée, mais pas toutes.
   Même symbole (la tâche n'est PAS faite), teinte grisée — exactement ce
   que montre la vue arbre, qui dispose d'un état intermédiaire natif.
   Les deux vues disaient jusqu'ici des choses différentes de la même
   tâche. */
.case.case-partielle {
  color: #9aa4ae;
  text-shadow: 0 0 1px rgba(0, 0, 0, 0.15);
}
.mode-sombre .case.case-partielle { color: #6e7A85; }

/* Sélection des émoticônes (page Préférences) : une grille de cases, plus
   compacte qu'une liste pour une vingtaine d'entrées. */
.pref-smileys {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 2px 8px;
  margin-top: 4px;
}
.pref-smiley {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px;
  border-radius: var(--rayon);
  cursor: pointer;
}
.pref-smiley:hover { background-color: rgba(0, 0, 0, 0.05); }
.pref-smiley-emoji { font-size: 1.2em; line-height: 1; }
.pref-smiley-code { font-family: ui-monospace, monospace; font-size: 0.8em; opacity: 0.75; }

/* La barre d'onglets n'a de sens qu'en portrait : en paysage les sept
   colonnes sont déjà toutes visibles côte à côte. */
.onglets-zones { display: none; }
@media screen and (max-aspect-ratio: 13/9) { .onglets-zones { display: flex; } }


/* Titre de zone : couleurs reprises du style inline retiré d'index.php et
   d'arbre.php. Elles n'avaient rien à faire dans le PHP — c'est de
   l'apparence, et les avoir en feuille permet au mode sombre de les
   reprendre.
   ATTENTION : cette règle est en FIN de fichier, donc APRÈS le bloc
   portrait. Y déclarer « position » écraserait le « sticky » que ce bloc
   pose sur le titre — c'est ce qui est arrivé : le titre se retrouvait en
   « relative » avec un décalage de 135 px, glissant par-dessus les tâches
   au lieu de les coiffer. Le positionnement du paysage est donc déclaré
   dans sa propre media query, ci-dessous. */
.ContextManagment {
  background-color: gray;
  color: white;
}
/* En paysage seulement : ancre le bouton d'archivage, qui est en position
   absolue dans le titre. En portrait le titre est « sticky », ce qui ancre
   tout aussi bien. */
@media screen and (min-aspect-ratio: 13/9) {
  .ContextManagment { position: relative; }
}

/* Pastille de contexte survolée pendant un glisser-déposer : même vidéo
   inversée que les onglets de zones. Les deux sont des cibles de dépôt, le
   retour visuel doit être le même — sans quoi on hésite sur ce qui va
   recevoir la tâche.
   L'inversion porte sur toute la surface, y compris le texte : à côté d'une
   vingtaine de pastilles aux couleurs proches, un simple contour se
   remarquerait à peine. */
.contexte-pastille.pastille-survolee,
.coin .contexte-pastille.pastille-survolee,
.colonne-contextes .contexte-pastille.pastille-survolee {
  background-color: var(--couleur-texte) !important;
  color: var(--couleur-fond) !important;
  border-color: var(--couleur-texte) !important;
}
/* Le pastille porte parfois une pastille de couleur (badge) : elle doit
   rester visible sur le fond inversé. */
.contexte-pastille.pastille-survolee [class^="cercle"] { filter: invert(1); }

/* ---------- page « Mes accès » ---------- */
.tableau-acces {
  border-collapse: collapse;
  width: 100%;
  margin: 0.6em 0 1em;
}
.tableau-acces th,
.tableau-acces td {
  text-align: left;
  padding: 7px 10px;
  border-bottom: 1px solid var(--couleur-bordure);
  vertical-align: top;
}
.tableau-acces thead th { background-color: var(--couleur-accent-clair); }
.tableau-acces tbody th { font-weight: 600; white-space: nowrap; }
/* Le chiffrement n'est pas une façon d'entrer mais une façon de stocker :
   le trait le sépare des quatre lignes précédentes. */
.tableau-acces-separation th,
.tableau-acces-separation td { border-top: 3px solid var(--couleur-bordure); }
.acces-oui { color: #1a7f37; font-weight: 600; }
.acces-non { color: #6b6b6b; }
.acces-externe { color: #6b6b6b; font-style: italic; }
/* Le lien secret reste masqué jusqu'à ce qu'on le demande : sur un écran
   partagé, l'afficher d'emblée reviendrait à le publier. */
.lien-masque { letter-spacing: 2px; }
#lien-acces {
  display: inline-block;
  word-break: break-all;
  background-color: var(--couleur-accent-clair);
  padding: 6px 10px;
  border-radius: var(--rayon);
}
/* Sur écran étroit, un tableau à trois colonnes déborde : les cellules
   passent les unes sous les autres, chacune précédée de son intitulé. */
@media screen and (max-width: 600px) {
  .tableau-acces thead { display: none; }
  .tableau-acces tr { display: block; margin-bottom: 12px; }
  .tableau-acces th, .tableau-acces td { display: block; border-bottom: none; }
  .tableau-acces tbody th { background-color: var(--couleur-accent-clair); border-radius: var(--rayon); }
  .tableau-acces tr { border-bottom: 1px solid var(--couleur-bordure); }
}

/* ---------- arbre de décision (page « Mes accès ») ---------- */
.arbre-acces {
  border: 1px solid var(--couleur-bordure);
  border-radius: 12px;
  padding: 14px 16px;
  margin: 0.6em 0 1.2em;
}
.arbre-intitule { font-weight: 600; margin: 0 0 4px; }
/* La précision est ce qui rend la question répondable : sans elle,
   « sensible » veut tout et rien dire. Elle est donc lisible, pas reléguée
   en gris pâle. */
.arbre-precision { margin: 0 0 12px; opacity: 0.8; font-size: 0.92em; }
.arbre-acces .bouton { min-width: 96px; min-height: 44px; margin-right: 8px; }
.arbre-resultat h3 { margin: 0 0 6px; }
.arbre-resultat p { margin: 0 0 10px; }
/* La mention du chiffrement se distingue : elle s'AJOUTE à la
   recommandation, elle ne la remplace pas. */
#arbre-chiffrement {
  border-left: 4px solid var(--couleur-accent);
  padding-left: 10px;
  border-radius: 0;
}
.liste-appareil { margin: 0.4em 0 1.2em; padding-left: 1.2em; }
.liste-appareil li { margin-bottom: 8px; }

/* ---------- corbeille de l'entête des contextes ----------
   Elle fait face au « + » aux deux extrémités de la même bande, sur TOUS
   les écrans. Les deux gestes sont voisins — ranger, jeter — et les deux
   cibles se trouvent au même endroit, là où l'on manipule les contextes.
   Elle reprend l'allure du « + » : pas de cadre, pas de fond, la couleur
   d'accent et une grande taille. Ce sont deux boutons de même nature,
   ils doivent se ressembler. */
.corbeille-contextes {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: auto;   /* colle au bord gauche, pousse le « + » à droite */
  padding: 0;
  border: none;
  background: none;
  box-shadow: none;
  color: var(--couleur-accent);
  font-size: 2.4em;
  line-height: 1;
  cursor: pointer;
}
.corbeille-contextes:hover,
.corbeille-contextes:active {
  background: none;
  transform: none;
}
/* Celle de la barre d'outils disparaît partout : deux cibles de dépôt
   simultanées prêteraient à confusion — on ne saurait pas laquelle vise le
   glissement.
   !important nécessaire : la règle de dimensionnement des boutons utilise
   « :not(#etat-sauvegarde) », et un :not() prend la SPÉCIFICITÉ de son
   argument — cet identifiant lui donne donc plus de poids qu'un sélecteur
   d'identifiant simple. Contre-intuitif, et suffisant pour que
   « display: none » soit ignoré. */
.barre-outils #btn-corbeille { display: none !important; }

/* ---------- formulaire « Mes accès » ----------
   Compact : trois groupes, une commande par ligne. Le texte
   d'accompagnement est fourni ailleurs — la page ne porte que les leviers. */
.formulaire-acces { margin: 0.4em 0 1.2em; max-width: 34em; }
.acces-bloc {
  border: 1px solid var(--couleur-bordure);
  border-radius: 10px;
  padding: 8px 14px 12px;
  margin: 0 0 12px;
}
.acces-bloc legend { font-weight: 600; padding: 0 6px; }
.acces-ligne {
  display: flex;
  align-items: center;
  gap: 10px;
  /* 44 px : hauteur minimale d'une cible tactile. Cocher ici engage la
     sécurité du compte, ce n'est pas l'endroit où viser juste. */
  min-height: 44px;
  cursor: pointer;
  margin: 0;
}
.acces-ligne input[type="checkbox"] { width: 20px; height: 20px; flex: 0 0 auto; }
/* Les boutons d'action se rangent sur une ligne et passent à la suivante
   quand l'écran est étroit, plutôt que de déborder. */
.acces-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 0; }
/* .acces-note portait « font-size: 0.93em » ET « opacity: 0.85 » : deux
   réductions cumulées, sur des textes qui expliquent des réglages de
   sécurité — c'est-à-dire précisément ceux qu'il faut lire. Le gris pâli
   d'un texte explicatif est une habitude de maquette, pas un service rendu.
   Taille normale, opacité pleine. */
.acces-note { margin: 8px 0; font-size: 1em; }
#lien-acces {
  display: inline-block;
  word-break: break-all;
  background-color: var(--couleur-accent-clair);
  padding: 6px 10px;
  border-radius: var(--rayon);
}
.lien-masque { letter-spacing: 2px; }
.bouton-principal { font-weight: 600; }

/* ==========================================================================
   SÉLECTION MULTIPLE DE TÂCHES
   ==========================================================================

   On entre dans ce mode par un appui long (ou un clic droit) sur une carte,
   pour déplacer ou jeter plusieurs tâches d'un coup.

   POURQUOI UN CONTOUR ET NON UN FOND. Sur une carte .item2, presque tout est
   déjà pris : le fond porte le mode sombre ET la couleur de contexte (style
   inline), le bord gauche porte le bandeau de priorité (.item2.colorN), les
   trois autres bords servent en mode sombre, et l'ombre signale le survol.
   « outline » ne participe pas à la mise en page — aucune carte ne se décale
   au moment où on clique dessus — et se dessine EN DEHORS du bord, donc sans
   jamais toucher au bandeau de priorité. C'est le même raisonnement, et la
   même valeur, que .arbre-cible-survolee et .ztree a.arbre-trouve. */
.item2.selectionnee {
  outline: 3px solid var(--couleur-accent);
  outline-offset: 2px;
}

/* Pendant la sélection, le clic ne sert plus à éditer ni à cocher : le
   curseur le dit avant qu'on ait cliqué. */
.mode-selection .item2 { cursor: pointer; }

/* Barre d'actions. C'est ELLE qui répond vraiment à « combien de tâches sont
   sélectionnées » : sur un tableau long, compter des contours après avoir
   défilé n'a aucun sens. Compteur, actions et sortie au même endroit.

   En bas plutôt qu'en haut : c'est le côté atteignable au pouce sur mobile,
   et la barre d'outils occupe déjà le haut. */
.barre-selection {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 16px;
  z-index: 5500; /* au-dessus du chat flottant (5000) : elle est modale par nature */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: #fff;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-moyenne);
  max-width: calc(100vw - 24px);
}
.barre-selection-compte { font-weight: 600; white-space: nowrap; }
.barre-selection button {
  /* 44 px : hauteur minimale d'une cible tactile. « Corbeille » est
     irréversible d'un geste (récupérable, mais il faut le savoir) : ce n'est
     pas l'endroit où viser juste. */
  min-height: 44px;
  padding: 8px 12px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  background: var(--couleur-fond);
  color: var(--couleur-texte);
  cursor: pointer;
  font-family: inherit;
  font-size: inherit;
}
.barre-selection button:hover { background: var(--couleur-accent-clair); }

/* Liste déroulante des contextes de destination. Elle s'ouvre VERS LE HAUT :
   la barre est déjà collée au bas de l'écran. */
.barre-selection-contextes {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 50vh;
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  box-shadow: var(--ombre-moyenne);
  display: flex;
  flex-direction: column;
}
.barre-selection-contextes button {
  border: none;
  border-radius: 0;
  text-align: left;
  width: 100%;
}

.mode-sombre .barre-selection,
.mode-sombre .barre-selection-contextes {
  background: #262b30;
  border-color: #363c43;
}
.mode-sombre .barre-selection button {
  background: #2f353b;
  border-color: #363c43;
  color: #e6e9ec;
}
.mode-sombre .barre-selection button:hover { background: #3a4149; }

/* Icône de la corbeille (cf. icone_corbeille(), utils.php). Une image
   remplace l'ancien caractère « 🗑 », qui dépendait de la police système et
   n'avait pas le même dessin d'un appareil à l'autre.

   Hauteur en em et non en pixels : les boutons suivent l'échelle de texte
   réglable dans les Préférences, l'icône doit grandir avec eux.

   pointer-events:none — indispensable : la corbeille est une CIBLE DE DÉPÔT,
   et sans cela l'image intercepterait le dragover/drop à la place du bouton
   qui la contient. Le glisser-déposer cessait de fonctionner dès qu'on
   visait le centre de l'icône. */
.icone-corbeille {
  height: 1.6em;
  width: auto;
  vertical-align: middle;
  pointer-events: none;
}

/* Page « Mes accès » — sections issues de la fusion avec l'ancienne page du
   code PIN (cf. set_pin.php, devenu une redirection). */
.acces-erreur { color: var(--couleur-priorite3); }
.acces-avertissement {
  color: var(--couleur-priorite3);
  font-weight: bold;
  max-width: 60ch;
}
.acces-recuperation {
  margin-top: 10px;
  padding: 10px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
}
.acces-bloc input[type="password"] { max-width: 32em; width: 100%; box-sizing: border-box; }

/* Bloc « en cas de vol » : signalé sans crier. Une bordure d'accent à gauche
   suffit à le distinguer — un fond rouge pleine largeur ferait fuir la
   lecture de la seule section qu'il faut justement lire calmement. */
.acces-urgence {
  border-left: 4px solid var(--couleur-priorite3);
}
.acces-urgence ol { max-width: 70ch; padding-left: 1.4em; }
.acces-urgence li { margin-bottom: 0.6em; }

/* Jauge d'occupation des pièces jointes. Présente dans le panneau (au moment
   de choisir un fichier) et dans les Préférences (pour aller vérifier). */
.attachments-quota { margin: 10px 0; }
.attachments-quota-jauge {
  height: 8px;
  border-radius: 4px;
  background: var(--couleur-bordure);
  overflow: hidden;
}
.attachments-quota-jauge span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--couleur-accent);
  transition: width 0.2s ease;
}
/* Au-delà de 80 %, un pourcentage cesse d'être une information pour devenir
   un avertissement — la couleur suit. */
.attachments-quota-alerte .attachments-quota-jauge span { background: var(--couleur-priorite3); }
.attachments-quota-texte {
  margin: 4px 0 0;
  font-size: 0.9em;
  opacity: 0.85;
}

@media (prefers-reduced-motion: reduce) {
  .attachments-quota-jauge span { transition: none; }
}

/* Page de première connexion (bienvenue.php). Volontairement étroite : c'est
   une décision à prendre, pas un tableau de bord à parcourir. */
.bienvenue { max-width: 40rem; margin: auto; }
.bienvenue-intro { font-size: 1.05em; }
.bienvenue input[type="password"] { max-width: 32em; width: 100%; box-sizing: border-box; }
/* Le renoncement est séparé par un filet : visible et atteignable, sans
   concurrencer le choix recommandé. Le déguiser en lien minuscule reviendrait
   à forcer la main tout en prétendant laisser le choix. */
.bienvenue-renoncer {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--couleur-bordure);
}

/* Bloc « appareil perdu » de la page d'accueil. Signalé par un filet
   d'accent, pas par un fond criard : c'est une section qu'il faut lire
   calmement, au moment précis où l'on est le moins calme. */
.accueil-urgence {
  margin-top: 0.8rem;
  padding-left: 0.8rem;
  border-left: 4px solid var(--couleur-priorite3);
}
.accueil-alerte { font-weight: bold; }
.accueil-etapes { padding-left: 1.3em; }
.accueil-etapes li { margin-bottom: 0.5em; }
.accueil-note { font-size: 0.92em; opacity: 0.85; }

/* Sélecteur de langue de la page d'accueil : discret mais atteignable. La
   barre d'outils, qui porte ce bouton partout ailleurs, n'existe pas ici. */
.accueil-langue { text-align: right; margin: 0 0 0.5rem; }

/* PAGE « MES ACCÈS » — séparation des protections.
   Elles étaient visuellement interchangeables : des cadres identiques, à la
   suite, qu'on lisait comme un seul réglage en plusieurs cases. Or ce sont
   des choses indépendantes — changer de lien, poser un code, chiffrer — et
   les confondre conduit à se croire protégé quand on ne l'est pas.

   Chaque pavé a donc SA teinte de fond : la couleur devient une information
   (« je ne suis plus dans la même protection »), pas une décoration. Elles
   restent très pâles — le texte doit rester le sujet — et sont doublées d'un
   filet à gauche, pour rester distinguables sans percevoir les couleurs. */
.acces-bloc {
  margin-bottom: 28px;
  /* Le retrait à gauche est celui qui manquait : le texte partait au ras du
     cadre. 22 px de confort, et le filet coloré ne mord pas dessus. */
  padding: 16px 20px 20px 22px;
  border-left: 5px solid var(--couleur-accent);
}
.acces-bloc legend {
  font-size: 1.14em;
  padding: 0 8px;
}
.acces-bloc p,
.acces-bloc label { max-width: 68ch; }  /* au-delà, l'œil perd la ligne */

.acces-bloc-lien         { background: #eef4f7; border-left-color: #3d7a8c; }
.acces-bloc-code         { background: #f3f1f8; border-left-color: #7b6cab; }
.acces-bloc-otp          { background: #f1f5ef; border-left-color: #6b8f5e; }
.acces-bloc-chiffrement  { background: #fdf5ec; border-left-color: #c98a3e; }
.acces-urgence           { background: #fdf0f0; border-left-color: var(--couleur-priorite3); }

/* Mode sombre : les mêmes teintes en clair seraient éblouissantes. On garde
   l'écart entre les pavés en assombrissant, pas en éclaircissant. */
.mode-sombre .acces-bloc-lien        { background: #233034; }
.mode-sombre .acces-bloc-code        { background: #2a2833; }
.mode-sombre .acces-bloc-otp         { background: #262e26; }
.mode-sombre .acces-bloc-chiffrement { background: #332c22; }
.mode-sombre .acces-urgence          { background: #342527; }

/* Le renoncement doit rester lisible : un texte rapetissé sous un bouton
   reviendrait à décourager le choix qu'on prétend offrir. La taille vient
   maintenant de .acces-note lui-même ; il reste à le passer à la ligne. */
.bienvenue-renoncer .acces-note {
  display: block;
  margin-top: 8px;
}

/* Liste des émoticônes dans la documentation (cf. tableau_smileys, aide.php).
   Remplace un tableau d'une ligne par symbole, qui occupait à lui seul plus
   d'un écran. */
.aide-smileys {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  margin: 10px 0;
}
.aide-smiley {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  border: 1px solid var(--couleur-bordure);
  border-radius: var(--rayon);
  white-space: nowrap;
}
.aide-smiley code { background: none; padding: 0; }

/* ==========================================================================
   PAGE « MES ACCÈS » — corrections de mise en page
   ==========================================================================

   Trois défauts, trois causes distinctes.

   1. CONTENU COLLÉ AU BORD. Le corps de page porte « margin: 0 » (dans les
      deux requêtes de média), et le contenu de cette page est posé
      directement dans <body>, sans conteneur. Rien ne l'écartait donc du
      bord de l'écran. On ajoute la marge sur les blocs eux-mêmes plutôt que
      sur <body>, dont dépend la mise en page du tableau.

   2. TEXTE TROP PETIT. La feuille laisse 1 rem en paysage, mais
      « max-width: 34em » comprimait tout dans une colonne étroite, ce qui
      fait paraître le texte plus petit qu'il n'est. On élargit ET on
      agrandit un peu — ces pages sont faites pour être lues, pas survolées.

   3. TITRE À CHEVAL SUR LE BORD. C'est le comportement NORMAL d'un <legend>
      dans un <fieldset> : il se place SUR la bordure haute. Invisible tant
      que le fond était blanc, criant depuis que chaque pavé a sa teinte —
      le titre se retrouve à moitié dedans, à moitié dehors. On le sort de
      ce mécanisme en le passant en bloc flottant. */

.formulaire-acces {
  max-width: 52em;
  margin: 0.4em 16px 1.2em;
}

/* Les pavés hors du formulaire (chiffrement, urgence) sont des enfants
   directs de <body> : ils ont besoin de la même marge. */
body > .acces-bloc,
body > .acces-urgence {
  max-width: 52em;
  margin-left: 16px;
  margin-right: 16px;
}

.acces-bloc {
  font-size: 1.05em;
  line-height: 1.55;
}

/* Le <legend> cesse de chevaucher la bordure : en bloc flottant, il devient
   un titre ordinaire posé À L'INTÉRIEUR du pavé. Le float évite l'espace
   fantôme que laisse un legend passé en display:block dans certains
   navigateurs. */
.acces-bloc legend {
  float: left;
  width: 100%;
  margin: 0 0 10px;
  padding: 0;
  font-size: 1.16em;
  font-weight: 600;
}
/* Un flottant ne pousse pas son parent : sans cela le pavé se refermerait
   sur le titre. */
.acces-bloc legend + * { clear: left; }

@media screen and (max-width: 700px) {
  /* Sur téléphone, 16 px de marge de chaque côté coûtent cher en largeur
     utile : on les réduit sans jamais revenir à zéro. */
  .formulaire-acces,
  body > .acces-bloc,
  body > .acces-urgence { margin-left: 10px; margin-right: 10px; }
  .acces-bloc { padding: 14px 14px 16px 16px; }
}

/* Le pavé « en cas de vol » est une <section> avec un <h2>, non un fieldset :
   il n'a jamais eu le problème du legend, mais son titre doit avoir la même
   apparence que les autres — sans quoi il paraîtrait d'un autre niveau. */
.acces-bloc > h2 {
  margin: 0 0 10px;
  font-size: 1.16em;
  font-weight: 600;
}

/* Page « Soutenir Toddo ». Étroite et sobre : c'est une demande, elle ne doit
   pas ressembler à une bannière publicitaire — ce serait exactement ce que
   Toddo promet de ne pas faire. */
.soutien { max-width: 46em; margin: 0 16px 2em; line-height: 1.55; }
.soutien-action { margin: 1.6em 0 0.8em; }
.soutien ul { padding-left: 1.3em; }
.soutien li { margin-bottom: 0.4em; }
