/* Feuille de style du front adm.
   La barre de navigation reste celle de l'ancien adm — navy #2a3542, filet vert,
   entrée active sur fond noir. Le tableau de bord, lui, adopte un langage plus
   actuel : fond blanc, blocs en cartes bordées, tableaux denses sans zébrure,
   badges d'état en pastilles. */

:root {
	--fond: #fff;
	--carte: #fff;
	--bord: #eee;
	--bord-fin: #eef2f6;
	--texte: #1f2a37;
	/* LE GRIS SECONDAIRE PORTE DE L'INFORMATION — numéros de client, type de suivi,
	   forme juridique, auteur d'une mise à jour : il tient 4,5:1 sur blanc (6,03), sur
	   l'en-tête (5,71) et sur la ligne survolée (5,17), en retrait du texte (14,5). */
	--muet: #566477;
	--tete: #f7f9fb;
	--survol: #e5eff7;
	--accent: #3ba776;
	/* Même mesure pour les deux bleus, celui des liens et celui des boutons pleins,
	   fond d'un libellé blanc : 5,15 et 4,78, dans les deux sens. */
	--lien: #4094a2;
	/* Le vert de la maison au survol, mais FONCÉ : le vert clair s'effacerait au
	   moment où l'on vise le lien. 5,67 sur blanc, 4,87 sur la ligne survolée. */
	--lienHover: #337681;
	/* Les actions en TEXTE — « Nouveau suivi », « Commenter », boutons-liens :
	   cliquables sans être des boutons pleins. */
	--lien-action: #4094a2;
	/* CE QUI S'EFFACE : l'indication dans un champ vide, un objet de suivi non
	   renseigné, un mois qui n'a pas encore eu lieu. En retrait du gris secondaire,
	   pour ne jamais être pris pour une valeur, mais lisible : 3,4:1 sur blanc. */
	--efface: #7f8c9b;
	/* Un geste que le serveur refuserait — crayon, corbeille ou croix : visible, et
	   éteint (`.est-verrouille`). */
	--verrouille: #cfd5db;
	--focus: #4393bd;
	--danger: #b42318;
	--navbar: #2a3542;
	/* Gouttière entre les blocs : colonnes, blocs empilés et version empilée
	   partagent cette valeur, qui gouverne à TOUTES les largeurs — les media
	   queries n'ajustent que les largeurs de colonnes et les marges extérieures,
	   jamais la gouttière, sinon le réglage n'aurait plus d'effet passé un seuil. */
	--gap: 18px;
	--radius: 6px;

	/* L'ÉCHELLE DES TEXTES : quatre crans, écrits ICI et nulle part ailleurs ; la
	   lisibilité se règle en une ligne.

	     mini   les en-têtes de colonnes, compteurs, marques
	     petit  le texte secondaire : méta, libellés, badges
	     base   le texte courant, cellules, champs, boutons
	     fort   noms et titres de bloc

	   Les titres au-delà (15 px et plus) et les ICÔNES gardent leur taille en
	   dur : une icône ne grossit pas avec le texte qui l'accompagne.
	   Pour un adm plus gros ou plus serré, c'est ici qu'on règle — les quatre
	   ensemble, d'un même pas. */
	--t-mini: 11px;
	--t-petit: 12px;
	--t-base: 13px;
	--t-fort: 14px;

	/* L'HELVETICA NEUE DE L'ANCIEN ADM, rendue comme lui, sans lissage (voir `body`) :
	   c'est ce rendu que les utilisateurs lisent le mieux. */
	--police: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

/* ============================================================================
   SOCLE — ce que Bootstrap 4 fournissait, et rien de plus
   ============================================================================
   Quatre classes — `.btn`, `.form-control`, `.text-truncate`, `.sr-only` — et le
   Reboot des balises nues que les vues emploient. Ce qui s'écarte de Bootstrap le
   dit sur place : `.form-control` à l'échelle des contrôles maison, `.btn-primary`
   à la teinte des actions (`--lien-action`), les liens `<a>` nus à `--lien`.

   Il est placé EN TÊTE, où Bootstrap se trouvait dans `index.html` : à spécificité
   égale, la règle qui suit l'emporte, et tous les correctifs de ce fichier comptent
   sur cet ordre.

   `1rem` = 16 px : `html` n'a pas de `font-size`, les 13 px du thème (`--t-base`)
   sont posés sur `body`. Les valeurs en `rem` sont donc laissées telles quelles.

   NE PAS étoffer ce bloc : ce n'est pas un reset d'usage général. Une balise
   nouvelle dans une vue se style dans sa propre section. */

/* Reboot n'est repris que pour les balises que les vues emploient réellement ;
   chaque omission a sa raison :

   - fieldset, legend, hr, small, blockquote, address, svg, kbd, pre, samp, et les
     entrées `number` et `search` : aucune vue ne les emploie ;
   - `h1 { font-size: 2.5rem }`, `h6 { font-size: 1rem }` : seul `<h4>` est employé ;
   - `h4 { font-size: 1.5rem }` : les cinq `<h4>` sont tous dans `.dialogue` ou
     `.comm-dialogue`, qui imposent 15 px (0,1,1 contre 0,0,1) ;
   - `html { font-family: sans-serif; line-height: 1.15 }` : `body` pose la police
     et l'interligne du thème, dont tout hérite ; rien ne se peint sur `html` ;
   - `body`, `* { box-sizing }` : ce fichier les pose déjà ;
   - `table { border-collapse: collapse }` : les deux seuls tableaux du front,
     `.tb_liste` et `.ecriture-panier-liste`, déclarent chacun le leur — et le
     premier veut `separate`, qu'exigent ses en-têtes collants ;
   - `th { text-align: inherit }` : les `<th>` vivent tous dans `.tb_liste`, qui
     pose `text-align: left` ;
   - `code { color: #e83e8c }` : la règle `code` plus bas pose `--lien`. */
html {
	/* Safari mobile grossit sinon le texte au basculement en paysage, et pose un
	   voile gris à chaque tape. */
	-webkit-text-size-adjust: 100%;
	-webkit-tap-highlight-color: transparent;
}

/* `font-weight: 500` compte : sans lui les cinq `<h4>` — tous des titres de
   dialogue de confirmation — repassent au gras du navigateur (700). Leur taille,
   elle, vient de `.dialogue h4` / `.comm-dialogue h4` (15 px), qui écrasait déjà
   le 1.5rem de Bootstrap. */
h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: .5rem; font-weight: 500; line-height: 1.2; }
p { margin-top: 0; margin-bottom: 1rem; }
dl, ol, ul { margin-top: 0; margin-bottom: 1rem; }
ol ol, ol ul, ul ol, ul ul { margin-bottom: 0; }
b, strong { font-weight: bolder; }
img { vertical-align: middle; border-style: none; }

/* `--lien`, et non plus le bleu de Bootstrap : voir l'avertissement du bloc. */
a { color: var(--lien); text-decoration: none; background-color: transparent; }
a:hover { color: var(--lienHover); text-decoration: none!important; }
/* Une ancre sans `href` ni classe n'est pas un lien : ni couleur, ni soulignement. */
a:not([href]):not([class]) { color: inherit; text-decoration: none; }
a:not([href]):not([class]):hover { color: inherit; text-decoration: none; }

/* Les codes de base des sociétés et des abonnements. `kbd`, `pre` et `samp` ne
   sont pas reprises : aucune vue ne les emploie. Le 87,5 % vient de la
   typographie de Bootstrap, qui écrasait le `1em` de son propre Reboot — l'oublier
   grossissait les six `<code>`. La couleur est posée plus bas, sur `--lien`. */
code {
	font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
	font-size: 100.5%;
	word-wrap: break-word;
}

/* Les 82 `<label>` sans classe tiennent d'ici leur bloc en ligne et leurs 8 px
   de dessous. */
label { display: inline-block; margin-bottom: .5rem; }

/* LA règle qui compte : sans `font: inherit`, les 152 boutons, 63 champs, 18
   listes et 11 zones de texte repassent à la police du navigateur — 13,33 px
   Arial sous Chrome contre les 13 px Helvetica du thème. */
button, input, optgroup, select, textarea {
	margin: 0;
	font-family: inherit;
	font-size: inherit;
	line-height: inherit;
}
button { border-radius: 0; }
button, input { overflow: visible; }
button, select { text-transform: none; }
select { word-wrap: normal; }
textarea { overflow: auto; resize: vertical; }
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; padding: 0; }
[type="button"], [type="reset"], [type="submit"], button { -webkit-appearance: button; }
[type="button"]:not(:disabled), [type="reset"]:not(:disabled),
[type="submit"]:not(:disabled), button:not(:disabled) { cursor: pointer; }
/* Firefox pose un liseré intérieur sur les boutons, invisible jusqu'au focus. */
[type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner, button::-moz-focus-inner { padding: 0; border-style: none; }
/* Le clic ne doit pas laisser d'anneau : seul le clavier le mérite. */
button:focus:not(:focus-visible) { outline: 0; }
::-webkit-file-upload-button { font: inherit; -webkit-appearance: button; }

/* --- Les quatre classes qui restaient ------------------------------------- */

.btn {
	display: inline-block;
	font-weight: 400;
	color: #212529;
	text-align: center;
	vertical-align: middle;
	user-select: none;
	background-color: transparent;
	border: 1px solid transparent;
	padding: .375rem .75rem;
	font-size: 1rem;
	line-height: 1.5;
	border-radius: .25rem;
	transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
.btn:hover { color: #212529; text-decoration: none; outline:none!important;}
.btn.focus, .btn:focus { outline: 0; box-shadow: 0 0 0 .2rem rgba(64, 148, 162, .25);outline:none!important; }
.btn.disabled, .btn:disabled { opacity: .65; }
.btn:not(:disabled):not(.disabled) { cursor: pointer; outline:none!important;}
/* Un `<a class="btn">` désactivé reste cliquable sans ça — popup_documents.js en
   pose un. */
a.btn.disabled, fieldset:disabled a.btn { pointer-events: none; }

.btn-sm { padding: .25rem .5rem; font-size: .875rem; line-height: 1.5; border-radius: .2rem; outline:none!important;}

/* Le bleu Bootstrap est TRANCHÉ ici : le bouton d'action prend la teinte des
   actions (`--lien-action`), ses états des nuances assombries de la même — le
   survol est celui de `.bloc-action`, pour que toute la famille réponde
   pareil. L'anneau de focus reprend la teinte en transparence. Blanc dessus :
   4,78 au repos, 6,2 au survol, 7,4 enfoncé. */
.btn-primary { color: #fff; background-color: var(--lien-action); border-color: var(--lien-action); outline:none!important;}
.btn-primary:hover { color: #fff; background-color: #16659a; border-color: #135a89; outline:none!important;}
.btn-primary.focus, .btn-primary:focus {
	color: #fff; background-color: #16659a; border-color: #135a89;
	box-shadow: 0 0 0 .2rem rgba(27, 120, 180, .45);outline:none!important;
}
.btn-primary.disabled, .btn-primary:disabled { color: #fff; background-color: var(--lien-action); border-color: var(--lien-action); }
.btn-primary:not(:disabled):not(.disabled):active,
.btn-primary:not(:disabled):not(.disabled).active { color: #fff; background-color: #135a89; border-color: #125682; }
.btn-primary:not(:disabled):not(.disabled):active:focus,
.btn-primary:not(:disabled):not(.disabled).active:focus { box-shadow: 0 0 0 .2rem rgba(27, 120, 180, .45); }

.btn-danger { color: #fff; background-color: #dc3545; border-color: #dc3545; }
.btn-danger:hover { color: #fff; background-color: #c82333; border-color: #bd2130; }
.btn-danger.focus, .btn-danger:focus {
	color: #fff; background-color: #c82333; border-color: #bd2130;
	box-shadow: 0 0 0 .2rem rgba(225, 83, 97, .5);
}
.btn-danger.disabled, .btn-danger:disabled { color: #fff; background-color: #dc3545; border-color: #dc3545; }
.btn-danger:not(:disabled):not(.disabled):active,
.btn-danger:not(:disabled):not(.disabled).active { color: #fff; background-color: #bd2130; border-color: #b21f2d; }
.btn-danger:not(:disabled):not(.disabled):active:focus,
.btn-danger:not(:disabled):not(.disabled).active:focus { box-shadow: 0 0 0 .2rem rgba(225, 83, 97, .5); }

/* LE CHAMP DE SAISIE DU FRONT, décidé ici : le dessin de `.select-annee`
   (l'échelle des contrôles du front, 30 px). Les contextes ne disent que ce qui
   LEUR est propre : leur hauteur et leur rembourrage. */
.form-control {
	display: block;
	/* `width: 100%` est structurel, pas décoratif : plusieurs règles plus bas s'en
	   servent comme base de `flex-basis` (voir la note sur les formulaires à deux
	   colonnes de champs). */
	width: 100%;
	height: 30px;
	padding: 0 8px;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--carte);
	color: var(--texte);
	font: inherit;
	box-shadow: none;
	transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
}
/* Un filet d'un pixel, pas l'anneau de 3 px de Bootstrap : les champs vont par
   sept ou huit dans un popup, et l'anneau empiéterait sur le voisin. Un champ
   composé (les adresses en pastilles) le prend quand l'un de ses champs a le focus. */
.form-control:focus, .form-control:focus-within {
	border-color: var(--focus);
	outline: 0;
	box-shadow: 0 0 0 1px var(--focus);
}
.form-control::placeholder { color: var(--efface); opacity: 1; }
.form-control:disabled, .form-control[readonly] { background: var(--tete); color: var(--muet); }
textarea.form-control { height: auto; padding: 6px 8px; line-height: 1.5; }
/* Sans ça, Safari impose sa propre hauteur aux deux entrées `date`. */
input[type="date"].form-control, input[type="datetime-local"].form-control,
input[type="month"].form-control, input[type="time"].form-control { appearance: none; }

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

/* Lu par les lecteurs d'écran, invisible à l'œil. */
.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Bootstrap coupait ses transitions sous ce réglage ; le socle en hérite. */
@media (prefers-reduced-motion: reduce) {
	.btn, .form-control { transition: none; }
}

/* ======================= fin du socle ==================================== */

/* LA CASE À COCHER — dessinée une seule fois, comme `.form-control` : la case
   native varie d'un navigateur à l'autre et jurait à côté des contrôles
   maison. Le dessin vit ici ; les contextes — cellule de tableau
   (`.case-cellule`), ligne de popup (`.popup-case`), option de relance
   (`.rappel-option`) — ne disent que leur mise en place.
   `vertical-align` cale la case sur le texte des contextes en ligne ; les
   contextes en flex l'ignorent sans dommage.

   Le dessin est celui de Redox (redox/css/desktop.css, « Style input checkbox /
   radio ») : 17 px, coins à 3 px, bordure #d9d9d9, et la couleur d'action au
   survol, au focus et à la coche — chez Redox `--color-info`, ici
   `--lien-action`, la même que celle des boutons : une case et un bouton d'un
   même formulaire ne doivent pas se contredire. La marque est peinte en FOND et
   non en pseudo-élément, comme chez
   Redox : un input est un élément remplacé, et Chrome et Firefox ne
   positionnent pas identiquement un `::after` à l'intérieur — la coche
   d'adm, tracée en bordures tournées, se décalait d'un pixel selon le
   navigateur. Un `background-position: center` est interopérable au pixel.
   Les boutons radio suivent, pour ne pas dépareiller le jour où l'un paraît. */
input[type="checkbox"],
input[type="radio"] {
	appearance: none;
	-webkit-appearance: none;
	flex: 0 0 auto;
	position: relative;
	box-sizing: border-box;
	width: 17px; height: 17px;
	margin: 0;
	padding: 0;
	border: 1px solid #d9d9d9;
	border-radius: 3px;
	background-color: #fff;
	vertical-align: middle;
	cursor: pointer;
	outline: none;
	transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}

input[type="radio"] { border-radius: 50%; }

input[type="checkbox"]:hover,
input[type="radio"]:hover {
	border-color: var(--lien-action);
	background-color: #eef4f6;
}

input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
	border-color: var(--lien-action);
	box-shadow: 0 0 0 3px rgba(64, 148, 162, .2);
}

input[type="checkbox"]:checked,
input[type="radio"]:checked { border-color: var(--lien-action); }

input[type="checkbox"]:checked {
	background-color: var(--lien-action);
	background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 10 3 3 6-7'/></svg>");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 15px 15px;
}

/* « Une partie seulement » : un trait, jamais une coche. Confondre les deux ferait
   croire que tout est sélectionné. */
input[type="checkbox"]:indeterminate {
	background-color: #fff;
	border-color: var(--lien-action);
	background-image: linear-gradient(var(--lien-action), var(--lien-action));
	background-repeat: no-repeat;
	background-position: center;
	background-size: 8px 2px;
}

input[type="radio"]:checked {
	background-color: #fff;
	background-image: radial-gradient(circle at center, var(--lien-action) 4px, transparent 4.6px);
	background-repeat: no-repeat;
	background-position: center;
}

input[type="checkbox"]:disabled,
input[type="radio"]:disabled,
input[type="checkbox"]:disabled:hover,
input[type="radio"]:disabled:hover {
	cursor: not-allowed;
	background-color: #f5f5f5;
	border-color: #e0e0e0;
}

input[type="checkbox"]:checked:disabled { background-color: #bdbdbd; border-color: #bdbdbd; }
input[type="radio"]:checked:disabled { background-image: radial-gradient(circle at center, #bdbdbd 4px, transparent 4.6px); }

/* Mise en page pleine hauteur : la page elle-même ne défile jamais. La barre de
   navigation, le bandeau de titre, les onglets et les en-têtes de colonnes
   restent visibles, seuls les corps de tableaux bougent. `min-height: 0` sur les
   enfants flex est indispensable : sans lui, un enfant refuse de descendre sous
   la hauteur de son contenu et le défilement interne ne s'active jamais. */
html, body { height: 100%; }

body {
	margin: 0;
	/* 1.4 : 18,2 px de ligne à 13 px, et les listes gardent leur nombre de lignes. */
	font: 400 var(--t-base)/1.4 var(--police);
	color: var(--texte);
	background: var(--fond);
	/* PAS DE `-webkit-font-smoothing: antialiased` : il amincit les lettres sur Mac,
	   et à 12 ou 13 px l'Helvetica Neue y perd la moitié de sa graisse. L'ancien adm ne
	   le pose pas, et c'est ce rendu que l'utilisateur lit le mieux. */
}

#application {
	height: 100%;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.is-hidden { display: none !important; }
.tright { text-align: right; }
code { color: var(--lien); }

#application > .booting,
.chargement { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; color: var(--muet); }
.erreur { padding: 20px; color: #c62828; }

/* Connexion ----------------------------------------------------------------- */

/* --- L'écran de connexion --------------------------------------------------------
   Repris au langage du reste de l'application — surface blanche, coins adoucis,
   les mêmes variables — plutôt qu'au Bootstrap 3 de l'ancien adm : carte grise
   sur fond noir, angles à 1 px, graisses fines. C'est la première chose qu'on
   voit le matin, elle doit ressembler à ce qui suit. */
#login-page {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	display: flex;
	align-items: center;
	justify-content: center;
	/* La carte est remontée : le rembourrage BAS est plus épais que le haut, ce qui
	   décale le centrage optique vers le haut. Exprimé en `vh`, le décalage suit la
	   taille de l'écran au lieu d'être juste sur un seul. Le minimum garde la carte
	   d'aplomb sur un écran court. */
	padding: 24px 16px max(64px, 30vh);
	/* Un fond calme et profond, avec deux halos très doux : de la présence sans
	   décoration. Un aplat noir écraserait la carte, un blanc la dissoudrait. */
	background:
		radial-gradient(900px 480px at 22% 12%, rgba(59, 167, 118, .16), transparent 62%),
		radial-gradient(760px 420px at 82% 84%, rgba(67, 147, 189, .18), transparent 60%),
		linear-gradient(160deg, #202a36 0%, #2a3542 55%, #1c242e 100%);
}

.login-carte {
	width: 100%;
	max-width: 380px;
	padding: 34px 32px 30px;
	border: 1px solid rgba(255, 255, 255, .06);
	border-radius: 12px;
	background: var(--carte);
	box-shadow: 0 18px 48px rgba(8, 14, 22, .34), 0 2px 6px rgba(8, 14, 22, .18);
}

/* Le logo de la maison — le fichier même qu'impriment les contrats et les
   lettres. Sa hauteur est fixée, sa largeur suit : la source fait 300 × 68, on
   l'affiche à 150 pour que les densités doubles restent nettes. */
.login-marque { display: flex; justify-content: center; }
.login-marque img {
	width: 90px;
	margin-bottom: 16px;
	height: auto;
	/* Le fichier est un aplat blanc sans transparence : sur la carte blanche, il
	   se fond — inutile de le détourer. */
	display: block;
}


.login-faute {
	margin: 0 0 16px;
	padding: 9px 11px;
	border: 1px solid #f3ccc8;
	border-left: 3px solid var(--danger);
	border-radius: 5px;
	background: #fdf3f2;
	color: #8f2b23;
	font-size: var(--t-base);
	line-height: 1.35;
}

.login-champ { display: block; margin-bottom: 14px; }
/* L'icône est DANS le champ, et le champ entier réagit au focus — la bordure et
   l'icône ensemble, pour que l'œil sache où il est sans chercher le curseur. */
.login-boite {
	position: relative;
	display: flex;
	align-items: center;
}
.login-boite > i:first-child {
	position: absolute;
	left: 12px;
	color: #b9c4ce;
	font-size: 13px;
	pointer-events: none;
	transition: color .15s ease;
}
.login-boite input {
	width: 100%;
	height: 42px;
	padding: 0 12px 0 36px;
	border: 1px solid var(--bord-fin);
	border-radius: 8px;
	background: var(--tete);
	color: var(--texte);
	font-size: var(--t-fort);
	transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.login-boite input::placeholder { color: var(--efface); }
.login-boite input:focus {
	outline: none;
	background: #fff;
	border-color: var(--focus);
	box-shadow: 0 0 0 3px rgba(67, 147, 189, .16);
}
.login-boite:focus-within > i:first-child { color: var(--focus); }

/* Voir ce qu'on tape. Sur un clavier suisse, une frappe manquée se diagnostique
   en une seconde au lieu de trois essais refusés. */
.login-oeil {
	position: absolute;
	right: 4px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	border: 0;
	border-radius: 6px;
	background: none;
	color: #b9c4ce;
	cursor: pointer;
	font-size: 13px;
}
.login-oeil:hover { color: var(--muet); background: var(--survol); }

.login-bouton {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	height: 42px;
	margin-top: 20px;
	border: 0;
	border-radius: 8px;
	background: var(--lien);
	color: #fff;
	cursor: pointer;
	font-size: var(--t-fort);
	font-weight: 600;
	transition: background .15s ease, transform .06s ease;
}
.login-bouton:hover { background: #005f94; }
.login-bouton:active { transform: translateY(1px); }
.login-bouton:disabled, .login-bouton.est-occupe { background: #8fbfd8; cursor: default; }
.login-spin { font-size: 13px; }

/* Le second temps du mode redox : la demande est partie vers l'app du téléphone, et
   le bloc prend la place des champs. Le compte à rebours garde sa largeur en défilant. */
.login-validation {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	text-align: center;
}
.login-validation > i { font-size: 28px; color: var(--lien); }
.login-validation-texte { margin: 0; color: var(--texte); font-size: var(--t-fort); font-weight: 600; }
.login-rebours { margin: 0; color: var(--muet); font-size: var(--t-base); font-variant-numeric: tabular-nums; }
.login-annuler {
	height: 36px;
	margin-top: 8px;
	padding: 0 18px;
	border: 1px solid var(--bord-fin);
	border-radius: 8px;
	background: var(--carte);
	color: var(--texte);
	cursor: pointer;
	font-size: var(--t-base);
}
.login-annuler:hover { background: var(--survol); }
.login-annuler:disabled { color: var(--efface); cursor: default; }

@media (max-width: 480px) {
	.login-carte { padding: 28px 22px 24px; }
}

/* Barre de navigation -------------------------------------------------------- */

.navbar-my {
	flex: 0 0 auto;
	/* Repère de positionnement du panneau déroulant sur écran étroit. */
	position: relative;
	z-index: 30;
	display: flex;
	align-items: stretch;
	min-height: 43px;
	min-width: 0;
	background: var(--navbar);
	color: #fff;
	font-weight:400;
	font-size: var(--t-base);
}

/* Bouton d'ouverture du menu : absent tant que la barre tient en largeur. */
.navbar-toggle {
	display: none;
	align-items: center;
	padding: 0 14px;
	background: none;
	border: 0;
	color: #bbb;
	font-size: 15px;
	cursor: pointer;
}

.navbar-toggle:hover { background: #000; color: #fff; }

.navbar-my .navbar-brand {
	display: flex; align-items: center;
	padding: 0 15px;
	/* Ces trois lignes ne servent pas le texte — c'est le logo — mais le `alt`
	   qu'elles habillent : si l'image ne se charge pas, « Golink SA » s'affiche à sa
	   place, et doit rester lisible sur la barre. */
	font-size: 18px; font-weight: 400; color: #aaa;
	white-space: nowrap;
}
/* 22 px dans une barre haute de 40 : le logo respire sans la dilater. La largeur
   suit le rapport 300/68 du fichier plutôt qu'un chiffre écrit à la main, qui
   déformerait la marque au premier logo remplacé. */
.navbar-my .navbar-logo { display: block; height: 18px; width: auto; }

/* La piste du menu, horizontale comme celle de l'ancien adm : cette règle porte
   seule sa mise en page. Quand la largeur manque, le menu défile horizontalement
   en interne plutôt que de replier une entrée ou de pousser la page. */
.navbar-my .nav {
	display: flex;
	flex-direction: row;
	margin: 0;
	padding: 0;
	list-style: none;
	overflow-x: auto;
	scrollbar-width: none;
}

.navbar-my .nav::-webkit-scrollbar { display: none; }
.navbar-my .nav li { display: flex; }

.navbar-my .nav a {
	display: flex; align-items: center;
	padding: 10px 15px;
	color: #eee;
	text-decoration: none;
	white-space: nowrap;
}

.navbar-my .nav a:hover { background: #000; color: #ccc; }
.navbar-my .nav a:not(.dropdownItem).activer { background: #000; }
.navbar-my .nav a.dropdownItem.activer { background: #eee; }

/* Menu déroulant d'un groupe. Il vit DANS son entrée, et c'est `dropdownRedox`
   en `strategy: 'fixed'` qui le positionne : la piste `.nav` défile
   horizontalement, et un panneau posé dedans y serait rogné — sauf en
   positionnement fixe, qu'un `overflow` ordinaire ne rogne pas. Le dernier
   groupe ne déborde donc pas de l'écran. */
.navbar-my .nav-groupe .fa-caret-down { margin-left: 5px; font-size: 10px; opacity: .7; }
/* L'ENTRÉE OUVERTE SE DÉDUIT DE L'ÉTAT DU GREFFON, elle ne se suit plus à la
   main. `dropdownRedox` pose `.show` sur la RACINE autant que sur le panneau : la
   couleur en découle, et ne peut donc pas diverger.
   Une classe entretenue en JavaScript restait noire sur le groupe qu'on venait de
   quitter — le gestionnaire ne connaissait que le lien CLIQUÉ, jamais celui que le
   greffon refermait dans le même geste. */
.navbar-my .nav li.nav-groupe-boite.show > a.nav-groupe { background: #000; color: #fff; }
/* L'entrée porte le greffon : `inline-block` casserait l'alignement des `li` de
   la piste, qui sont en `flex`. */
.navbar-my .nav li.nav-groupe-boite { display: flex; position: relative; }

/* Le panneau reprend l'habillage SOMBRE de la barre : les autres menus de l'app
   sont clairs sur fond clair, celui-ci pend d'une barre ardoise et doit lui
   appartenir. On surcharge donc la base du greffon. */
.navbar-my .dropdownContent.nav-tiroir {
	min-width: 200px;
	padding: 4px 0;
	background: #fff;
	border: 1px solid #ddd;
	border-radius: 0 0 6px 6px;
	box-shadow: 0 6px 14px rgba(16, 24, 40, .28);
}

.navbar-my .dropdownContent.nav-tiroir .dropdownItem {
	display: block;
	padding: 8px 15px;
	border-radius: 0;
	color: #333;	
	font-size: var(--t-fort);
	text-decoration: none;
	white-space: nowrap;
}

.navbar-my .dropdownContent.nav-tiroir .dropdownItem:hover { background: #eee; }

.navbar-my .nav-spacer { flex: 1 1 auto; }

/* Le nom de l'utilisateur OUVRE son compte : c'est un bouton, pas une étiquette.
   Il en garde pourtant l'apparence au repos — la barre ne doit pas se mettre à
   ressembler à une rangée de boutons —, et ne se déclare cliquable qu'au survol
   et au clavier. */
.navbar-my .user-badge {
	display: flex; align-items: center; gap: 7px;
	padding: 0 12px;
	white-space: nowrap;
	background: none; border: 0;
	color: inherit; font: inherit;
	cursor: pointer;
	align-self: stretch;
}
.navbar-my .user-badge .fa-user-circle { font-size: 15px; opacity: .8; }
.navbar-my .user-badge:hover .fa-user-circle { opacity: 1; }
/* Le contour ne paraît qu'au clavier : `:focus-visible` et non `:focus`, sinon
   il resterait après le clic qui vient d'ouvrir la fenêtre. */
.navbar-my .user-badge:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

.navbar-my .nav_logout {
	display: flex; align-items: center;
	padding: 0 15px;
	color: #4ca64c;
	text-decoration: none;
	font-size: 14px;
}

.navbar-my .nav_logout:hover { background: #000; }

/* Bandeau de titre ----------------------------------------------------------- */

/* Onglets applicatifs ---------------------------------------------------------
   Plusieurs écrans restent ouverts et se retrouvent d'un clic. Le DOM de chaque
   onglet reste vivant, simplement masqué : la position de défilement et la
   recherche saisie survivent à la bascule. */

.onglets {
	flex: 0 0 auto;
	display: flex;
	align-items: stretch;
	gap: 0px;	
	padding: 0px 0px;
	background: #e8e9e9;
	/* border-bottom: 1px solid var(--bord); */
	overflow-x: auto;
	scrollbar-width: none;
}

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

/* Quand les onglets dépassent la fenêtre, la barre devient un rail qui défile :
   l'ascenseur est masqué, ce sont deux flèches et deux dégradés de bord qui le
   disent, et ils ne paraissent QUE dans ce cas — une barre qui tient n'a rien à
   annoncer. `onglets.js` mesure le débordement et pose `deborde`, `a-gauche`,
   `a-droite` sur le cadre ; la molette y défile en horizontal et l'onglet activé
   est ramené dans le champ. Le fond est porté par le cadre : les flèches sont
   hors du rail, elles doivent se fondre dans la même bande. */
.onglets-cadre {
	flex: 0 0 auto;
	position: relative;
	display: flex;
	align-items: stretch;
	min-width: 0;
	background: #dbdfe1;
}

.onglets-cadre .onglets { flex: 1 1 auto; min-width: 0; scroll-behavior: smooth; }

.onglets-fleche {
	display: none;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	width: 26px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--muet);
	font: inherit;
	font-size: 11px;
	cursor: pointer;
}

.onglets-fleche:hover { background: #eaeef2; color: var(--texte); }
.onglets-fleche[disabled] { opacity: .3; cursor: default; background: transparent; }
.onglets-cadre.deborde .onglets-fleche { display: inline-flex; }

/* Les dégradés couvrent le bord du rail, contre chaque flèche ; ils ne se
   montrent que du côté où il reste des onglets à découvrir. */
.onglets-cadre::before,
.onglets-cadre::after {
	content: "";
	position: absolute;
	top: 0; bottom: 0;
	width: 36px;
	opacity: 0;
	transition: opacity .15s;
	pointer-events: none;
	z-index: 1;
}
.onglets-cadre::before { left: 26px; background: linear-gradient(to right, #dbdfe1, rgba(219, 223, 225, 0)); }
.onglets-cadre::after { right: 26px; background: linear-gradient(to left, #dbdfe1, rgba(219, 223, 225, 0)); }
.onglets-cadre.a-gauche::before, .onglets-cadre.a-droite::after { opacity: 1; }

.onglet {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	max-width: 220px;
	padding: 8px 10px 8px 15px;
	background: transparent;
	border: 1px solid transparent;
	border-bottom: 0;
	border-radius: 0 0;
	font: inherit;
	font-size: var(--t-base);
	white-space: nowrap;
	cursor: pointer;
}

.onglet:hover { background: #eaeef2; color: var(--texte); }

/* L'onglet actif se prolonge dans le contenu : son fond blanc et le filet
   interrompu sous lui le rattachent à l'écran affiché. */
.onglet.is-actif {
	background: var(--carte);
	/* border-color: var(--bord); */
	color: var(--texte);
	
}

.onglet-titre { overflow: hidden; text-overflow: ellipsis; }

/* L'icône de l'écran, devant son titre. Discrète tant que l'onglet dort — c'est
   le titre qu'on lit —, elle prend la couleur du lien sur l'onglet actif : sur
   une barre de dix onglets, c'est elle qui dit où l'on est avant le mot.
   `flex: 0 0 auto` la protège du rétrécissement : un onglet serré perd son titre
   (ellipse), jamais son signe. */
.onglet-icone {
	/* Pas de marge : `.onglet` est un flex avec `gap: 8px`, qui espace déjà. */
	flex: 0 0 auto;
	font-size: 12px;
	color: var(--muet);
}
.onglet.is-actif .onglet-icone { color: var(--lien); }

.onglet-fermer {
	flex: 0 0 auto;
	/* Le gris secondaire, et non un gris plus clair : sur une barre de dix onglets,
	   une croix sous 4,5:1 se devine plus qu'elle ne se voit. */
	color: var(--muet);
	font-size: 10px;
	line-height: 1;
	padding: 2px;
	border-radius: 3px;
}

.onglet-fermer:hover { background: #dde3e8; color: var(--danger); }

/* Réordonnancement des onglets — le geste est écrit à la main dans `onglets.js`.
   L'onglet saisi est le vrai onglet, translaté sur place, et non la vignette
   translucide du glisser-déposer natif. Il garde donc son opacité pleine — c'est
   LUI qu'on déplace, pas une trace de lui — et passe au blanc, qui le détache du
   fond de la barre.
   L'ombre est LATÉRALE, et c'est imposé : la barre est un rail (`overflow-x`),
   elle rogne donc ce qui dépasse en haut et en bas, et un onglet fait toute sa
   hauteur — une ombre portée classique y serait coupée. De part et d'autre, elle
   passe, et c'est le bon axe : c'est là que l'onglet chevauche ses voisins. Elle
   sert aussi à le distinguer de l'onglet ACTIF, blanc lui aussi, quand le
   glissement le mène juste à côté. */
.onglet.est-glisse {
	position: relative;
	z-index: 2;
	background: var(--carte);
	color: var(--texte);
	box-shadow: -9px 0 12px -9px rgba(8, 14, 22, .45), 9px 0 12px -9px rgba(8, 14, 22, .45);
	cursor: grabbing;
}

/* Le curseur reste fermé sur toute la barre. `body.en-glissement` le pose déjà,
   mais `.onglet` déclare `pointer` pour son compte et l'emporterait sur chaque
   onglet que le curseur touche. */
body.en-glissement .onglet { cursor: grabbing; }

/* Les voisins s'écartent en glissant, jamais par saut : ce mouvement est ce qui
   montre le creux où l'onglet se posera. La transition n'existe QUE le temps du
   geste — au dépôt, les translations sont remises à zéro dans la même image que
   le déplacement dans le DOM, et une transition les ferait revenir en arrière.
   L'onglet saisi, lui, colle au curseur sans lissage, et ne retrouve la
   transition que pour se poser. Les 180 ms sont reprises dans `onglets.js`. */
.onglets.est-reorganisee .onglet { transition: transform .18s cubic-bezier(.2, .7, .3, 1); }
.onglets.est-reorganisee .onglet.est-glisse { transition: none; }
.onglets.est-reorganisee .onglet.est-glisse.se-pose { transition: transform .18s cubic-bezier(.2, .7, .3, 1); }

/* Le rail défile par pas d'une image pendant le geste : `smooth` y ajouterait son
   propre lissage, et le défilement traînerait derrière le curseur. */
.onglets-cadre .onglets.est-reorganisee { scroll-behavior: auto; }

#contenu-page {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

/* Un écran occupe tout l'espace de l'onglet : c'est lui qui porte la colonne
   flex dont dépend le défilement interne des tableaux. */
.ecran {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

.a-venir { padding: 0 18px; color: var(--muet); }

/* Grille du tableau de bord ---------------------------------------------------
   Trois colonnes : les suivis prennent la place restante, les deux colonnes
   latérales ont une largeur propre qui se resserre avec la fenêtre. Aucune
   hauteur en pixels : la grille occupe ce qui reste sous le bandeau. */

.dash {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: grid;
	grid-template-columns: minmax(0, 1fr) 320px 340px;
	gap: var(--gap);
	padding: 16px 18px;
}

.dash-suivis,
.dash-blocages,
.dash-stats {
	display: flex;
	flex-direction: column;
	gap: var(--gap);
	min-height: 0;
	min-width: 0;
}

/* Les deux listes de blocage se partagent la colonne, la plus longue en tête. */
.dash-blocages .bloc:first-child { flex: 3 1 0; }
.dash-blocages .bloc:last-child { flex: 2 1 0; }
.dash-stats .bloc { flex: 1 1 auto; }

/* Écran Adresses : une seule carte pleine largeur, sociétés et membres en
   onglets. Chaque volet porte sa zone défilante et son pied de total, d'où la
   colonne flex — sans elle, le pied flotterait sous une liste de hauteur libre.

   Le sélecteur double n'est pas un ornement : `.dash` est réajusté par quatre
   media queries écrites plus bas, à spécificité égale. Écrit `.dash-adresses`,
   ce réglage perdrait contre elles et l'écran retomberait sur les trois colonnes du
   tableau de bord, laissant 600 px de vide à droite. */
.dash.dash-adresses { grid-template-columns: minmax(0, 1fr); }
.dash-societes { min-height: 0; min-width: 0; }

/* Écrans de liste simple (Factures, Abonnements) : une carte pleine largeur, un
   titre et une recherche, une seule liste. Le sélecteur double, ici aussi,
   protège de la grille à trois colonnes que les media queries réaffirment plus
   bas. */
.dash.dash-liste { grid-template-columns: minmax(0, 1fr); }
.dash-carte { min-height: 0; min-width: 0; }

.dash-liste .volet {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
}

/* Écran Rapports -------------------------------------------------------------
   Les graphiques sont des barres CSS : le front n'embarque aucune bibliothèque,
   et une série de treize points n'en demande pas. Chaque graphique est mis à
   l'échelle de sa plus haute barre, calculée dans le gabarit. */

.rapport-corps {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	padding: var(--gap);
}

/* Les chiffres clés en tête : ce qu'on vient chercher d'abord. */
.rapport-chiffres {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--gap);
	margin-bottom: var(--gap);
}

.rapport-cle {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 12px 14px;
	border: 1px solid var(--bord);
	border-radius: var(--radius);
	background: var(--carte);
}

.rapport-etiquette { color: var(--muet); font-size: var(--t-petit); text-transform: uppercase; letter-spacing: .04em; }
.rapport-valeur { font-size: 20px; font-weight: 650; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.rapport-valeur.est-alerte { color: var(--danger); }
.rapport-valeur.est-muette { color: var(--muet); }
.rapport-detail { color: var(--muet); font-size: var(--t-petit); }

/* Le point d'interrogation ouvre une explication : un chiffre qu'on ne sait pas
   lire ne vaut rien. */
.rapport-aide {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 13px;
	height: 13px;
	border: 1px solid var(--bord);
	border-radius: 50%;
	color: var(--muet);
	font-size: var(--t-mini);
	cursor: help;
}

.rapport-note {
	margin: 0 0 var(--gap);
	padding: 9px 12px;
	border-left: 2px solid var(--bord);
	color: var(--muet);
	font-size: var(--t-petit);
}

/* Le conteneur d'un graphique ApexCharts. Sa hauteur est fixée ici, la
   bibliothèque s'y adapte : sans hauteur explicite, elle en choisit une par
   défaut qui ignore la place disponible. */
.rapport-graphe {
	margin-bottom: var(--gap);
	border: 1px solid var(--bord);
	border-radius: var(--radius);
	padding: 6px 4px 0;
}

/* Tableau et graphique côte à côte. Le tableau porte huit colonnes : il reçoit
   la plus grande part, et le graphique épouse sa hauteur plutôt que de s'étirer
   sur une colonne à moitié vide. */
.rapport-duo {
	display: grid;
	/* `min-content` : la piste du tableau ne descend pas sous sa largeur propre. À
	   huit colonnes, il sortirait sinon de sa carte à 1440 px et s'écrirait par-dessus
	   le graphique à 1280. */
	grid-template-columns: minmax(min-content, 1.25fr) minmax(0, 1fr);
	gap: var(--gap);
	align-items: start;
}

.rapport-graphe.est-cote { margin-bottom: 0; }

/* Un mois qui n'a pas encore eu lieu : présent pour que le tableau garde sa
   hauteur, effacé pour qu'on ne le lise pas comme un mois à zéro. */
.rapport-table tr.est-a-venir td { color: var(--efface); }
/* Les TOTAUX sont la ligne qu'on vient lire : ils n'héritent pas de l'en-tête —
   11 px, capitales grises — sous des lignes à 13 px. */
.rapport-table tfoot th.c-montant { font-size: var(--t-base); letter-spacing: 0; color: var(--texte); }

/* Les quatre courbes, deux par rangée. */
.rapport-mosaique {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--gap);
}

.rapport-vignette {
	min-width: 0;
	border: 1px solid var(--bord);
	border-radius: var(--radius);
	padding: 12px 14px 10px;
	background: var(--carte);
}

.rapport-titre { font-size: var(--t-base); font-weight: 650; letter-spacing: -.005em; }

/* Dans une vignette, le graphique n'a pas besoin de son propre encadré : la
   vignette le porte déjà. */
.rapport-vignette .rapport-graphe { border: 0; padding: 0; margin-bottom: 0; }
.rapport-vignette .rapport-note { margin-bottom: 8px; }

/* La bibliothèque pose ses propres polices : on la ramène à celle de
   l'application. */
.apexcharts-canvas text { font-family: inherit !important; }
.apexcharts-tooltip { font-family: inherit !important; }

/* Les tableaux d'un rapport ne défilent pas pour eux-mêmes : c'est le corps qui
   défile, sans quoi on perdrait le graphique en lisant les chiffres. */
.rapport-table { overflow-y: visible; border: 1px solid var(--bord); border-radius: var(--radius); }
@media (max-width: 860px) { .rapport-table .tb_liste th, .rapport-table .tb_liste td { padding-left: 6px; padding-right: 6px; } }

.rapport-marque {
	margin-left: 6px;
	padding: 0 6px;
	border-radius: 20px;
	background: #fffaeb;
	color: #b54708;
	font-size: var(--t-mini);
	font-weight: 400;
}

.rapport-mention { margin-left: auto; color: var(--muet); font-size: var(--t-petit); }
.c-montant.est-muette { color: var(--muet); }

/* Écran Paramètres -----------------------------------------------------------
   Quatre sections. « Général » empile des cartes thématiques ; les trois autres
   partagent le même maître/détail, liste à gauche et contenu à droite. */

/* La grille est bornée et ses cartes (.bloc) n'ont pas de plancher : une rangée
   prend la hauteur de ses cartes, sinon elles se chevauchent, et la grille défile. */
.param-grille {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	grid-auto-rows: max-content;
	gap: var(--gap);
	padding: var(--gap);
	align-content: start;
}

.param-carte { align-self: start; }

/* Ce qu'une carte porte hors de sa table — le logo, l'aide des taux — a son propre rembourrage. */
.param-carte-corps { padding: 10px 12px; }

.param-duo {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 2.2fr);
	gap: var(--gap);
	padding: var(--gap);
}

.param-liste, .param-detail { min-height: 0; min-width: 0; }

/* Un seul panneau visible à la fois ; c'est lui qui porte la colonne flex dont
   dépend le défilement du contenu. */
.param-panneau {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
}

/* Titre de regroupement dans la liste : ce n'est pas une ligne cliquable. */
.param-groupe td {
	background: var(--tete);
	color: var(--texte);
	font-weight: 650;
	font-size: var(--t-petit);
	text-transform: uppercase;
	letter-spacing: .04em;
}

.ligne_param { cursor: pointer; }
.param-liste .tb_liste tbody tr.param-groupe:hover td { background: var(--tete); }

/* L'ARBORESCENCE DES COURRIERS — le groupe est un nœud qui se déplie : chevron
   qui pivote, dossier ouvert ou fermé, compte à droite. Les modèles en sont les
   feuilles, en retrait, reliées par un trait de guide. */
.param-arbre tr.param-noeud td { padding: 0; cursor: pointer; user-select: none; }
.param-arbre .noeud {
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 7px 10px;
}
.param-arbre .noeud-chevron {
	flex: 0 0 auto;
	width: 10px;
	color: #9aa7b4;
	font-size: 9px;
	transition: transform 160ms ease;
}
.param-arbre .param-noeud.est-ouvert .noeud-chevron { transform: rotate(90deg); }
.param-arbre .noeud-dossier { flex: 0 0 auto; color: #b3bdc8; font-size: 12px; }
.param-arbre .param-noeud.est-ouvert .noeud-dossier { color: var(--lien); }
.param-arbre .noeud-libelle { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.param-arbre .noeud-compte {
	flex: 0 0 auto;
	padding: 0 7px;
	border-radius: 9px;
	background: rgba(100, 116, 139, 0.1);
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 600;
	line-height: 16px;
	letter-spacing: 0;
	text-transform: none;
}
/* Le nœud se clique : le survol doit le dire. */
.param-liste .param-arbre tbody tr.param-noeud:hover td { background: #e9edf1; }
.param-arbre tr.param-noeud:focus-visible,
.param-arbre tr.param-feuille:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* Les feuilles : en retrait sous le chevron, un trait vertical les rattache à
   leur groupe. */
.param-arbre tr.param-feuille td {
	position: relative;
	padding-left: 36px;
}
.param-arbre tr.param-feuille td::before {
	content: "";
	position: absolute;
	left: 14px;
	top: 0;
	bottom: 0;
	width: 1px;
	background: #e1e6ec;
}
.param-arbre .feuille-icone { margin-right: 7px; color: #b3bdc8; font-size: 11px; }
.param-arbre tr.param-feuille.est-actif .feuille-icone { color: var(--lien); }

.param-corps { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px; }
.param-champ + .param-champ { margin-top: 14px; }

.param-etiquette {
	display: block;
	margin-bottom: 3px;
	color: var(--muet);
	font-size: var(--t-petit);
	text-transform: uppercase;
	letter-spacing: .04em;
}

/* Les textes sont multi-lignes et doivent se lire tels qu'ils partiront. Le CSS
   rend les retours, jamais du HTML : tout est échappé. */
.param-texte {
	padding: 8px 10px;
	border: 1px solid var(--bord-fin);
	border-radius: var(--radius);
	background: var(--tete);
	white-space: pre-wrap;
	word-break: break-word;
}

.param-texte.est-long { min-height: 90px; }

.param-note { margin-top: 2px; color: var(--muet); font-size: var(--t-petit); font-weight: 400; text-transform: none; letter-spacing: 0; }

.param-vars { display: flex; flex-wrap: wrap; gap: 5px; }

.param-var {
	padding: 1px 7px;
	border-radius: 20px;
	background: #eef2f7;
	color: #4a5b6d;
	font-family: Menlo, Consolas, "Courier New", monospace;
	font-size: var(--t-mini);
}

/* Une variable que personne ne remplace partirait telle quelle au client. */
.param-var.est-inconnue { background: #fef3f2; border: 1px solid #fecdca; color: var(--danger); cursor: help; }

.param-marque {
	margin-left: 6px;
	padding: 0 6px;
	border-radius: 20px;
	background: #eef2f7;
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 400;
}

.param-marque.est-orpheline { background: #fffaeb; color: #b54708; cursor: help; }

/* Les trois signatures se lisent côte à côte, comme dans le popup qui les
   modifie : trois variantes courtes d'un même texte, qu'on compare d'un regard.
   Leurs cadres prennent la hauteur du plus long — trois boîtes inégales côte à
   côte se lisent comme un alignement raté. L'écart entre elles est celui de la
   grille : l'empilement de `.param-champ + .param-champ` ne vaut pas ici. */
.param-signatures {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 14px;
	margin-top: 14px;
	padding-top: 12px;
	border-top: 1px solid var(--bord-fin);
}
.param-signatures > .param-champ { display: flex; flex-direction: column; }
.param-signatures > .param-champ + .param-champ { margin-top: 0; }
.param-signatures .param-texte { flex: 1 1 auto; }

/* Sous 620 px, le panneau (pleine largeur depuis 1 100 px) ne leur laisse plus
   que 190 px chacune : elles s'empilent, comme dans le popup. */
@media (max-width: 620px) {
	.param-signatures { grid-template-columns: minmax(0, 1fr); }
}

.select-annee {
	flex: 0 0 auto;
	height: 30px;
	padding: 0 6px;
	border: 1px solid var(--bord);
	border-radius: 7px;
	background: var(--carte);
	color: var(--texte);
	width: 120px;
	font: inherit;
	font-variant-numeric: tabular-nums;
}

.select-annee:focus { border-color: var(--focus); outline: 0; }

/* Un compte fermé le dit : le 1020 n'a plus bougé depuis 2019. */
.compta-clos {
	margin-left: 4px;
	padding: 0 5px;
	border-radius: 20px;
	background: #f2f5f8;
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 400;
}

/* La nature de l'écriture, en retrait : c'est un repère, pas une donnée qu'on
   vient chercher. */
.compta-genre { color: var(--muet); font-size: var(--t-petit); }
.compta-genre.est-manuel { color: #8a6d3b; }

.compta-correction { margin-left: 8px; font-size: var(--t-petit); cursor: help; }

/* Le solde du compte, dans la tranche, juste avant le sélecteur d'exercice. Il est
   posé là parce que c'est le chiffre qu'on vient chercher — celui qu'on compare au
   relevé bancaire —, et non en pied de tableau où il faudrait le deviner. La bordure
   et le fond le détachent des onglets sans en faire un bouton : seul son jour se saisit. */
.compta-solde {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: baseline;
	gap: 8px;
	height: 30px;
	padding: 5px 10px;
	border: 1px solid var(--bord);
	border-radius: 7px;
	background: var(--tete);
	white-space: nowrap;
	cursor: help;
}

.compta-solde-nom { color: var(--muet); font-size: var(--t-petit); }

/* Le jour du solde, dans la pastille même : un champ de date du front, à la hauteur de
   la pastille. Le chiffre est celui de ce soir-là. */
.compta-solde-date {
	width: 86px;
	height: 20px;
	padding: 0 4px;
	font-size: var(--t-petit);
	font-variant-numeric: tabular-nums;
	text-align: center;
	cursor: text;
}
.compta-faute { color: var(--danger); font-size: var(--t-petit); white-space: nowrap; }
.compta-solde b { font-variant-numeric: tabular-nums; letter-spacing: -.01em; }

/* Un compte de trésorerie à découvert n'est pas une anomalie d'affichage : le
   chiffre le dit lui-même plutôt que d'attendre qu'on lise le signe. */
.compta-solde.est-negatif b { color: var(--danger); }

.tb_compta th:first-child, .tb_compta td:first-child { width: 1%; white-space: nowrap; }
.tb_compta td:nth-child(3) { width: 1%; white-space: nowrap; }


/* Numéros de facture et d'abonnement : deux formats cohabitent, on les aligne
   au chiffre pour que la colonne reste lisible. */
.c-num-fact { font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--muet); }
.c-montant { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }

/* Séparateurs du pied de liste : le total, puis ce qui le nuance. */
.pied-sep::before { content: "·"; margin: 0 7px; color: #c2ccd6; }
.pied-fort { color: var(--texte); font-weight: 600; }
.pied-alerte { color: #b54708; }

/* La liste est bornée : le dire, plutôt que de laisser croire à un décompte. */
.pied-borne {
	margin-left: 8px;
	padding: 0 6px;
	border: 1px solid var(--bord);
	border-radius: 20px;
	font-size: var(--t-mini);
}

/* Pied de liste : le total, toujours visible sous la zone défilante. */
/* Sur l'écran des rappels, le pied porte une phrase ET un groupe d'action : en
   grille, la phrase se replie à gauche et l'action reste à sa droite, au lieu de
   retomber seule sur une seconde ligne, calée à gauche (vu à 1280 px). */
.bloc-pied:has(> .rappel-action) { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 12px; }
.bloc-pied > .rappel-echecs { grid-column: 1 / -1; }
/* En fenêtre étroite l'action ne laisse plus que 230 px à la phrase : elle
   repasse dessous, calée à droite. */
@media (max-width: 960px) {
	.bloc-pied:has(> .rappel-action) { grid-template-columns: minmax(0, 1fr); row-gap: 6px; }
	.bloc-pied > .rappel-action { justify-self: end; }
}

.bloc-pied {
	flex: 0 0 auto;
	padding: 6px 12px;
	border-top: 1px solid var(--bord);
	background: var(--tete);
	color: var(--muet);
	font-size: var(--t-petit);
}

.c-numcli { font-variant-numeric: tabular-nums; color: var(--muet); white-space: nowrap; }
.c-npa { font-variant-numeric: tabular-nums; white-space: nowrap; }
.c-tel { font-variant-numeric: tabular-nums; white-space: nowrap; color: #4a5b6d; }

.c-base code { font-size: var(--t-petit); line-height: 1; color: var(--lien); }
.ligne_societe, .ligne_membre, .ligne_facture, .ligne_email { cursor: pointer; }

/* Blocs ---------------------------------------------------------------------- */

.bloc {
	display: flex;
	flex-direction: column;
	min-height: 0;
	min-width: 0;
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: var(--radius);
	/* box-shadow: 0 1px 2px rgba(16, 24, 40, .045); */
	overflow: hidden;
}

.dash-suivis { flex: 1 1 auto; }

.bloc-titre {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 4px 12px;
	border-bottom: 1px solid var(--bord-fin);
	background-color: var(--tete);
	font-size: var(--t-base);
	font-weight: 500;
	letter-spacing: -.005em;
}

.bloc-compte {
	flex: 0 0 auto;
	font-size: var(--t-mini);
	font-weight: 600;
	color: var(--muet);
	background: #eef2f7;
	border-radius: 20px;
	padding: 1px 7px;
}

/* Sections d'écran et recherche ------------------------------------------------
   Une section d'écran se présente comme la fiche société : les onglets en
   tranche de dossier, le classeur dessous. La barre d'onglets soulignée de
   l'ancien adm a disparu — un seul langage pour toutes les sections. */

/* La colonne qui porte la tranche et son classeur. */
.ecran-colonne {
	display: flex;
	flex-direction: column;
	min-height: 0;
	min-width: 0;
}

/* Le classeur et ses volets forment la CHAÎNE qui rend le défilement possible :
   sans hauteur bornée jusqu'à la zone défilante, `overflow-y: auto` ne trouve
   jamais de débordement et la table pousse la page à la place.
   La règle est GÉNÉRIQUE : le tableau de bord et les rappels ont la structure et les
   classes de l'écran Adresses, et défilent comme lui. Un motif nommé pareil doit se
   comporter pareil. */
.ecran-classeur {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
}

.ecran-classeur > .volet {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
}
.ecran-classeur > .volet.is-hidden { display: none; }

/* Recherche, sélecteur d'exercice : ce qui accompagne les onglets file à droite
   de la tranche, aligné sur leur base. */
.ecran-outils {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 10px;
}

/* Dans la tranche, la recherche ne pousse pas : c'est la piste d'onglets qui
   occupe la place restante. Quand la place manque, c'est elle qui cède, et la
   piste ne se resserre pas tant que le champ a de quoi donner : sinon le dernier
   onglet passerait sous le champ. `:has()` parce que la piste précède le champ
   dans le balisage ; la feuille s'en sert déjà pour les cellules à case. Sous
   1240 la colonne tombe à 417 px, la piste défilerait de toute façon : elle
   reprend le droit de se resserrer, dans la media query plus bas. */
.ecran-outils .search-inline { margin-left: 0; flex-shrink: 4; }
.ecran-piste:has(+ .ecran-outils .search-inline) { flex-shrink: 0; }
/* La barre d'outils ne rétrécit pas (`flex: 0 0 auto`)… sauf quand elle porte une
   recherche : avec la piste figée, elle déborderait de la colonne. Le champ est ce
   qui cède en elle, jusqu'à son minimum. */
.ecran-outils:has(> .search-inline) { flex-shrink: 1; min-width: 0; }

/* Une recherche qui OUVRE la tranche, devant les onglets — Adresses : c'est par
   elle qu'on entre dans les adresses, pas en parcourant la liste. La vue la sort
   de la barre d'outils, qui file au bout de la tranche comme partout, et la pose
   en premier enfant de la tranche, collée aux onglets et sur leur base, un peu
   plus large qu'ailleurs. La marge gauche automatique du champ, qui le pousse à
   droite partout ailleurs, est annulée : en tête de rangée elle l'enverrait au
   bout. L'enfant direct seul est visé — une recherche restée dans les outils,
   comme à l'accueil ou en comptabilité, n'est pas concernée.

   Quand la place manque, c'est la recherche qui cède, et elle seule : la piste
   qui la suit ne se resserre pas tant que le champ a de quoi donner, sans quoi
   elle défilerait et son dernier onglet passerait derrière le bouton. Sous 1240
   la piste reprend le droit de se resserrer, dans la media query plus bas, et le
   champ part de 240 px. */
.ecran-onglets > .search-inline { flex: 0 1 340px; margin: 0 1px 0 0; }
.ecran-onglets > .search-inline + .ecran-piste { flex-shrink: 0; }

/* La barre d'outils d'un RAPPORT, au-dessus du tableau qu'elle pilote — et non
   dans la barre d'onglets, commune à sept sections dont une seule la regarde. */
.rapport-outils { justify-content: flex-start; gap: 10px; }
.rapport-outils-cle { margin: 0; color: var(--muet); font-size: var(--t-base); }

/* Un bouton de la tranche ne se replie jamais sur deux lignes : il est étroit par
   nature, et « + Écriture » coupé en deux double la hauteur de toute la barre. */
.ecran-outils .btn { flex: 0 0 auto; white-space: nowrap; }

/* Le champ de recherche est un contrôle unique : loupe cliquable à gauche,
   effacement à droite, et la bordure entière réagit au focus. */
.search-inline {
	margin-left: auto;
	flex: 0 1 280px;
	min-width: 150px;
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 5px 8px;
	background: #fff;
	border: 1px solid var(--bord);
	border-radius: 7px;
}

.search-inline:focus-within { border-color: var(--focus); box-shadow: 0 0 1px var(--focus); }

.search-inline .btn-search {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	padding: 0;
	background: none;
	border: 0;
	color: var(--muet);
	font-size: 12px;
	cursor: pointer;
}

.search-inline .btn-search:hover { color: var(--texte); }

.search-inline .form-control {
	flex: 1 1 auto;
	min-width: 0;
	height: auto;
	padding: 0;
	font: inherit;
	color: var(--texte);
	background: transparent;
	border: 0;
	box-shadow: none;
}

.search-inline .form-control:focus { outline: none; border: 0; box-shadow: none; background: transparent; }
.search-inline .form-control::placeholder { color: var(--efface); }

/* L'effacement ne se montre que s'il y a quelque chose à effacer, mais sa place
   reste réservée : masqué par `visibility`, il ne décale ni la boîte ni la
   saisie en apparaissant, et sort de l'ordre de tabulation. */
.search-inline .btn-clear {
	flex: 0 0 auto;
	display: flex;
	visibility: hidden;
	align-items: center;
	padding: 0;
	background: none;
	border: 0;
	color: var(--muet);
	font-size: 11px;
	line-height: 1;
	cursor: pointer;
}

.search-inline.is-filled .btn-clear { visibility: visible; }
.search-inline .btn-clear:hover { color: var(--danger); }

/* Remise à jour de la liste. HORS de la boîte de recherche, et c'est le point :
   dedans, il aurait été le troisième bouton d'un contrôle qui en a déjà deux, et
   on aurait cherché lequel efface. Il en emprunte en revanche la boîte — même
   bordure, même fond — plutôt que le style d'un bouton d'action : « Nouvelle
   adresse » engage quelque chose, redemander la même liste n'engage rien.

   Sa hauteur n'est ni fixée ni étirée : mêmes marge interne, bordure et POLICE
   que le champ — donc même ligne de base, donc même hauteur, quelle que soit
   celle du bandeau. Un `align-self: stretch` l'aurait suivie, et une ligne de
   totaux repliée sous 1240 px lui aurait donné le double. */
.btn-rafraichir {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	padding: 4px 0;
	background: #fff;
	border: 1px solid var(--bord);
	border-radius: 7px;
	color: var(--muet);
	font: inherit;
	cursor: pointer;
}

.btn-rafraichir i { font-size: 12px; }
.btn-rafraichir:hover { color: var(--texte); border-color: #c8d2dc; }

/* L'icône tourne pendant l'aller-retour. Elle ne s'arrête jamais : le rendu
   emporte le bouton, et son remplaçant naît immobile — l'arrêt de l'animation EST
   l'arrivée de la donnée. C'est aussi la seule attente visible sur ces écrans,
   qui gardent leurs anciennes lignes tant que les nouvelles ne sont pas là. */
.btn-rafraichir.tourne i { animation: tourne-rafraichir .7s linear infinite; }

@keyframes tourne-rafraichir { to { transform: rotate(360deg); } }

/* LE BOUTON QUI TRAVAILLE. Un bouton d'action se désactive pendant son appel, et
   à 65 % d'opacité il se lirait « indisponible », pas « en cours ». L'encaissement
   le tient une à deux secondes : il republie le PDF de chaque facture touchée
   avant de répondre.

   Le libellé cède la place à un anneau qui tourne, SANS que le bouton change de
   taille : le texte reste là, rendu transparent, et c'est lui qui garde la
   largeur. L'anneau est en `::after`, donc sans une ligne de gabarit.

   RIEN NE PARAÎT AVANT 300 MS. Sur la plupart des écrans l'appel répond plus
   vite, et un anneau qui clignote le temps d'une image se lit comme un défaut,
   pas comme une attente. Le délai est dans l'animation, pas dans un minuteur :
   poser la classe suffit, et la retirer avant l'échéance ne laisse rien paraître.

   Réservé aux deux boutons d'action (`btn-primary`, `btn-danger`), les seuls à
   texte blanc — l'anneau l'est aussi. Et seulement `:disabled` : une classe
   oubliée au retour de l'appel ne ferait pas tourner un bouton redevenu actif. */
.btn-primary.est-occupe:disabled,
.btn-danger.est-occupe:disabled {
	position: relative;
	animation: occupe-masque 0s .3s forwards;
}

.btn-primary.est-occupe:disabled::after,
.btn-danger.est-occupe:disabled::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 12px;
	height: 12px;
	margin: -6px 0 0 -6px;
	box-sizing: border-box;
	border: 2px solid rgba(255, 255, 255, .35);
	border-top-color: #fff;
	border-radius: 50%;
	opacity: 0;
	animation: occupe-parait 0s .3s forwards, tourne-rafraichir .7s linear infinite;
}

@keyframes occupe-masque { to { color: transparent; } }
@keyframes occupe-parait { to { opacity: 1; } }

/* Tableaux -------------------------------------------------------------------- */

/* La zone défilante prend la hauteur restante de son bloc. */
.div_tb_normal {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overflow-x: auto;
}

/* perfect-scrollbar remplace ici `::-webkit-scrollbar`, qui n'habillait que Chrome
   et Safari : Firefox posait la barre grise du système au milieu d'une interface
   dense. Les couleurs et les 9 px sont ceux des anciennes règles — seul le moteur
   change.
   Le rail est posé en absolu DANS le conteneur : sans repère, il se placerait par
   rapport à la page. La feuille du greffon ne le pose pas, Redox l'ajoute de son
   côté. */
.ps { position: relative; }

.ps > .ps__rail-y > .ps__thumb-y,
.ps > .ps__rail-x > .ps__thumb-x { background: #cfd8e3; border-radius: 9px; }
.ps > .ps__rail-y > .ps__thumb-y { width: 9px; right: 0; }
.ps > .ps__rail-x > .ps__thumb-x { height: 9px; bottom: 0; }
.ps > .ps__rail-y:hover > .ps__thumb-y,
.ps > .ps__rail-x:hover > .ps__thumb-x { background: #b3c2d3; }

/* POUCE MASQUÉ AU REPOS, révélé pendant le défilement puis effacé de lui-même :
   c'est PS qui retire `ps--scrolling-y` une seconde après le dernier mouvement
   (`scrollingThreshold: 1000`). Redox refait ce délai à la main dans
   `utils.js:scrollbar` — deux minuteries, quatre gestionnaires de souris et des
   styles en ligne — parce que SA règle CSS équivalente ne s'applique jamais :
   sa liste de sélecteurs se termine par une virgule avant l'accolade
   (desktop.css:2884), ce qui l'invalide entièrement. La classe suffit, et le
   greffon reste tel qu'il sort de npm. */
.ps__thumb-y, .ps__thumb-x { visibility: hidden; }
.ps--scrolling-y > .ps__rail-y > .ps__thumb-y,
.ps--scrolling-x > .ps__rail-x > .ps__thumb-x,
.ps--clicking > .ps__rail-y > .ps__thumb-y,
.ps--clicking > .ps__rail-x > .ps__thumb-x,
.ps > .ps__rail-y:hover > .ps__thumb-y,
.ps > .ps__rail-x:hover > .ps__thumb-x { visibility: visible; }

/* Le rail lui-même reste invisible : la feuille du greffon le fait apparaître en
   gris dès que la souris entre dans le conteneur, ce qui allume une bande sur le
   bord de chaque liste survolée. */
.ps > .ps__rail-y, .ps > .ps__rail-x { background: transparent !important; }

/* `border-collapse: separate` est requis : en mode `collapse`, la bordure d'un
   en-tête collant se détache et disparaît au défilement. */
.tb_liste {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
}

.tb_liste th {
	position: sticky;
	top: 0;
	z-index: 2;
	background: var(--tete);
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 700;
	/* .05em : à 11 px les capitales se lisent sans plus d'air, et les colonnes
	   étroites (« Ouv. », « Échu », « Total dû ») ne s'élargissent pas. */
	letter-spacing: .05em;
	/* 1.25 : l'en-tête garde 27,8 px de haut avec un corps de 11 px. */
	line-height: 1.25;
	text-transform: uppercase;
	text-align: left;
	padding: 7px 10px;
	/* border-bottom: 1px solid var(--bord); */
	white-space: nowrap;
}
.tb_liste tbody tr td, .tb_liste tbody tr th { border:none; }
.tb_liste td { padding: 6px 10px; border-bottom: 1px solid var(--bord-fin); vertical-align: middle; }
.tb_liste tbody tr:last-child td { border-bottom: 0; }
/* Un zébrage très léger, une ligne sur deux : sur vingt colonnes de factures,
   l'œil perd sa ligne entre le numéro et le montant. Un ton sous `--tete`, pour
   ne pas concurrencer la sélection ni le survol — écrit AVANT eux, qui gagnent
   à spécificité égale par leur rang. */
.tb_liste tbody tr:nth-child(even) td, tr:nth-child(even) th { background: #fafbfc; }
.tb_liste tbody tr:hover td { background: var(--survol); }

/* Le total reste lisible pendant le défilement. */
.tb_liste tfoot td {
	position: sticky;
	bottom: 0;
	z-index: 2;
	background: var(--tete);
	border-top: 1px solid var(--bord);
	border-bottom: 0;
	font-weight: 700;
	padding: 7px 10px;
	border:none;
}

.ligne_suivi, .ligne_adresse { cursor: pointer; }

/* Colonnes -------------------------------------------------------------------- */

.c-id { font-variant-numeric: tabular-nums; color: var(--muet); font-size: var(--t-petit); white-space: nowrap; }
.c-type { white-space: nowrap; color: #4a5b6d; }
.c-sujet { font-weight: 400; }
.c-client { white-space: nowrap; }
/* La date et son auteur tiennent sur une ligne TANT QU'IL Y A LA PLACE, et l'auteur
   passe dessous sinon — d'un bloc, jamais coupé au milieu du nom. Tout en
   `nowrap`, la colonne imposerait sa pleine largeur : sur l'accueil, à 1440 px,
   le tableau des suivis dépasserait sa carte, et la pastille de la dernière
   colonne serait rognée sans rien pour le dire. */
.c-maj { font-variant-numeric: tabular-nums; }
/* Les tableaux serrés resserrent l'écart des cellules : ceux de l'accueil, et les huit
   colonnes des factures d'une fiche, où deux pastilles tiennent ainsi côte à côte à 1280 px. */
.dash-suivis .tb_liste th, .dash-suivis .tb_liste td,
.dash-blocages .tb_liste th, .dash-blocages .tb_liste td,
.factu-liste .tb_liste th, .factu-liste .tb_liste td { padding-left: 7px; padding-right: 7px; }
.c-maj span { color: var(--muet); font-variant-numeric: normal; white-space: nowrap; }
.c-dr { text-align: right!important; }
.c-num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 650; white-space: nowrap; }
.c-date { font-variant-numeric: tabular-nums; color: #4a5b6d; white-space: nowrap; }

/* Colonne d'état : une pastille de couleur, sans en-tête, comme dans l'ancien
   adm. Elle ne prend que sa largeur propre. */
.c-etat { width: 1%; padding-right: 0; white-space: nowrap; }

.pastille {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	vertical-align: middle;
}

.pastille.est-actif { background: #3ba776; }
.pastille.est-inactif { background: #d0574f; }
.vide { color: var(--muet); }

/* Badges d'état ---------------------------------------------------------------
   Fond teinté plutôt qu'aplat plein : sur une liste où toutes les lignes portent
   « Alert », un rectangle saturé par ligne formerait un mur qui n'informe plus.

   Les couleurs sont celles de `.badgeRedox` (redox/css/desktop.css, variables
   `--color-bg-*-light` / `--color-text-*-light` en tête de fichier) : un fond
   TRANSLUCIDE et un texte de la même famille, sans bordure. Le fond en rgba
   n'est pas une coquetterie — il se compose avec la ligne survolée ou
   sélectionnée au lieu de poser un rectangle blanc dessus. La bordure est
   gardée transparente plutôt que retirée, pour ne pas décaler d'un pixel tout
   ce qui est aligné sur ces badges. Correspondance : ok = success,
   danger = danger, warning et attente = warning, neutre = le badge nu. */
.label {
	display: inline-block;
	padding: 1px 7px;
	font-size: var(--t-mini);
	/* Un interligne propre : la pastille à 12 px tient dans la ligne de texte. Plus
	   haute, chaque ligne qui en porte une gagnerait un pixel, et les listes de
	   Factures et des Rappels perdraient une ligne à l'écran. */
	line-height: 1.3;
	font-weight: 500;
	letter-spacing: .02em;
	border: 1px solid;
	border-radius: 20px;
	white-space: nowrap;
}

.label { border-color: transparent; }
/* Les trois encres sont réglées sur LEUR fond teinté, pas sur du blanc : c'est là
   qu'elles se lisent. Les anciennes (#c83535, #9f5f00, #367b50) y donnaient 4,3 à
   4,5 et tombaient sous 4 sur une ligne survolée ; celles-ci tiennent 4,5 partout
   — 5,6 · 5,5 · 5,2 sur blanc. */
.label-danger { color: #c83535; background: rgba(239, 68, 68, .12); }
.label-warning, .label-attente { color: #9f5f00; background: rgba(250, 175, 20, .22); }
.label-ok { color: #367b50; background: rgba(21, 168, 61, .15); }
.label-neutre { color: #595757; background: rgba(100, 116, 139, .09); }
.label + .label { margin-left: 4px; }

.muet { color: var(--muet); }

/* Aide en infobulle --------------------------------------------------------------
   Pour une explication qui sert la première fois et encombre ensuite : un point
   d'interrogation, et le texte au survol ou au focus. Elle reste à un geste sans
   prendre une ligne à l'écran.

   Le texte est un ÉLÉMENT, pas un `attr()` comme l'infobulle des rappels de
   suivi : il se replie sur plusieurs lignes, un lecteur d'écran le lit, et il
   peut porter un lien — la bulle ouverte se survole et se clique. Elle s'ouvre
   sous l'icône, calée à sa droite : l'icône se pose en bout de ligne, et la
   bulle s'étend vers l'intérieur de l'écran.

   Posée dans un en-tête de tableau, elle en hériterait les capitales, l'interlettre
   et l'alignement : ils sont remis à plat ici. */
.bulle-aide {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	color: var(--muet);
	cursor: help;
}
.bulle-aide:hover, .bulle-aide:focus-within { color: var(--lien); }
.bulle-aide-texte {
	position: absolute;
	top: calc(100% + 6px);
	right: -4px;
	width: max-content;
	max-width: 340px;
	padding: 6px 10px;
	border-radius: 5px;
	background: var(--navbar);
	color: #fff;
	font-size: var(--t-petit);
	font-weight: 400;
	line-height: 1.45;
	letter-spacing: normal;
	text-transform: none;
	text-align: left;
	white-space: normal;
	cursor: default;
	opacity: 0;
	pointer-events: none;
	transition: opacity .12s ease .12s;
	z-index: 5;
}
/* Le pont : la souris qui descend de l'icône vers la bulle traverse les 6 px qui
   les séparent sans la refermer. */
.bulle-aide-texte::before { content: ""; position: absolute; left: 0; right: 0; top: -6px; height: 6px; }
.bulle-aide:hover .bulle-aide-texte, .bulle-aide:focus-within .bulle-aide-texte { opacity: 1; pointer-events: auto; }
/* Une bulle à plusieurs chiffres : une ligne chacun, et aucun montant coupé en
   « CHF 2 » / « 029.00 ». Les encres sont celles du fond sombre de la bulle. */
.bulle-ligne { display: block; white-space: nowrap; }
.bulle-fort { font-weight: 600; }
.bulle-alerte { color: #fdba74; }
.bulle-aide-texte a { color: #8ec9f2; }

/* Notification éphémère ------------------------------------------------------- */

.notif {
	position: fixed;
	left: 50%; bottom: 24px;
	transform: translateX(-50%);
	background: #2a3542; color: #fff;
	padding: 8px 16px;
	font-size: var(--t-base);
	border-radius: 6px;
	/* Au-dessus des popups, qui partent de 1000 et s'incrémentent à chaque
	   ouverture : une notification déclenchée depuis un popup doit rester
	   lisible, y compris tard dans une session. */
	z-index: 100000;
}
/* Tenue jusqu'au clic : au-dessus des messages éphémères, qui passent dessous. */
.notif-tenue { bottom: 64px; max-width: min(640px, 90vw); cursor: pointer; }

/* Adaptation aux largeurs d'écran ---------------------------------------------
   Placé en toute fin de feuille à dessein : une media query ne l'emporte pas sur
   une règle de même spécificité écrite plus bas. */

@media (min-width: 1900px) {
	.dash { grid-template-columns: minmax(0, 1fr) 360px 380px; padding: 18px 22px; }
}

@media (max-width: 1520px) {
	/* 270 et 290 pour les deux colonnes de côté : celle des suivis, qui prend le
	   reste, garde la place de son texte. Sans elle, l'auteur passerait sous la date
	   une ligne sur deux et la liste perdrait une ligne à l'écran. */
	.dash { grid-template-columns: minmax(0, 1fr) 270px 290px; padding: 13px 14px; }
}

/* Entre ces deux seuils, le nom du client et l'auteur peuvent se replier : tout
   en `nowrap`, la liste des suivis demanderait plus que sa colonne n'offre à
   1366 px de large, et la pastille de retard sortirait du cadre sans rien pour
   le dire. */
@media (max-width: 1400px) {
	.dash-suivis .c-client { white-space: normal; }
	/* `inline-block` : l'auteur passe sous la date d'UN SEUL TENANT ; en simple
	   `normal`, son nom se couperait au milieu et le point médian resterait seul en
	   bout de ligne. */
	.dash-suivis .c-maj span { white-space: normal; display: inline-block; }
}

@media (max-width: 1240px) {
	.dash { grid-template-columns: minmax(0, 1fr) 260px 280px; }
	.search-inline { flex-basis: 210px; }
	/* Les trois onglets de suivis tiennent en serrant leurs marges et en laissant
	   la recherche céder la première : « Tous les suivis » se couperait sous elle. */
	.dash-suivis .ecran-onglet { padding-left: 9px; padding-right: 9px; }
	.dash-suivis .ecran-outils { flex-shrink: 1000; min-width: 150px; }
	/* 122 et non 110 : sous cette largeur, « Recherche » se lit « Recherch ». */
	.dash-suivis .search-inline { min-width: 122px; }
	/* Voir « Une recherche qui OUVRE la tranche » : la colonne des suivis ne
	   contient plus les trois onglets, la piste doit pouvoir défiler. */
	.ecran-onglets > .search-inline { flex: 0 4 240px; }
	.ecran-onglets > .search-inline + .ecran-piste { flex-shrink: 1; }
	/* Sélecteur triple à dessein : la variante `.liste-tete-recherche` est écrite
	   plus BAS dans la feuille et l'emporterait à spécificité égale. */
	.liste-tete.liste-tete-recherche .search-inline { flex-basis: 240px; }
	.ecran-piste:has(+ .ecran-outils .search-inline) { flex-shrink: 1; }
}

/* Sous 1020 px la barre de navigation se replie en panneau déroulant. Seuil calé
   sur la mesure : la barre SERRÉE (bloc suivant) réclame encore 1003 px.
   Ajouter des entrées au menu demandera de relever ce seuil. */
@media (max-width: 1020px) {
	.navbar-toggle { display: flex; }

	/* `:not(.nav-droite)` : les entrées calées à droite ne se replient PAS dans le
	   tiroir. Elles portent la même classe `nav` que la piste — sans cette
	   exception elles disparaîtraient sous 1020 px, et le panneau déroulant se
	   dédoublerait. */
	.navbar-my .nav:not(.nav-droite) {
		display: none;
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		flex-direction: column;
		background: var(--navbar);
		border-bottom: 2px solid green;
		box-shadow: 0 6px 12px rgba(0, 0, 0, .25);
		overflow-x: visible;
		max-height: calc(100vh - 42px);
		overflow-y: auto;
	}

	.navbar-my.is-open .nav:not(.nav-droite) { display: flex; }
	.navbar-my .nav:not(.nav-droite) li { display: block; }
	.navbar-my .nav a { padding: 9px 15px; }

	/* REPLIÉ, LE TIROIR D'UN GROUPE EST DANS LE FLUX, sous son entrée, et pousse
	   les suivantes : en panneau fixe au bas de son entrée, il recouvrirait les
	   entrées d'après, exactement là où l'on va cliquer ensuite.
	   `!important` parce que c'est un style EN LIGNE qu'il faut battre : Popper
	   réécrit `position: fixed` et le coin à chaque ouverture, et rien d'autre ne
	   passe devant. `left` et `top`, qu'il écrit aussi, ne disent rien à un élément
	   en flux.
	   L'habillage suit : ni cadre, ni ombre, ni fond blanc, qui diraient « panneau
	   posé par-dessus ». Les sous-entrées sont des lignes du menu, en retrait sous
	   leur groupe et un ton plus sombre que lui. */
	.navbar-my .dropdownContent.nav-tiroir {
		position: static !important;
		min-width: 0;
		padding: 0;
		border: 0;
		border-radius: 0;
		box-shadow: none;
		background: rgba(0, 0, 0, .22);
	}
	.navbar-my .dropdownContent.nav-tiroir .dropdownItem { padding: 9px 15px 9px 30px; color: #eee; font-size: var(--t-base); }
	.navbar-my .dropdownContent.nav-tiroir .dropdownItem:hover { background: #000; color: #ccc; }
	/* L'écran affiché se marque en noir, comme une entrée de premier rang : le
	   gris clair du panneau flottant rendrait ici le libellé, clair lui aussi,
	   illisible. */
	.navbar-my .nav a.dropdownItem.activer { background: #000; }

	.dash { grid-template-columns: minmax(0, 1fr) 210px 230px; }
}

/* ENTRE LE REPLI ET LA PLEINE LARGEUR, la barre se SERRE au lieu de défiler en
   silence. Le menu complet demande 1235 px et ne se replie qu'à 1020 : entre les
   deux la piste défilerait sans ascenseur, et « Développement » se lirait
   « Développ » contre « Paramètres ».
   Marges resserrées et libellés de droite réduits à leur icône : 1087 px de
   besoin ; sous 1110, le nom laisse la place à son seul badge : 1003 px. */
/* Le nom du compte ne dicte pas la largeur de la barre : au-delà de 90 px il se
   coupe, sans quoi un nom long ferait défiler la piste. */
.navbar-my .user-badge .user-badge-nom { max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (min-width: 1021px) and (max-width: 1250px) {
	.navbar-my .nav a { padding-left: 11px; padding-right: 11px; }
	.navbar-my .nav-droite a .libelle { display: none; }
}
@media (min-width: 1021px) and (max-width: 1110px) {
	.navbar-my .user-badge .user-badge-nom { display: none; }
}

/* Sous 900 px tout tient sur une colonne. Se partager la hauteur n'a alors plus
   de sens : trois listes réduites à une lamelle ne se lisent pas. On rend à
   chaque bloc une hauteur exploitable et c'est la grille qui défile — le seul
   endroit de l'application où la vue défile d'un bloc. */
@media (max-width: 900px) {
	/* Le −20 px en ligne du gabarit compense la gouttière de la colonne ; en
	   `display: block` elle n'existe pas, et la carte mordrait le champ de recherche. */
	.dash-suivis > .ecran-classeur { margin-top: 0 !important; }
	.dash {
		display: block;
		overflow-y: auto;
		padding: 12px;
	}

	.dash-suivis,
	.dash-blocages,
	.dash-stats {
		display: block;
		margin-bottom: var(--gap);
	}

	.dash-blocages .bloc + .bloc { margin-top: var(--gap); }

	/* Les conteneurs intermédiaires reprennent leur hauteur naturelle : laissés
	   en `flex: 1` avec `min-height: 0`, ils s'effondreraient à zéro et la liste
	   déborderait par-dessus le bloc suivant.

	   La règle est portée par `.dash-suivis`, la seule grille qui s'empile ici.
	   Écrite `.volet` toute seule, elle n'aurait de toute façon jamais atteint
	   les autres écrans : leur propre règle porte deux classes et l'emporte,
	   media query ou pas. */
	.dash-suivis .volet { display: block; flex: 0 0 auto; }

	/* Adresses et Facturation ne sont qu'UNE carte : rien à empiler, elles gardent
	   la pleine hauteur et leur défilement interne. Sans ces deux lignes, le
	   `display: block; overflow-y: auto` posé sur `.dash` plus haut s'appliquerait
	   aussi à elles et le pied de liste sortirait de l'écran, hors d'atteinte. */
	.dash.dash-adresses,
	.dash.dash-liste { display: grid; overflow-y: hidden; }
	.dash-suivis .div_tb_normal { flex: 0 0 auto; height: 300px; }
	.dash-blocages .div_tb_normal { flex: 0 0 auto; height: 200px; }
}

/* L'ACCUEIL S'EMPILE DÈS 1170 PX : à trois colonnes, sa liste des suivis ne tient
   pas sous 1130 px de large — les pastilles de retard sortiraient du cadre, le
   troisième onglet serait rogné, les lignes monteraient à trois et quatre rangs.
   Chaque bloc reprend une hauteur exploitable et c'est la grille qui défile,
   comme sous 900 px. */
@media (min-width: 901px) and (max-width: 1170px) {
	.dash-suivis > .ecran-classeur { margin-top: 0 !important; }
	.dash:has(> .dash-suivis) { display: block; overflow-y: auto; padding: 12px; }
	.dash-suivis, .dash-blocages, .dash-stats { display: block; margin-bottom: var(--gap); }
	.dash-blocages .bloc + .bloc { margin-top: var(--gap); }
	.dash-suivis .volet { display: block; flex: 0 0 auto; }
	.dash-suivis .div_tb_normal { flex: 0 0 auto; height: 300px; }
	.dash-blocages .div_tb_normal { flex: 0 0 auto; height: 200px; }
}

@media (max-width: 620px) {
	/* Le NOM s'efface, pas le bouton : il porte l'accès à son propre compte, et le
	   masquer entièrement retirerait la seule voie vers le changement de mot de passe
	   sur écran étroit. Il ne reste que l'icône, comme pour « Paramètres » dans la
	   barre de droite. */
	.navbar-my .user-badge .user-badge-nom { display: none; }
	.navbar-my .user-badge { padding: 0 10px; }
	.navbar-my .navbar-brand { font-size: 15px; padding: 0 10px; }
	.navbar-my .navbar-logo { height: 18px; }
}

/* Fiche société ---------------------------------------------------------------
   Métaphore du dossier : l'identité du client coiffe l'ensemble — on sait de qui
   il s'agit avant de choisir quelle section ouvrir —, les onglets forment la
   tranche, et le classeur en dessous porte le contenu. L'onglet actif s'y soude
   par une interruption du filet. Comme partout, seul le corps défile : ni le nom
   du client ni l'onglet ouvert ne quittent l'écran. */

.fiche {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
	padding: 14px 18px 18px;
}

/* La tranche du dossier. Le filet continu sur lequel reposent les onglets est
   peint par le conteneur, hors de la piste : il reste intact quand celle-ci
   défile. */
/* Les onglets en tranche de dossier ne sont pas propres à la fiche : tous les
   écrans à sections les portent. Les sélecteurs sont groupés plutôt que
   recopiés — une seule définition, deux familles de noms. */
.fiche-onglets,
.ecran-onglets {
	position: relative;
	flex: 0 0 auto;
	display: flex;
	align-items: flex-end;
	margin-bottom: 12px;
}

.fiche-onglets::after,
.ecran-onglets::after {
	content: "";
	position: absolute;
	left: 0; right: 0; bottom: 0;
	height: 0px;
	background: var(--bord);
	z-index: 0;
}

/* Fin de rail : n'apparaît qu'en étroit, quand la piste peut réellement
   déborder, pour signaler qu'il reste des onglets à droite. */
.fiche-onglets::before,
.ecran-onglets::before {
	content: "";
	position: absolute;
	right: 0; top: 0; bottom: 1px;
	width: 34px;
	background: linear-gradient(to right, rgba(255, 255, 255, 0), #fff 78%);
	opacity: 0;
	pointer-events: none;
	z-index: 2;
}

/* Les onglets sont soudés : pas de gouttière, et seuls les deux bouts de la
   piste sont arrondis. La tranche se lit alors comme une seule pièce plutôt que
   comme une rangée d'étiquettes détachées. */
.fiche-piste,
.ecran-piste {
	position: relative;
	z-index: 1;
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	align-items: flex-end;
	gap: 0;

	overflow-x: auto;
	overflow-y: hidden;
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.fiche-piste::-webkit-scrollbar,
.ecran-piste::-webkit-scrollbar { height: 0; width: 0; display: none; }

.fiche-onglet,
.ecran-onglet {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	padding: 4px 13px;
	border: 1px solid var(--bord);
	border-radius: 0;
	background: #e9ebed;
	color: #555;
	font-size: var(--t-base);
	white-space: nowrap;
	cursor: pointer;
}

/* Deux onglets voisins partagent leur filet : sans ce recouvrement, les deux
   bordures d'1 px se cumuleraient en une couture de 2 px. */
.fiche-onglet + .fiche-onglet,
.ecran-onglet + .ecran-onglet { margin-left: -1px; }

/* Seuls les bouts de la piste sont arrondis — l'intérieur reste à angle droit,
   c'est ce qui soude la rangée. */
.fiche-piste > :first-child,
.ecran-piste > :first-child { border-top-left-radius: var(--radius); }

.fiche-piste > :last-child,
.ecran-piste > :last-child { border-top-right-radius: var(--radius); }

.fiche-onglet:focus-visible,
.ecran-onglet:focus-visible { outline: 2px solid var(--focus); outline-offset: -3px; }

.ecran-onglet.est-actif,
.fiche-onglet.est-actif { cursor: default; }

/* Le survol tire l'onglet vers le blanc de l'onglet ouvert : il annonce ce qui
   va se passer. */
.ecran-onglet:not(.est-actif):hover,
.fiche-onglet:not(.est-actif):hover { background: #f7f9fb; color: var(--texte); }

/* L'onglet ouvert : fond du classeur, filet inférieur repeint en blanc pour
   souder les deux. Il passe au-dessus de ses voisins, sans quoi le
   recouvrement d'1 px lui mangerait un côté. */
.fiche-onglet.est-actif,
.ecran-onglet.est-actif {
	position: relative;
	z-index: 1;
	background: var(--carte);
	border-bottom-color: var(--carte);
	color: var(--texte);
	font-weight: 400;
}

/* Le compteur d'un onglet : le volume de sa section. */
.ecran-compte {
	display: inline-block;
	min-width: 19px;
	margin-left: 7px;
	padding: 0 6px;
	border-radius: 20px;
	background: #eef2f7;
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 600;
	line-height: 16px;
	text-align: center;
}

.ecran-onglet.est-actif .ecran-compte { background: #e4f4ec; color: #1e7a52; }

/* Le classeur : le panneau que les onglets ouvrent. Son filet supérieur est
   celui de la barre, d'où l'absence de bordure haute. */
.fiche-classeur {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: flex;
	flex-direction: column;
	background: var(--carte);
	/* border: 1px solid var(--bord); */
	border-top: 0;
	border-radius: 0 0 var(--radius) var(--radius);
}

/* L'identité, au-dessus de la tranche. Son retrait de gauche est celui de la
   piste d'onglets : le nom et le premier onglet s'alignent. */
.fiche-entete {
	flex: 0 0 auto;
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 8px var(--gap);
	padding: 0 4px 10px 0px;
}

.fiche-identite { min-width: 0; }
.fiche-type { font-size: var(--t-mini); text-transform: uppercase; letter-spacing: .09em; color: var(--muet); }
.fiche-titre { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 2px; }
.fiche-nom { font-size: 17px; font-weight: 650; letter-spacing: -.012em; }
.fiche-nom-facture { font-size: var(--t-fort); font-weight: 500; letter-spacing: -.012em; }

/* La traçabilité ne se lit qu'une fois par an ; le dossier des pièces, lui, se
   clique. L'entête les porte donc en une RANGÉE d'objets — responsable, repère
   d'aide, dossier — alignée sur le nom de la société, et non en lignes de texte. */
.fiche-meta {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: var(--t-petit);
	color: var(--muet);
	text-align: right;
}

.fiche-meta b { font-weight: 600; color: var(--texte); }

/* Le repère de traçabilité : « créée le », « modifiée le ». Même objet que le
   « ? » des rapports — un rond discret qui ne se lit qu'au survol —, mais il
   porte un « i » : ce n'est pas une question, c'est une information de plus.
   `tabindex` le rend atteignable au clavier ; sans lui, l'information n'existe
   que pour la souris. */
.fiche-trace {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 15px;
	height: 15px;
	/* `--bord` vaut #eee : sur la carte blanche de la fiche, le cercle disparaît
	   et le repère ne se voit plus comme une cible. Un gris à peine plus soutenu
	   suffit — il reste discret, mais on sait qu'il y a quelque chose à survoler. */
	border: 1px solid #d3dbe3;
	border-radius: 50%;
	color: var(--muet);
	font-size: var(--t-mini);
	font-style: italic;
	font-weight: 600;
	line-height: 1;
	cursor: help;
	/* Le titre natif garde les retours à la ligne : les deux dates se lisent
	   l'une sous l'autre plutôt qu'en une phrase. */
	white-space: pre-line;
}

.fiche-trace:hover, .fiche-trace:focus-visible { border-color: var(--focus); color: var(--lien); }

/* Le dossier vient à l'extrémité droite, contre le bord : c'est un objet qu'on
   vise, pas une donnée qu'on lit. Il perd donc le `margin-left: auto` de
   `.fiche-crayon`, qui le repousserait au-delà de la rangée. */
.fiche-meta .pj-dossier { margin-left: 0; }

.fiche-volet { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

.fiche-colonnes {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--gap);
	/* padding: var(--gap); */
	align-items: start;
}

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

/* Tableau clé/valeur : le libellé tient sa colonne, la valeur prend le reste.

   La largeur est en PIXELS, pas en pourcentage. Un pourcentage se calculerait sur
   le conteneur, or la même règle sert la grille à 3 colonnes de la fiche, celle
   à 2 colonnes sous 1240px, la colonne unique sous 860px et `.facture-col-gauche`
   — 38% n'y voudrait pas dire la même chose, et réserverait dans la fiche 152px
   pour un libellé qui n'en occupe jamais plus de 109.

   Avec `table-layout: auto` et `white-space: nowrap`, cette valeur n'est qu'un
   PLANCHER : un tableau dont un libellé dépasse 90px élargit sa colonne de
   lui-même. Rien n'est jamais tronqué — six libellés sont dans ce cas
   (« Locale monétaire », « Renouvellement », « Numéro de TVA », « Forme
   juridique », « Rappel bloqué », « E-mail facture »), et leurs tableaux
   s'ajustent seuls. */
.tb_fiche th {
	position: static;
	/* L'interligne serré des en-têtes de liste (1.25) n'est pas pour ces libellés :
	   une ligne sans valeur en perdrait deux pixels sur ses voisines. */
	line-height: 1.4;
	width: 90px;
	background: transparent;
	color: var(--muet);
	font-size: var(--t-petit);
	font-weight: 400;
	letter-spacing: 0;
	text-transform: none;
	border-bottom: 1px solid var(--bord-fin);
	padding: 5px 10px;
	white-space: nowrap;
}

.tb_fiche td { word-break: break-word; }
.tb_fiche tr:last-child th, .tb_fiche tr:last-child td { border-bottom: 0; }

/* Une ligne clé/valeur ne se survole pas : il n'y a rien à y cliquer. Le `tbody`
   est explicite parce que celui de `.tb_liste tbody tr:hover td` l'est aussi —
   l'analyseur le crée de toute façon, et sans lui cette règle perdrait d'un
   point de spécificité. */
.tb_fiche tbody tr:hover td, .tb_fiche tbody tr:hover th { background: transparent; }

.fiche-vide { padding: 10px 12px; color: var(--muet); }
.fiche-liste { max-height: 220px; border-top: 1px solid var(--bord-fin); }

/* Membres : une carte de la fiche, pas un onglet — savoir à qui l'on parle fait
   partie de l'identité du client. Chaque personne tient sur deux lignes :
   qui elle est, puis de quoi la joindre. */
.fiche-membres { margin: 0; padding: 0; list-style: none; }

.fiche-membre { padding: 7px 12px; }
.fiche-membre + .fiche-membre { border-top: 1px solid var(--bord-fin); }

.fiche-membre-tete { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }

/* Le crayon d'un membre se range au bout de sa ligne et ne se montre qu'au survol :
   il y en a un par membre, et six crayons visibles en permanence feraient de la
   carte une barre d'outils. Il reste atteignable au clavier — `focus-within` le
   révèle —, sans quoi il serait invisible à qui ne se sert pas de la souris. */
.fiche-membre-crayon { margin-left: auto; opacity: 0; transition: opacity .12s; }
.fiche-membre:hover .fiche-membre-crayon,
.fiche-membre:focus-within .fiche-membre-crayon { opacity: 1; }
.fiche-membre-crayon:focus-visible { opacity: 1; }
.fiche-membre-nom { font-weight: 400; }

.fiche-membre-fonction {
	padding: 1px 7px;
	border-radius: 20px;
	background: #f2f5f8;
	color: var(--muet);
	font-size: var(--t-petit);
}

/* « Plus en poste » : l'ancien adm le signalait déjà en rouge. La personne
   reste dans la fiche — elle apparaît dans l'historique — mais on ne l'appelle
   plus. */
.fiche-membre-fonction.est-sorti { background: #fdeceb; color: #a33a33; }

.fiche-membre-contact {
	display: flex;
	flex-wrap: wrap;
	gap: 2px 12px;
	margin-top: 2px;
	font-size: var(--t-petit);
	color: var(--muet);
}

/* Onglet Suivis --------------------------------------------------------------
   Liste à gauche, détail à droite, chacun avec sa propre zone défilante. Le
   volet perd son `overflow-y` : sinon les deux panneaux défileraient ensemble et
   les en-têtes collants ne serviraient plus à rien. */

.fiche-volet-plein {
	overflow-y: hidden;
	display: flex;
	flex-direction: column;
	/* padding: var(--gap); */
}

.suivis-duo {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: grid;
	/* À droite on LIT : le texte d'un commentaire veut la plus grande part. À
	   gauche on CHERCHE, sur une ligne qui s'empile — type, objet, noms, chacun sur
	   sa ligne, l'objet en ellipse : le plancher ne garde que de quoi loger pastille
	   d'état, objet lisible et rappels datés sans repli. */
	grid-template-columns: minmax(420px, 1fr) minmax(0, 1.4fr);
	gap: var(--gap);
}

.suivis-liste, .suivis-detail { min-height: 0; min-width: 0; }

/* Un seul panneau de détail est visible à la fois ; c'est lui qui porte la
   colonne flex dont dépend le défilement des commentaires. */
.suivi-panneau {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
}

/* Chaque suivi tient sur deux lignes : le type — la catégorie situe — puis
   l'objet — c'est ce qu'on cherche en parcourant la liste. L'état ouvre la
   ligne, la vie du suivi tient dans son infobulle, et le panneau de droite n'a
   plus alors qu'un seul sujet, les commentaires. */
.tb_suivis td { vertical-align: top; padding-top: 9px; padding-bottom: 10px; }

.tb_suivis .c-statut { width: 1%; white-space: nowrap; }

/* La cellule prend toute la place restante ; `max-width: 0` est le levier qui
   autorise l'ellipse dans un tableau en layout auto — sans lui, un objet long
   étirerait la colonne au lieu de s'abréger. */
.suivi-cellule { width: 100%; max-width: 0; }

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

.suivi-objet.est-vide { font-weight: 400; color: var(--efface); }

/* Les noms sous l'objet — qui a ouvert, qui a fermé — séparés d'un point
   médian ; les dates restent dans l'infobulle de la pastille d'état. */
.suivi-qui { margin-top: 2px; color: var(--muet); font-size: var(--t-petit); }
.suivi-qui span + span::before { content: "· "; color: #c2ccd6; }

.suivi-type {
	display: inline-block;
	/* padding: 1px 7px; */
	/* border-radius: 20px; */
	/* background: #eef2f7; */
	/* color: #5d6b7b; */
	font-weight: 500;
	white-space: nowrap;
}

.c-etats { white-space: nowrap; }
/* Dans la fiche, les pastilles se replient quand la place manque : à trois sur
   une facture, elles chasseraient la colonne Montant hors de la carte sous
   1357 px de large. */
/* Quatre classes : la cellule est aussi `c-dr`, et la règle « côte à côte »
   ci-dessous (0,3,1) annulerait ce repli écrit en (0,2,0) — la colonne Montant
   déborderait à 1280 px. */
.factu-liste .tb_liste td.c-dr.c-etats { white-space: normal; }
.factu-liste td.c-etats { padding-top: 4px; }
.factu-liste .c-etats .label { margin-top: 2px; }
/* Deux pastilles d'une même cellule restent côte à côte (« Prospect » « Négatif »). */
.tb_liste td.c-dr:has(> .label) { white-space: nowrap; }
.suivi-commentaires td { padding: 7px 10px; vertical-align: top; }

/* Deux colonnes par commentaire : le QUI et le QUAND à gauche, le texte à
   droite. La colonne de gauche se parcourt comme une chronologie, et le texte
   commence toujours au même bord. */
.commentaire-meta { width: 150px; color: var(--muet); font-size: var(--t-petit); line-height: 1.45; }
.commentaire-date { white-space: nowrap; font-variant-numeric: tabular-nums; }
.commentaire-par { color: #4a5b6d; font-weight: 600; }
/* Le rappel d'un commentaire n'est qu'une ICÔNE auprès du dossier : la cloche
   tant que l'alerte est armée, l'horloge inversée pour un report passé. Le
   détail — date, retard, destinataire — tient dans l'infobulle maison :
   « Rappel 17.03.2026 · 3 j de retard · Prénom Nom » n'a sa place ni dans la
   colonne méta ni dans une pastille qui irait à la ligne. */
.commentaire-rappel {
	position: relative;
	display: inline-flex;
	align-items: center;
	padding: 2px 5px;
	font-size: 11px;
	line-height: 1;
	cursor: help;
}
.commentaire-rappel.est-attente { color: #b54708; }
.commentaire-rappel.est-danger { color: var(--danger); }
/* Le report passé s'efface : il informe, il n'alerte plus. */
.commentaire-rappel.est-passe { color: #a8b3bf; }

/* L'infobulle sort à GAUCHE de l'icône : perfect-scrollbar impose
   `overflow: hidden` à la zone des commentaires, au-dessus ou en dessous elle
   serait rognée sur la première ou la dernière ligne. À gauche, elle s'étend
   sur la largeur du texte, toujours disponible. */
.commentaire-rappel::after {
	content: attr(data-bulle);
	position: absolute;
	top: 50%;
	right: calc(100% + 6px);
	transform: translateY(-50%);
	padding: 4px 9px;
	border-radius: 5px;
	background: var(--navbar);
	color: #fff;
	font-size: var(--t-petit);
	font-weight: 400;
	line-height: 1.4;
	white-space: nowrap;
	opacity: 0;
	pointer-events: none;
	transition: opacity .12s ease .12s;
	z-index: 5;
}
.commentaire-rappel:hover::after { opacity: 1; }

/* `description` est un texte multi-ligne. Les <br> hérités deviennent des sauts
   de ligne côté serveur ; c'est le CSS qui les rend, jamais du HTML. */
.commentaire-texte { white-space: pre-wrap; word-break: break-word; }

.tb_liste tbody tr.est-actif td,
.tb_liste tbody tr.est-actif:hover td { background: var(--survol); }

/* Onglet Facturation de la fiche : les factures disent ce qui a été émis,
   l'abonnement ce qui sera facturé. Les deux côte à côte, les factures à gauche
   et avec la plus grande part — huit colonnes et des années de factures, quand
   l'abonnement en compte une ou deux lignes. */
.factu-duo {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: grid;
	grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
	gap: var(--gap);
}

/* L'abonnement épouse sa hauteur au lieu d'étirer une carte vide sur tout
   l'écran ; la liste des factures, elle, prend toute la hauteur et défile. */
.factu-abos { align-self: start; max-height: 100%; }
.factu-liste { min-height: 0; }

/* Les lignes de factures ouvrent la pièce, dans ce volet même : elles gardent
   donc le survol et le curseur. Les abonnements, eux, ne mènent nulle part —
   pas de survol qui promette un écran qui n'existe pas. */
.factu-abos .tb_liste tbody tr:hover td { background: transparent; }

/* Onglet Compte de la fiche : le compte courant du client, un grand livre. Une
   seule carte, qui prend toute la hauteur du volet. */
.compte-bloc { flex: 1 1 auto; min-height: 0; }

.c-periode { color: var(--muet); white-space: nowrap; }

/* Date et période n'ont besoin que de leur contenu. Sans contrainte, le
   navigateur leur distribue leur part de la largeur restante et ouvre un grand
   vide avant le libellé, qui est pourtant ce qu'on lit. */
.tb_compte th:first-child, .tb_compte td:first-child,
.tb_compte .c-periode { width: 1%; white-space: nowrap; }

/* Le solde progressif porte la lecture : il est plus appuyé que les mouvements,
   et vire au rouge dès que le client doit. */
.c-solde { font-weight: 600; color: #067647; }
.c-solde.est-debiteur { color: var(--danger); }

.tb_compte tbody tr:hover td { background: transparent; }

/* Les totaux de l'année vivent à droite du pied, séparés du cumul : l'ancien
   écran mélangeait les deux périmètres sur la même ligne sans le dire. Le flex
   est posé sur ce seul pied — les autres écrans se contentent d'un flux de
   texte, et les passer en flex décalerait leurs séparateurs. */
.compte-bloc .bloc-pied,
.compta-pied { display: flex; align-items: baseline; flex-wrap: wrap; }

/* Journal des e-mails (Rapports › E-mails) --------------------------------------
   La coche verte se lit d'un coup d'œil sur une colonne entière ; le nombre à
   côté est le compteur d'ouvertures, pas un booléen. */
.c-ouverture { white-space: nowrap; font-variant-numeric: tabular-nums; }
.c-ouverture .est-ouvert { color: #16a34a; }
.c-ouverture .est-ferme { color: #dc2626; opacity: .55; }

/* Les deux colonnes d'adresse sont longues et se ressemblent : on les tient sur
   une ligne et on les tronque plutôt que de laisser le tableau s'étirer. */
/* 240 px : les adresses longues tiennent sans se couper, et la colonne Objet
   voisine a la place. */
.c-mail { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.facture-piece .c-mail { max-width: 260px; }
/* Sous 1260 px, les 50 px de plus seraient pris à l'Objet, qui passerait sur deux
   lignes : la colonne y garde 190 px. */
@media (max-width: 1259px) { .c-mail { max-width: 190px; } }


/* Écrans Communication ---------------------------------------------------------
   Deux colonnes fixes, comme l'ancien : ce qu'on peut envoyer à gauche, le
   panneau d'envoi à droite. La liste de gauche n'a pas besoin de plus de place
   — elle ne porte qu'un libellé. */
.dash.dash-comm { grid-template-columns: 300px minmax(0, 1fr); }

.dash-comm .ligne_modele { cursor: pointer; }
.dash-comm .ligne_modele.est-actif td { background: var(--selection, #eef6fb); font-weight: 600; }
.news-date { margin-left: 8px; font-weight: 400; font-variant-numeric: tabular-nums; }

/* Le panneau de droite : vide tant qu'on n'a rien choisi. */
.comm-vide {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 10px;
	color: var(--muet);
}

.comm-vide i { font-size: 30px; opacity: .35; }
.comm-vide p { margin: 0; }

.comm-form {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	flex-direction: column;
}

/* L'état du canal d'envoi, affiché en permanence plutôt que découvert au clic. */
.comm-garde {
	flex: 0 0 auto;
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 8px 14px;
	background: #fff8ec;
	border-bottom: 1px solid #f0d9ab;
	color: #92400e;
	font-size: var(--t-base);
}

.comm-champs {
	flex: 0 0 auto;
	padding: 12px 14px;
	border-bottom: 1px solid var(--bord);
}

.comm-ligne {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 3px 0;
}

.comm-ligne label {
	flex: 0 0 70px;
	margin: 0;
	color: var(--muet);
	font-size: var(--t-petit);
}

.comm-ligne .form-control { flex: 1 1 auto; min-width: 0; }

/* L'expéditeur n'est pas modifiable : le relais le force. Le montrer en clair
   vaut mieux qu'offrir une saisie sans effet, comme le faisait l'ancien. */
.comm-fixe { flex: 1 1 auto; min-width: 0; padding: 4px 0; }

.comm-corps {
	flex: 1 1 auto;
	min-height: 0;
	width: 100%;
	padding: 14px;
	border: 0;
	border-radius: 0;
	resize: none;
	font-family: inherit;
	font-size: var(--t-base);
	line-height: 1.5;
}

.comm-corps:focus { outline: 0; background: #fffef8; }

/* L'aperçu vit dans une iframe : le document a ses propres styles et son propre
   <body>, l'injecter dans la page emporterait la mise en page. */
.comm-apercu {
	flex: 1 1 auto;
	min-height: 0;
	width: 100%;
	border: 0;
	background: #f6f9fc;
}

.comm-pied {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: var(--gap);
	padding: 8px 14px;
	border-top: 1px solid var(--bord);
	background: var(--tete);
	font-size: var(--t-petit);
}

.comm-cible { flex: 1 1 auto; min-width: 0; }
.comm-forcer { display: flex; align-items: center; gap: 6px; white-space: nowrap; color: #b54708; font-weight: 600; }
.comm-erreur { color: #b54708; font-weight: 600; }
.comm-succes { color: #166534; font-weight: 600; }

/* La confirmation nomme le segment et le nombre — celle de l'ancien ne disait
   ni l'un ni l'autre. Le même habillage sert à toute confirmation qui doit
   énoncer ses conséquences avant de les produire, d'où la classe générique
   `.dialogue` à côté de celle de l'écran Communication. */
.comm-dialogue, .dialogue {
	max-width: 440px;
	padding: 18px 20px;
	border: 1px solid var(--bord);
	border-radius: var(--radius);
	color: var(--texte);
	font-size: var(--t-base);
}

.comm-dialogue::backdrop, .dialogue::backdrop { background: rgba(16, 24, 40, .45); }
.comm-dialogue h4, .dialogue h4 { margin: 0 0 10px; font-size: 15px; }
.comm-dialogue p, .dialogue p { margin: 0 0 10px; line-height: 1.5; }
.comm-avert, .dialogue-avert { color: #b54708; }
.comm-dialogue-pied, .dialogue-pied { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }

/* Ce que la suppression toucherait, énuméré. Une ligne par facture : son numéro,
   la part que ce versement lui avait portée, et la mention « rouvre » quand elle
   repassera à l'impayé. */
/* LA LISTE EST BORNÉE. Au rapprochement bancaire elle tient à un versement ; le
   cycle de facturation, lui, y énumère TOUT un lot. Sans plafond, la question
   sortirait de l'écran par le bas, boutons compris : on ne pourrait plus ni
   valider ni annuler autrement qu'au clavier. */
.dialogue-liste { margin: 0 0 10px; padding: 8px 10px; border: 1px solid var(--bord); border-radius: 5px; background: var(--tete); max-height: 40vh; overflow-y: auto; }
.dialogue-liste div { display: flex; gap: 8px; padding: 2px 0; }
.dialogue-liste .c-montant { margin-left: auto; }
.dialogue-liste .est-rouverte { color: #b54708; }

/* La confirmation générique (`$adm.confirmer`). Une largeur PLANCHER en plus du
   plafond hérité de `.dialogue` : sans elle, « Supprimer ce commentaire ? » et
   « Envoyer la facture à … » s'ouvriraient dans deux boîtes de tailles très
   différentes, et le bouton d'action sauterait d'un endroit à l'autre de l'écran
   d'un geste au suivant. */
.dialogue-confirmer { min-width: 340px; }
/* Le détail vide ne doit pas creuser un blanc sous le texte. */
.dialogue-confirmer [data-conf-detail]:empty { display: none; }
/* La ligne signalée, même code couleur qu'au rapprochement bancaire — où elle
   s'appelle `.rap-dlg-doute`, propre à cet écran. */
.dialogue-ligne.est-doute, .dialogue-ligne.est-doute .c-montant { color: var(--danger); font-weight: 500; }

/* Une étiquette destinée aux seuls lecteurs d'écran : la colonne des corbeilles
   n'a pas d'en-tête visible — elle n'en a pas besoin —, mais un tableau dont une
   colonne n'est pas nommée se parcourt mal à la voix. */
.sr-only {
	position: absolute;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* La saisie d'une écriture : trois champs sur une ligne, le libellé prenant la
   place restante — c'est lui qu'on écrit le plus longuement. */
.ecriture-champs {
	display: flex;
	align-items: flex-end;
	gap: 10px;
	margin-bottom: 12px;
}

.ecriture-champs label {
	display: flex;
	flex-direction: column;
	gap: 4px;
	margin: 0;
	color: var(--muet);
	font-size: var(--t-petit);
}
/* Le champ est DANS son libellé et en hériterait la taille : la date tapée serait
   plus petite que celles du panier juste dessous. */
.popup-form .ecriture-champs .form-control { font-size: var(--t-base); }

/* Ces champs gardent les 30 px de la base : c'est le cran normal du front, et une
   ligne d'écriture n'est pas serrée comme un popup. Rien à redire ici.
   Assez large pour « 11.08.2026 » en entier : rognée, une date se relit mal et se
   corrige encore plus mal. */
.ecriture-champs [data-champ-date] { width: 112px; text-align: center; font-variant-numeric: tabular-nums; }
.ecriture-champs [data-champ-montant] { width: 104px; text-align: right; font-variant-numeric: tabular-nums; }
.ecriture-libelle { flex: 1 1 auto; min-width: 0; }
.ecriture-libelle .form-control { width: 100%; }

/* Débit ou crédit : deux boutons plutôt qu'une liste. Le choix est binaire, il
   engage le sens de l'écriture, et il doit se voir sans être déplié. Le mot
   comptable est doublé de son effet réel — « sortie », « entrée » — parce que le
   sens s'inverse selon qu'on regarde la trésorerie ou le plan comptable. */
.ecriture-sens { display: flex; gap: 8px; margin-bottom: 12px; }

.ecriture-sens-choix {
	flex: 1 1 0;
	padding: 5px 10px;
	border: 1px solid var(--bord);
	border-radius: 7px;
	background: var(--carte);
	color: var(--texte);
	font: inherit;
	cursor: pointer;
	text-align: center;
}

.ecriture-sens-choix .muet { display: block; font-size: var(--t-petit); }
.ecriture-sens-choix:hover { border-color: #cfd8e3; background: var(--tete); }

.ecriture-sens-choix.est-actif {
	border-color: var(--focus);
	background: var(--survol);
	font-weight: 600;
}

.ecriture-sens-choix:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* Le bouton « Ajouter » se pose au bout du choix de sens : il termine la ligne en
   cours, il n'engage pas le lot. C'est « Enregistrer », au pied, qui écrit. */
.ecriture-ajout { flex: 0 0 auto; white-space: nowrap; }

/* Le panier : ce qui sera écrit, relisible avant de l'être. Il défile au-delà d'une
   dizaine de lignes plutôt que de pousser le pied de la fenêtre hors de l'écran. */
.ecriture-panier {
	max-height: 240px;
	overflow-y: auto;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--tete);
}

.ecriture-panier-vide { padding: 14px; color: var(--muet); text-align: center; }

.ecriture-panier-liste { width: 100%; border-collapse: collapse; background: var(--carte); }
.ecriture-panier-liste td { padding: 4px 9px; border-bottom: 1px solid var(--bord-fin); }
.ecriture-panier-liste tr:last-child td { border-bottom: 0; }
.ecriture-panier-liste .c-date { width: 1%; white-space: nowrap; color: var(--muet); font-variant-numeric: tabular-nums; }
.ecriture-panier-liste .c-montant { width: 1%; white-space: nowrap; }
.ecriture-panier-liste .c-act { width: 1%; }

/* D ou C plutôt qu'une colonne à part : le panier est étroit, et la lettre suffit
   à distinguer deux lignes voisines de sens contraire. */
.ecriture-sens-court {
	display: inline-block;
	min-width: 14px;
	margin-left: 6px;
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 400;
}

.ecriture-panier-liste .est-credit { color: #1e7a52; }

/* Les deux totaux du lot, au pied de la fenêtre, face aux boutons. Séparés et non
   soldés : c'est ainsi qu'on pointe un relevé bancaire, colonne par colonne. */
.ecriture-total { color: var(--muet); font-size: var(--t-petit); font-variant-numeric: tabular-nums; }

/* L'en-tête du compte client : la recherche ouvre la rangée, comme sur Adresses
   et l'accueil, puis le compteur ; le solde et la saisie sont calés à droite —
   c'est le solde qui porte la marge automatique, et il ne s'y trouve jamais
   seul : rafraîchir et l'acompte le suivent. La marge gauche automatique du
   champ, qui le pousse à droite ailleurs, est annulée ici.

   Le champ part de 200 px et GRANDIT jusqu'à 340 : la rangée se replie
   (`flex-wrap`), et un repli se décide sur les bases, avant tout rétrécissement
   — à 340 px de base, « Acompte » tomberait seul à la ligne dès 780 px de bloc,
   alors qu'à 200 la rangée tient bien plus bas. */
.compte-tete { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.compte-tete .compte-recherche { margin-left: 0; flex: 1 1 200px; max-width: 340px; }
.compte-tete .compte-solde { margin-left: auto; }
.compte-tete .btn { flex: 0 0 auto; white-space: nowrap; }

/* Ce qu'un acompte va écrire, montré AVANT de l'écrire. Les deux lignes côte à
   côte sont tout l'intérêt de l'opération unique : deux saisies séparées ne les
   montreraient jamais ensemble. */
.acompte-apercu:not(:empty) {
	margin: 4px 0 12px;
	padding: 8px 10px;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--tete);
	font-size: var(--t-petit);
}

.acompte-apercu-titre { margin-bottom: 4px; color: var(--muet); }
.acompte-apercu div { display: flex; gap: 10px; padding: 1px 0; }
.acompte-apercu .c-montant { margin-left: auto; font-variant-numeric: tabular-nums; }
.acompte-apercu-tva { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--bord-fin); color: var(--muet); }
/* Les factures abandonnées d'un client qui revient, chacune avec son « Réactiver » : dans la
   fenêtre du versement, et sous la tête du panneau des encaissements, à ses marges. */
.versement-abandonnees div { align-items: center; }
.enc-reactiver .acompte-apercu:not(:empty) { margin: 8px 12px 0; }

/* Les cinq étapes de relance, en tête de l'écran « En retard de paiement ». Le
   bandeau EST la navigation : chaque étape porte son compte et son montant, et se
   clique. L'ancien affichait les mêmes chiffres dans un tableau inerte, avec un
   sélecteur séparé pour changer de liste. */
.rappel-etapes {
	flex: 0 0 auto;
	display: flex;
	gap: 8px;
	padding: 0 0 8px;
	overflow-x: auto;
}

/* Deux lignes par étape, pas trois : le nom, puis le compte et le montant sur la
   même ligne de base, le montant calé à droite. Le bandeau y gagne un tiers de
   hauteur, rendu à la liste qu'il surmonte. Sans montant, la seconde ligne ne
   porte que le compte. Le minimum de largeur garantit la seconde ligne : sous
   150 px, « 37 » et « CHF 12 480.50 » ne tiennent plus côte à côte et le montant
   retomberait en troisième ligne — le bandeau défile plutôt. */
.rappel-etape {
	flex: 1 1 0;
	min-width: 165px;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: 8px;
	row-gap: 0;
	padding: 6px 12px 5px;
	border: 1px solid var(--bord);
	border-radius: 7px;
	background: var(--carte);
	color: var(--texte);
	font: inherit;
	text-align: left;
	cursor: pointer;
}
/* Cinq étapes à 165 px ne tiennent pas sous 880 px de fenêtre : elles passent à
   150 px, marges serrées, et « Blocage » reste dans le champ. */
@media (max-width: 880px) { .rappel-etape { min-width: 150px; padding-left: 8px; padding-right: 8px; column-gap: 6px; } }

.rappel-etape:hover { border-color: #cfd8e3; background: var(--tete); }
.rappel-etape.est-actif { border-color: var(--focus); background: var(--survol); }
.rappel-etape:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

.rappel-etape-nom { flex: 1 0 100%; color: var(--muet); font-size: var(--t-petit); }
.rappel-etape-nb { font-size: 17px; font-weight: 600; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.rappel-etape-du { margin-left: auto; color: var(--muet); font-size: var(--t-petit); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Le blocage est le bout de la chaîne : il se distingue sans crier. */
.rappel-etape.est-blocage .rappel-etape-nb { color: var(--danger); }

/* Une facture pas encore relançable reste lisible mais en retrait : elle est là
   pour être vue, pas pour être traitée aujourd'hui. */
.tb_liste tr.est-attente td { color: var(--muet); }

.rappel-action { margin-left: auto; display: inline-flex; align-items: center; gap: 10px; }
.rappel-choisies { color: var(--muet); }
/* Les deux options des dernières étapes. Elles portent à conséquence — un SMS
   chez le client, un service coupé — donc elles se lisent, et le libellé entier
   bascule la case. */
.rappel-option { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-weight: 400; color: var(--muet); cursor: pointer; }
.rappel-option:hover { color: var(--texte); }
.rappel-option input { margin: 0; cursor: pointer; }

/* La case à cocher d'une ligne de liste ------------------------------------------
   Dessinée plutôt que laissée au système : celle du navigateur est minuscule, sa
   couleur ne suit pas la charte, et son état intermédiaire ne se distingue pas de
   son état coché.

   Le `label` remplit la CELLULE : c'est lui la cible de clic, pas les 13 px de la
   case. Sans cela, un clic qui rate d'un cheveu tombe sur la ligne — qui, elle,
   ouvre la facture. */
/* La cellule cède son rembourrage au label : sans quoi la zone cliquable
   s'arrêterait avant les bords, et le clic manqué retomberait sur la ligne. */
.tb_liste td.c-act:has(.case-cellule),
.tb_liste th.c-act:has(.case-cellule) { padding: 0; }

.case-cellule {
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	padding: 6px 10px;
	cursor: pointer;
}

/* Le dessin de la case elle-même vient de la base, après le socle : il ne se
   redit pas ici. */

/* La cellule entière réagit au survol : elle annonce qu'elle se clique. */
.tb_liste tbody tr:hover .case-cellule input[type="checkbox"]:not(:checked) { border-color: var(--lien-action); }

/* Le compte rendu d'un lot d'envois (relance, cycle) : ce qui n'est pas parti, ou
   reste à vérifier — ce qu'on ne doit pas apprendre par hasard. Le bandeau reste
   jusqu'au prochain rendu, là où une notification se serait effacée. */
.rappel-echecs {
	margin: 0 0 8px;
	padding: 6px 10px;
	border-radius: 5px;
	background: #fffaeb;
	border: 1px solid #fedf89;
	color: #b54708;
}


/* Bandeau de tête d'une liste sans onglet : les totaux à gauche, la recherche à
   droite. Les totaux sont en tête plutôt qu'en pied parce qu'avec un chargement
   au défilement, un pied ne se lirait qu'après avoir déroulé toute la liste. */
.liste-tete {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: var(--gap);
	padding: 7px 12px;
	color: var(--muet);
	font-size: var(--t-base);
}

/* Ses segments se replient ENTRE eux, jamais dans un montant : l'espace des
   milliers est sécable, et la ligne se couperait en « CHF 2 » / « 029.00 ». */
.liste-totaux { min-width: 0; font-size: var(--t-petit); }
.liste-totaux .pied-sep { white-space: nowrap; }
.pied-annee { margin-left: auto; padding-left: var(--gap); color: var(--muet); }

/* Variante où la recherche PASSE À GAUCHE — encaissements, rappels, factures :
   des listes où l'on commence par chercher son client ou son numéro plutôt que
   par parcourir. `.search-inline` porte `margin-left: auto` par défaut, ce qui
   la collerait à droite quel que soit son rang dans le balisage : c'est cette
   poussée qu'on retire, pour la donner aux totaux. Placée à gauche, elle a la
   largeur des autres recherches de tête, 340 px, et 240 sous 1240 px dans la
   media query plus haut : à 280 elle serait plus courte que son placeholder. */
.liste-tete-recherche .search-inline { margin-left: 0; flex-basis: 340px; }
.liste-tete-recherche .liste-totaux { margin-left: auto; text-align: right; }

/* Un bouton de tête de liste ne se replie jamais sur deux lignes — même règle
   que dans la tranche d'onglets : « Générer le cycle » coupé en deux doublerait la
   hauteur du bandeau dès que la recherche, passée à gauche, prend sa place. */
.liste-tete .btn { flex: 0 0 auto; white-space: nowrap; }

/* Sous 1240 px la fiche passe à deux colonnes, puis à une seule. Les cartes de
   réglages suivent le même chemin. */
@media (max-width: 1240px) {
	.fiche-colonnes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.param-grille { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* La piste d'onglets ne se replie jamais sur deux rangs — la tranche d'un
   dossier n'a qu'une épaisseur. Elle devient un rail qui défile, et le dégradé
   de fin de rail le signale. */
@media (max-width: 980px) {
	.fiche-onglets::before { opacity: 1; }
}

/* Sous 1100 px, liste et détail côte à côte deviennent deux lamelles illisibles.
   Ils s'empilent, chacun reprend une hauteur exploitable, et c'est le volet qui
   défile — même dérogation assumée que la grille du tableau de bord sous 900 px. */
@media (max-width: 1100px) {
	.fiche-volet-plein { overflow-y: auto; }
	.suivis-duo { display: block; }
	.suivis-liste, .suivis-detail { display: block; }
	.suivis-liste { margin-bottom: var(--gap); }
	.suivis-liste .div_tb_normal { flex: 0 0 auto; height: 280px; }
	.suivi-panneau { display: block; }
	.suivi-commentaires { flex: 0 0 auto; height: 320px; }

	.rapport-mosaique { grid-template-columns: minmax(0, 1fr); }

	/* Même seuil pour les paramètres : la liste passe au-dessus du contenu et
	   c'est le volet qui défile. */
	.param-duo { display: block; overflow-y: auto; }
	.param-liste, .param-detail, .param-panneau { display: block; }
	.param-liste { margin-bottom: var(--gap); }
	.param-liste .div_tb_normal { flex: 0 0 auto; height: 220px; }
	.param-corps { overflow-y: visible; }
}

/* RAPPORTS ET FACTURATION S'EMPILENT DÈS 1240 PX : en deçà, le tableau des
   abonnements d'une fiche rognerait sa colonne « Par mois », et les mois du
   graphique des rapports se chevaucheraient. Les factures d'abord, et c'est le
   volet qui défile. */
@media (max-width: 1240px) {
	.fiche-volet-plein { overflow-y: auto; }
	.rapport-duo { display: block; }
	.rapport-graphe.est-cote { margin-top: var(--gap); }
	.factu-duo { display: block; }
	.factu-abos { max-height: none; }
	.factu-liste { display: block; margin-bottom: var(--gap); }
	/* Au moins 360 px, et toute la hauteur que la fenêtre offre : figée à 360, la
	   liste ne montrait que dix factures quelle que soit la taille de l'écran. */
	.factu-liste .div_tb_normal { flex: 0 0 auto; height: max(360px, calc(100vh - 369px)); }
}

@media (max-width: 860px) {
	.fiche-colonnes { grid-template-columns: minmax(0, 1fr); }
	.param-grille { grid-template-columns: minmax(0, 1fr); padding: 12px; }
	.fiche { padding: 12px; }
	.fiche-volet-plein { padding: 12px; }
	.fiche-onglet { padding-left: 11px; padding-right: 11px; }
	.fiche-entete { flex-direction: column; gap: 6px; }
	.fiche-meta { justify-content: flex-start; text-align: left; }
	.suivi-doc { max-width: 150px; }
}

/* Écrans Communication en largeur réduite. Ces règles sont en fin de feuille,
   là où vivent toutes les media queries : à spécificité égale, c'est la
   dernière écrite qui l'emporte, media query ou pas.

   La colonne de gauche ne porte qu'un libellé : elle rétrécit avant tout le
   reste. Sous 900 px les deux se rangent l'une sous l'autre — c'est le seul
   endroit, avec le tableau de bord, où la vue défile d'un bloc. */
@media (max-width: 1240px) {
	.dash.dash-comm { grid-template-columns: 240px minmax(0, 1fr); }
}

@media (max-width: 900px) {
	.dash.dash-comm { display: block; overflow-y: auto; }
	.dash-comm .dash-carte { display: block; margin-bottom: var(--gap); }
	.dash-comm .div_tb_normal { flex: 0 0 auto; height: 200px; }
	.dash-comm .comm-form { display: block; }
	.dash-comm .comm-corps { height: 320px; }
	.dash-comm .comm-apercu { height: 420px; }
	.dash-comm .comm-vide { padding: 40px 0; }
}

/* Popup ------------------------------------------------------------------------
   Styles du plugin popupRedox, repris de redox/css/desktop.css:982-1218. Ce qui
   ne concernait que Redox est laissé là-bas : les onglets Bootstrap dans l'en-
   tête, le panneau de réglages, les zones headerCenter/headerLeft/headerRight.
   Quatre variables de couleur sont remappées sur le vocabulaire d'ici, et la
   croix de fermeture est en markup — l'original la posait en ::before avec une
   fonte « Font Awesome Pro » que cette application n'a pas. */

.popupRedoxGlobal {
	position: fixed;
	top: 0; left: 0; right: 0; bottom: 0;
	display: flex;
	justify-content: center;
	align-items: center;
	overflow: hidden;
	z-index: 1000;
	padding: 20px 16px 40px 16px;
	box-sizing: border-box;
}

/* Le fond. Posé dans un écran, il ne couvre QUE cet écran : sa géométrie lui est
   donnée par le JS, mesurée sur l'onglet (l'original la codait à 75 px du haut).
   Les valeurs ci-dessous ne servent donc qu'au cas « body ». */
.popupRedoxBackdrop,
.popupRedoxBackdropBody {
	z-index: 1;
	position: fixed;
	inset: 0;
	overflow: hidden;
	transition: opacity .3s ease;
}

.popupRedoxBackdrop { background: linear-gradient(to bottom, rgba(0, 0, 0, .02), rgba(40, 40, 40, .3)); }
.popupRedoxBackdropBody { background: rgba(40, 40, 40, .2); }
.popupRedoxBackdrop.visible,
.popupRedoxBackdropBody.visible { opacity: 1; }

.popupRedoxGlobal.popup-pos-top { align-items: flex-start; }
.popupRedoxGlobal.popup-pos-center { align-items: center; }
.popupRedoxGlobal.popup-pos-bottom { align-items: flex-end; }
.popupRedoxGlobal.popup-force-top { align-items: flex-start !important; }

.popupRedox {
	pointer-events: auto;
	position: relative;
	max-width: 95%;
	width: auto;
	height: auto;
	background-color: var(--carte);
	box-shadow: rgba(0, 0, 0, .15) 0 3px 28px 0, rgba(0, 0, 0, .1) 0 2px 4px 0;
	opacity: 0;
	transform: translate(0, 8%);
	transition: transform .5s ease-in-out, opacity .5s ease-in-out, height .5s ease-in-out;
	z-index: 10;
	top: 0;
	border-radius: var(--radius);
	margin: 0;
	overflow: hidden;
	transform-origin: center;
}

.popupRedox.noHideOverflow { overflow: visible; }
.popupRedox.active { opacity: 1; transform: translate(0, 0); }
.popupRedox.full-height { height: 100% !important; max-height: none !important; overflow: hidden; }
.popupRedox.full-width { width: 100%; overflow: hidden; }

.popupRedoxHeader {
	position: relative;
	display: flex;
	align-items: center;
	padding: 15px 25px 10px 25px;
	/* `min-height` et non `height` : la police d'ici est plus petite que celle
	   de Redox, un titre sur deux lignes doit pouvoir pousser l'en-tête. */
	min-height: 45px;
	border-radius: var(--radius) var(--radius) 0 0;
}

.popupRedoxTitle {
	font-weight: 500;
	font-size: var(--t-fort);
	white-space: normal;
	line-height: 1.3;
}

.popupRedoxTitle i { margin-right: 3px; }

.popupRedoxClose {
	position: absolute;
	top: 15px; right: 15px;
	z-index: 5;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px; height: 22px;
	border-radius: 50%;
	/* `--efface` et non un gris plus pâle : dans quatre fenêtres sans pied, cette
	   croix est la seule façon visible de fermer. */
	color: var(--efface);
	font-size: 15px;
	line-height: 1;
	cursor: pointer;
	outline: none;
	transition: color .25s ease, background .25s ease;
}

.popupRedoxClose:hover { color: var(--muet); background: var(--tete); }
.toolbar .popupRedoxClose {
	top: 10px; right: 11px;
}
.popupRedoxContent {
	padding: 10px 25px 22px 25px;
	transition: padding 300ms ease;
}

/* Quand un pied existe, le contenu lui laisse la place. La règle se met à jour
   toute seule : le plugin RETIRE le pied du DOM quand `isFooter` est faux. */
.popupRedox:has(.popupRedoxFooter) .popupRedoxContent { padding: 10px 25px 10px 25px; }

.popupRedox .popupRedoxFooter {
	display: flex;
	align-items: center;
	width: 100%;
	padding: 15px 25px 20px 25px;
	background-color: transparent;
	border-radius: 0 0 var(--radius) var(--radius);
}

.popupRedox .popupRedoxFooter > .footerLeft { margin-right: auto; display: flex; align-items: center; gap: 20px; }
.popupRedox .popupRedoxFooter > .footerRight { margin-left: auto; display: flex; align-items: center; gap: 20px; }
.popupRedoxGlobal .full-height .popupRedoxFooter { position: fixed; bottom: 0; }
.popupRedoxFooter button { margin-left: 7px; }
/* Un bouton de pied ne passe pas sur deux lignes : « Reprendre l'adresse
   principale » le ferait, à 2 px près, et la fenêtre grandirait de 20 px. */
.popupRedoxFooter .btn { white-space: nowrap; }
.popupRedox .popupRedoxFooter > .footerLeft > button:first-child { margin-left: 0; }

/* Message d'erreur d'un formulaire de popup : sous les champs, là où le regard
   descend avant d'atteindre le bouton. */
.popup-faute { margin: 10px 0 0; color: #b54708; font-weight: 600; }

/* Édition de la fiche ------------------------------------------------------------
   Le crayon vit dans le titre du bloc : l'action est là où porte la modification,
   plutôt que dans une barre d'outils éloignée de ce qu'elle touche. Il reste
   discret tant que la souris n'entre pas dans le bloc. */
.bloc-titre { display: flex; align-items: center; gap: 8px; }

.fiche-crayon {
	margin-left: auto;
	padding: 2px 6px;
	border: 0;
	border-radius: 4px;
	background: none;
	color: #a4a8ac;
	font-size: 11px;
	line-height: 1;
	cursor: pointer;
	/* Atténué au repos plutôt qu'invisible : un crayon qui n'apparaît qu'au
	   survol ne se découvre pas, et rien d'autre sur la fiche n'annonce qu'elle
	   est modifiable. */
	opacity: .75;
	transition: opacity .15s ease, color .15s ease, background .15s ease;
}

.bloc:hover .fiche-crayon,
.fiche-entete:hover .fiche-crayon,
.fiche-crayon:focus-visible { opacity: 1; }
.fiche-crayon:hover { background: var(--tete); color: var(--lien); }
/* Le crayon d'un commentaire qui n'est pas le sien : visible, grisé, inerte — il
   dit que le commentaire existe et à qui il est, sans rien promettre. */
.fiche-crayon.est-verrouille,
.fiche-crayon.est-verrouille:hover { color: var(--verrouille); background: none; cursor: not-allowed; }

/* Dans l'entête, le crayon suit la pastille de statut plutôt que de filer à
   droite : c'est elle qu'il modifie. */
.fiche-identite { display: flex; align-items: center; gap: 8px; }
.fiche-identite .fiche-crayon { margin-left: 0; }
.fiche-convertir { margin-left: 4px; }

/* Formulaire de popup : la grille libelle/champ de .comm-ligne, avec un libellé
   plus large — « Renouvellement » et « Case postale » ne tiennent pas dans les
   70 px de l'écran Communication. */
/* Deux mesures gouvernent cette grille : la largeur du libellé et la gouttière
   qui l'en sépare. Elles sont déclarées ICI et nulle part ailleurs — tout retrait
   qui doit tomber sous le champ vaut la somme des deux, et une valeur recopiée à
   la main finit toujours par mentir de la différence. */
/* 100 : « Téléphone direct » (94,7 px) et « Locale monétaire » (97) y tiennent sur
   une ligne, même quand le libellé grossit d'un demi-point. */
.popup-form { --popup-libelle: 100px; --popup-gouttiere: 10px; }
/* `gap` tout court poserait AUSSI 10 px entre les RANGS d'une ligne qui enveloppe :
   la note d'un champ se retrouverait plus près du champ suivant que du sien, et la
   fenêtre du modèle de message déborderait de son plafond. */
.popup-form .comm-ligne { gap: 0 var(--popup-gouttiere); }
.popup-form .comm-ligne { align-items: center; padding: 0; margin-bottom: 6px; }
.popup-form .comm-ligne > label { flex: 0 0 var(--popup-libelle); }

/* Un cran plus serré que les 30 px de la base — ces champs vont par sept ou huit
   dans un popup. Le reste du dessin (bordure, rayon, fond, police, filet de
   focus, teinte du texte indicatif) vient de la base et n'est pas redit ici.
   `font: inherit` reste, lui : il pèse (0,2,0) et la note sur
   `textarea.param-editeur.form-control` plus bas s'appuie sur ce poids. */
.popup-form .form-control {
	flex: 1 1 auto;
	min-width: 0;
	height: 27px;
	font: inherit;
}

/* Un select natif garde sa flèche : sans réserve à droite, elle chevauche le
   texte des libellés longs. */
.popup-form select.form-control { padding-right: 4px; }

/* Les adresses e-mail en pastilles (le champ `adresses`) : le cadre est celui d'un
   champ, et ses pastilles, puis la frappe de la suivante, s'y rangent sur autant de
   lignes qu'il faut. */
.popup-form .saisie-adresses {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 3px;
	height: auto;
	min-height: 27px;
	padding: 2px 4px;
	cursor: text;
}
.saisie-adresses-pastilles { display: contents; }
.saisie-adresses-frappe {
	flex: 1 1 8em;
	min-width: 8em;
	height: 21px;
	padding: 0 4px;
	border: 0;
	background: transparent;
	color: inherit;
	font: inherit;
	outline: 0;
}
/* Une adresse ne se coupe pas : trop longue, elle s'ellipse, et son infobulle la
   porte entière. Les couleurs sont celles de `.label-neutre`, que la pastille porte. */
.adresse-pastille {
	display: inline-flex;
	align-items: center;
	max-width: 100%;
	height: 21px;
	border-radius: 11px;
	font-size: var(--t-petit);
	white-space: nowrap;
}
/* Le texte couvre la pastille jusqu'à la croix : un clic n'importe où la rouvre. */
.adresse-pastille-texte {
	overflow: hidden;
	text-overflow: ellipsis;
	padding-left: 8px;
	cursor: pointer;
}
.adresse-pastille-retirer {
	padding: 0 7px 0 5px;
	color: var(--muet);
	font-size: var(--t-fort);
	line-height: 1;
	cursor: pointer;
}
.adresse-pastille-retirer:hover { color: var(--danger); }
.adresse-pastille-edition {
	max-width: 100%;
	min-width: 12em;
	height: 21px;
	padding: 0 8px;
	border: 1px solid var(--focus);
	border-radius: 11px;
	background: var(--carte);
	color: var(--texte);
	font: inherit;
	font-size: var(--t-petit);
	outline: 0;
}

/* Les dates sont courtes et se lisent au chiffre : leur donner toute la largeur
   d'une ligne les noie. */
.popup-form input[data-date] { flex: 0 0 108px; font-variant-numeric: tabular-nums; }

.popup-fige { flex: 1 1 auto; color: var(--muet); font-variant-numeric: tabular-nums; }
.popup-case { flex: 1 1 auto; display: flex; align-items: center; gap: 8px; }
.popup-aide { color: var(--muet); }

.popup-note {
	margin: 12px 0 0;
	padding: 8px 10px;
	background: var(--tete);
	border-radius: 5px;
	color: var(--muet);
	line-height: 1.4;
}

/* Lecteur PDF ------------------------------------------------------------------
   Styles repris de redox/css/desktop.css:10653-10934. Ce qui servait les
   miniatures, la recherche, perfect-scrollbar et le lecteur d'images est resté
   là-bas. Les cinq variables de couleur de Redox sont remappées ici, et deux
   corrections sont faites au passage : `.toolbar a` avait une hauteur de 10 px
   pour une icône de 16 (elle débordait), et `.pdfSpot` était en `overflow:hidden`
   parce que perfect-scrollbar prenait le relais — le défilement est natif ici.

   Le fond gris du plan de travail et le blanc de la page ne sont PAS branchés
   sur les variables de thème : ce sont des conventions de lecteur PDF, pas des
   choix de charte. */

.viewerdocRedox {
	overflow: hidden !important;
	/* Colonne : la barre garde sa hauteur, le plan de travail prend le reste.
	   L'original tenait sa hauteur d'un plugin qui mesurait un conteneur absent
	   d'ici — sans ce flex, aucune page ne s'afficherait. */
	display: flex;
	flex-direction: column;
}

.viewerdocRedox .toolbar {
	flex: 0 0 40px;
	position: relative;
	display: flex;
	align-items: center;
	width: 100%;
	padding: 0 4px;
	background-color: var(--tete);
	border: 1px solid var(--bord);
	border-bottom: none;
	border-radius: var(--radius) var(--radius) 0 0;
	overflow: hidden;
	user-select: none;
}

.viewerdocRedox .toolbar-center {
	flex: 1;
	min-width: 0;
	padding: 0 10px;
	color: var(--texte);
	font-size: var(--t-base);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.viewerdocRedox .toolbar-right { flex-shrink: 0; display: flex; align-items: center; gap: 1px; padding-right: 4px; }
.viewerdocRedox .toolbar-group { display: inline-flex; align-items: center; }

.viewerdocRedox .toolbar a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 24px;
	border-radius: 5px;
	text-decoration: none;
	transition: background-color .12s;
}

.viewerdocRedox .toolbar i { font-size: 15px; color: var(--lien); }
.viewerdocRedox .toolbar a:not(.link_disabled):hover { background: #e9eef3; }
.viewerdocRedox .toolbar a:not(.link_disabled):hover i { color: var(--accent); }
.viewerdocRedox .toolbar a.link_disabled { cursor: default; }
.viewerdocRedox .toolbar a.link_disabled i { color: #c3ccd5; }

.viewerdocRedox .toolbar-sep { width: 1px; height: 16px; margin: 0 6px; background-color: #ccc; flex-shrink: 0; }
/* Réserve la place de la croix de fermeture, qui est en position absolue. */
.viewerdocRedox .toolbar-sep.spaceclose { width: 0; margin-right: 28px; }

.pageNav.navStuff { display: inline-flex; align-items: center; gap: 4px; }
.redoxPdfReader .pageNavArrows { display: inline-flex; flex-direction: column; align-items: center; line-height: 1; }
.redoxPdfReader .prev, .redoxPdfReader .next { height: 12px; }
.redoxPdfReader .prev i, .redoxPdfReader .next i { font-size: 11px; }

.viewerdocRedox .pageNav .currentPageInput,
.viewerdocRedox .toolbar input.zoomPercent {
	height: 22px;
	padding: 0 3px;
	border: 0;
	border-radius: 3px;
	background: var(--carte);
	font: inherit;
	font-variant-numeric: tabular-nums;
}

.viewerdocRedox .pageNav .currentPageInput { width: 34px; text-align: right; }
.viewerdocRedox .toolbar input.zoomPercent { width: 56px; text-align: center; }
.viewerdocRedox .npages { margin-left: 3px; color: var(--muet); white-space: nowrap; }

.redoxPdfReader .pdfParent {
	flex: 1 1 auto;
	min-height: 0;
	position: relative;
	width: 100%;
	border: 1px solid var(--bord);
	border-top: none;
	border-radius: 0 0 var(--radius) var(--radius);
	background-color: #f8f8f8;
}

.redoxPdfReader .pdfSpot {
	position: relative;
	width: 100%;
	height: 100%;
	overflow: auto;
	text-align: center;
	background-color: #eee;
}

.redoxPdfReader .canvasWrapper {
	margin: auto;
	margin-bottom: 5px;
	background-color: #fff;
	overflow: hidden;
}

.redoxPdfReader .pdfSpot .canvasWrapper:last-child { margin-bottom: 0; }
.redoxPdfReader .pdfSpot canvas { display: block; margin: auto; }

/* La couche texte : invisible, mais sélectionnable et copiable. C'est elle qui
   fait la différence entre un lecteur et une image de page. pdfjs place chaque
   mot avec `--scale-factor`, que le contrôleur pose. */
.redoxPdfReader .textLayer {
	position: absolute;
	inset: 0;
	overflow: hidden;
	opacity: 1;
	line-height: 1;
	z-index: 2;
}

.redoxPdfReader .textLayer > span {
	position: absolute;
	color: transparent;
	white-space: pre;
	cursor: text;
	transform-origin: left top;
	z-index: 3;
}

.redoxPdfReader .textLayer ::selection { background: rgba(64, 148, 162, .35); }

.redoxPdfReader .progress {
	position: absolute;
	left: 0; top: 0;
	width: 100%;
	height: 3px;
	margin: 0;
	border-radius: 0;
	background-color: transparent;
	z-index: 4;
}

.redoxPdfReader .progress .progress-bar { background-color: var(--lien); transition: width .3s ease; }

/* Un PDF absent est un cas courant, pas une exception : des factures reprises
   n'en ont jamais eu. Le message se pose dans la fenêtre. */
.redoxPdfReader .pdfFaute {
	position: absolute;
	left: 0; right: 0; top: 45%;
	padding: 0 30px;
	color: var(--muet);
	text-align: center;
	z-index: 5;
}

/* L'icône PDF précède le numéro de facture. Discrète, mais présente : c'est le
   seul indice qu'on peut ouvrir la pièce. Grisée quand elle n'existe pas. */
.c-num-fact .voir-pdf { color: #c0392b; text-decoration: none; opacity: .75; }
.c-num-fact .voir-pdf:hover { opacity: 1; }

/* Action de ligne : une icône nue, discrète tant qu'on ne la vise pas. La
   colonne ne prend que sa largeur — elle n'est là que pour elle. */
.c-act { width: 1%; white-space: nowrap; }
.btn.btn-sm{
	padding:2px 10px!important;
	font-size: var(--t-base)!important;
	font-weight:500;
}
.btn-ligne {
	padding: 1px 5px;
	border: 0;
	background: transparent;
	color: #c3ccd6;
	cursor: pointer;
	line-height: 1;
}

.btn-ligne:hover { color: var(--danger); }
.btn-ligne:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
.btn-ligne:disabled, .btn-ligne:disabled:hover { color: #c3ccd6; opacity: .45; cursor: not-allowed; }
.c-num-fact .pdf-absent { color: #d5dbe1; }

/* La facture dans la fiche ---------------------------------------------------------
   Elle prend la place de la liste des factures, dans le volet Facturation. Deux
   colonnes : à gauche à qui et quand, à droite ce qui est facturé. Les lignes
   plafonnent à neuf dans toute la base — aucune zone de défilement interne n'est
   nécessaire, c'est le volet qui défile. */
.facture-piece { display: flex; flex-direction: column; min-height: 0; height: 100%; }

.facture-tete {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: var(--gap);
	padding-bottom: 10px;
	margin-bottom: var(--gap);
	border-bottom: 1px solid var(--bord);
}

.facture-tete .fiche-identite { flex: 1 1 auto; min-width: 0; }
.facture-tete .fiche-meta { flex: 0 0 auto; text-align: right; }

/* Le retour précède le titre : c'est le premier geste attendu quand on a fini
   de lire la pièce. */
.facture-retour {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px; height: 26px;
	margin-right: 2px;
	border-radius: 5px;
	color: var(--muet);
	text-decoration: none;
	transition: background .15s ease, color .15s ease;
}

.facture-retour:hover { background: var(--tete); color: var(--lien); }

.facture-corps { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

.facture-colonnes {
	display: grid;
	grid-template-columns: minmax(260px, 320px) minmax(0, 1fr);
	gap: 22px;
	align-items: start;
}

/* Les blocs empilés d'une colonne respirent : sans cette gouttière ils se
   toucheraient, et Lignes, Envois et Versements se liraient comme un seul pavé. */
.facture-col-gauche,
.facture-col-droite { display: flex; flex-direction: column; gap: 22px; min-width: 0; }

.facture-adresse { padding: 10px 12px; line-height: 1.6; }
.facture-adresse .muet { font-size: var(--t-petit); }

/* Les totaux prolongent le tableau des lignes : même largeur, filet de
   séparation, libellés poussés à droite pour tomber sous la colonne Montant. */
.facture-totaux { margin-top: 0; border-top: 1px solid var(--bord); }
.facture-totaux th { width: auto; text-align: right; font-weight: 400; color: var(--muet); }
.facture-totaux td { width: 130px; }
.facture-totaux tr.est-fort th { color: var(--texte); font-weight: 600; }
.facture-totaux tr.est-fort td { font-weight: 600; }
/* La teinte de `.c-solde` : `--accent`, à 3,01:1, ferait de « Reste à payer 0.00 »
   le texte le plus pâle de la pièce, et c'est lui qui la dit réglée. */
.facture-totaux tr.est-solde td { color: #067647; }
.facture-totaux tbody tr:hover td { background: transparent; }

/* Une précision qui n'a pas à peser autant que le libellé. */
.facture-note {
	margin-left: 6px;
	padding: 0 5px;
	border-radius: 20px;
	background: var(--tete);
	color: var(--muet);
	font-size: var(--t-mini);
}

.c-compte { font-variant-numeric: tabular-nums; color: var(--muet); }

@media (max-width: 1100px) {
	.facture-colonnes { grid-template-columns: minmax(0, 1fr); }
}

/* Deux types de champ de plus dans les popups d'édition : un nombre court et un
   texte sur deux lignes ; la fenêtre des LIGNES DE FACTURE s'en sert, quantité
   et prix.
   LE SÉLECTEUR PORTE `.comm-ligne >`, ET CE N'EST PAS DÉCORATIF. Sans lui, la
   règle vaudrait (0,3,0) — exactement comme `.popup-form .comm-ligne >
   .form-control { flex-basis: 0 }`, écrite plus bas, qui l'emporterait : les
   deux champs tomberaient à 18 px au lieu de 90.
   On ne peut pas déplacer l'autre règle : elle empêche un champ accompagné d'une
   note de réclamer la ligne entière et de tomber sous son libellé. On égalise
   donc la forme du sélecteur et l'on ajoute la classe, ce qui donne (0,4,0) : la
   règle gagne quel que soit l'ordre du fichier. */
/* L'heure voisine de sa date : largeur fixe — « 14:32 » tient en cinq
   caractères —, calée à droite de la date qui prend le reste de la ligne. Même
   poids de sélecteur que `.popup-nombre` juste en dessous, pour la même raison :
   `.popup-form .form-control` pose `flex: 1 1 auto` sur tout champ. */
.popup-form .comm-ligne > .form-control.popup-heure-voisine { flex: 0 0 70px; text-align: center; font-variant-numeric: tabular-nums; }

.popup-form .comm-ligne > .form-control.popup-nombre {
	flex: 0 0 90px;
	text-align: right;
	font-variant-numeric: tabular-nums;
}
.popup-form .comm-ligne-haut { align-items: flex-start; }
.popup-form .comm-ligne-haut > label { padding-top: 5px; }
.popup-form textarea.popup-texte-long { height: auto; padding: 5px 8px; line-height: 1.4; resize: vertical; }

/* Les actions d'une facture : ajouter une ligne, modifier l'en-tête. Discrètes
   dans les titres de bloc, comme les crayons de la fiche société. */
.facture-piece .bloc-titre .fiche-crayon { font-size: 11px; }
/* Les lignes se cliquent pour être modifiées — mais pas la ligne de SAISIE, qui
   est un formulaire : ni main, ni survol sur elle. */
.facture-lignes tbody:not(.facture-saisie) tr { cursor: pointer; }
.facture-lignes tbody:not(.facture-saisie) tr:hover td { background: var(--survol); }
/* La désignation garde ses retours à la ligne, comme l'ancien les rendait. Sans
   cela, une désignation de trois lignes se lisait d'un bloc, et la retrouver
   découpée dans la ligne de saisie surprenait. */
.facture-table td.c-designation { white-space: pre-line; }

/* --- La ligne de saisie ---------------------------------------------------------
   En tête du tableau, sur un fond légèrement teinté : on doit y reconnaître la
   zone où l'on écrit, distincte des lignes déjà enregistrées. Les champs sont
   serrés à la hauteur d'une ligne de tableau — on compose une facture ligne à
   ligne, on ne remplit pas un formulaire. */
.facture-saisie td {
	padding: 6px 4px;
	background: var(--tete);
	border-bottom: 1px solid var(--bord);
	vertical-align: top;
}
.facture-saisie td:first-child { padding-left: 8px; }
.facture-saisie .form-control {
	height: 28px;
	padding: 3px 7px;
	font-size: var(--t-base);
}
.facture-saisie .c-dr .form-control { text-align: right; font-variant-numeric: tabular-nums; }
/* La désignation part sur une ligne et s'agrandit avec son texte : c'est le
   contrôleur qui ajuste sa hauteur. Pas de poignée — elle n'aurait rien à régler. */
.facture-saisie textarea.form-control {
	min-height: 28px;
	line-height: 1.4;
	resize: none;
	overflow: hidden;
}
/* Le montant se calcule à mesure : il s'aligne sur les champs, pas sur le haut
   de la cellule. */
.facture-saisie [data-saisie-montant] { padding-top: 11px; color: var(--muet); }
.facture-saisie .saisie-actions { white-space: nowrap; text-align: right; padding-right: 8px; }
.facture-saisie .saisie-annuler { margin-left: 9px; font-size: var(--t-base); color: var(--lien); }
.facture-saisie .saisie-annuler:hover { color: var(--lienHover); }
/* LA LIGNE DE SAISIE NE PREND PAS LE SURVOL DES TABLEAUX. La règle générique
   `.tb_liste tbody tr:hover td` la passerait au bleu des lignes cliquables dès que
   la souris la traverse pour atteindre « Modifier » : elle perdrait son ambre de
   modification, et ressemblerait à une ligne qu'on pourrait cliquer. Même
   spécificité relevée d'un cran, pour gagner. */
.tb_liste tbody.facture-saisie tr:hover td { background: var(--tete); }
.tb_liste tbody.facture-saisie.est-en-edition tr:hover td { background: #fff8e6; }
.tb_liste tbody.facture-saisie tr.saisie-faute:hover td { background: var(--tete); }

/* Une ligne se modifie aussi au clavier : elle prend le focus, et le montre. */
.facture-lignes tbody tr[data-ligne]:focus { outline: none; }
.facture-lignes tbody tr[data-ligne]:focus-visible td { background: var(--survol); }
.facture-lignes tbody tr[data-ligne]:focus-visible td:first-child { box-shadow: inset 3px 0 0 var(--focus); }

/* Le refus du serveur, sous la ligne qu'il concerne. */
.facture-saisie .saisie-faute td { padding: 0 8px 7px; background: var(--tete); color: var(--danger); font-size: var(--t-base); }

/* Le catalogue flotte au-dessus de la page (`placer()`, dans `app.js`, le pose en
   `position: fixed` et lui donne sa largeur — plus large que la colonne
   « Service », trop étroite pour lire un service, sa désignation et son prix côte
   à côte). Au-dessus du volet et de ses blocs, sous les fenêtres (1000). */
.facture-saisie .popup-choix { z-index: 950; }
/* La quantité par défaut, entre la désignation et le prix : sans elle,
   « Espace disque … 2 » se lirait comme une ligne de 2 CHF. */
.popup-choix .choix-quantite { flex: 0 0 auto; color: var(--muet); font-variant-numeric: tabular-nums; }
.popup-choix .choix-quantite:empty { display: none; }

/* EN MODIFICATION, la ligne de saisie ET la ligne d'origine se signalent. L'ancien
   soulignait les champs sans rien marquer dans le tableau : avec deux lignes
   voisines de même service, on ne savait plus laquelle on corrigeait. */
.facture-saisie.est-en-edition td { background: #fff8e6; }
.facture-saisie.est-en-edition .form-control { border-color: #e0a526; }
.facture-lignes tbody tr.est-en-edition td,
.facture-lignes tbody tr.est-en-edition:hover td { background: #fff3d6; }
.facture-lignes tbody tr.est-en-edition td:first-child { box-shadow: inset 3px 0 0 #e0a526; }

/* LES COLONNES CHIFFRÉES ONT UNE LARGEUR FIXE, comme dans l'ancien (100 px). Sans
   elle, le tableau répartissait la place à parts presque égales : la quantité —
   un ou deux chiffres — recevait autant que la désignation, qui est le seul
   champ long de la ligne, et c'est elle qui se retrouvait à l'étroit. L'ordre des
   colonnes est celui des deux gabarits, facture et abonnement. */
.facture-table thead th:nth-child(1) { width: 170px; }
.facture-table thead th:nth-child(3) { width: 72px; }
.facture-table thead th:nth-child(4),
.facture-table thead th:nth-child(5) { width: 100px; }

/* La colonne des actions : juste la place d'une corbeille. */
.facture-lignes .c-action { width: 1%; white-space: nowrap; text-align: right; }
/* La corbeille est discrète tant qu'on ne la vise pas : elle est sur chaque
   ligne, et une colonne de rouge vif crierait plus fort que les montants. */
.ligne-suppr {
	padding: 1px 5px;
	border: 0;
	background: none;
	color: var(--muet);
	opacity: .55;
	cursor: pointer;
}
.facture-lignes tr:hover .ligne-suppr { opacity: .9; }
.ligne-suppr:hover, .ligne-suppr:focus-visible { color: var(--danger); opacity: 1; }

/* Le document a été republié — ou n'a pas pu l'être. Le second cas doit se voir. */
.facture-pdf-faute {
	margin-bottom: var(--gap);
	padding: 10px 12px;
	border: 1px solid #f0c5c0;
	border-radius: var(--radius);
	background: #fdf1f0;
	color: #a03127;
	line-height: 1.5;
}

/* Pourquoi une pièce ne se modifie plus : dit avant qu'on essaie. */
.facture-gel { margin: 0 0 8px; color: var(--muet); font-size: var(--t-petit); line-height: 1.5; }

/* Suggestion depuis le catalogue des services. La liste se pose sous le champ
   sans pousser le contenu : le popup ne doit pas grandir à la frappe. */
.popup-suggestion { position: relative; flex: 1 1 auto; min-width: 0; }

.popup-choix {
	position: absolute;
	left: 0; right: 0; top: 100%;
	z-index: 20;
	max-height: 190px;
	margin: 2px 0 0;
	padding: 3px 0;
	list-style: none;
	overflow-y: auto;
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 5px;
	box-shadow: 0 6px 16px rgba(16, 24, 40, .14);
}

.popup-choix li {
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 4px 9px;
	cursor: pointer;
}

.popup-choix li.est-vise { background: var(--survol); }
.popup-choix .choix-service { flex: 0 0 auto; font-weight: 600; }
.popup-choix .choix-designation { flex: 1 1 auto; min-width: 0; color: var(--muet); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.popup-choix .choix-prix { flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* Le popup ne rogne pas la liste de suggestions : le plugin met `overflow:hidden`
   sur le cadre, d'où la classe `noHideOverflow` qu'il prévoit lui-même. */
.popupRedox .popupRedoxContent.popup-form { overflow: visible; }

/* La colonne de gauche de la facture est un seul bloc en trois parties : le
   destinataire, la facture, ses rappels. Un filet et un intitulé les séparent —
   trois cartes distinctes découperaient une information qui se lit d'un trait. */
.facture-separation {
	margin-top: 4px;
	padding: 7px 12px 5px;
	border-top: 1px solid var(--bord);
	background: var(--tete);
	color: var(--muet);
	font-size: var(--t-mini);
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
}

/* Le bloc ne porte qu'un titre pour trois parties : ses tableaux ne doivent
   pas rajouter de filet au-dessus d'eux. */
.facture-col-gauche .tb_fiche { margin: 0; }

/* Fenêtre d'envoi : le corps du message a besoin de place, et les jetons non
   substitués doivent se voir avant qu'on clique. */
.popup-form textarea.popup-courrier-corps { height: auto; min-height: 190px; line-height: 1.5; resize: vertical; }
.popup-avert { margin: 8px 0 0; padding: 8px 10px; border-radius: 5px; background: #fdf6e9; color: #92400e; }

/* Les actions de la facture : côte à côte, en boutons discrets, et non empilées
   comme les lignes d'audit de `.fiche-meta`. */
.facture-actions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }

.facture-actions a {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 5px 11px;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--carte);
	color: var(--texte);
	text-decoration: none;
	white-space: nowrap;
	transition: background .15s ease, border-color .15s ease;
}

.facture-actions a:hover { background: var(--tete); border-color: #d8dfe6; }
.facture-actions a .fa-file-pdf { color: #c0392b; }
.facture-actions a .fa-paper-plane { color: var(--lien); }

/* Le code base de l'abonnement, à côté de son numéro : c'est la clé qui le relie
   à Redox. */
.abo-base { margin-left: 8px; font-size: var(--t-petit); }
.ligne_abonnement { cursor: pointer; }
.factu-abos .tb_liste tbody tr.ligne_abonnement:hover td { background: var(--survol); }

/* Le cycle mensuel : trois étapes, chacune disant ce qu'elle ferait avant de le
   faire. La numérotation est visuelle — l'ordre compte, et sauter une étape n'a
   pas de sens. */
.cycle-etapes { margin-top: var(--gap); }
.cycle-liste { margin: 0; padding: 0; list-style: none; }

.cycle-etape {
	padding: 12px 0;
	border-top: 1px solid var(--bord);
}

.cycle-tete { display: flex; align-items: center; gap: 10px; }

.cycle-rang {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px; height: 22px;
	border-radius: 50%;
	background: var(--tete);
	color: var(--muet);
	font-size: var(--t-petit);
	font-weight: 600;
}

.cycle-etape.est-faite .cycle-rang { background: #e4f4ec; color: #1e7a52; }
.cycle-nom { flex: 1 1 auto; font-weight: 600; }
.cycle-detail { margin: 5px 0 0 32px; color: var(--texte); line-height: 1.45; }
.cycle-detail.muet { color: var(--muet); }
.cycle-alerte { display: block; margin-top: 3px; color: #92400e; }

/* Qui sera facturé, nommément. Le décompte seul ne se vérifie pas : c'est la
   liste qui permet de repérer le client inattendu, ou celui qui manque. Elle
   défile au-delà de six lignes — le parc en compte plus de cent. */
.cycle-qui {
	max-height: 168px;
	margin-top: 8px;
	overflow-y: auto;
	border: 1px solid var(--bord);
	border-radius: 5px;
}

.cycle-qui .tb_liste td { padding: 4px 9px; border-bottom: 1px solid var(--bord-fin); }
.cycle-qui .tb_liste tr:last-child td { border-bottom: 0; }
.cycle-qui .tb_liste tbody tr:hover td { background: var(--survol); }
.cycle-qui .c-num-fact { width: 1%; }
/* Trois classes, pour passer devant le zébrage du `tb_liste`. */
.cycle-qui .tb_liste tr.est-vide td { background: #fdf6e9; }
.cycle-alerte-ligne { color: #92400e; }

/* Les abonnements écartés du cycle, avec leur motif. Discrets mais lisibles :
   c'est une information de contrôle, pas une alerte. */
.cycle-ecartes { margin-top: 8px; }
.cycle-ecartes ul { margin: 4px 0 0; padding-left: 18px; }
.cycle-ecartes li { margin-bottom: 2px; }

/* Encaissements ---------------------------------------------------------------
   Les clients à gauche, les factures du client choisi à droite, dans l'ordre où
   un paiement les éteindrait. Même motif liste-détail que les suivis : un
   encaissement est un geste répétitif, et une fenêtre à ouvrir puis fermer
   coûterait deux clics par client. */
.enc-duo {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	display: grid;
	/* 1.05 : la liste des clients y gagne de quoi garder sur une ligne le nom le
	   plus long avec sa pastille d'avance. */
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
	gap: var(--gap);
	padding: 5px;
}

.enc-clients, .enc-detail { min-height: 0; min-width: 0; }

/* Le détail est une carte : il porte une saisie, et une bordure dit où elle
   commence. La liste de gauche, elle, reste à même le fond. */
.enc-detail {
	display: flex;
	flex-direction: column;
	border: 1px solid var(--bord);
	border-radius: var(--radius);
	background: var(--carte);
}

.enc-vide {
	margin: auto;
	padding: var(--gap);
	color: var(--muet);
}

.ligne_client { cursor: pointer; }

/* --- La recherche du payeur : ce qu'elle a trouvé, et pourquoi -------------------
   Le surlignage est un fond, pas une couleur de texte : il doit se lire sur du
   texte courant comme sur du texte `--muet` (la forme juridique, le numéro), et
   les deux passent 4,5:1 sur ce jaune. */
mark.trouve {
	padding: 0 1px;
	border-radius: 2px;
	background: #ffec99;
	color: inherit;
}

/* Sous le nom, la raison : le membre, l'adresse, la facture qui ont désigné ce
   client. Un cran en dessous du nom, et jamais en gras — la ligne choisie passe
   en 600, la raison reste une annotation. Elle REPLIE au lieu de s'allonger : la
   colonne est étroite, et un libellé collé peut porter trois raisons. */
.enc-raisons {
	display: flex;
	flex-wrap: wrap;
	gap: 0 12px;
	margin-top: 2px;
	font-size: var(--t-petit);
	font-weight: 400;
	line-height: 1.45;
	color: var(--texte);
}
.enc-raison { min-width: 0; overflow-wrap: anywhere; }
.enc-raison-genre { color: var(--muet); }
.enc-manque { color: #92400e; }

/* « Voici les plus proches » : une réserve, pas une alerte. Même ocre que les
   mises en garde du cycle de facturation. */
.tb_liste tr.enc-piste td {
	padding: 7px 10px;
	background: #fdf6e9;
	color: #92400e;
	white-space: normal;
}
.enc-piste i { margin-right: 4px; }

.enc-rien span { display: block; margin-top: 3px; }

/* L'aide de la recherche, sous l'invite du panneau vide. */
.enc-vide { max-width: 420px; text-align: center; }
.enc-aide { display: block; margin-top: 8px; font-size: var(--t-petit); line-height: 1.5; }

/* Dans le panneau : la raison redite au-dessus de la saisie, et la facture que la
   recherche a désignée. Trois classes, pour passer devant le zébrage. */
.enc-trouve {
	display: flex;
	flex-wrap: wrap;
	gap: 0 12px;
	padding: 5px 12px;
	border-bottom: 1px solid var(--bord-fin);
	font-size: var(--t-petit);
	line-height: 1.45;
}
.enc-trouve-titre { color: var(--muet); }
.enc-liste .tb_liste tr.est-visee td { background: #fff8db; }
.enc-liste .tb_liste tr.est-visee td:first-child { box-shadow: inset 3px 0 0 #e0b100; }
/* Trois classes, pour passer devant le zébrage du `tb_liste`. */
.tb_liste tr.ligne_client.est-actif td { background: var(--survol); font-weight: 600; }

/* Tête du panneau : qui, et combien il doit en tout. */
.enc-tete {
	flex: 0 0 auto;
	display: flex;
	align-items: baseline;
	gap: 8px;
	padding: 8px 12px;
	border-bottom: 1px solid var(--bord);
	background: var(--tete);
}

.enc-nom { font-size: var(--t-base); font-weight: 600; letter-spacing: -.005em; }
.enc-du { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 600; }
/* Seul le nom se replie : le numéro de client, le montant et la pastille de
   blocage ne se coupent pas (« C250501- » / « 352 », « CHF 3 » / « 728.00 »). */
.enc-tete > .muet, .enc-tete > .enc-du, .enc-tete > .label { flex: 0 0 auto; white-space: nowrap; }

.enc-liste { flex: 1 1 auto; min-height: 0; }
.enc-liste td { padding-top: 4px; padding-bottom: 4px; }
.enc-rang { width: 1%; color: var(--muet); font-variant-numeric: tabular-nums; }

/* L'échéance passée est la seule couleur du tableau : c'est l'échéance qui range
   les factures, dans l'ordre où le surplus d'un encaissement les paie et où la
   question se pose avant une autre que la plus ancienne. */
.c-date.est-echue { color: #b54708; }

/* Le cran le plus serré du front — ces champs vont par vingt-cinq, un par ligne
   de tableau, et chaque pixel de haut coûte une facture de moins à l'écran. Le
   dessin vient de la base. */
.enc-detail .form-control {
	height: 24px;
	padding: 0 7px;
}

/* Le montant est préchargé au dû : le geste courant est un clic sur OK, et le
   champ n'est là que pour le versement partiel. */
.enc-saisie { display: inline-flex; align-items: center; gap: 5px; }
.enc-saisie .btn-sm { padding: 1px 7px; font-size: var(--t-petit); }

.enc-montant {
	/* 88 : à 13 px un chiffre fait 7,2 px, et un montant à six chiffres remplit la
	   case au pixel près. */
	width: 88px;
	text-align: right;
	font-variant-numeric: tabular-nums;
}

/* Une barre de saisie, sous la tête du panneau : ce qui vaut pour le client entier
   et non pour une ligne — aujourd'hui, la case de déblocage. */
.enc-barre {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 8px 12px;
	border-bottom: 1px solid var(--bord);
	background: var(--tete);
	color: var(--muet);
	/* La barre se REPLIE par blocs entiers. Sans cela, sur un client bloqué, la case
	   se couperait en « Débloquer ce / client » et son rappel au milieu du montant
	   (« CHF 3 » / « 728.00 ») ; une faute s'y ajouterait sur quatre lignes. */
	flex-wrap: wrap;
	row-gap: 6px;
}

.enc-barre label { display: flex; align-items: center; gap: 6px; margin: 0; }
.enc-barre .form-control { width: auto; }
/* 96 : réglée au pixel sur un texte plus petit, la case couperait le dernier
   chiffre de l'année. */
.enc-barre [data-date] { width: 96px; text-align: center; font-variant-numeric: tabular-nums; }
.enc-barre select.form-control { padding-right: 4px; }

/* La même barre dans la tête de l'écran, pour la date et le compte : ils valent
   pour TOUT le relevé qu'on encaisse, se saisissent une fois et servent chaque
   client. Dans le panneau, repeint à chaque client choisi, la date revenait au
   jour à chaque fois. Ici elle se pose à même le bandeau, à la place des totaux. */
.liste-tete .enc-barre {
	margin-left: auto;
	padding: 0;
	border: 0;
	background: none;
	flex-wrap: nowrap;
}
/* La date retenue d'un repeint à l'autre qui n'est pas celle du jour se signale :
   elle survit au rafraîchissement, et vingt versements partiraient à cette date. */
.enc-barre [data-date].est-autre-jour { color: #b54708; border-color: #f5c58a; font-weight: 600; }

/* Les totaux de la liste, à un survol, en bout de bandeau. */
.enc-totaux i { font-size: 14px; }
/* Le filtre des avances posé, la tête le dit hors de l'infobulle. */
.enc-filtre-actif { display: none; font-size: var(--t-petit); font-weight: 600; white-space: nowrap; }
.enc-totaux:has(.lien-filtre.est-actif) { color: var(--lien); }
.enc-totaux:has(.lien-filtre.est-actif) .enc-filtre-actif { display: inline; }
.bulle-aide-texte .lien-filtre.est-actif { color: #fff; }

/* La faute d'un versement, sous la tête du client. */
.enc-faute { padding: 6px 12px; border-bottom: 1px solid var(--bord-fin); color: var(--danger); }

/* La case de déblocage. Elle n'apparaît que sur un client bloqué, et elle porte
   à côté d'elle le nombre de factures encore échues : c'est le chiffre sur
   lequel la décision se prend, il doit être lu sans quitter la barre.

   AUCUNE TAILLE N'EST REDÉFINIE ICI : `width: auto; height: auto` annulerait le
   17x17 px de la règle générale, et les cases de l'app, dessinées en
   `appearance: none`, n'ont pas d'autre dimension. `accent-color` serait vain
   pour la même raison : il ne peint que l'apparence native, justement désactivée.

   Ce qui reste propre à ce contexte : le libellé porte une décision lourde, il
   se lit en texte normal et non dans le gris de la barre, et le rappel du retard
   garde le ton de la mise en garde. */
.enc-debloquer { color: var(--texte); font-weight: 500; cursor: pointer; white-space: nowrap; }
.enc-debloquer .muet { font-weight: 400; color: var(--danger); }

/* L'EMPILEMENT SOUS 1100 PX, ICI ET NON AVEC LES AUTRES : écrit dans le bloc
   commun, plus haut dans la feuille, il passerait AVANT `.enc-duo`, `.enc-detail`
   et `.enc-liste`, qui l'emporteraient à spécificité égale, et le bouton OK
   d'encaissement sortirait du champ. `.enc-clients` et `.div_tb_normal` sont sur
   le même nœud : un sélecteur descendant ne matcherait rien. */
@media (max-width: 1100px) {
	.enc-duo { display: block; overflow-y: auto; }
	.enc-clients, .enc-detail { display: block; }
	.enc-clients { margin-bottom: var(--gap); height: 300px; }
	.enc-liste { flex: 0 0 auto; height: 280px; }
}

/* --- dropdownRedox --------------------------------------------------------------
   Le plugin vient de Redox (`js/common/dropdownRedox.js`), repris tel quel. Son
   habillage est ici transposé aux variables d'adm : mêmes classes, mêmes formes,
   les couleurs de la maison. Sans cela, le menu s'ouvrirait sans fond ni ombre —
   le plugin ne pose que la position. */
.dropdownRedox { position: relative; display: inline-block; }

.dropdownRedox .dropdownContent {
	display: none;
	position: absolute;
	z-index: 1100;
	min-width: 190px;
	padding: 4px;
	border: 1px solid var(--bord);
	border-radius: 10px;
	background: var(--carte);
	box-shadow: 0 10px 30px rgba(15, 23, 42, .16);
	white-space: nowrap;
	will-change: transform, opacity;
}

/* C'est le plugin qui pose `.show` : sans cette règle, il ouvrait le menu sans
   que rien ne s'affiche. Le plugin gère la position, la feuille de style gère la
   visibilité — les deux moitiés du même contrat. */
.dropdownRedox .dropdownContent.show {
	display: block;
	animation: zoom-dropdown 160ms forwards;
}

@keyframes zoom-dropdown {
	from { opacity: 0; transform: scale(.96); }
	to   { opacity: 1; transform: scale(1); }
}

.dropdownRedox .dropdownContent .dropdownItem {
	display: block;
	position: relative;
	margin: 0;
	padding: 7px 14px;
	border-radius: 6px;
	color: var(--texte);
	text-decoration: none;
	font-weight: 400;
	cursor: pointer;
	border: none;
}

.dropdownRedox .dropdownContent .dropdownItem:hover { background: var(--survol); }
.dropdownRedox .dropdownContent .dropdownItem i { width: 16px; margin-right: 6px; color: var(--muet); }

/* Le canal retenu porte une pastille : le bouton dit déjà lequel, mais le menu
   ouvert doit le confirmer sans qu'on relise l'étiquette derrière. */
.dropdownRedox .dropdownContent .dropdownItem.est-actif { background: var(--survol); font-weight: 600; }
.dropdownRedox .dropdownContent .dropdownItem.est-actif i { color: var(--focus); }
.dropdownRedox .dropdownDivider { height: 1px; margin: 4px 0; background: var(--bord); }

/* La ligne du compteur n'a pas d'étiquette : elle prolonge le champ au-dessus. */
.comm-ligne-aide { margin-top: -6px; }
.popup-aide.est-trop-long { color: var(--danger); font-weight: 600; }

/* --- Le bouton d'envoi ----------------------------------------------------------
   UN SEUL bouton, qui n'envoie rien : il ouvre le choix du canal. Il en a donc
   l'apparence — un chevron discret, en retrait de l'étiquette, qui annonce un
   menu et non un départ. Un bouton soudé « Envoyer | ▾ » enverrait d'un clic,
   sur un canal qu'on n'a pas relu. */
.facture-actions .envoi-bouton { cursor: pointer; }
.facture-actions .envoi-caret { margin-left: 1px; font-size: 11px; color: var(--muet); }

/* Ouvert, le bouton se tient enfoncé : le menu qui pend dessous lui appartient. */
.facture-actions .dropdownRedox.show .envoi-bouton {
	background: var(--survol);
	border-color: var(--focus);
}
.facture-actions .dropdownRedox.show .envoi-caret { color: var(--focus); }

/* Le même bouton dans l'entête de la fiche société, contre le dossier. La rangée
   `.fiche-meta` est en petit texte gris, calé à droite : le bouton reprend la
   taille et la couleur du texte courant, et son menu se relit à gauche. */
.fiche-meta .envoi-bouton {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 4px 10px;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--carte);
	color: var(--texte);
	font-size: var(--t-base);
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition: background .15s ease, border-color .15s ease;
}
.fiche-meta .envoi-bouton:hover { background: var(--tete); border-color: #d8dfe6; }
.fiche-meta .envoi-bouton .fa-paper-plane { color: var(--lien); }
.fiche-meta .envoi-caret { margin-left: 1px; font-size: 11px; color: var(--muet); }
.fiche-meta .dropdownRedox.show .envoi-bouton { background: var(--survol); border-color: var(--focus); }
.fiche-meta .dropdownRedox.show .envoi-caret { color: var(--focus); }
.fiche-meta .dropdownContent { font-size: var(--t-base); text-align: left; }

/* Une facture ouverte dans le volet VISIBLE de la fiche porte son propre bouton
   « Correspondance », qui envoie LA FACTURE. Celui de l'entête, qui écrit au
   client hors facture, se retire tant qu'elle est à l'écran : deux boutons du
   même nom l'un au-dessus de l'autre, et l'on ne sait plus lequel envoie quoi.
   Il revient dès qu'on quitte la facture — retour à la liste, autre onglet de
   la fiche — sans qu'aucun contrôleur ait à s'en souvenir : c'est l'état du
   document qui décide, comme pour les pistes de `:has()` plus haut. Un
   navigateur sans `:has()` le laisse simplement affiché. */
.fiche:has(.fiche-volet:not(.is-hidden) [data-piece="facture"]) .fiche-meta .envoi-canal { display: none; }

/* Sous chaque voie, la coordonnée qu'elle utilisera — ou, grisée, la raison
   pour laquelle elle ne mène nulle part. Décalée de la largeur de l'icône, elle
   s'aligne sous le libellé. */
.dropdownRedox .dropdownContent .envoi-vers {
	display: block;
	margin: 1px 0 0 22px;
	font-size: var(--t-petit);
	color: var(--muet);
}
.dropdownRedox .dropdownContent .envoi-indispo {
	display: block;
	padding: 7px 14px;
	color: var(--muet);
	opacity: .7;
	cursor: default;
}
.dropdownRedox .dropdownContent .envoi-indispo i { width: 16px; margin-right: 6px; }

/* --- Suivis : les commandes d'édition -------------------------------------------
   Le bouton d'ajout vit dans le titre du bloc, poussé à droite ; le crayon de
   ligne, lui, ne doit pas hériter du `margin-left: auto` de `.fiche-crayon`, qui
   le décollerait des pastilles d'état. */
.bloc-action { margin-left: auto; padding: 2px 9px; font-size: var(--t-petit); color: var(--lien-action); outline:none!important; }
/* `.btn:hover` remettrait le texte en sombre — même spécificité, mais écrit
   avant : celui-ci gagne. L'icône suit par héritage. */
.bloc-action:hover { color: #16659a;outline:none!important; }
.bloc-titre .bloc-action i { margin-right: 0px; }
.c-etats .fiche-crayon { margin-left: 4px; vertical-align: middle; }

/* Un client qui n'a QU'UNE AVANCE : rien ne lui est réclamé, sa ligne ne doit donc
   pas se lire comme les autres. Le nom reste net — c'est lui qu'on cherche —, seuls
   les tirets des colonnes vides s'effacent, et la pastille d'avance porte le
   montant. */
.ligne_client.est-avance .c-montant { color: var(--muet); }
/* Le compteur d'avances fait office de filtre : sans lui, ces clients restent au
   fond d'une liste triée par montant dû, c'est-à-dire nulle part. */
.lien-filtre { cursor: pointer; }
.lien-filtre.est-actif { font-weight: 600; color: var(--lien); }
.enc-clients.est-filtre-avances .ligne_client:not(.porte-avance) { display: none; }
.enc-avance {
	margin: 10px 0 0;
	padding: 12px 14px;
	border: 1px solid var(--bord);
	border-radius: 8px;
	background: var(--tete);
}
.enc-avance p { margin: 0 0 8px; color: var(--texte); }

/* --- Le dossier d'un suivi et de ses commentaires --------------------------------
   Un bouton par commentaire, à droite : plein et vert quand il porte des pièces,
   ouvert et gris sinon. C'est la convention de l'ancien adm — un coup d'œil sur
   une colonne de quinze commentaires suffit à voir lesquels ont des fichiers. */
/* Le dossier est TOUJOURS fermé : plein ou vide, c'est le même objet, et deux
   silhouettes différentes obligeraient à relire l'icône au lieu de la reconnaître.
   Ce qui change, c'est le remplissage — plein et vert quand il porte des pièces,
   simple trait quand il est vide — et le CHIFFRE, posé dans la chemise. */
.pj-dossier { display: inline-flex; align-items: center; gap: 6px; }
/* La chemise et son chiffre partagent la même boîte : le nombre se cale sur le
   GLYPHE, pas sur le bouton, sinon il glisse dès qu'un libellé s'ajoute à côté. */
.pj-dossier .pj-chemise { position: relative; display: inline-flex; line-height: 1; }
.pj-dossier .fa-folder { font-size: 19px; line-height: 1; }
.pj-dossier .far.fa-folder { color: #b9c4ce; }
/* Un dossier qui PORTE des pièces est une information, pas un crayon discret :
   pleine opacité, et la teinte des actions sous son chiffre blanc (4,78:1). */
.pj-dossier.est-plein { opacity: 1; }
.pj-dossier.est-plein .fas.fa-folder { color: var(--lien-action); }
.pj-dossier:hover .far.fa-folder { color: var(--muet); }

/* Le compte, DANS la chemise. Le corps du dossier commence sous son onglet : un
   simple centrage poserait le chiffre à cheval sur le pli, d'où le décalage vers
   le bas — exprimé en pourcentage pour suivre la taille de l'icône. */
.pj-nb {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	padding-top: 5%;
	font-size: var(--t-mini);
	font-weight: 700;
	line-height: 1;
	color: #fff;
	pointer-events: none;
}

.suivi-pj-bloc {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 10px;
	border-bottom: 1px solid var(--bord);
	background: var(--tete);
}
/* Le bouton du dossier de suivi porte un libellé : le chiffre reste dans l'icône,
   le texte dit seulement de quoi il s'agit. */
.suivi-pj-bloc .btn { display: inline-flex; align-items: center; gap: 7px; }

/* --- La fenêtre du dossier ------------------------------------------------------ */
.popup-doc { display: flex; flex-direction: column; gap: 12px; }

/* Les pièces en TABLEAU, comme toutes les listes de l'application : la pièce,
   la date, le poids, le déposant. Le cadre est celui des tableaux de rapport ;
   c'est le panneau qui défile, l'en-tête collant du `tb_liste` reste en haut. */
.doc-liste { border: 1px solid var(--bord); border-radius: var(--radius); overflow: hidden; }
.doc-table { table-layout: fixed; }
.doc-col-date { width: 88px; }
.doc-col-taille { width: 66px; }
.doc-col-par { width: 96px; }
.doc-col-x { width: 30px; }
.doc-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-table .c-num { font-weight: 500; color: var(--muet); }
.doc-par { color: var(--muet); }
.doc-vide { padding: 18px 10px; color: var(--muet); text-align: center; }

.doc-nom {
	display: flex;
	align-items: center;
	gap: 8px;
	width: 100%;
	min-width: 0;
	color: var(--texte);
	font-weight:400!important;
	font-size: var(--t-base)!important;
}
/* Un nom long passe sur deux lignes au lieu d'être coupé : coupé, sa fin ne se
   lirait qu'en ouvrant la pièce. */
.doc-nom span { white-space: normal; overflow-wrap: anywhere; }
.doc-nom:hover { text-decoration: none;}

/* La croix ne se montre qu'au survol de sa ligne : retirer une pièce est rare, et
   une croix permanente sur chaque fichier transforme la liste en champ de mines. */
.doc-suppr {
	border: 0;
	background: none;
	padding: 0 2px;
	color: transparent;
	cursor: pointer;
	font-size: 12px;
	line-height: 1;
}
.doc-ligne:hover .doc-suppr { color: var(--muet); }
.doc-suppr:hover { color: var(--danger); }
/* Celle d'une pièce qui n'est pas à soi : grisée et inerte, comme le crayon verrouillé. */
.doc-ligne:hover .doc-suppr.est-verrouille,
.doc-suppr.est-verrouille:hover { color: var(--verrouille); cursor: not-allowed; }

/* Le dépôt. Il ne se VISE plus : la surface, c'est la fenêtre entière — viser une
   case de la taille d'un timbre avec un fichier au bout du curseur est un
   exercice, pas un geste. Ne restent ici qu'un bouton et la limite. */
/* Le bouton de dépôt vit dans l'EN-TÊTE de la fenêtre, À LA SUITE du titre : il
   se lit dans la foulée de « Pièces jointes », et loin de la croix de fermeture,
   posée en absolu à droite, qu'il n'a pas à contourner. */
.popupRedoxHeader .doc-joindre { margin-left: 14px; white-space: nowrap; }
.doc-joindre.est-occupe { opacity: .55; }
/* Les limites tiennent sur une ligne sous la liste : elles décrivent la surface
   de dépôt, pas un bouton, et n'ont donc plus à s'aligner sur lui. */
.doc-limites { line-height: 1.4; }
.doc-limites { display: block; margin-top: -4px; font-size: var(--t-petit); color: var(--muet); }

/* La nappe : elle couvre les DEUX volets et ne paraît que le temps qu'un fichier
   survole la fenêtre. `pointer-events: none` est INDISPENSABLE — sans lui, la
   nappe qui apparaît sous le curseur déclenche un `dragleave` sur ce qu'elle
   recouvre, et elle clignote. */
.doc-nappe {
	position: absolute;
	inset: 0;
	z-index: 20;
	display: none;
	align-items: center;
	justify-content: center;
	padding: 16px;
	background: rgba(255, 255, 255, .82);
	pointer-events: none;
}
.doc-nappe.est-visible { display: flex; }
.doc-nappe-boite {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
	padding: 28px 44px;
	border: 2px dashed var(--focus);
	border-radius: 10px;
	background: #fff;
	box-shadow: 0 6px 24px rgba(0, 0, 0, .10);
	color: var(--texte);
	font-weight: 600;
}
.doc-nappe-boite .fa-arrow-up-from-bracket { font-size: 26px; color: var(--focus); }
.lien-bouton {
	border: 0;
	background: none;
	padding: 0;
	color: var(--lien-action);
	cursor: pointer;
	font: inherit;
	text-decoration: underline;
}

/* Le dossier et le crayon d'un commentaire, groupés et calés en haut à droite du
   texte. Deux icônes qui flottent au milieu d'une ligne de texte se cherchent à
   chaque commentaire ; collées au bord, elles forment une colonne qu'on parcourt
   d'un seul regard. Le flotteur laisse le texte reprendre toute la largeur sous
   elles. */
.commentaire-actions { float: right; display: inline-flex; align-items: center; margin-left: 8px; }

/* --- La fenêtre des pièces jointes, à deux volets --------------------------------
   La liste à gauche, le visualiseur à droite — la disposition du `popup_upload` de
   Redox. On parcourt un dossier sans ouvrir un onglet par fichier. */
/* La hauteur se BORNE ici, pas au petit bonheur du contenu. Le visualiseur n'a
   pas de hauteur propre — il prend celle qu'on lui donne —, donc sans borne il
   pousse la fenêtre hors de l'écran par le bas. La chaîne doit être COMPLÈTE :
   une hauteur sur la fenêtre, `flex: 1` + `min-height: 0` sur le contenu, puis
   `height: 100%` sur la grille. Un maillon qui manque et tout retombe en auto. */
.popupRedox:has(.popup-doc) {
	display: flex;
	flex-direction: column;
	/* `!important` est ici le bon outil, et le seul : le plugin écrit
	   `height: auto` EN LIGNE sur la fenêtre (popup.js), ce qu'aucune règle de
	   feuille ne peut surpasser autrement. Sans ça la fenêtre retombe sur son
	   `min-height` et le visualiseur se retrouve dans une bande de 380 px. */
	height: calc(100vh - 150px) !important;
	max-height: calc(100vh - 150px);
	min-height: 380px;
}
.popupRedox:has(.popup-doc) .popupRedoxHeader { flex: 0 0 auto; }

/* Sans pied, les volets toucheraient le bord : le document semblerait coupé
   plutôt que terminé. On leur rend une marge en bas — la même qu'un pied
   laisserait — et on arrondit leurs coins inférieurs sur ceux de la fenêtre, pour
   que la forme se referme. */
.popup-doc { position: relative; flex: 1 1 auto; padding: 0 0 16px 0; min-height: 0; overflow: hidden; }
.doc-duo {
	display: grid;
	grid-template-columns: minmax(500px, 440px) minmax(0, 1fr);
	height: 100%;
	min-height: 0;
	/* border-top: 1px solid var(--bord); */
	/* border-bottom: 1px solid var(--bord); */
	overflow: hidden;
	padding-right: 16px;
}

.doc-panneau-liste {
	display: flex;
	flex-direction: column;
	gap: 10px;
	min-height: 0;
	padding: 0px 12px 12px 12px;
	/* border-right: 1px solid var(--bord); */
	overflow-y: auto;
}
.doc-panneau-vue { display: flex; flex-direction: column; min-width: 0; min-height: 0; background: #f0f2f5; overflow: hidden; }

/* La fiche de la pièce choisie, au-dessus du lecteur : « déposée le … par … » à
   gauche, le poids à droite. PAS le nom — la barre du lecteur l'affiche déjà.
   Dessinée comme une rangée de cette barre : même fond, même filet, les coins
   du haut arrondis à sa place ; la barre du lecteur, dessous, perd les siens et
   ne garde qu'un trait fin entre les deux. Sans pièce, le bandeau se retire. */
.doc-vue-tete {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
	height: 28px;
	padding: 0 12px;
	background: var(--tete);
	border: 1px solid var(--bord);
	border-bottom: 0;
	border-radius: var(--radius) var(--radius) 0 0;
	font-size: var(--t-petit);
	color: var(--muet);
	user-select: none;
}
.doc-vue-mention { white-space: nowrap; }
.doc-vue-mention + .doc-vue-mention::before { content: "·"; margin-right: 8px; }
.doc-vue-poids { margin-left: auto; font-variant-numeric: tabular-nums; }
/* Le poids est calé à droite : le point qui sépare les mentions n'a plus rien à
   séparer. Même spécificité que le séparateur, écrit après lui. */
.doc-vue-mention + .doc-vue-poids::before { content: none; }

.doc-vue { position: relative; flex: 1 1 auto; min-height: 0; overflow: hidden; }
.doc-vue > .viewerdocRedox { height: 100%; }
.doc-vue-tete:not(.is-hidden) + .doc-vue .viewerdocRedox .toolbar { border-top: 1px solid var(--bord-fin); border-radius: 0; }

.doc-vue-attente {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 10px;
	height: 100%;
	padding: 24px;
	color: var(--muet);
	text-align: center;
}
.doc-vue-attente .fas { font-size: 30px; color: #c8d0d8; }

/* Le nom est un bouton pleine largeur de sa cellule : c'est la pièce qu'on
   choisit, pas son nom. La sélection reste visible pendant qu'on lit à droite —
   sur les CELLULES, comme le survol du `tb_liste`, sans quoi il l'emporterait. */
.doc-nom {
	border: 0;
	background: none;
	padding: 0;
	cursor: pointer;
	font: inherit;
	text-align: left;
}
/* Même spécificité que le zébrage du `tb_liste`, et écrit après lui : une pièce
   choisie sur une ligne paire garde sa couleur de sélection. */
.doc-table tbody tr.est-actif td { background: var(--survol); }
.doc-ligne.est-actif .doc-nom { font-weight: 600; }

/* L'image dans son panneau : centrée, jamais rognée. */
.imageReader { display: flex; flex-direction: column; height: 100%; background: #f0f2f5; }
.imageReader .imageParent { flex: 1 1 auto; min-height: 0; overflow: auto; }
.imageReader .imageSpot { display: flex; align-items: center; justify-content: center; min-height: 100%; padding: 12px; }
.imageReader .imageSpot canvas { max-width: 100%; box-shadow: 0 1px 6px rgba(0, 0, 0, .18); background: #fff; }
.viewer-faute { margin: 0; padding: 24px; color: var(--muet); text-align: center; }

/* Le dossier du suivi est un vestige : il se lit, il ne se remplit pas. */
.doc-note { margin: 0; padding: 12px; border: 1px dashed var(--bord); border-radius: 6px; color: var(--muet); font-size: var(--t-petit); }

/* --- La fenêtre d'un envoi du journal des e-mails ---------------------------------
   L'en-tête d'envoi en haut, le message tel qu'il est parti dessous. Même chaîne de
   hauteurs que la fenêtre des pièces jointes, et pour la même raison : le cadre du
   message n'a pas de hauteur propre — il prend celle qu'on lui donne —, donc sans
   borne il pousse la fenêtre hors de l'écran. Une hauteur sur la fenêtre, `flex: 1`
   + `min-height: 0` sur le contenu, puis `height: 100%` sur le cadre : un maillon
   qui manque et tout retombe en auto. */
.popupRedox:has(.popup-email) {
	display: flex;
	flex-direction: column;
	/* Le plugin écrit `height: auto` EN LIGNE sur la fenêtre (popup.js) : aucune
	   règle de feuille ne le surpasse autrement. */
	height: calc(100vh - 150px) !important;
	max-height: calc(100vh - 150px);
	min-height: 380px;
}
.popupRedox:has(.popup-email) .popupRedoxHeader { flex: 0 0 auto; }

.popup-email { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; padding-bottom: 16px; }

/* Deux colonnes : les libellés alignés, les valeurs qui prennent le reste. La
   première colonne est FIXE — sept intitulés de longueurs inégales qui se recalent
   les uns sur les autres donnent une marge en dents de scie. */
.email-entete {
	flex: 0 0 auto;
	margin-bottom: 12px;
	padding-bottom: 10px;
	border-bottom: 1px solid var(--bord);
}
.email-champ { display: flex; align-items: baseline; gap: 10px; padding: 2px 0; }
.email-cle { flex: 0 0 92px; color: var(--muet); font-size: var(--t-petit); }
.email-val { flex: 1 1 auto; min-width: 0; word-break: break-word; }
.email-val .fa-paperclip { color: var(--muet); }

/* Le message est un document ÉTRANGER : du HTML d'e-mail, avec ses propres styles.
   Il vit dans son cadre, sur le gris des visualiseurs — le même fond que le volet
   des pièces jointes, pour que la page blanche du message se détache comme une
   feuille. */
.email-apercu {
	flex: 1 1 auto;
	width: 100%;
	min-height: 0;
	border: 1px solid var(--bord);
	border-radius: 6px;
	background: #f0f2f5;
}

/* Une action posée à côté d'une valeur, dans une table de fiche. Elle reste
   VISIBLE — une commande qu'il faut découvrir en promenant la souris n'existe pas
   pour qui ne la cherche pas — et elle se cale à DROITE de la cellule, où les
   crayons des blocs se trouvent déjà : elles forment ainsi une seule colonne
   d'actions au lieu de flotter derrière des valeurs de longueurs inégales.
   `float` plutôt que flex : la cellule reste une cellule de tableau, donc les
   largeurs de colonnes et les hauteurs de lignes ne bougent pas. */
.tb_fiche td .champ-action {
	float: right;
	margin-left: 8px;
	/* Un cran au-dessus des crayons, et EN COULEUR : ce sont des commandes qui
	   font partir quelque chose chez le client, pas des retouches de champ. Le
	   gris atténué des crayons dirait le contraire — d'où le bleu, à pleine
	   opacité, qui les sort de la colonne des valeurs sans rien ajouter. */
	padding: 1px 5px;
	font-size: 13.5px;
	color: #4094a2;
	opacity: 1;
}
.tb_fiche td .champ-action:hover { background: var(--tete); color: #337681; }

/* Le choix du filleul est un simple `select` : la liste ne porte que les sociétés
   sans parrain, triées par nom, et se parcourt au clavier. */

/* Les entrées calées à droite de la barre — les paramètres, contre le nom de
   l'utilisateur. Elles vivent hors de la piste défilante : celle-ci se rétrécit
   quand la largeur manque, et ce qu'on y pose disparaît avec elle. */
.navbar-my .nav-droite { flex: 0 0 auto; overflow: visible; }
.navbar-my .nav-droite a { gap: 7px; }
.navbar-my .nav-droite .fa-gear { font-size: 13px; opacity: .85; }

/* Sur écran étroit, le libellé s'efface : l'engrenage seul suffit à le désigner,
   et la barre garde le nom de l'utilisateur lisible. */
@media (max-width: 700px) {
	.navbar-my .nav-droite a { padding: 10px 12px; }
	.navbar-my .nav-droite a .libelle { display: none; }
}

/* --- Paramètres : l'édition ------------------------------------------------ */

/* Ces formulaires apportent trois choses de plus que .popup-form : un champ
   enveloppé (pour l'unité), une note SOUS le champ, et de vraies zones de texte.
   Sans ça, la note deviendrait une colonne étroite à droite, et une textarea de
   quatorze lignes serait écrasée aux 27 px des champs d'une ligne.
   L'enveloppement ne vaut QUE pour les lignes qui en ont besoin : ailleurs, un
   contenu trop large se comprime au lieu de passer à la ligne. */
.popup-form .comm-ligne:has(> .popup-aide),
.popup-form .comm-ligne:has(> .param-vars) { flex-wrap: wrap; }

/* La note passe à la ligne et s'aligne sous le champ, pas sous le libellé.
   La base est réduite d'autant que la marge : `flex-basis: 100%` se mesure sur le
   conteneur et la marge s'y AJOUTE — la note dépasserait de sa propre marge, et
   c'est le popup entier qui gagnerait une barre de défilement horizontale.
   La largeur du libellé vient de la même variable que le libellé lui-même : les
   deux ne peuvent pas diverger. */
.popup-form .comm-ligne > .popup-aide {
	flex: 0 0 calc(100% - var(--popup-libelle) - var(--popup-gouttiere));
	margin: 2px 0 0 calc(var(--popup-libelle) + var(--popup-gouttiere));
	font-size: var(--t-petit);
	line-height: 1.45;
}

/* Dans une colonne de duo, le libellé est large de son texte, non de 112 px : la
   note reprend toute la largeur, sans retrait. */
.popup-form .comm-duo .comm-ligne > .popup-aide { flex-basis: 100%; margin-left: 0; }

/* Une zone de texte se dimensionne par son attribut `rows` : la hauteur fixe des
   champs d'une ligne n'a pas de sens ici. Elle tient de la base son rembourrage
   sur deux axes, mais PAS son `height: auto` : `textarea.form-control` pèse
   (0,1,1) et perd contre les 27 px de `.popup-form .form-control` (0,2,0). Sans
   cette règle, toute zone de texte de popup sans classe propre serait écrasée à
   27 px. */
.popup-form textarea.form-control {
	flex: 1 1 auto;
	height: auto;
	/* Les signatures dépassent souvent leurs deux ou trois lignes : sans poignée,
	   le texte est coupé sans que rien ne le dise. */
	resize: vertical;
}

/* Face à un contenu haut — zone de texte ou nappe de jetons —, un libellé centré
   verticalement flotte au milieu de nulle part : il annonce le champ, il se pose
   donc à son début. */
.popup-form .comm-ligne:has(textarea),
.popup-form .comm-ligne:has(> .param-vars) { align-items: flex-start; }
.popup-form .comm-ligne:has(textarea) > label,
.popup-form .comm-ligne:has(> .param-vars) > label { padding-top: 5px; }

/* Un champ enveloppé n'est pas enfant direct de la ligne : il n'a pas le
   `flex: 1 1 auto` qui l'étirerait. */
.popup-form .param-saisie .form-control { width: 100%; }

/* Deux champs courts côte à côte — quantité et prix, module et intitulé. Chacun
   garde la grille libellé/champ de .comm-ligne, d'où le libellé rétréci : deux
   fois 112 px d'étiquette ne laisseraient rien aux saisies. */
/* Les deux colonnes s'alignent par le HAUT, pas par le milieu. Sans cela, celle
   qui porte une note sous son champ étire l'autre, qui centre alors son contenu
   dans la hauteur reçue : les deux champs, pourtant sur la même ligne, se
   décalent de la moitié de la note. */
.popup-form .comm-duo { display: flex; align-items: flex-start; gap: 14px; }
.popup-form .comm-duo > .comm-ligne { flex: 1 1 0; min-width: 0; }
.popup-form .comm-duo > .comm-ligne > label { flex: 0 0 auto; }

/* Trois zones de texte côte à côte — les signatures lettre, e-mail et SMS d'un
   modèle de courrier. Une colonne fait 230 px : un libellé de 90 px à sa gauche
   ne laisserait rien au champ. Il passe donc AU-DESSUS, comme ceux des corps de
   texte plus haut dans le même popup, et la colonne redevient un simple bloc.
   Deux règles de la grille libellé/champ agissent encore sans elle et sont
   défaites ici : le recalage du libellé face à une zone de texte (5 px), et le
   retrait de la note sous le champ, qui n'a plus de colonne à rattraper. */
.popup-form .comm-trio { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 14px; }
.popup-form .comm-trio > .comm-ligne { display: block; }
.popup-form .comm-trio > .comm-ligne > label { display: block; margin-bottom: 3px; padding-top: 0; }
.popup-form .comm-trio > .comm-ligne > .popup-aide { margin: 3px 0 0; }

/* En fenêtre étroite, le popup rétrécit avec elle (`max-width: 95%`) : sous
   620 px, trois colonnes n'en font plus que 170. Elles s'empilent. */
@media (max-width: 620px) {
	.popup-form .comm-trio { grid-template-columns: minmax(0, 1fr); }
}

/* L'unité — « jours », « % » — est affichée à côté du champ et non dedans : la
   valeur qui part au serveur est brute, et ce qui n'est pas saisissable ne doit
   pas ressembler à de la saisie. */
.param-saisie { flex: 1 1 auto; min-width: 0; }
.param-saisie.a-unite { display: flex; align-items: center; gap: 6px; }
.param-saisie.a-unite .form-control { flex: 1 1 auto; min-width: 0; }
.param-unite { flex: 0 0 auto; color: var(--muet); font-size: var(--t-petit); }

/* Les corps de message et les textes de courrier se lisent en largeur : le
   monospace garde les jetons de publipostage reconnaissables au milieu du texte.
   Le sélecteur pèse (0,2,1) et gagne contre `.popup-form .form-control { font:
   inherit }` (0,2,0) sans nommer `.popup-form` : il ne peut atteindre que ce qui
   porte déjà `.param-editeur`, soit popup_param_modele et popup_courrier, qui le
   veulent tous deux. */
textarea.param-editeur.form-control {
	font-size: var(--t-base);
	line-height: 1.5;
	resize: vertical;
}

/* LES TROIS CORPS D'UN MODÈLE, EN ONGLETS : une hauteur PLANCHER, et la même
   pour les trois. Sans elle, changer d'onglet ferait sauter la fenêtre — un
   texte de lettre est long, un SMS tient en deux lignes, et le popup se serait
   redimensionné à chaque bascule. Le plancher fige la zone ; `resize: vertical`,
   hérité de la règle ci-dessus, laisse l'agrandir quand un texte déborde.

   Une classe à part plutôt que `.param-editeur` : ce dernier sert aussi à
   popup_param_modele, qui n'a qu'un champ et n'a rien demandé. */
textarea.param-corps.form-control { min-height: 300px; }

/* La zone des onglets ne se comporte pas comme une ligne de formulaire : ses
   volets s'empilent au lieu de se ranger côte à côte. */
.comm-ligne-textes { display: block; }
.comm-ligne-textes .ecran-onglets { margin-bottom: 8px; }

/* `.form-control` porte `width: 100%`. Avec `flex-basis: auto`, c'est cette
   largeur-là qui sert de base : dans une ligne qui enveloppe — donc dès qu'une
   note accompagne le champ — le champ réclame la ligne entière et tombe SOUS son
   libellé, à une autre abscisse que les champs sans note : le formulaire aurait
   deux colonnes de champs.
   Une base nulle le laisse prendre ce qui reste de la ligne, sans plus rien
   réclamer. C'est la raison d'être du `width: 100%` de la base : le retirer
   ramènerait ce décalage. */
.popup-form .comm-ligne > .form-control { flex-basis: 0; }

/* Sauf la date, qui tient sa largeur de son contenu et non de la place restante :
   une base nulle sans `flex-grow` la réduirait à rien. Elle reprend donc la
   sienne, à la spécificité qu'il faut pour passer devant la règle ci-dessus. */
.popup-form .comm-ligne > input[data-date] { flex-basis: 108px; }

/* Le bloc de jetons n'a pas de largeur propre : dans une ligne qui enveloppe, il
   se mesure à son contenu, déborde des 100 % restants et passe sous son libellé.
   On lui donne la largeur qui reste une fois le libellé posé, à charge pour lui
   d'y replier ses jetons. */
.popup-form .comm-ligne > .param-vars {
	/* Base à zéro plutôt qu'une largeur calculée : `100% - libellé` reste juste
	   jusqu'à ce que le `gap` de la ligne s'y ajoute et fasse passer le bloc en
	   dessous. Une base nulle qui grandit prend exactement la place restante,
	   quel que soit le gap. */
	flex: 1 1 0;
	min-width: 0;
}

/* Les jetons proposés à l'insertion sont des boutons : ils se cliquent. */
.param-vars-choix { margin-top: 2px; }

.param-var.est-cliquable {
	border: 1px solid transparent;
	cursor: pointer;
	transition: background .12s, color .12s;
}
.param-var.est-cliquable:hover { background: #d9e7f5; color: var(--lien); }

/* Vingt-trois boutons se traversent au clavier et rien ne montrait lequel on
   tient : la pastille n'a pas de contour auquel le repère du navigateur puisse
   s'accrocher. */
.param-var.est-cliquable:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

/* `.fiche-crayon` et `.bloc-action` poussent à droite avec `margin-left: auto`.
   Quand un titre en porte plusieurs — crayon, ajout, corbeille des services —
   chacun pousse le suivant et le groupe s'écarte sur toute la largeur : seul le
   PREMIER doit pousser, les autres le suivent. */
.bloc-titre .fiche-crayon ~ .fiche-crayon,
.bloc-titre .fiche-crayon ~ .bloc-action,
.bloc-titre .bloc-action ~ .fiche-crayon { margin-left: 0; }

/* La colonne des crayons d'une table : au plus juste, et à droite. */
.tb_liste th.c-actions, .tb_liste td.c-actions { width: 1%; white-space: nowrap; text-align: right; }


/* --- Popup « modèle de message » : le libellé au-dessus du champ ------------
   TOUT ce qui suit passe par `.popup-modele`. Retirer la classe du gabarit annule
   le bloc entier et rend le popup à la grille commune : c'est le confinement
   qu'exige une feuille où `.popup-form` habille sept formulaires. */

/* Ce popup-ci n'a pas de colonne de libellés, et il ne le dit qu'UNE fois : la
   variable passe à zéro. Les règles partagées qui s'en déduisent — le retrait de
   la note sous son champ et sa largeur — suivent d'elles-mêmes, sans qu'on en
   récrive une seule, donc sans qu'aucune puisse diverger de la largeur du
   libellé. La note d'entête et le message d'erreur, enfants DIRECTS du contenu,
   n'ont ainsi pas de bord à rater, et le corps du message tient les 710 px du
   popup.
   Les deux classes sont portées par le MÊME élément : à sélecteur simple,
   `.popup-form` et `.popup-modele` pèsent pareil et l'ordre du fichier
   trancherait. */
.popup-form.popup-modele { --popup-libelle: 0px; }

/* Chaque champ devient un groupe : entête pleine largeur, champ dessous. C'est
   l'écart qui remplace la colonne comme repère de lecture — 4 px entre un libellé
   et son champ, 12 px entre deux groupes. Ce rapport de un à trois est ce qui
   fait le groupe ; à écarts égaux, la pile se lit comme une suite de lignes sans
   rapport entre elles. */
.popup-modele .comm-ligne { flex-wrap: wrap; align-items: flex-start; margin-bottom: 12px; }

/* Le champ occupe la ligne entière sous son entête. Base à 100 % SANS marge
   horizontale : une base à 100 % plus une marge déborderait le popup et lui
   donnerait une barre de défilement horizontale (vérifié à 0 de débordement, de
   380 à 760 px). Cette base explicite remplace le `width: 100%` de
   `.form-control`, qui ferait tomber le corps sur sa propre ligne dans la
   plupart des modèles et le laisserait à côté du libellé dans les autres : la
   même grille changerait de forme selon le contenu du message. */
.popup-modele .comm-ligne > .form-control { flex: 1 1 100%; }

/* L'entête d'un groupe : le libellé à gauche, ce qu'il y a à dire du champ à
   droite, dans la largeur reprise à la colonne. Elle se replie : à 760 px rien
   ne déborde, mais un texte plus long ou un navigateur zoomé doit faire tomber la
   mention à la ligne suivante plutôt qu'écraser le libellé.
   Le libellé n'est pas enfant direct de `.comm-ligne` : il échappe du même coup
   à `flex: 0 0 var(--popup-libelle)` ET aux `padding-top` de recalage vertical,
   qui n'ont pas d'objet quand rien n'est côte à côte. Rien n'est donc à
   surcharger là-bas, et `.popup-form .comm-ligne-haut > label` reste seul à
   régler ce qu'il règle. */
.popup-modele .modele-tete {
	flex: 0 0 100%;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 8px;
	margin-bottom: 4px;
}

/* Sans colonne, la position ne dit pas « ceci est un libellé » : c'est au dessin
   du texte de le dire. Petit, gras, capitales espacées et gris, il ne peut pas
   se confondre avec ce qu'on saisit. C'est la formule de `.param-etiquette`,
   celle de l'écran Paramètres que ce popup modifie : on édite dans la langue
   visuelle où l'on vient de lire.
   `.comm-ligne label` impose 70 px de large et 11.5 px à tout libellé du bloc,
   d'où le sélecteur à deux classes, qui le surclasse. */
.popup-modele .modele-tete > label,
.popup-modele .modele-tete > .modele-etiquette {
	flex: 0 0 auto;
	margin: 0;
	color: var(--muet);
	font-size: var(--t-petit);
	font-weight: 600;
	letter-spacing: .04em;
	text-transform: uppercase;
}

/* L'indice précise le champ, il ne le nomme pas : même gris, mais casse normale
   et poussé à droite, pour ne pas se lire dans la foulée du libellé. */
.popup-modele .modele-indice { margin-left: auto; color: var(--muet); font-size: var(--t-petit); }

/* Ce popup n'a pas de colonne de libellés, donc pas de gouttière à compenser :
   son retrait de note est nul. Quatre classes pour passer devant la règle
   partagée sans dépendre de l'ordre du fichier. */
.popup-form.popup-modele .comm-ligne > .popup-aide { flex-basis: 100%; margin-left: 0; }

/* La pastille « HTML » suit son libellé : sa marge propre (app.css:683)
   s'ajouterait au `gap` de l'entête et la décrocherait. */
.popup-modele .modele-tete > .param-marque { margin-left: 0; }

/* La note d'entête décrit le JEU de modèles, pas un champ — elle n'est pas dans
   une ligne de grille. Elle reste un simple paragraphe : sans colonne, elle
   commence déjà exactement où commencent libellés et champs. En encart gris, son
   propre rembourrage décalerait SON texte de 10 px : on aurait remplacé un
   décalage de 122 px par un de 10, et fabriqué une exception de plus, puisque
   popup_service et popup_parrain posent la même note libre sans encart. */
.popup-modele > .popup-aide { margin: 0 0 12px; }

/* Un objet fait 17 à 30 caractères. Sur 710 px, le champ promettrait une saisie
   qu'on n'y fait jamais et mettrait sur le même plan la ligne unique et les huit
   paragraphes du corps. `max-width` plutôt qu'une base flex : le champ reste
   extensible et rien ne peut entrer en conflit avec les bases posées ailleurs
   sur `.form-control` — une base imposée à un champ portant déjà `flex: 0 0
   108px` le réduirait à zéro. La borne du serveur reste 255 caractères, pas ce
   qu'on voit. */
.popup-modele input[data-titre] { max-width: 420px; }

/* Un jeton que personne ne remplace part en clair chez le client : c'est la faute
   que tout ce popup cherche à empêcher. L'écran de LECTURE la signale en rouge ;
   l'écran d'ÉDITION, le seul où on puisse la corriger, la signale aussi, avant
   l'enregistrement. Le rouge, la bordure et le fond sont ceux de
   `.param-var.est-inconnue` : le même fait se dit de la même façon. */
.popup-modele .modele-alerte {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
	margin: 0 0 12px;
	padding: 7px 10px;
	border: 1px solid #fecdca;
	border-radius: 5px;
	background: #fef3f2;
	color: var(--danger);
	font-size: var(--t-petit);
	line-height: 1.45;
}

/* `.is-hidden` pèse (0,1,0) et perdrait contre le `display: flex` ci-dessus. */
.popup-modele .modele-alerte.is-hidden { display: none; }

.popup-modele .modele-alerte-liste { display: inline-flex; flex-wrap: wrap; gap: 5px; }

/* Sur le rose de l'alerte, la pastille rouge se fond dans son fond : elle reprend
   le blanc de la carte pour rester une pastille. */
.popup-modele .modele-alerte .param-var.est-inconnue { background: var(--carte); }

/* Les 23 jetons gardent leur pleine encre : ce sont eux qu'on CLIQUE, et le clic
   est le seul garde-fou contre la faute de frappe que tout le reste du popup
   cherche à empêcher. Les délaver pour faire ressortir les 3 à 6 employés
   effacerait l'affordance de ceux dont on a justement besoin et descendrait leur
   texte sous le seuil AA (#6b7a8c sur blanc = 4,39:1).
   Ce sont donc les employés qui gagnent un cran. Le fond est celui du survol des
   pastilles, DÉJÀ dans la feuille (app.css:3456) — aucune couleur nouvelle ; le
   texte passe au gris du corps de texte, soit 11,5:1 contre 6,2:1 pour la
   pastille ordinaire. */
.popup-modele .param-var.est-employe { background: #d9e7f5; color: var(--texte); font-weight: 500; }

/* Un jeton employé a déjà le fond du survol : sans ceci, le survol ne se verrait
   pas sur les 3 à 6 pastilles qu'on regarde le plus. */
.popup-modele .param-var.est-employe:hover { color: var(--lien); }

/* --- Paramètres : le logo des documents ------------------------------------ */

/* La carte du logo se pose en DERNIER et dans la dernière colonne, quel qu'en
   soit le nombre — trois en large, deux en étroit. `-2 / -1` désigne la dernière
   piste sans avoir à la nommer, donc sans se désaccorder du jour où la grille
   changera de largeur. Sans cet ancrage, elle suivrait le flux et tomberait au
   milieu du dernier rang. */
.param-grille > .param-logo { grid-column: -2 / -1; }

/* Le logo s'imprime à 30 mm de large sur les PDF, soit une vignette. On le
   montre plus grand pour qu'on juge de sa netteté, sur un damier clair : un
   logo à fond transparent sur fond blanc ne laisse pas voir ses bords. */
.param-logo-vue {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 96px;
	margin-bottom: 8px;
	padding: 10px;
	border: 1px solid var(--bord-fin);
	border-radius: 5px;
	background-color: #fbfcfd;
	background-image:
		linear-gradient(45deg, #f0f3f6 25%, transparent 25%, transparent 75%, #f0f3f6 75%),
		linear-gradient(45deg, #f0f3f6 25%, transparent 25%, transparent 75%, #f0f3f6 75%);
	background-size: 14px 14px;
	background-position: 0 0, 7px 7px;
}

.param-logo-vue img { max-width: 100%; max-height: 140px; }

/* Absent, ou enregistré mais introuvable : dans les deux cas les documents
   sortent sans en-tête, et c'est ce qu'il faut lire. */
.param-logo-vide {
	display: flex;
	align-items: center;
	gap: 8px;
	min-height: 96px;
	margin-bottom: 8px;
	padding: 10px 14px;
	border: 1px dashed var(--bord);
	border-radius: 5px;
	color: var(--muet);
	font-size: var(--t-petit);
	line-height: 1.45;
}

.param-logo-vide i { font-size: 20px; opacity: .5; }

.param-logo-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
.param-logo-actions .param-note { margin: 0; }

/* --- Rapports : le décompte de TVA ----------------------------------------- */

.rapport-decompte {
	margin-top: 16px;
	border: 1px solid var(--bord);
	border-radius: 6px;
	background: var(--carte);
}

/* Les deux dates, les raccourcis de trimestre et le bouton sur une seule ligne :
   le geste est court, il ne mérite pas un formulaire empilé. Il se replie sur les
   écrans étroits plutôt que de déborder. */
.decompte-form {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px;
	padding: 12px;
}

.decompte-form .comm-ligne { flex: 0 0 auto; padding: 0; }
.decompte-form .comm-ligne > label { flex: 0 0 auto; }
/* Deux dates jj.mm.aaaa, à largeur fixe : le dessin vient de la base, il ne reste que
   la largeur, le cran serré du popup et les chiffres à pas constant. */
.decompte-form .form-control {
	flex: 0 0 auto;
	width: 104px;
	height: 27px;
	font-variant-numeric: tabular-nums;
}

/* Les trimestres échus, en raccourci : c'est la cadence réelle d'un décompte, et
   la saisie manuelle de deux dates est la façon la plus simple de se tromper de
   période d'un jour. */
.decompte-trimestres { display: flex; flex-wrap: wrap; gap: 4px; }
.decompte-trimestres .btn {
	padding: 2px 9px;
	border: 1px solid var(--bord);
	border-radius: 20px;
	background: var(--tete);
	color: var(--muet);
	font-size: var(--t-petit);
	font-variant-numeric: tabular-nums;
}
.decompte-trimestres .btn:hover { background: #d9e7f5; color: var(--lien); border-color: #b9d3ea; }

/* La case qui dit le décompte envoyé : elle arrête la banque, elle se lit à côté du bouton. */
.decompte-declare { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-weight: 500; cursor: pointer; white-space: nowrap; }
.decompte-declare input { margin: 0; cursor: pointer; }

.rapport-decompte .rapport-note { margin: 0 12px 10px; }
.rapport-decompte .rapport-note:empty { display: none; }
.rapport-decompte [data-tva-faute] { color: var(--danger); font-weight: 500; }

/* Mon compte -------------------------------------------------------------------
   Deux blocs dans une seule fenêtre, et il faut qu'on le VOIE : ce sont deux
   opérations séparées, chacune avec son bouton et son verdict. Un simple espace
   les ferait lire comme un seul formulaire coupé par la mise en page, et le
   deuxième bouton passerait pour un doublon. */
.popup-compte { --popup-libelle: 84px; }

.popup-compte .compte-bloc {
	margin-top: 14px;
	padding-top: 12px;
	border-top: 1px solid var(--bord-fin);
}

.popup-compte .compte-titre {
	margin-bottom: 8px;
	font-weight: 600;
	color: var(--muet);
	font-size: var(--t-base);
	text-transform: uppercase;
	letter-spacing: .04em;
}

/* Le bouton du bloc est à DROITE, et son accusé de réception à sa gauche : on lit
   le verdict là où on vient de cliquer, sans le chercher en haut de la fenêtre. */
.popup-compte .compte-pied {
	display: flex; align-items: center; justify-content: flex-end; gap: 12px;
	margin-top: 10px;
}
.popup-compte .compte-dit { color: var(--muet); font-size: var(--t-base); }
.popup-compte .compte-dit.est-reussi { color: var(--accent); font-weight: 600; }

/* L'œil se pose DANS le champ, comme sur l'écran de connexion. */
.popup-compte .compte-secret { position: relative; display: flex; flex: 1 1 auto; min-width: 0; }
.popup-compte .compte-secret .form-control { flex: 1 1 auto; min-width: 0; padding-right: 32px; }
.popup-compte .compte-oeil {
	position: absolute; right: 0; top: 0; bottom: 0;
	width: 30px;
	display: flex; align-items: center; justify-content: center;
	background: none; border: 0; padding: 0;
	color: var(--muet); cursor: pointer;
}
.popup-compte .compte-oeil:hover { color: var(--texte); }

/* La règle de longueur est une aide, pas une faute : elle se lit sous les champs
   sans crier, et n'a pas de libellé à sa gauche. */
.popup-compte .popup-aide[data-regle] { margin: 2px 0 0 calc(var(--popup-libelle) + var(--popup-gouttiere)); }
.popup-compte .popup-faute { margin-top: 8px; }


/* --- Le tableau de développement ---------------------------------------------
   Quatre colonnes de hauteur égale qui défilent CHACUNE, plutôt qu'une page qui
   défile en entier : les en-têtes de colonne doivent rester en vue quand une
   pile s'allonge, sinon on ne sait plus ce qu'on regarde. */
.kanban {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--gap);
	flex: 1 1 auto;
	min-height: 0;
	padding: 5px 0px 5px 0px;
}

/* CHAQUE COLONNE PORTE SA COULEUR, sur trois pixels en tête : sans elle, pour
   savoir laquelle on regarde il faudrait lire son nom — et pendant un glissement,
   la carte cachant le curseur, on ne lit rien. La teinte suit le flux : gris pour
   ce qui attend, bleu pour ce qui avance, ambre pour ce qui attend un regard,
   vert pour ce qui est livré. Elle sert aussi de marque de dépôt (`est-visee`),
   d'où la variable. */
.kanban-colonne {
	display: flex;
	flex-direction: column;
	min-height: 0;
	border: 1px solid #e2e6e8;
	border-top: 2px solid var(--col, #cfd5da);
	border-radius: 6px;
	background: #f3f4f4;
}
.kanban-colonne[data-colonne="afaire"]  { --col: #8a97a6; }
.kanban-colonne[data-colonne="encours"] { --col: #0088cc; }
.kanban-colonne[data-colonne="revue"]   { --col: #c07600; }
.kanban-colonne[data-colonne="fait"]    { --col: #3ba776; }

.kanban-tete {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 9px 12px;
	border-bottom: 1px solid #e2e6e8;
}
.kanban-nom { font-weight: 600; font-size: var(--t-base); }
/* La pastille prend un gris plus sombre que la colonne, qui la renfonce : au fond
   blanc des cartes, elle se lirait comme une mini-carte posée dans l'en-tête. */
.kanban-nb {
	margin-left: auto;
	min-width: 20px;
	padding: 1px 6px;
	border-radius: 10px;
	background: #e4e8ea;
	color: var(--muet);
	font-size: var(--t-petit);
	text-align: center;
}

/* La pile défile seule, et reste une cible de dépôt même vide — d'où la hauteur
   minimale : sans elle, une colonne vide serait haute de zéro et impossible à
   viser à la souris. `relative` porte la ligne d'insertion, posée en absolu. */
.kanban-pile {
	position: relative;
	flex: 1 1 auto;
	min-height: 60px;
	overflow-y: auto;
	padding: 8px;
	display: flex;
	flex-direction: column;
	gap: 8px;
}
/* La colonne visée s'éclaire ENTIÈRE, en-tête compris : c'est une colonne qu'on
   choisit, pas une simple zone de dépôt, et le nom de la colonne est ce qu'on
   lit pour se décider. La marque est posée sur la COLONNE et non sur la pile —
   l'en-tête en est le frère, et aucun sélecteur ne remonte à un frère précédent.
   Elle prend sa propre teinte, au trait comme au fond, pour se voir d'un coup
   d'œil entre deux colonnes mitoyennes. */
.kanban-colonne.est-visee {
	background: #fff;
	border-color: var(--col);
	box-shadow: inset 0 0 0 1px var(--col), 0 0 0 3px rgba(0, 136, 204, .10);
}

/* LA LIGNE D'INSERTION : où la carte va tomber, et entre quelles voisines. En
   ABSOLU dans la pile, jamais intercalée entre les cartes : une ligne dans le
   flux pousserait les cartes de sa propre hauteur, la suivante passerait sous le
   curseur, et la ligne sauterait d'un cran sans fin. */
.kanban-place {
	position: absolute;
	left: 8px;
	right: 8px;
	height: 2px;
	border-radius: 2px;
	background: var(--col, #0088cc);
	pointer-events: none;
}
.kanban-place::before {
	content: '';
	position: absolute;
	left: -3px;
	top: -3px;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--col, #0088cc);
}

.kanban-carte {
	border: 1px solid #d4d4d4;
	border-left: 3px solid var(--bord);
	border-radius: 6px;
	background: var(--carte);
	padding: 8px 10px;
	cursor: grab;
	box-shadow: 0 1px 2px rgba(8, 14, 22, .06);
	transition: box-shadow .12s, border-color .12s;
}
/* Au survol, la carte se SOULÈVE : une ombre et un trait, qui se voient sur tout
   écran, là où un fond à peine plus gris ne se verrait pas. */
.kanban-carte:hover { border-color: #b9c2ca; box-shadow: 0 3px 8px rgba(8, 14, 22, .13); }
.kanban-carte:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
/* Pendant le glissement, la carte source ne se voit plus du tout : une seule
   carte à l'écran, celle qui suit le curseur. La laisser en place — même en
   retrait — la ferait lire comme un clone, deux exemplaires de la même tâche.
   `visibility` et non `display` : la place reste prise, donc la pile ne se
   réagence pas sous le curseur au moment où l'on vise sa cible, et le creux
   laissé dit d'où la carte vient. */
.kanban-carte.est-prise { visibility: hidden; }

/* Le clone qui suit le curseur. C'est une carte comme les autres, simplement
   posée en `fixed` dans le document : elle est donc OPAQUE, ce que la vignette
   du glisser-déposer natif ne peut pas être — celle-là, macOS la dessine
   lui-même et la rend translucide, hors d'atteinte du CSS comme de
   `setDragImage`. C'est toute la raison du glissement écrit à la main dans
   `tache/taches.js`.
   Sortie de la grille des colonnes, la carte n'a plus de largeur : le
   contrôleur lui pose celle qu'il a mesurée avant de la détacher.
   `z-index` au-dessus de l'écran (30 au plus) et sous les fenêtres (1000).
   Droite, sans inclinaison : l'ombre seule dit qu'elle est soulevée. */
.kanban-fantome {
	position: fixed;
	z-index: 500;
	margin: 0;
	pointer-events: none;
	box-shadow: 0 8px 20px rgba(8, 14, 22, .18);
}

/* Le temps du glissement, plus rien ne se sélectionne : sans cela, promener le
   curseur bouton enfoncé surligne le texte de toutes les cartes traversées. */
body.en-glissement { -webkit-user-select: none; user-select: none; cursor: grabbing; }
/* Les cartes survolées en chemin déclarent `grab` pour leur compte : sans cette
   ligne, la main s'ouvrirait à chaque colonne traversée. Et leur survol se tait :
   une carte ne doit pas se soulever au passage de celle qu'on transporte. */
body.en-glissement .kanban-carte { cursor: grabbing; }
body.en-glissement .kanban-carte:hover { border-color: #d4d4d4; box-shadow: 0 1px 2px rgba(8, 14, 22, .06); }

/* La priorité se lit au bord gauche, pas à une pastille : elle doit se voir en
   balayant la colonne du regard, sans rien lire. Mais un liseré seul serait
   invisible à qui ne distingue pas le rouge, et muet pour un lecteur d'écran :
   l'étiquette « Urgent » du pied porte l'information, le liseré l'accompagne. */
.kanban-carte.prio-urgent { border-left-color: var(--danger); }
.kanban-carte.prio-normal { border-left-color: #ccc; }
.kanban-urgent {
	flex: 0 0 auto;
	padding: 0 5px;
	border-radius: 3px;
	background: #fdeceb;
	color: var(--danger);
	font-size: var(--t-mini);
	font-weight: 700;
	line-height: 15px;
	text-transform: uppercase;
	letter-spacing: .3px;
}

/* « FAIT » SE TAIT : une carte livrée perd son liseré d'urgence et son étiquette,
   sans quoi la colonne des choses terminées serait la plus criarde de l'écran.
   L'urgence d'une carte faite est de l'histoire — on la garde lisible, on cesse
   de l'alerter. */
.kanban-colonne[data-colonne="fait"] .kanban-carte { background: #fbfcfc; }
.kanban-colonne[data-colonne="fait"] .kanban-carte,
.kanban-colonne[data-colonne="fait"] .kanban-carte.prio-urgent { border-left-color: #cfd8d4; }
.kanban-colonne[data-colonne="fait"] .kanban-titre { color: #4b5866; font-weight: 400; }
.kanban-colonne[data-colonne="fait"] .kanban-urgent { background: #eef0f1; color: var(--muet); }

.kanban-titre { font-size: var(--t-base); line-height: 1.35;font-weight: 500; margin-bottom: 4px; }
/* L'aperçu de description : DEUX lignes, jamais plus, et les points de
   suspension posés par le navigateur lui-même. Une troncature comptée en
   caractères côté serveur couperait trop tôt sur une colonne large et trop tard
   sur une étroite — `line-clamp` mesure la ligne rendue, pas le texte source.
   `overflow-wrap` est là pour l'URL sans espace, qui sans lui déborde la carte. */
.kanban-desc {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
	overflow-wrap: anywhere;
	margin-bottom: 6px;
	color: var(--muet);
	font-size: var(--t-petit);
	line-height: 1.35;
}

/* Une seule respiration, la même partout : titre, description et pied se lisent
   ensemble. */
.kanban-pied {
	display: flex;
	align-items: center;
	gap: 6px;
	margin-top: 6px;
	font-size: var(--t-petit);
	color: var(--muet);
}
.kanban-qui { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* LES INITIALES DE L'ASSIGNÉ. Le nom seul se lirait mot à mot : pour trouver ses
   propres cartes dans une colonne, il faudrait parcourir chaque pied. Une
   pastille se reconnaît à la couleur, sans lire — le nom reste à côté pour lever
   l'ambiguïté et pour la voix.
   La teinte vient de l'IDENTIFIANT du compte, jamais du nom : deux homonymes
   gardent chacun la sienne, et corriger l'orthographe de son propre nom ne
   change pas sa couleur du jour au lendemain.
   Le cran `--t-mini`, dans un cercle de 22 px pour que deux capitales y tiennent,
   et six teintes foncées à luminosité seule : la couleur qu'on reconnaît reste la
   même, et toutes tiennent au moins 5,6:1 sous le blanc. */
.kanban-av {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	background: #5b6877;
	color: #fff;
	font-size: var(--t-mini);
	font-weight: 700;
	line-height: 1;
}
.kanban-av.av0 { background: #3d6996; }
.kanban-av.av1 { background: #337358; }
.kanban-av.av2 { background: #8e5b34; }
.kanban-av.av3 { background: #6a5da5; }
.kanban-av.av4 { background: #975074; }
.kanban-av.av5 { background: #316f78; }
/* Non assignée : le rond reste, vide. Sans lui, le pied des cartes sans assigné
   ne s'alignerait pas sur celui des autres, et la colonne perdrait sa trame. */
.kanban-av.est-vide { background: transparent; border: 1px dashed #b9c2ca; }

/* LA COLONNE VIDE NE DIT RIEN, elle se montre : une phrase en haut d'un rectangle
   gris serait une ligne orpheline, qui ne se lit pas comme l'explication du vide
   qu'elle surplombe. Reste la zone en pointillé, sans un mot : elle occupe la pile
   et dit qu'on peut déposer là. */
.kanban-vide {
	flex: 1 1 auto;
	min-height: 52px;
	margin: 0;
	border: 1px dashed #d3d9dd;
	border-radius: 6px;
}

/* L'ATTENTE SE VOIT : changer de semaine éteint le tableau sans le faire
   disparaître. On continue de lire ce qu'on avait sous les yeux, et plus rien ne
   répond au clic — sans ce signe, on recliquerait, et l'on sauterait deux
   semaines. */
.est-en-attente .kanban,
.est-en-attente .div_tb_normal { opacity: .45; pointer-events: none; }
.est-en-attente .sprint-barre { pointer-events: none; }
.est-en-attente { cursor: progress; }

/* Sous 1240 px, quatre colonnes deviennent illisibles : on passe à deux, et la
   grille défile verticalement comme le reste de l'écran. L'en-tête de colonne
   devient alors COLLANT : la promesse tenue au-dessus du seuil — savoir ce qu'on
   regarde quand on défile — serait sinon retirée juste là où elle sert le plus,
   les colonnes reprenant leur hauteur de contenu et les en-têtes sortant par le
   haut.
   LES RANGÉES PRENNENT LA HAUTEUR DE LEUR CONTENU (`max-content`), et se rangent
   en haut. Laissées en `auto` dans une grille de hauteur bornée, elles se
   partageraient ce qui reste, et une pile longue — qui ne défile plus à cette
   largeur — déborderait sur la rangée du dessous. C'est la grille qui défile :
   une rangée n'a donc aucune raison de se serrer. */
@media (max-width: 1240px) {
	.kanban {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		grid-auto-rows: max-content;
		align-content: start;
		overflow-y: auto;
	}
	.kanban-colonne { min-height: 220px; }
	.kanban-pile { overflow: visible; }
	.kanban-tete { position: sticky; top: 0; z-index: 2; background: #f3f4f4; border-radius: 0 0 0 0; }
}
/* Sous 780 px — un téléphone — deux colonnes de 140 px couperaient tous les noms à
   l'ellipse et jetteraient les titres sur cinq lignes. Une seule colonne, empilée. */
@media (max-width: 780px) {
	.kanban { grid-template-columns: minmax(0, 1fr); }
}

/* La barre de sprint : une semaine, deux flèches, et les raccourcis. Elle est
   au-dessus des filtres parce qu'elle change ce qu'on regarde, quand les filtres
   ne font que restreindre. */
.sprint-barre {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 9px 0px;
	border-bottom: 1px solid var(--bord-fin);
	flex-wrap: wrap;
}
.sprint-titre { font-weight: 500; font-size: 15px; }
/* LA SEMAINE EN COURS SE VOIT, et pas seulement au lecteur d'écran : une semaine
   qu'on visite est en retrait ; celle d'aujourd'hui est pleine. Un seul objet porte
   l'information, le titre lui-même — c'est ce qu'on lit, et deux objets feraient
   chercher lequel des deux répond. */
.sprint-titre.est-semaine { color: var(--muet); font-weight: 500; }
.sprint-titre.est-semaine.est-en-cours { color: var(--texte); font-weight: 700; }
/* Les deux flèches de semaine et les actions de la barre : de la navigation,
   donc des liens. Le chevron ne se souligne pas au survol — un glyphe souligné
   se lit mal ; il s'assombrit. */
.sprint-fleche {
	color: var(--lien);
	line-height: 1;
	padding: 0 0px;
	font-size: 20px;
	cursor: pointer;
}
.sprint-fleche:hover { color: var(--focus); text-decoration: none; }
/* Un bleu dense (5,5:1 sur blanc), et un survol qui fonce : le survol ne doit pas
   dégrader la lisibilité de ce qu'on s'apprête à cliquer. */
.sprint-lien {
	color: #0b6fa4;
	font-size: var(--t-fort);
	white-space: nowrap;
	cursor: pointer;
	font-weight:500;
}
.sprint-lien:hover { color: #08537a; }
/* La couleur seule ne dit pas qu'il y a là des actions : le soulignement, au
   survol seulement, est le seul indice non coloré de la barre. Il est rétabli ICI,
   contre `a:hover { text-decoration: none!important }` en tête de cette feuille. */
.sprint-barre a.sprint-lien:hover { text-decoration: underline !important; }
/* Ce qui ÉCRIT ne se confond pas avec ce qui navigue : « Reporter N cartes », au
   même bleu et à la même taille que « Backlog » et « Cette semaine », se cliquerait
   pour eux. Il est à droite, avec le reste des actions, et porte une icône — ses
   voisins de gauche n'en ont pas. */
.sprint-lien.est-action .fa-angles-right { margin-right: 3px; font-size: 12px; }
.sprint-espace { flex: 1 1 auto; }
/* Effacer une carte est irréversible : le lien reste discret, mais il porte la
   couleur du danger pour qu'on ne le confonde pas avec les autres. La
   confirmation, elle, ne dépend pas de cette couleur. Même rouge que le liseré
   d'urgence : deux rouges voisins dans un même module se liraient comme deux
   sens différents alors qu'il n'y en a qu'un. */
.lien-supprimer { color: var(--danger); font-size: var(--t-base); cursor: pointer; }
.lien-supprimer:hover { color: #8d1a12; text-decoration: underline; }
/* Le passage semaine ↔ backlog, au pied de la fenêtre d'une carte, à côté de
   « Supprimer » : un lien de la même taille, mais de la couleur des liens — il
   déplace la carte, il ne l'efface pas. */
.lien-semaine { color: var(--lien); font-size: var(--t-base); cursor: pointer; white-space: nowrap; }
.lien-semaine:hover { color: var(--lienHover); text-decoration: underline; }
/* Au bout de la barre : le compte des cartes, puis « Ajouter ». Le vide
   (`.sprint-espace`) les repousse à droite ; ni l'un ni l'autre ne se replie. */
.sprint-total { color: var(--muet); font-size: var(--t-base); white-space: nowrap; }
.sprint-barre .btn { flex: 0 0 auto; white-space: nowrap; }
.sprint-nb {
	margin-left: 5px;
	padding: 0 5px;
	border-radius: 8px;
	background: #e4e8ea;
	color: var(--muet);
	font-size: var(--t-base);
}

/* Le backlog est une LISTE : la priorité s'y lit au même liseré gauche que sur
   une carte du tableau, pour que l'œil n'ait pas à réapprendre le code couleur
   en changeant de vue. */
.ligne_tache { cursor: pointer; }
.ligne_tache:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.ligne_tache td:first-child { border-left: 3px solid transparent; }
.ligne_tache.prio-urgent td:first-child { border-left-color: var(--danger); }

/* Rapprochement bancaire ------------------------------------------------------
   Le sas entre l'avis de la banque et la comptabilité. L'écran s'ouvre sur ce qui
   demande une DÉCISION, pas sur l'historique : les quatre états sont des liens de
   navigation, pas des boutons — ils ne valident rien. */
.rap-etats { display: flex; align-items: center; gap: 14px; margin-right: auto; }
.rap-etat { color: var(--lien); font-size: var(--t-base); white-space: nowrap; cursor: pointer; }
.rap-etat:hover { color: var(--lien); text-decoration: underline; }
/* L'état REGARDÉ se distingue par le poids et par un liseré, jamais par la seule
   couleur : sur quatre liens tous bleus, rien ne dirait où l'on est. */
.rap-etat.est-actif {
	color: var(--texte);
	font-weight: 600;
	border-bottom: 2px solid var(--focus);
	padding-bottom: 2px;
}
.rap-etat.est-actif:hover { text-decoration: none; }

/* Le dépôt : `<label>` habillé en bouton, l'`<input type=file>` étant caché.
   C'est la seule façon d'obtenir un déclencheur présentable — le champ natif
   n'est pas stylable, et un vrai bouton ne peut pas ouvrir le sélecteur. */
.rap-depot { position: relative; cursor: pointer; margin-bottom: 0; }

.rap-message { margin: 8px 0; padding: 7px 11px; border-radius: 4px;
	background: var(--tete); color: var(--texte); font-size: var(--t-base); }
.rap-message-mauvais { background: #fdecea; color: #96271a; }

/* Une ligne SIGNALÉE se voit d'un coup d'œil : c'est elle qui appelle un geste,
   et le motif seul, noyé dans une colonne, se lit trop tard. */
.rap-ligne.rap-doute td:first-child { border-left: 3px solid var(--danger); }
.rap-ligne td:first-child { border-left: 3px solid transparent; }
.rap-ref { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t-base); }
.rap-motif { font-size: var(--t-base); color: var(--muet); max-width: 320px; }
.rap-num { margin-left: 6px; font-size: var(--t-petit); white-space: nowrap; }
/* La référence qui désigne un autre client que celui choisi à la main (Q77). */
.rap-reference { display: block; margin-top: 2px; font-size: var(--t-petit); color: #b54708; }
.rap-montant { white-space: nowrap; }
.rap-actions { white-space: nowrap; }
.rap-actions a { margin-left: 10px; }
.rap-actions a:first-child { margin-left: 0; }

/* Fenêtre « Choisir un client » -----------------------------------------------
   La liste défile DANS la fenêtre plutôt que de l'étirer : une recherche large
   rend des dizaines de clients, et une fenêtre haute de deux écrans cache son
   propre champ de recherche. */
/* Le CONTEXTE est encadré, pas posé en note grise : c'est le montant qu'on est
   en train de rattacher à un client, et il doit rester sous les yeux pendant
   qu'on cherche. */
.pc-contexte {
	margin: 0 0 12px; padding: 8px 11px;
	border-left: 3px solid var(--focus); border-radius: 0 4px 4px 0;
	background: var(--tete); color: var(--texte); font-size: var(--t-base);
}
/* La mise en garde de l'appelant, encadrée comme le contexte : elle se lit avant de choisir. */
.pc-avis {
	margin: 0 0 12px; padding: 8px 11px;
	border-left: 3px solid #b54708; border-radius: 0 4px 4px 0;
	background: var(--tete); color: #b54708; font-size: var(--t-base);
}
.pc-recherche { width: 100%; margin-bottom: 10px; }
.pc-liste { max-height: 340px; overflow-y: auto; border: 1px solid var(--bord); border-radius: 4px; }
.pc-liste .tb_liste { margin: 0; }
/* On choisit un client en BALAYANT une liste, pas en la lisant : le nom porte le
   poids, tout le reste s'efface. Des colonnes de même intensité obligeraient à
   lire chaque ligne entière pour trouver la bonne. */
.pc-ligne { cursor: pointer; }
.pc-ligne td { padding: 7px 10px; border-top: 1px solid var(--bord); }
.pc-ligne:first-child td { border-top: 0; }
.pc-ligne td:first-child { font-weight: 500; }
.pc-ligne:hover td { background: var(--tete); }
.pc-num { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t-petit); color: var(--muet); white-space: nowrap; }
.pc-lieu { color: var(--muet); font-size: var(--t-petit); white-space: nowrap; }
/* « Inactif » se signale, il ne se cache pas : le client reste désignable — il a
   pu payer une facture ancienne — mais on doit le savoir avant de cliquer. */
.pc-etat { text-align: right; font-size: var(--t-petit); white-space: nowrap; }
.pc-etat .muet {
	padding: 1px 7px; border-radius: 9px;
	background: #fdecea; color: #96271a;
}
.pc-faute { margin-bottom: 8px; padding: 6px 10px; border-radius: 4px;
	background: #fdecea; color: #96271a; font-size: var(--t-base); }

/* Rapprochement : la sélection multiple ---------------------------------------
   La barre n'apparaît QU'UNE FOIS quelque chose de coché. Une barre d'action
   vide occupe la place et fait chercher ce qu'elle attend. */
.c-case { width: 28px; text-align: center; }
.c-case input { cursor: pointer; }
.rap-lot {
	display: flex; align-items: center; gap: 14px;
	margin-top: 10px; padding: 9px 12px;
	border: 1px solid var(--focus); border-radius: 4px;
	background: var(--tete);
}
/* Le compte et le MONTANT sont l'information de la barre : c'est ce qu'on
   engage. Ils poussent les actions à droite. */
.rap-lot-compte { margin-right: auto; font-size: var(--t-base); font-weight: 600; color: var(--texte); }

/* La ligne SIGNALÉE dans le dialogue d'imputation. L'avertissement dit « les
   lignes en rouge ci-dessus » : sans cette règle, il désignerait des lignes qui
   ne le sont pas. */
.dialogue-ligne.rap-dlg-doute { color: var(--danger); font-weight: 500; }
.dialogue-ligne.rap-dlg-doute .c-montant { color: var(--danger); }

/* Boîte envois -----------------------------------------------------------------
   Une ligne se PARCOURT : la date et l'objet portent le sens, l'adresse et
   l'auteur s'effacent. Sur 240 envois, des colonnes de même intensité
   obligeraient à lire chaque ligne entière. */
.c-canal { width: 26px; text-align: center; }
.c-canal i { color: var(--muet); font-size: 12px; }
.env-ligne { cursor: pointer; }
.env-ligne:hover td { background: var(--tete); }
.env-email .c-canal i { color: var(--lien); }
.env-sms .c-canal i { color: #2b6b3a; }
.env-quand { white-space: nowrap; font-size: var(--t-base); }
.env-objet { font-weight: 500; }
/* Le texte d'un SMS tient dans la ligne — l'infobulle porte le message entier.
   Ouvrir une fenêtre pour trois phrases coûterait un geste pour rien. */
.env-sms-texte {
	display: inline-block; max-width: 420px;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
	vertical-align: bottom; font-weight: 400; color: var(--texte);
}
.env-dest { color: var(--muet); font-size: var(--t-base); max-width: 220px;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.env-ouv { white-space: nowrap; font-size: var(--t-base); }
.env-par { font-size: var(--t-petit); white-space: nowrap; }
/* JAMAIS OUVERT SE DIT. Un compteur à zéro se confond avec une absence de mesure,
   et c'est pourtant l'information qui décide d'un relancement. */
.env-jamais { color: var(--danger); font-size: var(--t-petit); }
/* Resté sans verdict du relais : ni parti ni refusé, à vérifier avant tout renvoi. */
.env-incertain { color: #b54708; font-size: var(--t-petit); font-weight: 600; white-space: nowrap; }
/* La zone qui DÉFILE. Sans hauteur bornée, le tableau pousse le volet et c'est la
   page entière qui défile — le crochet n'a alors jamais de « bas » à atteindre et
   ne demande jamais la tranche suivante. */
.env-defilement { max-height: calc(100vh - 221px); overflow-y: auto; }
/* Sous 861 px l'entête de la fiche passe sur deux rangs : 46 px de moins pour la liste. */
@media (max-width: 860px) { .env-defilement { max-height: calc(100vh - 267px); } }
/* Le texte d'un SMS, retours à la ligne conservés : un rappel en compte, et les
   écraser changerait ce que le client a lu. */
.sms-corps {
	margin-top: 12px; padding: 12px 14px;
	border: 1px solid var(--bord); border-radius: 6px;
	background: var(--tete);
	white-space: pre-wrap; word-break: break-word;
	font-size: var(--t-base); line-height: 1.5;
}
/* La ligne entière s'atténue : en balayant la liste, on doit voir d'un coup ce
   qui n'a pas été lu, sans chercher dans une colonne. */
.env-ligne.env-muet .env-objet { font-weight: 400; color: var(--muet); }