/* Skin Pilotis — habillage d'eldy, chargé après le thème sur toutes les pages.
   Jetons : Pilotis/site/web/assets/pilotis.css (une seule source, recopiée ici).
   Règles : rien ne change de place ; pas de dark mode. Cette police n'est utilisée
   que sur les titres, cf. la fin du fichier. */

@font-face {
	font-family: 'Fraunces';
	font-style: normal;
	font-weight: 500 700;
	font-display: swap;
	src: url('fonts/fraunces-latin.woff2') format('woff2');
}

/* Jetons du skin — la police de titre en fait partie, définie ci-dessous. */
:root {
	--pi-lagon-900: #052e37;
	--pi-lagon-700: #0e5a6b;
	--pi-turquoise: #18a7bd;
	--pi-ecume: #f7f4ee;
	--pi-sable: #efe8db;
	--pi-bois: #a9764a;
	--pi-encre: #13282e;
	--pi-encre-doux: #3d565d;
	--pi-ok: #2f9e6e;
	--pi-alerte: #c96f2d;
	--pi-erreur: #b8472f;
	--pi-radius: 8px;
	--pi-titres: 'Fraunces', Georgia, serif;

	/* On repeint les variables d'eldy : tout ce qui les lit suit sans sélecteur supplémentaire. */
	--colorbackhmenu1: var(--pi-lagon-900);
	--colortextbackhmenu: #ffffff;
	--colorbackbody: var(--pi-ecume);
	--colortext: var(--pi-encre);
	--colortextlink: var(--pi-lagon-700);
	/* Retour d'Amandine (fix3, 02/09/2026) : le lagon plein sur les lignes de titre de tableau
	   (Règlements, Marges, Description, Fichiers joints, Objets liés…) alourdit, et une loupe
	   bleue sur une ligne de filtre grise est laide. Le cœur lit ces DEUX variables pour toutes
	   les lignes de titre — de tableau (tr.liste_titre, global.inc.php:5124), de filtre
	   (.liste_titre_filter, global.inc.php:1628, !important) et de bloc du tableau de bord
	   (tr.box_titre, global.inc.php:6561) — donc les repeindre ici en clair (sable, texte lagon
	   foncé) recolore tout ce qui reste sans sélecteur dédié ; les lignes de titre de tableau
	   elles-mêmes reçoivent en plus, plus bas, un dégradé et une bordure turquoise. Une couleur
	   PLEINE ici (pas un dégradé) : ces deux variables servent aussi de `border-color` ailleurs
	   dans le cœur (ex. .liste_titre .select2-container… { border-bottom: solid 1px
	   var(--colorbacktitle1); }, global.inc.php:7593) où un dégradé serait une valeur invalide. */
	--colorbacktitle1: var(--pi-sable);
	--colortexttitle: var(--pi-lagon-900);
	/* Les lignes alternées d'eldy lisent les variantes « 2 », pas « 1 » (theme/eldy/global.inc.php:173,175) ;
	   « 1 » n'est jamais lue en CSS (seul un PHP côté cœur la lit ailleurs, pour un tout autre usage —
	   dropdown.inc.php). --oddevencolor (texte des lignes, global.inc.php:202) reste au défaut #202020 :
	   contraste correct aussi bien sur blanc que sur --pi-sable (ruling du 02/09/2026). */
	--colorbacklineimpair2: #ffffff;
	--colorbacklinepair2: var(--pi-sable);
	--colorbacklinepairhover: #e6f4f7;
	--colorbacklinepairchecked: #d9eff3;
	--butactionbg: var(--pi-lagon-700);
	--textbutaction: #ffffff;
	--butactiondeletebg: var(--pi-erreur);
	--colorbackvmenu1: #ffffff;
	--colortextbackvmenu: var(--pi-encre-doux);
}

/* ---- Barre haute ---- */
#id-top { background: var(--pi-lagon-900); }
li.tmenusel::after, li.tmenu:hover::after { border-bottom-color: var(--pi-turquoise); }
li.tmenucompanylogo .menulogocontainer::before {
	content: ''; display: inline-block; width: 34px; height: 34px; vertical-align: middle; margin-right: 6px;
	background: url('../img/logo-blanc.svg') center / contain no-repeat;
}
li.tmenucompanylogo img.mycompany[src*="dolibarr_512x512_white"] { display: none; }

/* ---- Menu gauche ----
   Le fond blanc porte sur .side-nav SEUL (retour d'Amandine, fix4 point 2, 03/09/2026) :
   c'est la vraie cellule de tableau (voir plus bas, confinement), elle seule s'étire à la
   pleine hauteur de la ligne — div#id-left, imbriqué dedans, ne fait que 225px de haut sur
   l'accueil d'Au Pétrin quand .side-nav en fait 4665 (mesuré 03/09/2026) : peindre le fond
   sur #id-left ne l'aurait jamais porté jusqu'en bas. --colorbackvmenu1 (jeton :root plus
   haut) le fait déjà par le cœur (theme/eldy/global.inc.php:2642, `.side-nav { background:
   var(--colorbackvmenu1); }`) ; cette règle reste posée en clair pour ne pas dépendre d'une
   indirection de variable pour un fait aussi visible. */
.side-nav { background: #ffffff; }
div.vmenu a.vsmenu:hover, div.vmenu a.vmenu:hover { color: var(--pi-turquoise); }
div.vmenu .menu_contenu.menu_contenu_selected a, div.vmenu .menu_titre_selected a { border-left: 3px solid var(--pi-turquoise); padding-left: 6px; }

/* ---- Titres : Fraunces, et seulement eux ----
   .titre seul atteindrait aussi td.titre (nom de société dans le menu gauche, main.inc.php:3448)
   et tr.titre (projet/card.php:1802) — d'où le besoin d'exclusion. `:not(td):not(tr)` l'obtenait
   mais montait la spécificité à (0,1,2) SANS raison fonctionnelle : ça faisait gagner la règle
   quel que soit l'ordre des feuilles, masquant sa vraie dépendance à l'ordre de chargement
   (revue finale du 02/09/2026). Remplacé par `div.fiche div.titre` (et
   `div.fiche .table-fiche-title .titre` pour la bannière de fiche) : exclut td.titre/tr.titre
   par le nom de balise lui-même (pas de td, pas de tr), et scope en plus au contexte fiche
   (spec §4.1, « titres de page et de fiche seulement »). Sa spécificité réelle —
   `div.fiche div.titre` = (0,2,2) (deux éléments div, deux classes .fiche/.titre) et
   `div.fiche .table-fiche-title .titre` = (0,3,1) — bat déjà `div.titre { font-weight: 400;
   … }` (0,1,1) du cœur sur ses propres mérites : le gain par l'ordre de chargement (notre feuille après eldy) n'est
   plus qu'une sécurité redondante, pas la seule raison pour laquelle on gagne (revue du
   fix3, 02/09/2026 — le commentaire précédent décrivait encore `div.titre` nu, plus le
   sélecteur réellement livré). `.login_table_title` a sa propre règle dédiée plus bas (fond
   sombre de connexion, texte forcément blanc) : le lister ici aussi était redondant, et le
   `color: var(--pi-lagon-900)` de ce groupe n'y aurait de toute façon jamais gagné contre le
   `!important` de cette règle dédiée — retiré (fix3, 02/09/2026). */
h1, div.fiche div.titre, div.fiche .table-fiche-title .titre, .pi-titre, .refid, div.refidno .refid {
	font-family: var(--pi-titres); font-weight: 600; color: var(--pi-lagon-900); letter-spacing: -.01em;
}

/* ---- Fiches ---- */
div.tabs div.tab a.tab.tabactive, div.tabs a.tabactive { border-bottom: 3px solid var(--pi-lagon-700); }
div.tabBar { border-radius: var(--pi-radius); }
table.border > tbody > tr > td, table.border > tr > td { border-bottom: 1px solid var(--pi-sable); }

/* ---- Boutons d'action ---- */
/* Pas de min-height ici (retiré, fix4 point 4, 03/09/2026 : « les boutons sont trop hauts »
   — sur PC, la hauteur reste celle du cœur, sans rien ajouter). Les 44px du bloc mobile
   plus bas (cible tactile) restent inchangés, scopés à ≤ 767px. */
.butAction, .butAction:link, .butAction:visited { background: var(--pi-lagon-700) !important; color: #ffffff; border-radius: var(--pi-radius); }
.butAction:hover { background: var(--pi-turquoise) !important; }
/* Texte du bouton Supprimer (fix5 point 2, 03/09/2026) : « la couleur des boutons Supprimer
   est bien, mais la couleur du texte est difficile à lire ». Cause mesurée : `color: #ffffff`
   ci-dessous n'avait pas `!important`, et le cœur pose `color: #444` sur EXACTEMENT les mêmes
   pseudo-classes (`.butActionDelete, .butActionDelete:link, .butActionDelete:visited,
   .butActionDelete:hover, .butActionDelete:active`, theme/eldy/btn.inc.php:132-133) à
   spécificité égale (0,2,0 sur chaque variante à pseudo-classe) : à égalité de spécificité
   c'est l'ordre de chargement qui tranche en théorie (notre feuille après eldy), mais un
   `!important` manquant d'un côté suffit à perdre — gris foncé sur fond erreur, mesuré peu
   lisible. `:hover`/`:active` ajoutés ici (le cœur les couvre, pas nous) : sans eux le survol
   retombait sur le gris du cœur malgré le fond plus sombre. Fond de survol légèrement plus
   sombre que l'aplat (cf. --pi-erreur), texte toujours blanc — contraste ≈ 5,2:1 au repos. */
.butActionDelete, .butActionDelete:link, .butActionDelete:visited, .butActionDelete:hover, .butActionDelete:active { background: var(--pi-erreur) !important; color: #ffffff !important; border-radius: var(--pi-radius); }
.butActionDelete:hover, .butActionDelete:active { background: #a03d28 !important; }
.button, .button-save, .button-add { border-radius: var(--pi-radius); }
.button-save { background: var(--pi-lagon-700); }

/* Entrées du menu déroulant d'actions (« Créer », « Plus d'actions » : le cœur y remet
   les mêmes classes .butAction/.butActionDelete que sur les vrais boutons, mais les veut
   PLATES — c'est une liste, pas six aplats empilés). Le cœur neutralise donc le fond
   (`.dropdown-content .butAction { background: none; color: #333 !important; }`,
   theme/eldy/dropdown.inc.php:569) — sans `!important` sur le fond, avec `!important` sur
   le texte. Nos règles plus haut posent l'inverse : `!important` sur le fond, rien sur le
   texte. Chacun gagne donc sur la moitié qui l'arrange, et le résultat est le pire des
   deux : fond --pi-lagon-700 (le nôtre passe) + texte #333 (le sien passe), contraste
   mesuré 1,6:1 — illisible, signalé par Amandine le 12/09/2026 (« bleu foncé sur bleu »).
   On reprend donc les DEUX propriétés, à spécificité supérieure (0,2,0 et 0,3,0 contre nos
   0,1,0 / 0,2,0 du bloc précédent) et `!important` des deux côtés : plat au repos, aplat
   lagon au survol comme le prévoit le cœur. Contrastes : lagon-900 sur blanc 14,5:1 ;
   blanc sur lagon-700 au survol 7,8:1 ; erreur sur blanc 5,3:1.
   ⚠️ `border-radius: 0` : les entrées sont jointives et pleine largeur (le cœur les passe
   en `display: flex`), un rayon y découperait des coins dans le fond blanc du menu. */
.dropdown-content .butAction, .dropdown-content .butAction:link, .dropdown-content .butAction:visited {
	background: none !important; color: var(--pi-lagon-900) !important; border-radius: 0;
}
.dropdown-content .butAction:hover, .dropdown-content .butAction:active {
	background: var(--pi-lagon-700) !important; color: #ffffff !important;
}
.dropdown-content .butActionDelete, .dropdown-content .butActionDelete:link, .dropdown-content .butActionDelete:visited {
	background: none !important; color: var(--pi-erreur) !important; border-radius: 0;
}
.dropdown-content .butActionDelete:hover, .dropdown-content .butActionDelete:active {
	background: var(--pi-erreur) !important; color: #ffffff !important;
}


/* ---- Boutons de CLASSEMENT MANUEL : rattrapage, pas geste courant -----------
   Demande d'Amandine (12/09/2026) : « Classer livrée », « Classer facturé » et leurs
   équivalents sur les autres documents « vont se classer automatiquement, non ? pourrait-on
   les mettre moins visibles, qu'ils prennent moins de place pour éviter que les gens se
   trompent ».

   CE QU'ILS SONT VRAIMENT — et c'est ce qui interdit de les supprimer. Le cœur ne les
   affiche QUE tant que le classement n'a pas eu lieu (commande/card.php:3626 exige
   `status == VALIDATED || SHIPMENTONPROCESS` ; :3632 exige `!$object->billed`). Ils ne
   doublent donc jamais une action déjà faite : ils apparaissent exactement quand
   l'automatisme n'a PAS joué — commande sans expédition, expédition partielle, facture
   d'acompte, et sur un tenant Pilotis où le module Workflow n'est pas activé, TOUJOURS.
   Les retirer laisserait ces documents ouverts à vie, sans recours.
   Le risque est à l'autre bout : cliquer AVANT d'avoir fait la facture marque la commande
   « facturée » sans facture et la sort du reste-à-facturer. D'où : discrets, jamais absents.

   ⚠️ SPÉCIFICITÉ — le bloc « Boutons d'action » plus haut pose
   `.butAction { background: var(--pi-lagon-700) !important }` (0,1,0). Il faut donc à la
   fois `!important` ET une spécificité supérieure : `div.tabsAction a.butAction[href*=…]`
   vaut (0,3,2). Et les DEUX propriétés du couple fond/texte sont reprises ensemble —
   n'en marquer qu'une donne le pire des deux feuilles, exactement la panne de contraste
   du 12/09 sur le menu déroulant (bloc précédent).

   ⚠️ DESCENDANT, PAS ENFANT DIRECT. `div.tabsAction > a.butAction` raterait la moitié des
   boutons visés : le cœur en emballe une partie dans `<div class="inline-block
   divButAction">` (fourn/commande/card.php:2739 pour « Classer réceptionné »,
   compta/tva/card.php:823 et compta/sociales/card.php:833 pour « Classer payé »), et les
   autres non (commande/card.php:3627). Les deux écritures cohabitent dans le même cœur.

   ⚠️ PORTÉE QUAND MÊME BORNÉE à `div.tabsAction` : `action=classify` tout court est le
   crayon « Lier au projet » du bandeau de référence (comm/propal/card.php:3031,
   expedition/card.php:2787) — un `a.editfielda` hors de la barre d'actions. Un sélecteur
   qui se contenterait de `[href*="action=classify"]` l'emporterait avec.

   ⚠️ TAILLE — la réduction de gabarit est scopée ≥ 768px. Sous ce seuil, le bloc mobile
   plus bas impose `min-height: 44px !important` avec `padding: 10px 14px` à (0,1,0) : une
   règle à (0,3,2) ici l'écraserait sans même avoir besoin d'`!important`, et raterait la
   cible tactile.

   Couverture vérifiée contre le cœur par test/scenarios-boutons.php, dans les DEUX sens :
   aucun sélecteur mort (une montée de version qui renommerait une action), aucun bouton de
   classement du cœur oublié (un document que Dolibarr ajouterait). Les deux actions
   délibérément hors périmètre y sont nommées avec leur raison, jamais tues. */
div.tabsAction a.butAction[href*="action=shipped"],
div.tabsAction a.butAction[href*="action=classifybilled"],
div.tabsAction a.butAction[href*="action=classifyunbilled"],
div.tabsAction a.butAction[href*="action=classifyclosed"],
div.tabsAction a.butAction[href*="action=classifyreception"],
div.tabsAction a.butAction[href*="action=paid"] {
	/* Contraste mesuré : --pi-encre-doux (#3d565d) sur --pi-ecume (#f7f4ee) = 7,1:1. */
	background: transparent !important;
	color: var(--pi-encre-doux) !important;
	border: 1px solid var(--pi-sable);
	font-weight: normal;
	box-shadow: none;
}
/* Au survol, le bouton redevient un bouton PLEIN : discret ne doit pas vouloir dire
   « désactivé ». Blanc sur --pi-lagon-700 = 7,8:1, le même couple que le reste du skin. */
div.tabsAction a.butAction[href*="action=shipped"]:hover,
div.tabsAction a.butAction[href*="action=classifybilled"]:hover,
div.tabsAction a.butAction[href*="action=classifyunbilled"]:hover,
div.tabsAction a.butAction[href*="action=classifyclosed"]:hover,
div.tabsAction a.butAction[href*="action=classifyreception"]:hover,
div.tabsAction a.butAction[href*="action=paid"]:hover {
	background: var(--pi-lagon-700) !important;
	color: #ffffff !important;
	border-color: var(--pi-lagon-700);
}
/* Garde du menu déroulant. Aujourd'hui AUCUNE action de classement n'y passe (vérifié :
   pas un seul `'url' => …action=classify|shipped|paid` dans le cœur 23.0.4, les entrées
   de `arrayforbutaction` ne servent qu'à « Créer »). Mais `.dropdown-content` vit DANS
   `div.tabsAction` : le jour où le cœur y déplacerait un de ces boutons, nos (0,3,2)
   ci-dessus battraient le (0,2,0) du bloc déroulant et rendraient une entrée encadrée au
   milieu d'une liste plate. La règle ci-dessous reprend la main à (0,4,2), sans toucher au
   reste. scenarios-boutons.php surveille l'hypothèse et rougit si elle change. */
div.tabsAction .dropdown-content a.butAction[href*="action=shipped"],
div.tabsAction .dropdown-content a.butAction[href*="action=classifybilled"],
div.tabsAction .dropdown-content a.butAction[href*="action=classifyunbilled"],
div.tabsAction .dropdown-content a.butAction[href*="action=classifyclosed"],
div.tabsAction .dropdown-content a.butAction[href*="action=classifyreception"],
div.tabsAction .dropdown-content a.butAction[href*="action=paid"] {
	background: none !important;
	color: var(--pi-lagon-900) !important;
	border: 0;
	border-radius: 0;
}
@media (min-width: 768px) {
	div.tabsAction a.butAction[href*="action=shipped"],
	div.tabsAction a.butAction[href*="action=classifybilled"],
	div.tabsAction a.butAction[href*="action=classifyunbilled"],
	div.tabsAction a.butAction[href*="action=classifyclosed"],
	div.tabsAction a.butAction[href*="action=classifyreception"],
	div.tabsAction a.butAction[href*="action=paid"] {
		font-size: 0.88em;
		padding: 4px 10px;
	}
}

/* ---- Listes ----
   Lignes de titre (en-têtes de liste, Règlements, Marges, Description des fiches, blocs
   Fichiers joints / Objets liés…) : dégradé clair plutôt qu'un aplat lagon — retour
   d'Amandine (fix3, 02/09/2026), remplace « en-tête lagon 700 sur texte blanc » de la spec
   §4.2 (le turquoise porte la ligne, pas le fond). */
tr.liste_titre, tr.liste_titre_sel, .liste_titre {
	background: linear-gradient(180deg, #ffffff 0%, var(--pi-sable) 100%);
	color: var(--pi-lagon-900); font-weight: 600; border-bottom: 2px solid var(--pi-turquoise);
}
tr.liste_titre td, tr.liste_titre th, tr.liste_titre a, .liste_titre input::placeholder { color: var(--pi-lagon-900); }
/* Ligne de filtres : sur écume, sans le dégradé/bordure ci-dessus — elle porte elle-même la
   classe .liste_titre sur ses <td> (le cœur la réutilise comme classe utilitaire générique,
   list.php), donc sans cette règle plus spécifique chaque cellule de filtre afficherait son
   propre petit dégradé et sa propre bordure turquoise, empilés juste sous ceux de la ligne de
   titre au-dessus : plus lourd, pas plus léger — c'est justement ce qu'on corrige. */
tr.liste_titre_filter td { background: var(--pi-ecume); border-bottom: 1px solid var(--pi-sable); }
/* Boutons d'icône posés sur une ligne claire (loupe/croix d'effacement de la ligne de filtres,
   et tout bouton du même genre ailleurs) : aucun fond coloré, juste l'icône teintée — la loupe
   bleue sur ligne grise qu'Amandine trouvait laide venait du fond hérité de .liste_titre
   ci-dessus (ces boutons — button.button_search, button.button_removefilter, list.php du
   cœur — portent eux-mêmes la classe .liste_titre). `border: 0` reprend aussi la bordure
   turquoise héritée : un icône n'a pas besoin d'un soulignement. */
button.liste_titre, .liste_titre button { background: none; border: 0; color: var(--pi-lagon-700); padding: 6px; }
button.liste_titre:hover, .liste_titre button:hover { color: var(--pi-turquoise); }
tr.oddeven:hover td { background: #e6f4f7 !important; }

/* ---- Statuts ---- */
.badge-status4, .badge-status4.badge-status { background: var(--pi-ok); }
.badge-status1, .badge-status1.badge-status { background: var(--pi-alerte); }
.badge-status8, .badge-status8.badge-status, .badge-status9 { background: var(--pi-erreur); }

/* ---- Messages ---- */
div.ok, div.warning, div.error, div.info { border-radius: var(--pi-radius); border-left: 4px solid; background: var(--pi-ecume); }
div.ok { border-color: var(--pi-ok); } div.warning { border-color: var(--pi-alerte); } div.error { border-color: var(--pi-erreur); } div.info { border-color: var(--pi-turquoise); }

/* ---- Connexion ---- */
body.bodylogin { background-color: var(--pi-lagon-900); }
.login_vertical_align::before {
	content: ''; display: block; width: 84px; height: 84px; margin: 0 auto 14px;
	background: url('../img/logo-blanc.svg') center / contain no-repeat;
}
div.login_table { border-radius: var(--pi-radius); background-color: #ffffff !important; }
img#img_logo[src*="dolibarr_logo"] { display: none; }
.login_table_title { font-family: var(--pi-titres); color: #ffffff !important; text-shadow: none; }
form#login .button, form#login input[type=submit], form#login button { background: var(--pi-lagon-700); color: #ffffff; border-radius: var(--pi-radius); }

/* ---- Accueil : tuiles « à faire » et widgets (2.17.0) ------------------------
   Spec : docs/specs/2026-09-11-accueil-pilotis-design.md. Les cartes de tuiles des modules
   Pilotis reçoivent leur icône ICI (le cœur pose `fa-dol-<clé de groupe>`, sans rien
   définir pour une clé qu'il ne connaît pas). Le FOND de la carte reste celui du cœur
   (gris) : un fond lagon les faisait ressortir « trop bleues » (Amandine, 12/09/2026). */
.info-box { border-radius: 12px; box-shadow: 0 1px 3px rgba(5, 46, 55, .08); border: 1px solid var(--pi-sable); background: #fff; }
.info-box .info-box-icon { border-radius: 12px 0 0 12px; }
.info-box-title { font-weight: 600; color: var(--pi-lagon-900); }
.fa-dol-gestionimpayes::before { content: "\f571"; } /* file-invoice-dollar */
.fa-dol-echeancesnc::before { content: "\f073"; }    /* calendar-alt */
.fa-dol-importauto::before { content: "\f56f"; }     /* file-import */
.fa-dol-tgcnc::before { content: "\f66f"; }          /* landmark */
div.box { border-radius: 12px; box-shadow: 0 1px 3px rgba(5, 46, 55, .08); border: 1px solid var(--pi-sable); background: #fff; overflow: hidden; }
div.box .boxtable tr.liste_titre th, div.box .boxtable tr.liste_titre td { font-weight: 600; background: var(--pi-ecume); color: var(--pi-lagon-900); }

/* ====================== Confinement (toutes largeurs) ======================
   #id-container / #id-right sont des cellules de tableau (display: table-cell,
   thème eldy) : sans contrainte, une cellule grandit jusqu'à son contenu le
   plus large au lieu de le contraindre — c'est la page entière qui défile
   alors. Le cœur ne pose ce confinement que sous son propre point de rupture
   « réduction 3 » (dépend du nombre d'entrées de menu, cf. global.inc.php) ;
   sur Au Pétrin (13 entrées) ce point tombe à 741 px, sous 768 : à 768 et
   1280 rien ne contraint plus #id-right. On le pose donc nous-mêmes, à toute
   largeur — c'est la même règle que le cœur applique déjà en dessous de son
   point de rupture, juste étendue.
   D'autres layouts du cœur redéfinissent #id-right/#id-container pour leurs propres
   besoins (.classforhorizontalscrolloftabs sur product/price.php,
   product/price_suppliers.php, workstation_list.php ; .bodyforlist.poslist ;
   .page-modulehelp). Sur ces pages, seul #id-right y est redéfini par le cœur avec un
   sélecteur plus spécifique (classe + id, ex. `.classforhorizontalscrolloftabs #id-right`)
   qui gagne sur notre `#id-right` seul ci-dessous. #id-container, lui, n'y est jamais
   redéfini au-delà de `width: 100%` (aucun display ni table-layout propres à ces layouts) :
   notre règle ci-dessous s'y applique donc quand même, sans qu'il y ait de conflit de
   spécificité à trancher. Que rien ne bouge visuellement n'est donc pas une conséquence de
   cascade déduite ici — c'est un résultat mesuré, pas supposé : test/skin/run.js, page
   « fournisseurs-produit », R1 et R6 verts à 1280 (revue du 02/09/2026). */
#id-container { display: table; table-layout: fixed; width: 100%; }
/* Colonne gauche (menu vertical, .side-nav) : aucune largeur propre dans le cœur, seul
   son contenu (.vmenu) est à largeur fixe. Sans elle, table-layout: fixed ci-dessus
   l'écrase à 0 — le menu disparaît, #id-right (width: 100% posé par le cœur) recouvre
   toute la largeur depuis le bord gauche (trouvé en revue, ruling du 02/09/2026).
   Retour d'Amandine (fix4 point 2, 03/09/2026) : « le bloc des entrées est plus large que
   le reste de la colonne ». Cause mesurée sur aupetrin.local à 1280px : la marge de
   sécurité ci-dessous (250) était plus étroite que ce que le cœur réserve réellement à
   .vmenu (260, mesuré), et la largeur posait sur DEUX éléments qui ne jouent pas le même
   rôle dans le tableau. Le cœur imbrique `<div class="side-nav"><div id="id-left">…`
   (main.inc.php:3176) : SEUL .side-nav est un enfant direct de notre #id-container
   (display: table ci-dessus) donc SEUL lui reçoit le traitement rigide de table-layout:
   fixed. #id-left, imbriqué un niveau plus bas, porte lui aussi `display: table-cell`
   (cœur, global.inc.php:2558) mais sans table-row parent direct : le navigateur l'entoure
   d'une table anonyme en layout AUTO, qui l'agrandit pour loger tout le contenu de .vmenu
   — ignorant notre largeur posée dessus. Deux sources de largeur qui ne peuvent PAS
   converger : poser un nombre sur #id-left ne change rien à ce que l'auto-layout calcule,
   poser un nombre différent sur .side-nav (table fixe, lui, obéit) créait le décalage.
   Solution : une SEULE source, sur .side-nav seul — #id-left n'a plus aucune largeur
   posée, il s'auto-dimensionne (layout auto) exactement sur .vmenu, qui rentre alors dans
   .side-nav sans déborder. Valeur : 258 = $leftmenuwidth (240px, global.inc.php:29) + les
   8px de margin-left de .vmenu (règle .vmenu, même fichier) + les 10px de padding-right
   !important de `div.vmenu, td.vmenu` (global.inc.php:2701) — trois valeurs fixes du
   cœur, jamais dépendantes du contenu (nombre d'entrées, langue) : plus une estimation de
   sécurité, un calcul exact. Le margin-right de 2px que le cœur pose sur `div.vmenu,
   td.vmenu` (global.inc.php:2700) est neutralisé juste en dessous : une fois que c'est
   nous qui dimensionnons le conteneur au pixel, cette réserve ne sert plus à rien — elle
   ne faisait que rouvrir l'écart d'1 à 3px qu'on referme ici. Vérifié 03/09/2026 :
   |right(div.vmenu) − right(.side-nav)| ≤ 1px sur accueil et fiche-facture à 1280 (R6). */
.side-nav { width: 258px; }
div.vmenu, td.vmenu { margin-right: 0; }
/* width: auto (pas 100% comme le pose le cœur) : avec table-layout: fixed, un pourcentage
   sur une cellule compte dans le calcul de largeur des colonnes (CSS2.1 §17.5.2.1) et
   ferait regrandir #id-container au-delà du viewport — on retrouverait le débordement de
   page que ce bloc corrige. À TOUTE largeur, jamais overflow-x ici (revue du 02/09/2026,
   fix round 2) : un overflow-x visible force l'axe y en auto sur la même boîte, donc un
   popup positionné en absolu qui dépasse la hauteur de #id-right (ex. le menu « Plus
   d'actions » du cœur, .dropdown-content, ouvert depuis la barre du bas) se ferait couper
   ou défiler dans la colonne au lieu de flotter par-dessus la page — vu et corrigé avant
   de committer. */
#id-right { width: auto; }
/* Bande 768-1000px (point de rupture propre du cœur, cf. global.inc.php) seulement : une
   fois la colonne gauche reprise (250px), #id-right y est parfois plus étroit que son
   contenu (le formulaire de création de facture à 768px a une largeur intrinsèque ~794px
   pour 518px de colonne disponible) — il défile dans sa propre boîte plutôt que de
   repousser la page, même stratégie que .pi-scroll et div.tabs. Scopé : à 1280px la
   colonne est assez large pour ne jamais en avoir besoin, et overflow-x n'y clipperait un
   popup en absolu pour rien. */
@media only screen and (min-width: 768px) and (max-width: 1000px) {
	#id-right { overflow-x: auto; }
}

/* ====================== Téléphone (point de rupture d'eldy) ====================== */
@media only screen and (max-width: 767px) {
	/* Menu haut mobile : une ligne défilable horizontalement, plus de « 4 entrées + Plus »
	   (retour d'Amandine, fix4 point 1, 03/09/2026 : « qu'on scroll vers la droite plutôt
	   que de devoir appuyer sur Plus »). Filet CSS pur en même temps que le comportement
	   normal (R15) : ces règles ne dépendent d'aucun JS, `ul.tmenu` défile tout seul —
	   `menuDefilant()` (skin.js) ne fait qu'amener l'entrée active dans le cadre visible au
	   chargement, il ne construit plus rien. `div.tmenudiv` (le cœur, white-space: nowrap,
	   sans limite de largeur) n'a plus besoin de porter son propre `overflow-x` : c'est
	   `ul.tmenu` lui-même qui défile désormais, un seul conteneur scrollable, pas deux
	   imbriqués. `scrollbar-width: none` (Firefox) + `::-webkit-scrollbar { display: none }`
	   (Chrome/Safari) : la barre de défilement système ne s'affiche pas sur un geste tactile
	   de toute façon, mais un pointeur/trackpad la ferait apparaître sans ces deux règles —
	   moins de bruit visuel dans une barre haute déjà chargée. */
	/* scroll-padding-left = largeur du hamburger collant ci-dessous (32px mesurés sur Au
	   Pétrin + 1px de bordure = 33, +1 de marge = 34) : sans elle, `menuDefilant()`
	   (skin.js, `scrollIntoView({inline:'nearest'})`) peut amener une entrée active tout
	   juste sous le bord droit du hamburger — la sticky le recouvre alors partiellement,
	   PROTOCOLE.md ne l'aurait pas détecté sans ce garde-fou (fix6 point 1, 03/09/2026). */
	ul.tmenu { display: flex; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; align-items: flex-end; scroll-padding-left: 34px; }
	ul.tmenu::-webkit-scrollbar { display: none; }
	/* Hamburger collant à gauche (fix6 point 1, 03/09/2026), retour d'Amandine « le menu (les
	   3 traits) du topmenu toujours accessible à gauche : en scrollant vers la droite on ne
	   le voit plus » — c'est le SEUL accès au menu gauche sur téléphone (cf. R5/R19), le
	   perdre en scrollant coupe l'utilisateur du reste de l'application. `position: sticky;
	   left: 0` sur un enfant flex d'un conteneur `overflow-x: auto` : vérifié en direct sur
	   Au Pétrin/Chromium (Playwright) avant d'écrire cette règle — le hamburger reste bien
	   collé au bord gauche après `ul.scrollLeft = ul.scrollWidth`, et reste cliquable
	   (`elementFromPoint` sur son centre rend bien l'icône, `isVisible()` vrai) : pas besoin
	   du repli JS (déplacer le hamburger hors de `ul.tmenu`) envisagé si sticky avait échoué.
	   `background` opaque (le jeton de fond de la barre haute, pas transparent) : sans elle
	   les entrées qui défilent sous le hamburger collant seraient visibles PAR-DESSOUS lui en
	   semi-transparence — z-index seul ne peint pas de fond. `border-right` : simple séparateur
	   visuel entre l'élément collant et ce qui défile dessous, discret (`rgba(255,255,255,.15)`
	   sur fond lagon 900, pas un jeton dédié pour un filet de 1px). `flex: 0 0 auto` inchangé
	   (ne se comprime jamais). */
	ul.tmenu > li.menuhider {
		flex: 0 0 auto; position: sticky; left: 0; z-index: 2;
		background: var(--pi-lagon-900); border-right: 1px solid rgba(255, 255, 255, .15);
	}
	/* Chaque entrée à sa largeur naturelle (elle ne se partage plus une largeur totale fixe
	   avec ses voisines : la ligne défile, elle ne se comprime plus) — `min-width: 64px` évite
	   qu'une icône seule (libellé très court) ne devienne une cible trop étroite. */
	ul.tmenu > li.tmenu:not(.menuhider):not(.tmenucompanylogo):not(.tmenuend),
	ul.tmenu > li.tmenusel:not(.menuhider):not(.tmenucompanylogo):not(.tmenuend) { flex: 0 0 auto; min-width: 64px; }
	/* max-width, pas seulement width : le cœur pose `div.tmenucenter { max-width: 26px; }`
	   (theme/eldy/global.inc.php:9114, "2nd reduction", active à 390px dès que le tenant a
	   plus de quelques entrées de menu) et cette propriété n'est PAS écrasée par `width: auto`
	   ci-dessus (deux propriétés distinctes) — sans le max-width explicite ici, l'entrée
	   resterait plafonnée à ~25px de large quel que soit l'espace réellement disponible sur
	   la ligne défilante (constat du 02/09/2026, toujours vrai avec la ligne défilable). */
	div.tmenucenter { width: auto; max-width: none; overflow: visible; }
	/* Libellé entier, une seule ligne (fix4 point 1, 03/09/2026) : la ligne défile
	   maintenant horizontalement, un mot tronqué ou coupé n'a plus de raison d'être — tout
	   l'intérêt du défilement est de garder le libellé complet, lisible d'un coup. Essayé en
	   direct sur Au Pétrin (13 entrées) : le rendu à une ligne est net et net plus lisible
	   que l'enroulement sur deux lignes essayé au fix précédent, gardé tel quel. */
	ul.tmenu > li.tmenu span.mainmenuaspan, ul.tmenu > li.tmenusel span.mainmenuaspan {
		display: block; max-width: none; white-space: nowrap; overflow: visible;
		line-height: 1.15; font-size: 11px; letter-spacing: -.01em; padding: 0 6px;
	}

	/* Barre d'actions collante. margin: 0 !important (trouvé en diagnostiquant le point 5,
	   03/09/2026) : `.pi-actions-fixe` (0,1,0) est ajoutée en JS SUR le même `div.tabsAction`
	   que le cœur styles déjà avec `margin: 20px 0 40px 0` (theme/eldy/global.inc.php:4251,
	   spécificité 0,1,1 — type + classe) — plus spécifique, elle gagnait sur notre `margin: 0`
	   malgré l'ordre de chargement. La barre restait donc collée à `bottom: 0` par son BORD DE
	   MARGE (les offsets d'un élément en `position: fixed` positionnent la boîte de marge, pas
	   la boîte de bordure — CSS2.1 §10.6.4), et son bord de bordure, lui, flottait 40px
	   au-dessus du vrai bas d'écran : mesuré sur Au Pétrin, la barre s'arrêtait à 804px sur un
	   viewport de 844. Le lanceur Pilotia (bottom: 84px, calculé pour une barre VRAIMENT collée
	   au bord) chevauchait donc la barre réelle de ~17px — la vraie cause du chevauchement
	   « le bouton Pilotia se superpose presque aux boutons du bas ». */
	/* Sélecteur `div.tabsAction.pi-actions-fixe` (fix6 point 3, 03/09/2026), pas `.pi-actions-fixe`
	   seul comme jusqu'à la 2.4.2 : retour d'Amandine « les boutons en bas, c'est beaucoup
	   mieux, mais remets une petite marge en haut et en bas » a révélé, en mesurant en
	   direct (`distanceHaut`/`distanceBas` = 0/0, `barreHeight` = 44 = la hauteur du bouton
	   SEUL), que le padding n'avait JAMAIS été rendu depuis la 2.4.0 malgré son écriture ici
	   — R7 (fix5) ne l'a pas vu : l'assertion « écarts égaux à 2px près » passait aussi bien
	   à 0/0 qu'à une vraie marge symétrique, un faux vert qui protégeait le centrage sans
	   jamais prouver l'existence de marge. Cause : le cœur pose `div.tabsAction { padding:
	   0em 0em; }` (theme/eldy/global.inc.php:4249, spécificité élément+classe = 0,1,1) — plus
	   spécifique que `.pi-actions-fixe` seul (une classe = 0,1,0), il gagnait quel que soit
	   l'ordre de chargement, exactement le même piège que la marge des enfants au fix5 point 3
	   (`div.tabsAction > a.butAction`, alors résolu ; le padding du CONTENEUR lui-même,
	   distinct, était resté sur l'ancien sélecteur). Solution identique : reprendre le
	   sélecteur du cœur préfixé de notre classe (`div.tabsAction.pi-actions-fixe`, élément +
	   deux classes = 0,2,1) — bat 0,1,1 sur ses propres mérites, sans dépendre de l'ordre des
	   feuilles. 12px (au lieu de 8) : « remets une petite marge », mesuré en direct après coup
	   — voir R7 étendu dans le protocole pour le seuil (≥ 10px des deux côtés, égaux à 2px
	   près) et la vérification que `body.pi-avec-actions #id-container { padding-bottom:
	   100px }` (plus bas) couvre encore la barre une fois plus haute. */
	div.tabsAction.pi-actions-fixe { position: fixed; left: 0; right: 0; bottom: 0; z-index: 1500; margin: 0 !important; padding: 12px 10px calc(12px + env(safe-area-inset-bottom)); display: flex; align-items: center; gap: 8px; overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap; background: var(--pi-ecume); box-shadow: 0 -4px 16px rgba(5, 46, 55, .18); }
	/* Centrage vertical (fix5 point 3, 03/09/2026) : « il n'y a pas de marge au-dessus du
	   bouton dans la ligne alors qu'il y en a en dessous ». Cause mesurée en direct (avant ce
	   correctif, `distanceHaut` = 0, `distanceBas` ≈ 17px) : les enfants gardent
	   `margin-bottom: 16px !important` (global.inc.php:4258, `div.tabsAction > a`, spécificité
	   0,1,2) et `margin-bottom: 1.4em !important` (btn.inc.php:93-101, `div.tabsAction >
	   a.butAction, …`, spécificité 0,2,2 — le plus spécifique des deux) — notre première
	   tentative, `.pi-actions-fixe > * { margin: 0 !important }` (0,1,0), perdait sur la
	   SPÉCIFICITÉ, pas sur `!important` seul : entre deux règles `!important`, c'est encore la
	   spécificité qui tranche, l'ordre de chargement ne sert qu'à départager une égalité.
	   Solution : reprendre le sélecteur du cœur tel quel, préfixé de nos deux classes
	   (`div.tabsAction.pi-actions-fixe > a.butAction`, etc., spécificité 0,3,2 minimum) —
	   ça bat (0,2,2) sur ses propres mérites. `align-items: center` sur le conteneur
	   (au-dessus) centre ensuite le bouton dans la bande visible, marges enfants nulles. */
	div.tabsAction.pi-actions-fixe > a.butAction, div.tabsAction.pi-actions-fixe > a.butActionDelete, div.tabsAction.pi-actions-fixe > a.butActionRefused,
	div.tabsAction.pi-actions-fixe > span.butAction, div.tabsAction.pi-actions-fixe > span.butActionDelete, div.tabsAction.pi-actions-fixe > span.butActionRefused,
	div.tabsAction.pi-actions-fixe > div.divButAction > a.butAction, div.tabsAction.pi-actions-fixe > div.divButAction > a.butActionDelete, div.tabsAction.pi-actions-fixe > div.divButAction > a.butActionRefused,
	div.tabsAction.pi-actions-fixe > div.divButAction > span.butAction, div.tabsAction.pi-actions-fixe > div.divButAction > span.butActionDelete, div.tabsAction.pi-actions-fixe > div.divButAction > span.butActionRefused,
	div.tabsAction.pi-actions-fixe > .dropdown > .dropdown-toggle { margin: 0 !important; }
	.pi-actions-fixe > .butAction, .pi-actions-fixe > .butActionDelete, .pi-actions-fixe > .butActionRefused, .pi-actions-fixe > .divButAction { flex: 0 0 auto; }
	/* `calc(100px + env(safe-area-inset-bottom))`, pas `100px` fixe (relecture du 03/09/2026) :
	   la barre elle-même grandit avec l'encoche (`padding: 12px … calc(12px + env(…))`,
	   point 3 plus haut) — sur un iPhone à encoche (~34px), sa hauteur réelle atteint
	   12+44+12+34 ≈ 102px, au-delà des 100px fixes ci-dessous : 2px de contenu passaient
	   sous la barre. La clairance doit croître au même rythme que ce qu'elle couvre. */
	body.pi-avec-actions div#id-container { padding-bottom: calc(100px + env(safe-area-inset-bottom)); }
	/* Respiration sous le lanceur Pilotia, hors barre d'actions (fix6 point 2, 03/09/2026),
	   retour d'Amandine « quand je crée une nouvelle facture, le bouton Annuler se retrouve
	   en dessous du bouton Pilotis » : `facture/card.php?action=create` n'a pas de
	   `div.tabsAction` (les boutons Créer/Annuler sont dans `div.center` du formulaire), donc
	   `body.pi-avec-actions` n'est jamais posé — la respiration de la ligne au-dessus ne
	   s'applique pas là où ça manque. `:not(.pi-avec-actions)` scope volontairement : quand
	   la barre d'actions collante EST présente, le `padding-bottom` ci-dessus la couvre déjà
	   (barre ≈68px + encoche avec le padding du point 3 + 8 de marge ≤ 100 + encoche), et le
	   lanceur y remonte lui-même à 84px (`body.pi-avec-actions #pilotia-launcher`, plus bas) —
	   deux règles pour ce même cas se chevaucheraient sans rien ajouter. `pi-avec-pilotia`
	   posée par `marquerAvecPilotia()` (skin.js), qui marque le corps de page dès que le
	   lanceur Pilotia existe dans le DOM — synchrone s'il y est déjà, différé sinon
	   (`MutationObserver`, même mécanisme que le bandeau PWA, débranché après 30s) :
	   `demarre()` l'appelle INCONDITIONNELLEMENT (pas seulement depuis `bandeauPwa()`), pour
	   qu'un visiteur qui a déjà fermé le bandeau PWA (`pilotis_pwa_ferme` en localStorage,
	   `bandeauPwa()` retourne alors avant même de poser son propre observateur) profite quand
	   même de cette marge — sans ce détachement, le bug qu'on corrige ici reviendrait pour
	   tout visiteur récurrent. `84px` reste fixe, PAS `calc(84px + env(…))` : contrairement à
	   la barre d'actions, le lanceur Pilotia lui-même (`Pilotis/pilotia/css/pilotia.css`,
	   `#pilotia-launcher { bottom: 22px }`) est posé en pixels bruts, sans `env()` — sa
	   position ne grandit pas avec l'encoche, donc la clairance qui le couvre n'a aucune
	   raison de grandir non plus (relecture du 03/09/2026). */
	body.pi-avec-pilotia:not(.pi-avec-actions) #id-container { padding-bottom: 84px; }

	/* Onglets de fiche (facture, tiers…) : une seule ligne défilable, jamais l'enroulement sur
	   plusieurs lignes du cœur — retour d'Amandine après essai en direct (fix3, 02/09/2026) :
	   div.tabs s'enroulait sur trois lignes à 390px. `flex-wrap: nowrap` + `overflow-x: auto`,
	   chaque onglet à sa largeur naturelle (`flex: 0 0 auto`, jamais compressé) ; l'onglet actif
	   est amené dans le cadre visible au chargement par skin.js (alignerOngletActif(),
	   scrollIntoView block:'nearest' — ne fait défiler QUE ce cadre, jamais la page). */
	div.tabs { display: flex; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; max-width: 100%; }
	div.tabs > * { flex: 0 0 auto; }

	/* Fichiers joints : le sélecteur de modèle de document et le bouton GÉNÉRER passaient à la
	   ligne alors qu'il y avait de la place — retour d'Amandine (fix3, 02/09/2026). Diagnostiqué
	   en direct (mesure des rects des enfants du <th> : select2 et bouton étaient déjà sur la
	   même ligne dans ce banc précis, mais le <th> lui-même, `th.formdoc.maxwidthonsmartphone`
	   (html.formfile.class.php:855), hérite de la règle générique du cœur
	   `.maxwidthonsmartphone { max-width: 100px; }` (theme/eldy/global.inc.php:2438, active
	   ≤1000px) — pensée pour un petit champ de saisie autocomplete, pas pour toute la cellule
	   qui porte le sélecteur ET le bouton. `max-width` sur une cellule de tableau est ignoré
	   par certains moteurs en `table-layout: auto` (Chromium) mais pas par d'autres (WebKit
	   mobile) : sur un moteur qui l'honore, 100px ne laisse de la place ni pour le select2
	   (~76px) ni pour le bouton (~90px) à côté — le bouton est mécaniquement rejeté à la ligne
	   suivante. On lève la contrainte pour cette cellule précise, sans toucher aux autres
	   usages de .maxwidthonsmartphone ailleurs dans le cœur. */
	th.formdoc.maxwidthonsmartphone { max-width: none; }

	/* Tableaux plus larges que l'écran : défilent dans leur cadre, jamais la page */
	.pi-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
	div.fiche > table.table-fiche-title, div.refidno, div.statusref { max-width: 100%; }
	/* Filet CSS pur (R15) : sans JS, tableauxDefilants() n'enveloppe jamais un tableau dans
	   .pi-scroll (ex. #tablelines, les lignes de facture — aucun wrapper du cœur ne l'entoure).
	   Un tableau ainsi contraint rend sa propre boîte scrollable au lieu de dépasser la page ;
	   quand JS tourne, sa largeur rendue tient déjà dans le viewport (contrainte ici même),
	   donc tableauxDefilants() (qui ne wrap que ce qui dépasse) ne l'enveloppe pas en plus —
	   pas de double défilement. */
	div.fiche table:not(.pi-scroll table) { max-width: 100%; }

	/* Cibles tactiles. !important : .butAction seul (0,1,0) perd contre les variantes pseudo-
	   classe du thème eldy (.butAction:link, .butAction:visited — btn.inc.php l.132, reprises
	   telles quelles par la section PC ci-dessus) : chaque pseudo-classe ajoutée compte comme
	   une classe, donc (0,2,0) — plus spécifique que le sélecteur mobile, quel que soit l'ordre
	   dans le fichier. Un lien (l'élément est un <a href>) correspond toujours à l'une des deux.
	   Comme le fait déjà la section PC pour le fond des boutons, on force. */
	.butAction, .butActionDelete, .butActionRefused, .button, div.tabs div.tab a.tab, .dropdown-toggle { min-height: 44px !important; display: inline-flex !important; align-items: center; padding: 10px 14px; box-sizing: border-box; }
	input[type=checkbox], input[type=radio] { transform: scale(1.5); margin: 12px 10px; }
	input[type=text], input[type=password], input[type=email], input[type=number], input[type=search], select, .select2-container .select2-selection--single { min-height: 44px; }
	a.butActionNew { min-width: 44px; min-height: 44px; }
	/* Bouton de date (fix5 point 1, 03/09/2026) : « le bouton pour saisir une date n'est pas
	   beau ». La cause exacte a demandé une vérification en direct (le brief citait
	   html.form.class.php:7857-7915 pour un `<button class="dpInvisibleButtons"><img
	   class="datecallink">…</button>` — mesure sur `aupetrin.local` : ce bloc est mort, entier
	   dans un commentaire du cœur (délimité comme celui-ci), jamais exécuté ; le calendrier réellement affiché
	   sur un champ actif est configuré en JS avec `showOn: 'button', buttonImageOnly: true`
	   (html.form.class.php ~7902-7911), et c'est **jQuery UI lui-même** qui insère l'image
	   déclencheur, NUE, sans bouton englobant : `<img class="ui-datepicker-trigger" src="…">`,
	   sibling direct du champ. `dpInvisibleButtons`/`datecallink` ne s'y appliquent QUE pour un
	   champ désactivé (l.7915) — pas le cas ici. C'est justement `.ui-datepicker-trigger {
	   min-width: 44px; min-height: 44px }` (l'ancienne règle, ci-dessus jusqu'à ce fix) qui
	   étirait l'image elle-même en carré flou : à la fois cible ET coupable, faute d'élément
	   à qui déléguer le padding. Solution : l'image garde sa taille naturelle (`width`/
	   `height: 18px`), la cible tactile vient du PADDING de l'image elle-même (`box-sizing:
	   content-box`, 13px de chaque côté = 44px de boîte totale) — un `<img>` reçoit les clics
	   sur toute sa boîte de padding, pas seulement son contenu. `.datenowlink` (« Maintenant »,
	   un vrai `<button class="dpInvisibleButtons datenowlink">`, confirmé en direct) : même
	   principe, padding du bouton lui-même. */
	img.ui-datepicker-trigger { width: 18px; height: 18px; padding: 13px; box-sizing: content-box; vertical-align: middle; }
	.dpInvisibleButtons.datenowlink, .datenowlink { min-height: 44px; padding: 10px; display: inline-flex; align-items: center; }
	/* État désactivé (l.7915 du cœur, seul cas réel où dpInvisibleButtons enveloppe
	   datecallink) : même traitement, cohérent avec le champ actif ci-dessus. */
	.dpInvisibleButtons { min-height: 44px; padding: 10px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; }
	img.datecallink { width: 18px; height: 18px; }

	/* Champs optionnels vides repliés en création : gagne de la hauteur d'écran sans rien retirer du formulaire */
	tr.pi-replie { display: none; }
	a.pi-plus-options { display: block; margin: 10px 0 14px; padding: 12px 14px; min-height: 44px; box-sizing: border-box; border: 1px dashed var(--pi-lagon-700); border-radius: var(--pi-radius); color: var(--pi-lagon-700); text-align: center; }

	/* Halo du hamburger : « les 3 traits se mettent en surbrillance une demi-seconde avec un
	   cadre bizarre, comme deux cadres superposés » (retour d'Amandine, fix4 point 3,
	   03/09/2026). Deux effets tactiles empilés au tap sur `li.menuhider a.tmenuimage`, aucun
	   des deux voulu au toucher : le halo natif du navigateur (`-webkit-tap-highlight-color`),
	   et le petit triangle `li.tmenu:hover::after` (theme/eldy/global.inc.php:3271) qu'un tap
	   déclenche aussi, faute de vrai `:hover` sur tactile. ⚠️ Correction (re-revue du
	   05/09/2026) : le cœur ne pose PAS d'outline ici — `a.tmenuimage:focus,
	   .mainmenu.topmenuimage:focus { outline: none; }` (global.inc.php:3342-3344) le retire
	   déjà, ce n'était donc pas une des deux causes. Le contour `:focus-visible` ci-dessous
	   n'est pas une préservation d'un comportement du cœur : c'est un AJOUT du skin, pour que
	   le clavier garde un repère visuel une fois l'outline neutralisé plus largement par le
	   tap. */
	ul.tmenu a { -webkit-tap-highlight-color: transparent; }
	ul.tmenu a:focus:not(:focus-visible) { outline: none; box-shadow: none; }
	ul.tmenu a:focus-visible { outline: 2px solid var(--pi-turquoise); outline-offset: -2px; }
	@media (hover: none) {
		li.tmenu:hover::after { display: none; }
	}

	/* Bandeau d'installation PWA (iOS immédiat, Android sur beforeinstallprompt) */
	.pi-pwa { position: fixed; left: 10px; right: 10px; bottom: 86px; z-index: 1400; display: flex; align-items: center; gap: 10px; padding: 12px 14px; background: var(--pi-lagon-900); color: #fff; border-radius: var(--pi-radius); box-shadow: 0 10px 34px rgba(5, 46, 55, .3); font-size: 14px; }
	body:not(.pi-avec-actions) .pi-pwa { bottom: 12px; }
	/* Lanceur Pilotia présent (classe posée par skin.js, bandeauPwa()) : le bandeau passe
	   AU-DESSUS du lanceur plutôt qu'à côté (corrigé le 05/09/2026, re-revue de wave 4 sur
	   amandine.pilotis.nc où Pilotia est installé). Le premier essai (`right: 96px`, à côté)
	   supposait un lanceur carré de 48px — c'est en réalité une pilule étiquetée
	   (`Pilotis/pilotia/css/pilotia.css:34-51` : `inline-flex`, `padding: 11px 16px 11px
	   13px`, point 9px + espace 9px + texte 14px), ~100-120px de large sur ~36px de haut :
	   la placer « à côté » l'aurait fait déborder de l'écran ou recouvrir le lanceur selon le
	   libellé. Empiler au-dessus, sans toucher à `left`/`right` (10px, pleine largeur comme le
	   bandeau normal), fonctionne quelle que soit la largeur réelle de la pilule. 132px = le
	   haut du lanceur avec barre d'actions (bottom: 84px + hauteur ~36px = 120) + 12px de
	   respiration ; 70px = le haut du lanceur sans barre d'actions (bottom: 22px + hauteur
	   ~36px = 58) + 12px. */
	body.pi-avec-actions .pi-pwa.pi-pwa-avec-pilotia { bottom: 132px; }
	body:not(.pi-avec-actions) .pi-pwa.pi-pwa-avec-pilotia { bottom: 70px; }
	.pi-pwa-texte { flex: 1 1 auto; }
	.pi-pwa-installer { background: var(--pi-turquoise); color: #fff; border: 0; border-radius: var(--pi-radius); min-height: 44px; padding: 0 14px; font-weight: 600; }
	.pi-pwa-fermer { background: none; border: 0; color: #fff; font-size: 26px; line-height: 1; min-width: 44px; min-height: 44px; }

	/* Lanceur Pilotia (module Pilotia, Pilotis/pilotia/css/pilotia.css:36, position: fixed;
	   right: 22px; bottom: 22px) : « le bouton Pilotia se superpose presque aux boutons du
	   bas » (retour d'Amandine, fix4 point 5, 03/09/2026) — la barre d'actions collante
	   (.pi-actions-fixe, ~64px de haut + l'encoche de sécurité) le recouvrait presque. Remonté
	   au-dessus d'elle uniquement quand elle est présente (`body.pi-avec-actions`) ; Au Pétrin
	   local n'a pas le module Pilotia, vérifié en R7 par un bouton injecté synthétiquement. */
	body.pi-avec-actions #pilotia-launcher { bottom: 84px !important; }
}

/* Rotation téléphone → paysage (>767px, ex. 844×390 posé à plat) : skin.js ne relance rien sur
   resize, ces éléments mobiles peuvent donc survivre au-delà du point de rupture — artefact
   visuel, jamais un débordement (ils n'ont pas de contenu large). Purement défensif, hors du
   bloc mobile ci-dessus (ruling du 02/09/2026). */
@media only screen and (min-width: 768px) {
	a.pi-plus-options, .pi-pwa { display: none !important; }
}

/* ---- « Signaler un problème », en haut à droite ---------------------------
   Il prend la place du numéro de version du cœur : ce numéro n'apprend rien au
   client, et son infobulle lui apprend même quelque chose qu'on ne veut pas lui
   dire — le nom du logiciel et celui de sa base. Masqué ICI et pas par la
   constante MAIN_HIDE_VERSION : la constante s'écrirait à l'activation, donc il
   faudrait réactiver le module sur chaque tenant déjà servi pour un effet
   purement visuel. Cette feuille, elle, est déjà chargée sur toutes les pages.
   ⚠️ `:has()` cible le conteneur, sinon la boîte reste et laisse un trou. */
.login_block_elem:has(.aversion) { display: none; }
.aversion { display: none; }

/* ⚠️ De l'air à GAUCHE : sans elle, l'icône touche le bouton d'impression du cœur, et
   les deux se lisent comme un seul groupe. */
/* ⚠️ Le conteneur prend TOUTE la hauteur du bandeau et centre son contenu. Sans cela, la
   pastille — un `inline-flex` — repose sur la ligne de base du texte et tombe cinq pixels
   trop bas : mesuré, centre à 30,5 px quand le bandeau est centré à 25,5. Un
   `vertical-align` ne suffit pas quand la boîte est plus haute que la ligne. */
.pi-signaler-bloc { margin-left: 10px; display: inline-flex; align-items: center;
	height: 100%; vertical-align: middle; }
/* « Discrètement en avant » : une pastille au liseré à peine visible, qui se détache du
   bandeau sans crier — le bouton doit se trouver quand on le cherche, pas attirer l'œil
   en permanence. */
.pi-signaler { display: inline-flex; align-items: center; gap: 6px; text-decoration: none;
	white-space: nowrap; padding: 3px 10px; border-radius: 999px;
	border: 1px solid rgba(255, 255, 255, .28);
	background: rgba(255, 255, 255, .08); transition: background .15s, border-color .15s; }
.pi-signaler:hover { background: rgba(255, 255, 255, .18); border-color: rgba(255, 255, 255, .5); }
/* ⚠️⚠️ `display` posé par une CLASSE (0,1,0) l'emporte sur la règle d'agent utilisateur
   `[hidden]{display:none}` (0,1,0, mais déclarée avant) : sans cette ligne, l'attribut
   `hidden` ne masque RIEN et le bouton reste à l'écran pour qui ne peut pas s'en servir.
   Le module a déjà payé ce piège deux fois (groupes de durées, options du tunnel). */
.pi-signaler[hidden] { display: none; }
/* ⚠️ Le bandeau haut est SOMBRE : une couleur de texte prise dans les jetons de
   marque (pensés pour du texte sur fond clair) y devient illisible. On hérite donc
   de la couleur du bandeau, comme les autres boutons du cœur. */
.pi-signaler, .pi-signaler .fa, .pi-signaler .pi-signaler-txt { color: inherit; }
.pi-signaler .pi-signaler-txt { font-size: 12px; }
/* ⚠️ Marge explicite plutôt que le `gap` du flex : `atoplogin` (cœur) pose ses
   propres marges sur l'icône et les deux se collaient. */
.pi-signaler .fa { margin-right: 6px; }

/* ---- Le dialogue de signalement, ouvert par-dessus la page fautive ---------
   Il vit sur TOUTES les pages du tenant : il doit donc tenir sans rien attendre
   du thème, et rester lisible sur un fond clair comme sur un tableau de bord
   chargé. `::backdrop` assombrit ce qu'il y a derrière, sans le masquer — le
   client garde son problème sous les yeux, c'est tout l'intérêt. */
.pi-signaler-boite { width: min(560px, 92vw); border: 0; border-radius: 12px; text-align: left;
	padding: 22px 24px; box-shadow: 0 12px 40px rgba(0, 0, 0, .28); color: var(--pi-lagon-900); }
.pi-signaler-boite::backdrop { background: rgba(5, 46, 55, .45); }
.pi-signaler-boite h2 { margin: 0 0 6px; font-size: 18px; }
.pi-signaler-boite .pi-signaler-aide { margin: 0 0 14px; font-size: 13px; opacity: .75;
	line-height: 1.45; }
.pi-signaler-boite textarea { width: 100%; box-sizing: border-box; font: inherit;
	line-height: 1.5; padding: 10px 12px; border: 1px solid var(--pi-sable); border-radius: 8px; }
.pi-signaler-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; }
.pi-signaler-actions button { font: inherit; padding: 8px 16px; border-radius: 8px; cursor: pointer; }
.pi-signaler-annuler { background: transparent; border: 1px solid var(--pi-sable); color: inherit; }
.pi-signaler-envoyer { background: var(--pi-lagon-700); border: 1px solid var(--pi-lagon-700); color: #fff; }
.pi-signaler-envoyer:hover { background: var(--pi-lagon-900); border-color: var(--pi-lagon-900); }
/* Sur téléphone, le bandeau haut est déjà serré : l'icône seule suffit, et le
   libellé reste dans l'infobulle. */
/* ⚠️ Le libellé disparaît bien AVANT le téléphone. Le bandeau haut du cœur ne se replie
   pas : il déborde, et le bouton d'impression passait à la ligne sous la barre dès qu'on
   descendait sous ~1000 px. L'icône seule suffit alors, le libellé restant dans
   l'infobulle. */
@media (max-width: 1100px) { .pi-signaler .pi-signaler-txt { display: none; } }
