/*
 * socle-dense.css — v3.28.0 §D · Affichage dense, lisible et sans débordement.
 *              — v3.29.0 §A · Hotfix : les cellules ne s'empilent plus, la densité s'applique.
 *
 * POURQUOI UN FICHIER STATIQUE, ET PAS UN THÈME FILAMENT.
 * Les deux installations tournent sur du cPanel mutualisé : ni Node, ni Vite, ni chaîne de
 * compilation. Un thème Filament devrait être construit sur le serveur — impossible. Ce fichier est
 * donc livré tel quel dans `public/`, injecté par un render hook du panneau (voir
 * App\Filament\Support\TablesDenses et AdminPanelProvider), et l'archive de mise à jour ne
 * transporte qu'un `.css`. Retirer le render hook et ce fichier suffit à revenir en arrière.
 *
 * CE QUE LE GÉRANT DEMANDAIT, DANS L'ORDRE :
 *   1. voir le maximum d'infos sans glisser à droite ;
 *   2. le maximum de lignes en une page ;
 *   3. une écriture plus petite ;
 *   4. moins d'espace entre le menu de gauche et le tableau ;
 *   5. les libellés de colonnes figés en haut ;
 *   6. plus jamais de boutons coupés à droite.
 *
 * RÈGLES DE TENUE : additif (aucune règle ne masque un contenu), jamais d'`overflow: hidden` sur
 * une barre d'actions, et le mode sombre traité partout où une couleur est posée — Filament pose
 * la classe `.dark` sur `<html>`, une entête figée qui ne connaîtrait que le thème clair ferait
 * une bande blanche sur fond noir.
 *
 * Les sélecteurs sont ceux des vues de Filament v5 (`fi-ta-*`, `fi-in-*`, `fi-header-*`, `fi-ac`),
 * relevés dans les vues de Filament, sous `vendor/filament` : une classe inventée serait une
 * règle morte.
 *
 * ⚠️ v4.4.1 §1 — AUCUNE SÉQUENCE « étoile puis barre oblique » DANS UN COMMENTAIRE DE CE FICHIER
 * AVANT SA VRAIE FIN. Ce commentaire-ci portait le glob `vendor/filament/<étoile>/resources/views` :
 * la séquence de ce glob FERMAIT le commentaire trois lignes trop tôt, le reste de la ligne
 * devenait un jeton invalide, et le parseur CSS jetait tout jusqu'à la première accolade fermante
 * — c'est-à-dire le bloc `:root` ci-dessous en entier. `--socle-dense-gouttiere` n'existait donc
 * pas, `padding-inline: var(--socle-dense-gouttiere)` était invalide au calcul, et le contenu de
 * TOUTES les pages de l'admin collait au menu de gauche et au bord droit. Le défaut datait de la
 * v3.28.0 (commit 541e1f6) et a vécu jusqu'à la v4.4.0. Un test le garde désormais
 * (tests/Feature/Ui/FeuilleDenseTest.php).
 */

:root {
    /* Les repères du lot, en un endroit : les ajuster ne demande pas de relire la feuille. */
    --socle-dense-texte: 0.8125rem;      /* 13 px — lisible, nettement plus compact que 14 px */
    --socle-dense-cellule-y: 0.375rem;
    --socle-dense-cellule-x: 0.625rem;
    --socle-dense-gouttiere: 1rem;
    --socle-dense-entete-fond: #ffffff;
    --socle-dense-entete-bordure: rgba(0, 0, 0, 0.08);
}

.dark {
    --socle-dense-entete-fond: rgb(24 24 27);   /* le fond des panneaux Filament en sombre */
    --socle-dense-entete-bordure: rgba(255, 255, 255, 0.1);
}

/* --- 1 & 3. Des tables denses : police plus petite, cellules moins hautes ------------------- */

/*
 * v3.29.0 §A2 — LA DENSITÉ DOIT VRAIMENT S'APPLIQUER. Mesuré en prod : la v3.28.0 ciblait la
 * table et la cellule (`.fi-ta-cell`), mais Filament peint la police sur l'ÉLÉMENT DE TEXTE
 * (`.fi-ta-text-item.fi-size-sm` → 14 px, interligne FIXE de 1,5 rem) et le padding sur le
 * CONTENEUR DE COLONNE (`.fi-ta-text:not(.fi-inline)` et `.fi-ta-icon:not(.fi-inline)` → 12 px /
 * 16 px). La cellule, elle, est à `p-0` : nos règles gagnaient… sur un élément qui ne peint rien.
 * On cible donc l'élément peint, avec une spécificité qui l'emporte sur la feuille de Filament.
 */

.fi-ta-table {
    font-size: var(--socle-dense-texte);
}

.fi-ta-table .fi-ta-cell,
.fi-ta-table .fi-ta-header-cell {
    padding: var(--socle-dense-cellule-y) var(--socle-dense-cellule-x);
}

.fi-ta-table .fi-ta-cell .fi-ta-text,
.fi-ta-table .fi-ta-cell .fi-ta-text .fi-ta-text-item,
.fi-ta-table .fi-ta-cell .fi-ta-placeholder,
.fi-ta-table thead .fi-ta-header-cell {
    font-size: var(--socle-dense-texte);
    line-height: 1.3;
}

/* Le padding peint : le conteneur de colonne, pas la cellule. C'est LUI qui faisait 16 px de
   haut et de bas — le plancher de hauteur des lignes, colonnes d'icônes (favori/vu) et date
   comprises. */
.fi-ta-table .fi-ta-cell .fi-ta-text:not(.fi-inline),
.fi-ta-table .fi-ta-cell .fi-ta-icon:not(.fi-inline),
.fi-ta-table .fi-ta-cell .fi-ta-color:not(.fi-inline),
.fi-ta-table .fi-ta-cell .fi-ta-image:not(.fi-inline) {
    padding: var(--socle-dense-cellule-y) var(--socle-dense-cellule-x);
}

/* Les cellules d'actions et de sélection portent, elles, leur propre padding vertical. */
.fi-ta-table .fi-ta-cell:has(.fi-ta-actions),
.fi-ta-table .fi-ta-cell.fi-ta-selection-cell {
    padding-top: var(--socle-dense-cellule-y);
    padding-bottom: var(--socle-dense-cellule-y);
}

/* La description sous une valeur (« vu », « dans 12 jours ») : présente, jamais encombrante. */
.fi-ta-table .fi-ta-text-description {
    font-size: 0.6875rem;
}

/* --- 2. Zéro débordement horizontal --------------------------------------------------------- */

/*
 * Le conteneur de la table peut défiler s'il le faut — mais il ne coupe rien. La différence est
 * capitale : `overflow: hidden` amputerait la dernière colonne et le menu d'actions, ce qui est
 * exactement le reproche fait à l'écran d'avant.
 */
.fi-ta-ctn {
    overflow-x: auto;
}

/*
 * v3.29.0 §A1 — UNE LIGNE PAR CELLULE, tronquée net. La règle d'avant (`overflow-wrap: anywhere`)
 * a produit l'inverse de « dense » : elle autorisait la colonne Acheteur à s'effondrer à ~86 px,
 * et un nom d'organisme long s'empilait alors sur ~10 lignes — une ligne d'AO de 215 px, quatre
 * AO par écran. Plus AUCUNE cellule ne s'empile : le texte tient sur une ligne, coupé par une
 * ellipse, et le texte complet reste lisible au survol (tooltip posé par les colonnes).
 */
.fi-ta-table .fi-ta-cell .fi-ta-text-item {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 22rem;
}

/* --- 4. Moins d'espace entre le menu de gauche et le tableau -------------------------------- */

.fi-main {
    padding-inline: var(--socle-dense-gouttiere);
    max-width: 100%;
}

/* --- 5. Les libellés de colonnes restent visibles au défilement ----------------------------- */

.fi-ta-table thead {
    position: sticky;
    top: 0;
    z-index: 10;
}

.fi-ta-table thead .fi-ta-header-cell,
.fi-ta-table thead .fi-ta-empty-header-cell,
.fi-ta-table thead .fi-ta-actions-header-cell,
.fi-ta-table thead .fi-ta-selection-cell {
    position: sticky;
    top: 0;
    z-index: 10;
    /* Fond OPAQUE, dans les deux thèmes : sans lui, les lignes défileraient en transparence
       derrière les libellés et l'entête deviendrait illisible. */
    background-color: var(--socle-dense-entete-fond);
    box-shadow: inset 0 -1px 0 var(--socle-dense-entete-bordure);
}

/* --- 6. Des boutons entiers : ils passent à la ligne, ils ne sont jamais coupés -------------- */

.fi-ac,
.fi-header-actions-ctn,
.fi-ta-header-toolbar {
    flex-wrap: wrap;
    row-gap: 0.5rem;
}

/* Une barre d'actions de fiche ne se laisse pas rogner par son conteneur. */
.fi-header,
.fi-header-actions-ctn,
.fi-ta-header,
.fi-ta-header-toolbar {
    overflow: visible;
}

/*
 * v4.4.1 §5 — L'EN-TÊTE D'UNE FICHE À HUIT ACTIONS. Mesuré dans le navigateur sur une fiche
 * marché, à 1 728 px : `.fi-header` est un `flex` en ligne, `nowrap` ; son premier enfant — fil
 * d'Ariane et titre — est en `flex: 0 1 auto` et se laisse écraser jusqu'à 115 px, tandis que la
 * barre d'actions, en `flex: 0 0 auto`, occupe 1 314 px et sort de la fenêtre. Son `.fi-ac` a beau
 * être `flex-wrap: wrap`, son CONTENEUR ne peut pas rétrécir : rien n'y passe jamais à la ligne.
 * C'est la disposition par défaut de Filament, pensée pour un titre court et deux actions.
 *
 * Trois règles, et le titre reprend sa place : l'en-tête s'autorise à passer à la ligne, le bloc
 * du titre a le droit de grandir et un plancher de largeur (jamais plus que la place disponible),
 * et la barre d'actions accepte enfin de rétrécir. Les actions se rangent donc à droite du titre
 * quand elles tiennent, et passent SOUS le titre, repliées, quand elles ne tiennent pas. Aucune
 * action n'est retirée ni repliée dans un menu : elles sont toutes visibles, c'est le but.
 *
 * Le bloc du titre n'a pas de classe dans la vue de Filament (`components/header/index.blade.php`)
 * : c'est le premier enfant de l'en-tête, et il n'y en a que deux.
 */
.fi-header {
    flex-wrap: wrap;
    align-items: flex-start;
    row-gap: 0.75rem;
}

.fi-header > div:first-child {
    flex: 1 1 auto;
    min-width: min(28rem, 100%);
}

.fi-header-actions-ctn {
    flex: 0 1 auto;
    min-width: 0;
    max-width: 100%;
}

/* --- 7. Les fiches détail suivent la même mesure -------------------------------------------- */

.fi-in-entry-label,
.fi-in-text {
    font-size: var(--socle-dense-texte);
}

/* Les tableaux HTML que les sections IA rendent elles-mêmes (dossier, exigences, vigilance) :
   ils défilent dans leur propre cadre plutôt que d'élargir la page. */
.fi-in-text table {
    font-size: var(--socle-dense-texte);
}

.fi-in-text {
    overflow-x: auto;
}

/* --- 8. v3.29.0 §B — Le texte intégral du dossier : lisible en entier, jamais un mur ---------- */

/*
 * La section « Texte intégral du dossier (portail / OCR) » rend le texte brut rangé dans les
 * notes (bloc source, avis océrisé, CPS). Elle est repliée par défaut côté PHP ; même dépliée,
 * elle ne doit pas faire une fiche de 9 000 px : son corps est borné et défile dans son cadre.
 * Mesuré en prod (v3.28.0) : ce bloc atteignait 4 709 px à lui seul.
 */
.socle-texte-integral .fi-section-content-ctn {
    max-height: 60vh;
    overflow-y: auto;
}

/* --- 9. v3.30.0 §E — Mobile : des cartes empilées COMPACTES ---------------------------------- */

/*
 * En dessous de `md`, la table se rend en cartes empilées et une carte de veille faisait 637 px :
 * un AO par écran. Les colonnes secondaires ne se rendent plus du tout en empilé
 * (`visibleFrom('md')` posé côté PHP) ; ici, on resserre ce qui reste — l'objectif est ≤ 180 px
 * par carte, quatre à cinq AO par écran. Additif : rien n'est masqué, tout est resserré.
 */
@media (max-width: 767px) {
    .fi-ta-table .fi-ta-cell .fi-ta-text:not(.fi-inline),
    .fi-ta-table .fi-ta-cell .fi-ta-icon:not(.fi-inline),
    .fi-ta-table .fi-ta-cell .fi-ta-color:not(.fi-inline),
    .fi-ta-table .fi-ta-cell .fi-ta-image:not(.fi-inline) {
        padding-top: 0.15rem;
        padding-bottom: 0.15rem;
    }

    .fi-ta-table .fi-ta-record {
        padding-block: 0.35rem;
    }

    /* Une cellule empilée ne déborde jamais de l'écran : coupée net, le reste au survol/fiche. */
    .fi-ta-table .fi-ta-cell .fi-ta-text-item {
        max-width: 100%;
    }
}

/* --- 10. v3.32.0 §A — La fiche AO refaite (classes `fao-*`) --------------------------------- */

/*
 * Le HTML de la fiche est produit par App\Support\FicheAoHtml (le même que la vue imprimable) ;
 * ces règles l'habillent DANS le panneau, en clair comme en sombre — Filament pose `.dark` sur
 * `<html>`, chaque couleur posée ici a donc sa contrepartie sombre. La typo reste celle du thème.
 */
:root {
    --fao-muted: #6b7280;
    --fao-line: rgba(0, 0, 0, 0.08);
    --fao-accent: #b45309;
    --fao-accent-soft: #fdf3e3;
    --fao-accent-ink: #8a3f06;
    --fao-ok: #15803d;
    --fao-ok-soft: #e9f6ec;
    --fao-chip: #eef1f4;
    --fao-chip-ink: #3d4650;
}

.dark {
    --fao-muted: #9ca3af;
    --fao-line: rgba(255, 255, 255, 0.10);
    --fao-accent: #f0a63a;
    --fao-accent-soft: #2a2113;
    --fao-accent-ink: #f5bc66;
    --fao-ok: #4ade80;
    --fao-ok-soft: #12291a;
    --fao-chip: #222a33;
    --fao-chip-ink: #c3cad2;
}

/* En-tête : qui, quoi, quand. */
.fao-l1 { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 0.55rem; }
.fao-ref { font-family: ui-monospace, Menlo, monospace; font-weight: 600; font-size: 0.85rem; letter-spacing: 0.02em; }
.fao-sep, .fao-acheteur { color: var(--fao-muted); font-size: 0.82rem; font-weight: 500; }
.fao-badge { display: inline-flex; align-items: center; font-size: 0.72rem; font-weight: 600; padding: 0.15rem 0.55rem; border-radius: 999px; background: var(--fao-chip); color: var(--fao-chip-ink); white-space: nowrap; }
.fao-badge--ok { background: var(--fao-ok-soft); color: var(--fao-ok); }
.fao-badge--warn { background: var(--fao-accent-soft); color: var(--fao-accent-ink); }
.fao-objet { font-size: 1.15rem; font-weight: 700; line-height: 1.35; margin: 0 0 0.7rem; max-width: 46em; }
.fao-l2 { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.5rem; }
.fao-fams { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; flex: 1 1 16rem; }
.fao-fam { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.72rem; font-weight: 600; padding: 0.15rem 0.55rem; border-radius: 999px; background: var(--fao-chip); color: var(--fao-chip-ink); }
.fao-fam--p1 { background: var(--fao-accent-soft); color: var(--fao-accent-ink); }
.fao-part { font-family: ui-monospace, Menlo, monospace; color: inherit; opacity: 0.8; }
/* v3.37.0 §D3 — Le métier d'un marché montré sous sa nature : présent, jamais concurrent. */
.fao-fam--metier { background: transparent; color: var(--fao-muted); font-weight: 500; box-shadow: inset 0 0 0 1px var(--fao-line); }
.fao-compte { margin-left: auto; text-align: right; }
.fao-quand { font-family: ui-monospace, Menlo, monospace; font-weight: 600; font-size: 0.95rem; }
.fao-dans { display: inline-block; font-size: 0.75rem; color: var(--fao-accent-ink); background: var(--fao-accent-soft); border-radius: 0.4rem; padding: 0.1rem 0.5rem; font-weight: 600; margin-top: 0.2rem; }
.fao-echeances { font-size: 0.7rem; color: var(--fao-muted); margin-top: 0.25rem; }

/* La grille des 12 champs clés : 4 colonnes desktop, 2 en mobile. */
/* Pas d'`overflow: hidden` (règle de tenue de cette feuille) : le rayon du cadre reste doux
   sans jamais risquer de rogner un contenu. */
.fao-grille { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--fao-line); border-radius: 0.5rem; margin-top: 0.9rem; }
.fao-champ { padding: 0.6rem 0.8rem 0.55rem; border-right: 1px solid var(--fao-line); border-bottom: 1px solid var(--fao-line); }
.fao-champ:nth-child(4n) { border-right: 0; }
.fao-champ:nth-last-child(-n+4) { border-bottom: 0; }
.fao-champ-l { font-size: 0.62rem; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--fao-muted); margin-bottom: 0.15rem; }
.fao-champ-v { font-size: 0.83rem; font-weight: 600; }
.fao-mono { font-family: ui-monospace, Menlo, monospace; font-weight: 500; }
.fao-vide { color: var(--fao-muted); font-weight: 500; }
.fao-ecart { display: inline-block; font-size: 0.62rem; font-weight: 700; color: var(--fao-accent-ink); background: var(--fao-accent-soft); border-radius: 999px; padding: 0 0.4rem; margin-left: 0.3rem; cursor: help; }

/* Le travail à faire. */
.fao-resume { font-size: 0.88rem; max-width: 64em; margin: 0; border-left: 3px solid var(--fao-accent); padding-left: 0.85rem; }

/* Bordereau & tableaux : le cadre défile, jamais la page. */
.fao-tbl-wrap { overflow-x: auto; }
.fao-tbl { border-collapse: collapse; width: 100%; font-size: 0.82rem; }
.fao-tbl th { font-size: 0.64rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--fao-muted); text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--fao-line); }
.fao-tbl td { padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--fao-line); vertical-align: top; }
.fao-tbl tr:last-child td { border-bottom: 0; }
.fao-n { width: 2.1rem; color: var(--fao-muted); font-family: ui-monospace, Menlo, monospace; }
.fao-u { width: 4.4rem; font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; }
.fao-mt { text-align: right; font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; width: 8rem; }
.fao-fmini { font-size: 0.66rem; color: var(--fao-muted); margin-top: 1px; }
.fao-tbl-note, .fao-res-note { font-size: 0.72rem; color: var(--fao-muted); margin: 0.5rem 0 0; }
/* v4.20.0 §A — `.fao-brut` a disparu, et avec elle le pavé monospace « tableau brut du dossier ».
   Un bordereau qu'on n'a pas su découper n'est plus présenté comme un bordereau : la section se
   referme, et la file `bordereau=brut` rend le dossier à la moissonneuse. Le texte, lui, reste
   lisible dans « Texte intégral du dossier », qui a sa propre règle (`.socle-texte-integral`). */

/* Exigences & conditions : deux colonnes, une seule en mobile. */
.fao-deux { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; }
.fao-h { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--fao-muted); margin: 0 0 0.5rem; }
.fao-item { display: flex; gap: 0.6rem; padding: 0.3rem 0; font-size: 0.83rem; border-bottom: 1px solid var(--fao-line); }
.fao-item:last-child { border-bottom: 0; }
.fao-il { flex: 0 0 46%; color: var(--fao-muted); font-size: 0.76rem; padding-top: 1px; }
.fao-iv { font-weight: 600; }
ul.fao-liste { margin: 0; padding: 0; list-style: none; }
ul.fao-liste li { padding: 0.28rem 0 0.28rem 1rem; position: relative; font-size: 0.83rem; border-bottom: 1px solid var(--fao-line); }
ul.fao-liste li:last-child { border-bottom: 0; }
ul.fao-liste li::before { content: ""; position: absolute; left: 0.1rem; top: 0.72rem; width: 0.3rem; height: 0.3rem; border-radius: 999px; background: var(--fao-accent); }

/* Résultat & concurrence. */
.fao-res-grille { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.9rem; margin-bottom: 0.8rem; }
.fao-res-v { font-size: 0.88rem; font-weight: 700; }
.fao-tag { display: inline-block; font-size: 0.7rem; font-weight: 600; padding: 0.1rem 0.5rem; border-radius: 999px; background: var(--fao-chip); color: var(--fao-chip-ink); }
.fao-tag--ok { background: var(--fao-ok-soft); color: var(--fao-ok); }
.fao-tag--off { background: transparent; border: 1px solid var(--fao-line); color: var(--fao-muted); font-weight: 500; }
.fao-gagnant td { font-weight: 700; }
.fao-lien { color: inherit; text-decoration: underline; text-decoration-color: var(--fao-line); text-underline-offset: 2px; }
.fao-lien:hover { text-decoration-color: currentColor; }

/* --- 11. v4.0.0 §D — La typologie sur la fiche (badges, lots, articles, compte rendu) --------
   Les couleurs sont celles de la maquette MAQUETTE-VEILLE-V4.html, ramenées aux variables
   `--fao-*` pour qu'elles suivent le thème clair ET sombre comme le reste de la fiche. */

/* Les badges de l'en-tête : source · type · forme de prix · « N lots ». */
.fao-typo { display: inline-flex; align-items: center; font-size: 0.7rem; font-weight: 600; padding: 0.12rem 0.5rem; border-radius: 999px; background: var(--fao-chip); color: var(--fao-chip-ink); white-space: nowrap; }
.fao-typo--marche { background: #dbeafe; color: #1e40af; }
.fao-typo--bdc { background: #fef3c7; color: #92400e; }
.fao-typo--type { background: #ccfbf1; color: #115e59; }
.fao-typo--prix { background: var(--fao-chip); color: var(--fao-chip-ink); }
.fao-typo--lots { background: #ede9fe; color: #5b21b6; }
:root.dark .fao-typo--marche { background: #17263f; color: #93c5fd; }
:root.dark .fao-typo--bdc { background: #2a2113; color: #fcd34d; }
:root.dark .fao-typo--type { background: #0f2b28; color: #5eead4; }
:root.dark .fao-typo--lots { background: #241a3d; color: #c4b5fd; }

/* Le bandeau d'annulation : la première chose à savoir, il n'y a plus rien à préparer. */
.fao-annule { margin: 0 0 0.6rem; padding: 0.35rem 0.7rem; border-left: 3px solid #dc2626; background: rgba(220, 38, 38, 0.08); color: #b91c1c; font-size: 0.8rem; font-weight: 600; border-radius: 0 0.35rem 0.35rem 0; }
:root.dark .fao-annule { color: #fca5a5; }

/* « Sans objet pour ce type » — jamais un vide silencieux (§D2). */
.fao-sans-objet { margin: 0; padding: 0.5rem 0.75rem; border: 1px dashed var(--fao-line); border-radius: 0.5rem; color: var(--fao-muted); font-size: 0.83rem; }

/* La raison classée d'un bordereau manquant : c'est ce que le gérant vient chercher. */
.fao-raison { margin: 0 0 0.7rem; padding: 0.4rem 0.7rem; border-left: 3px solid var(--fao-accent); background: var(--fao-accent-soft); color: var(--fao-accent-ink); font-size: 0.82rem; font-weight: 600; border-radius: 0 0.35rem 0.35rem 0; }

/* Une pièce que le lecteur n'a pas su exploiter : elle porte sa raison, en orange. */
.fao-piece-ko td { color: var(--fao-accent-ink); }

/* Les lots : la table, le sélecteur de décision, et un bordereau par lot. */
.fao-decision { font-size: 0.78rem; padding: 0.15rem 0.4rem; border: 1px solid var(--fao-line); border-radius: 0.4rem; background: transparent; color: inherit; max-width: 9rem; }
.fao-lot { margin-top: 0.8rem; border: 1px solid var(--fao-line); border-radius: 0.5rem; padding: 0.5rem 0.7rem; }
.fao-lot-t { cursor: pointer; font-size: 0.78rem; font-weight: 700; letter-spacing: 0.03em; color: var(--fao-muted); text-transform: uppercase; }
.fao-lot-n { font-weight: 500; text-transform: none; letter-spacing: 0; }
.fao-lot[open] .fao-lot-t { margin-bottom: 0.5rem; }

/* Les spécifications d'un article de bon de commande : repliées, dépliables. */
.fao-specs { margin-top: 0.2rem; }
.fao-specs summary { cursor: pointer; font-size: 0.7rem; color: var(--fao-muted); }
.fao-specs div { margin-top: 0.25rem; font-size: 0.78rem; color: var(--fao-muted); white-space: pre-wrap; }

@media (max-width: 767px) {
    .fao-grille { grid-template-columns: 1fr 1fr; }
    .fao-champ:nth-child(4n) { border-right: 1px solid var(--fao-line); }
    .fao-champ:nth-child(2n) { border-right: 0; }
    .fao-champ:nth-last-child(-n+4) { border-bottom: 1px solid var(--fao-line); }
    .fao-champ:nth-last-child(-n+2) { border-bottom: 0; }
    .fao-deux { grid-template-columns: 1fr; }
    .fao-compte { margin-left: 0; text-align: left; }
    .fao-res-grille { grid-template-columns: 1fr; }
}

/* --- 12. v4.22.0 §B — LA LISTE D'AO EN CARTES ÉPURÉES (maquette validée par le gérant) -------
 *
 * L'HISTOIRE EN DEUX TEMPS. La v4.18.0 §A a retiré aux trois listes d'AO le repli en cartes de
 * Filament : plus d'AO par écran, l'objet en entier, aucun défilement latéral. C'était la bonne
 * réponse à la bonne question. Devant l'écran obtenu, le gérant en a posé une autre : « moche,
 * pas pro ». Il a raison, et le défaut n'est pas la densité — c'est l'absence de HIÉRARCHIE.
 * Douze mentions de même corps, de même poids, chacune criant aussi fort que l'objet du marché.
 *
 * CE QUE LA REFONTE POSE, ET C'EST LA MAQUETTE. Une carte calme par AO, du blanc autour, une
 * seule pastille — celle de l'échéance —, et trois lignes qui se lisent dans l'ordre où l'on
 * décide : les repères, l'objet, le pied. Ce qui en sort (famille, source · type · prix, mise en
 * ligne, ancienneté, concurrence, et la grappe de pastilles de chaque liste) vit sur la FICHE, à
 * un doigt. Déplacement, jamais amputation : les colonnes restent déclarées côté PHP et portent
 * toujours le tri, la recherche et les résumés.
 *
 * AÉRÉ N'EST PAS L'INVERSE DE COMPACT. Le gérant veut du blanc ET cinq AO par écran. Les deux
 * tiennent parce que la carte ne porte plus que ce qui sert à trier. Mesuré à 375 px sur la
 * veille : la carte fait 108,8 px (objet d'une ligne) à 129,8 px (objet de deux), et la ligne
 * entière 146,8 à 167,8 px — les 38 px d'écart sont la rangée d'actions de Filament, que la
 * maquette ne montrait pas et qu'on garde. Soit 4,86 AO par écran de 800 px.
 *
 * Les règles ci-dessous ne visent que les lignes portant `.ao-ligne`, posée par les trois tables
 * — aucune autre liste du socle n'est touchée. Le mode sombre est traité partout où une couleur
 * est posée : Filament pose `.dark` sur la racine, et une carte blanche y ferait une lampe.
 */

:root {
    /* Les repères de la carte épurée. Chaque valeur vient de la maquette validée. */
    --ep-fond: #fbfbfa;
    --ep-carte: #ffffff;
    --ep-bord: #eeedea;
    --ep-encre: #1f1e1c;
    --ep-encre-2: #6b6863;
    /* v4.22.1 §C — Les deux gris du texte secondaire sont FONCÉS en thème clair : la maquette les
       donnait à 3,62 : 1 (la ligne de méta et la mention d'état) et 2,94 : 1 (la référence), sous
       le seuil AA. Ils passent à 4,86 : 1 et 4,59 : 1 sur la carte blanche, en gardant l'échelle
       d'avant — encre (16,2) > acheteur (5,55) > méta (4,86) > référence (4,59). Le mode sombre
       n'est pas touché : il était déjà à 6,13 et 5,08 : 1. */
    --ep-faible: #757168;
    --ep-tres-faible: #79756c;
    --ep-point: #d8d5cf;
    --ep-proche: #b54a3a;
    --ep-moyen: #b45309;
    /* v4.23.0 §C — Le dernier gris pâle de la carte. La pastille d'échéance « lointain » était
       restée à 3,62 : 1 sur la carte blanche, sous AA : la seule des trois échéances à ne pas
       être lisible. Elle passe à 4,73 : 1 sur la carte (#ffffff) et 4,57 : 1 sur le fond de page
       (#fbfbfa), et garde son rang — c'est toujours la plus discrète des trois : proche 5,24,
       moyen 5,02, lointain 4,73. Le mode sombre n'est pas touché, il était déjà bon. */
    --ep-lointain: #777369;
    --ep-etoile: #d9a441;
    --ep-etoile-eteinte: #cfcbc4;
    --ep-vu: #b7b3ac;
    /* v4.22.1 §B — Le vu ALLUMÉ est vert, comme avant la refonte. C'est le vert « entrée » de
       cette même palette, repris tel quel : 4,89 : 1 sur la carte blanche. `--ep-vu` (gris) reste
       le vu ÉTEINT et l'encre des boutons d'action de la ligne. */
    --ep-vu-actif: #3f7d5b;
    --ep-entree-fond: #eaf3ee;
    --ep-entree-encre: #3f7d5b;
    --ep-sortie-fond: #f6ecea;
    --ep-sortie-encre: #b54a3a;
    --ep-attente: #b4863a;
    --ep-survol: rgba(0, 0, 0, 0.05);

    /* Les anciennes variables du bloc restent : le bloc dense générique les lit encore, et la
       barre d'actions de la ligne aussi. Elles ne sont plus la palette de la carte. */
    --ao-ligne: rgba(0, 0, 0, 0.07);
    --ao-faible: #6b7280;
    --ao-fond-vu: rgba(0, 0, 0, 0.015);
    --ao-fond-survol: rgba(0, 0, 0, 0.06);
    --ao-danger: #dc2626;
    --ao-warning: #b45309;
    --ao-success: #15803d;
    --ao-gray: #6b7280;
    --ao-info: #1d4ed8;
    --ao-primary: #4338ca;
}

/*
 * LE MODE SOMBRE N'EST PAS UNE INVERSION : c'est une seconde palette, mesurée.
 *
 * Chaque encre y est contrôlée sur le fond de la carte sombre (#1d2026, luminance relative
 * 0,0143) : l'encre principale 13,2 : 1, l'acheteur 7,7 : 1, la méta 6,2 : 1, la référence
 * 5,1 : 1, le délai proche 6,9 : 1, le délai moyen 7,5 : 1. Toutes au-dessus de 4,5 : 1.
 * Les deux fonds de pastille de sens (§16) portent leur encre à 6,8 et 6,0 : 1.
 */
.dark {
    --ep-fond: #16181c;
    --ep-carte: #1d2026;
    --ep-bord: #2c3038;
    --ep-encre: #eceae6;
    --ep-encre-2: #bdb8af;
    --ep-faible: #a39e95;
    --ep-tres-faible: #948f87;
    --ep-point: #3a3e46;
    --ep-proche: #f0907f;
    --ep-moyen: #e2a356;
    --ep-lointain: #a39e95;
    --ep-etoile: #e8b84e;
    --ep-etoile-eteinte: #7a756e;
    --ep-vu: #8e8981;
    /* Une nuance plus claire que le vert du jour : 5,46 : 1 sur la carte sombre (#1d2026). */
    --ep-vu-actif: #5fa37d;
    --ep-entree-fond: #1e3329;
    --ep-entree-encre: #7cc79c;
    --ep-sortie-fond: #3a2622;
    --ep-sortie-encre: #f0907f;
    --ep-attente: #d9a75c;
    --ep-survol: rgba(255, 255, 255, 0.06);

    --ao-ligne: rgba(255, 255, 255, 0.09);
    --ao-faible: #9ca3af;
    --ao-fond-vu: rgba(255, 255, 255, 0.02);
    --ao-fond-survol: rgba(255, 255, 255, 0.10);
    --ao-danger: #f87171;
    --ao-warning: #fbbf24;
    --ao-success: #4ade80;
    --ao-gray: #9ca3af;
    --ao-info: #93c5fd;
    --ao-primary: #a5b4fc;
}

/* LA CARTE, C'EST LA LIGNE ELLE-MÊME — et non un bloc posé dedans.
 *
 * Filament rend déjà chaque ligne en carte (fond blanc, anneau, rayon, ombre). La v4.18.0 lui
 * ôtait tout cela pour en faire un trait de liste ; ici on la reprend telle quelle et on la
 * réaccorde. L'intérêt n'est pas théorique : la BARRE D'ACTIONS de la ligne (écarter, Drive,
 * Portail, menu) est un frère du lien de la fiche, à l'intérieur de la ligne. Faire la carte
 * ailleurs l'aurait laissée dehors, flottant sous un bord arrondi.
 *
 * `box-shadow: none` n'est pas décoratif : l'anneau de Filament EST une ombre
 * (`--tw-ring-shadow`), et la bordure d'un pixel de la maquette le remplace. */
/* ⚠️ `min-width: 0` SUR TOUTE LA CHAÎNE, ET CE N'EST PAS UNE PRÉCAUTION.
 *
 * `.fi-ta-content` est une GRILLE et la ligne en est un élément : sa taille minimale automatique
 * vaut le max-content de son contenu. L'acheteur étant coupé à l'ellipse (donc `nowrap`), ce
 * max-content est le nom entier de l'organisme — mesuré sans ces lignes, à 375 px : la ligne
 * faisait 630 px, et l'`overflow-x: clip` de `.fi-layout` la retaillait SANS barre de défilement
 * pour aller chercher la moitié droite. C'est le même piège que la v4.21.0 §B avait rencontré, à
 * l'autre bout de la chaîne : il se désamorce en autorisant chaque maillon à rétrécir. */
.fi-ta-record.ao-ligne,
.fi-ta-record.ao-ligne .fi-ta-record-content-ctn,
.fi-ta-record.ao-ligne .fi-ta-record-content-ctn > *,
.ao-ligne .ao-bloc {
    min-width: 0;
}

.fi-ta-record.ao-ligne {
    background-color: var(--ep-carte);
    border: 1px solid var(--ep-bord);
    border-radius: 14px;
    box-shadow: none;
    margin: 6px 12px;
    align-items: stretch;
}

/* La gouttière de la carte est portée par la carte, pas par la ligne de Filament : le pied doit
   pouvoir caler ses boutons de 40 px contre le bord intérieur sans laisser un trou. */
.fi-ta-record.ao-ligne .fi-ta-record-content-ctn {
    padding-block: 0 4px;
    row-gap: 0;
}

.ao-ligne .ao-bloc {
    display: flex;
    flex-direction: column;
    gap: 8px;
    /* Pas de gouttière basse : les deux boutons du triage portent la leur — 40 px de cible pour
       17 px d'icône, soit 11 px de blanc sous elle. En ajouter serait la payer deux fois, et
       chaque pixel se paie ici cinq fois par écran. */
    padding: 15px 16px 0;
    color: var(--ep-encre);
    line-height: 1.4;
}

/* LA CASE À COCHER EST DÉJÀ UNE GOUTTIÈRE. Quand la table a des actions de lot, Filament pose la
   case EN TÊTE de la ligne, dans le flux : 16 px de case et deux marges de 12. Y ajouter les
   16 px de gouttière de la carte, c'est payer deux fois le même blanc — et, à 375 px, retirer
   douze pixels au nom de l'acheteur et à l'objet. La carte ne garde donc sa gouttière gauche
   entière que là où il n'y a pas de case. */
.fi-ta-record.ao-ligne.fi-ta-record-with-content-prefix .ao-bloc,
.fi-ta-record.ao-ligne.fi-ta-record-with-content-prefix .fi-ta-actions {
    padding-inline-start: 4px;
}

/* --- Ligne 1 : les repères ------------------------------------------------------------------ */

.ao-ligne .ao-n1 {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.ao-ligne .ao-ref {
    flex: 0 0 auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11.5px;
    color: var(--ep-tres-faible);
    white-space: nowrap;
}

/* Le point qui sépare la référence de l'acheteur. Il est un ÉLÉMENT et non un `::before` parce
   qu'il doit disparaître avec sa rangée si jamais elle se recompose — et parce qu'un rond de
   3 px se centre plus sûrement qu'un caractère de ponctuation. */
.ao-ligne .ao-point {
    flex: 0 0 auto;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background-color: var(--ep-point);
}

/* L'acheteur prend la place restante, coupé net. C'est l'organisme qui publie : le second
   critère de triage après l'objet, et un nom d'organisme marocain est long. */
.ao-ligne .ao-acheteur {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 12px;
    color: var(--ep-encre-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* LA SEULE PASTILLE DE LA CARTE : un point coloré, et le délai. La date limite, elle, est
   l'infobulle de cette pastille — ce qu'on lit cinquante fois en triant est le nombre de jours,
   jamais le quantième. */
.ao-ligne .ao-ech {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-inline-start: auto;
    font-size: 12px;
    font-weight: 600;
    color: var(--ep-lointain);
    white-space: nowrap;
}

.ao-ligne .ao-ech-point {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background-color: currentcolor;
}

.ao-ligne .ao-ech--danger { color: var(--ep-proche); }
.ao-ligne .ao-ech--warning { color: var(--ep-moyen); }
.ao-ligne .ao-ech--gray { color: var(--ep-lointain); }

/* --- L'objet : ce qu'on lit ------------------------------------------------------------------ */

.ao-ligne .ao-objet {
    min-width: 0;
    font-size: 15px;
    font-weight: 550;
    line-height: 1.4;
    color: var(--ep-encre);
    /* Deux lignes, coupées net. C'est le principal poste de hauteur d'une carte, et la fiche
       montre l'objet en entier. Le préfixe `-webkit-` n'est pas une survivance : `line-clamp`
       sans préfixe n'est pas encore servi partout, et c'est Safari iOS qu'on vise. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Un AO déjà vu passe au second plan — il ne quitte pas la liste pour autant. Avec l'icône du
   bouton, qui passe du cercle vide au cercle plein, c'est la SEULE marque du « vu » sur la carte
   depuis la refonte : le petit tag qui doublait l'icône a disparu avec le reste du bruit.

   ⚠️ PAS d'`opacity` SUR LA CARTE, et c'est délibéré : elle fanerait aussi les deux boutons du
   triage — dont celui qu'on vient d'allumer. On grise ce qui se LIT, jamais ce qui se clique.
   L'encre suit la bascule optimiste : la classe est posée par Alpine à l'instant du clic. */
.ao-ligne .ao-bloc--vu .ao-objet {
    color: var(--ep-faible);
    font-weight: 500;
}

.ao-ligne .ao-bloc--vu .ao-montant {
    color: var(--ep-encre-2);
    font-weight: 600;
}

/* --- Ligne du bas : le montant, l'état, les deux gestes -------------------------------------- */

/* LE PIED EST UNE RANGÉE, ET LES MENTIONS UNE BOÎTE DEDANS.
 *
 * Mises au même niveau que les deux boutons, elles les poussaient sur une rangée à elles dès
 * qu'une liste en ajoutait deux : mesuré sur les soumissionnés, quatre rangées et une carte de
 * 207 px là où la veille en faisait 163. Dans leur propre boîte, elles passent à la ligne entre
 * elles pendant que les boutons restent calés à droite, centrés sur la rangée. La carte respire
 * autant, et les trois listes gardent la même silhouette. */
.ao-ligne .ao-n2 {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    font-size: 12px;
    color: var(--ep-faible);
}

.ao-ligne .ao-mentions {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 10px;
}

.ao-ligne .ao-montant {
    flex: 0 0 auto;
    font-size: 13px;
    font-weight: 650;
    color: var(--ep-encre);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* L'UNIQUE mention d'état : « Bordereau · 24 postes », « À lire » (pas encore lu) ou « Sans
   bordereau » (lu, sans tableau — en orange, par `.ao-item--warning` ci-dessous). La raison classée
   du compte rendu reste sur la fiche, où l'on peut en faire quelque chose. */
.ao-ligne .ao-statut,
.ao-ligne .ao-n2 .ao-item {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Ce que la liste ajoute, rendu en TEXTE et non en pastille : un ton ne teinte plus qu'une
   encre. C'est précisément la « soupe de badges » que la refonte retire. */
.ao-ligne .ao-n2 .ao-item--danger { color: var(--ep-proche); }
.ao-ligne .ao-n2 .ao-item--warning { color: var(--ep-moyen); }
.ao-ligne .ao-n2 .ao-item--success { color: var(--ep-entree-encre); }
.ao-ligne .ao-n2 .ao-item--info,
.ao-ligne .ao-n2 .ao-item--primary,
.ao-ligne .ao-n2 .ao-item--gray { color: var(--ep-faible); }

.ao-ligne .ao-k {
    opacity: 0.75;
}

/* Les deux gestes du triage, calés à droite du pied : la boîte des mentions est l'espace
   flexible de la maquette — elle prend tout ce qui reste, eux gardent leur place au bord. */
.ao-ligne .ao-bloc-triage {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0;
}

/* Les colonnes Filament rendues DANS la carte (les deux boutons de triage) perdent leurs marges
   de cellule. `flex: 0 0 auto` et `width: auto` ne sont pas décoratifs : Filament pose
   `width: 100%` sur `.fi-ta-col`, et un élément large de 100 % occuperait à lui seul toute une
   rangée du pied. */
.ao-ligne .ao-n2 .fi-ta-col,
.ao-ligne .ao-bloc-triage .fi-ta-col {
    padding: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    flex: 0 0 auto;
    width: auto;
    max-width: 100%;
}

/* v4.20.1 §C — LES DEUX BOUTONS DU TRIAGE, RENDUS PAR NOUS.
 *
 * Ils ne sont plus des `IconColumn` à `action()` (un aller-retour avant que l'icône change) mais
 * une vue à bascule optimiste : d'où leur habillage ici, et non plus par Filament.
 *
 * v4.21.0 — LA CIBLE TACTILE FAIT 2,5 REM (40 px), AUX DEUX LARGEURS. Au doigt, une cible de
 * 28 px se manque une fois sur trois, et un triage qui ouvre la fiche au lieu de poser l'étoile
 * fait perdre deux gestes. C'est la CIBLE qui est large, pas l'icône : les 12 px gagnés sont de
 * la gouttière cliquable, invisible tant qu'on ne la touche pas.
 *
 * v4.22.0 §B — Les deux couleurs de l'étoile viennent de la maquette. Le « vu », lui, garde la
 * même encre allumé ou éteint : ce qui change est son DESSIN (cercle plein contre cercle vide)
 * et, surtout, la carte entière qui passe au second plan. Une troisième couleur au pied d'une
 * carte qu'on veut calme n'aurait rien dit de plus. */
.ao-ligne .ao-triage {
    display: inline-flex;
    align-items: center;
}

.ao-ligne .ao-triage-bouton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: 0;
    border-radius: 0.5rem;
    background: transparent;
    color: var(--ep-vu);
    cursor: pointer;
    /* L'icône bascule à l'instant du clic : la transition porte la couleur, jamais l'attente. */
    transition: color 120ms ease-out, background-color 120ms ease-out;
}

.ao-ligne .ao-triage--fige .ao-triage-bouton {
    cursor: default;
}

.ao-ligne .ao-triage-icone {
    width: 1.05rem;
    height: 1.05rem;
}

.ao-ligne .ao-triage--etoile .ao-triage-bouton {
    color: var(--ep-etoile-eteinte);
}

.ao-ligne .ao-triage--etoile.ao-triage--actif .ao-triage-bouton {
    color: var(--ep-etoile);
}

/* v4.22.1 §B — LE VU ALLUMÉ REDEVIENT VERT. La v4.22.0 lui laissait la même encre grise allumé ou
   éteint ; à l'usage, le gérant ne voyait plus d'un coup d'œil ce qu'il venait de marquer — le
   dessin de l'icône (cercle plein contre cercle vide) ne porte pas seul à la vitesse du triage.
   La couleur ne touche QUE la pastille : la carte vue, elle, reste dé-emphasée (`--ep-faible`),
   et le vu éteint garde son gris. */
.ao-ligne .ao-triage--vu.ao-triage--actif .ao-triage-bouton {
    color: var(--ep-vu-actif);
}

/* Au doigt comme à la souris, le bouton dit qu'il est un bouton. */
.ao-ligne .ao-triage-bouton:hover {
    background-color: var(--ep-survol);
}

.ao-ligne .ao-triage-bouton:focus-visible {
    outline: 2px solid var(--ao-info);
    outline-offset: 1px;
}

/* Le temps qu'Alpine démarre, l'icône que l'état ne montre pas reste cachée : sans cette règle,
   les deux se voient au chargement et la liste clignote. */
.ao-ligne [x-cloak] {
    display: none !important;
}

/* La barre d'actions de la ligne (écarter, liens Drive et Portail, menu) : la maquette ne la
   montre pas — elle n'en avait pas —, mais elle reste, et elle vit DANS la carte, sous le pied,
   discrète. Compacte, et jamais rognée : c'est la règle de tenue de cette feuille. */
.fi-ta-record.ao-ligne .fi-ta-actions {
    gap: 0.1rem;
    padding-inline: 12px;
}

.fi-ta-record.ao-ligne .fi-ta-actions .fi-icon-btn {
    color: var(--ep-vu);
}

/* La liste n'a plus d'en-tête de table : le sélecteur de tri de Filament le remplace, et il doit
   rester visible et lisible au-dessus des cartes. */
.fi-ta-content-ctn .fi-ta-sorting-settings {
    font-size: var(--socle-dense-texte);
}

/* --- 13. v4.20.2 — LE DÉFILEMENT DES LISTES D'AO REVIENT À LA PAGE --------------------------
 *
 * Le gérant : « je n'arrive pas à défiler de haut en bas la liste de veille ». La v4.20.1 §B
 * voulait fluidifier ce geste ; elle l'a figé. Voici pourquoi, et pourquoi on ne le refait pas.
 *
 * `.fi-ta-ctn` porte `overflow-x: auto` (§2 de cette feuille), nécessaire aux AUTRES tables qui
 * débordent en largeur. Règle CSS peu connue : dès qu'UN seul axe d'`overflow` vaut `auto` ou
 * `scroll`, l'autre axe — laissé `visible` — est calculé en `auto` lui aussi. `.fi-ta-ctn` est
 * donc, de fait, un conteneur qui défile AUSSI en vertical. La v4.20.1 §B y avait ajouté
 * `touch-action: pan-y` + `overscroll-behavior-y: contain` : le premier verrouille le geste à
 * l'intérieur, le second l'empêche de se chaîner à la page. Résultat : le doigt (et la molette)
 * butaient dans une zone interne quasi immobile au lieu de faire défiler l'écran.
 *
 * Le correctif ne contraint plus le geste : il retire au conteneur son caractère de « scroller ».
 * Depuis les blocs à deux niveaux (v4.18.0 §A), une liste d'AO n'a PLUS RIEN à faire défiler en
 * largeur — l'objet passe à la ligne, aucune cellule ne dépasse l'écran. `overflow: visible` sur
 * les DEUX axes ⇒ ni scroll horizontal, ni scroll vertical parasite ⇒ c'est la PAGE qui défile,
 * naturellement, au doigt comme à la molette. Rien n'est coupé : l'ellipse de la référence et des
 * pastilles (règle juste en dessous) reste le garde-fou anti-débordement horizontal.
 *
 * ⚠️ Ne jamais réintroduire `touch-action` / `overscroll-behavior` ici : c'est le duo fautif.
 * ⚠️ La portée est le cœur de la règle : `:has(.ao-ligne)` ne vise QUE les conteneurs qui portent
 * des blocs d'AO. La règle de base `.fi-ta-ctn { overflow-x: auto; }` (§2) reste intacte, donc les
 * autres tables du socle (écritures, salaires, plis…) gardent leur défilement horizontal, dont
 * elles ont besoin — les priver du geste latéral leur amputerait des colonnes.
 *
 * ⚠️ v4.22.0 §A — CETTE RÈGLE N'EST PAS DEVENUE REDONDANTE, et on la garde pour cela. Le §14
 * neutralise l'`overflow` de TOUTES les tables, mais seulement en dessous de 768 px. Celle-ci
 * vaut à toutes les largeurs, et c'est ce qu'il faut : depuis les blocs à deux niveaux
 * (v4.18.0 §A), puis la carte épurée (v4.22.0 §B), une liste d'AO n'a plus rien à faire défiler
 * en largeur — même au bureau. Lui laisser un axe en `auto` lui rendrait, par la règle ci-dessus,
 * un défilement vertical interne dont elle n'a que faire.
 *
 * ⚠️ v4.22.1 §A — ET ELLE NE SUFFISAIT PAS SEULE : `.fi-ta-content-ctn`, le conteneur PARENT du
 * contexte de positionnement collant, restait un scroller au bureau. Il est neutralisé juste en
 * dessous, aux mêmes conditions et avec la même portée `:has(.ao-ligne)`.
 */
.fi-ta-ctn:has(.ao-ligne) {
    overflow: visible;
    /* v4.22.0 §B — Et le fond sur lequel les cartes se détachent : une carte blanche sur un
       conteneur blanc n'est pas une carte, c'est une bordure qui flotte. */
    background-color: var(--ep-fond);
}

/* v4.22.1 §A — LE PARENT AUSSI, ET À TOUTES LES LARGEURS.
 *
 * `.fi-ta-ctn` n'est pas le seul conteneur de la table : `.fi-ta-content-ctn` (celui qui porte
 * `.fi-fixed-positioning-context`) calcule `overflow-x: auto` ET `overflow-y: auto`, posés par
 * Filament sur TOUTES les tables. Le §14 ne le neutralise qu'en dessous de 768 px — au bureau, il
 * restait donc un conteneur à défilement POSÉ SUR les cartes. Sur un trackpad, un tel conteneur
 * capte le glissement vertical et ne le rend pas à la page : c'est le cousin bureau du blocage
 * iOS, confirmé par le gérant sur la Veille ET les Clôturés (les deux portent `.ao-ligne`).
 *
 * Une liste d'AO n'a JAMAIS besoin que ce conteneur défile : les blocs passent à la ligne, aucune
 * colonne ne déborde, et la liste pagine. On le neutralise donc à toutes les largeurs, exactement
 * comme le parent juste au-dessus.
 *
 * ⚠️ La portée est tout : `:has(.ao-ligne)` ne vise QUE les listes d'AO. Les tables à colonnes
 * (Opérations, Factures, RH…) gardent leur `.fi-ta-content-ctn` en `overflow: auto` au bureau —
 * elles ont besoin du geste latéral, et le priver leur amputerait des colonnes.
 * ⚠️ Toujours pas de `touch-action` ni d'`overscroll-behavior` : c'est le duo que la v4.20.2 a
 * retiré parce qu'il figeait le geste au lieu de le libérer. */
.fi-ta-content-ctn:has(.ao-ligne) {
    overflow: visible;
}

/* L'autre moitié de la règle : si une seule chose du bloc forçait une largeur plus grande que
   l'écran, le débordement reviendrait — et avec lui le geste horizontal qu'on vient d'ôter. Les
   deux seuls éléments qui refusent le passage à la ligne (la référence en chasse fixe, les
   pastilles rendues par Filament) sont donc bornés à la largeur disponible, ellipse comprise. */
.ao-ligne .ao-ref,
.ao-ligne .ao-n2 .fi-badge,
.ao-ligne .ao-n2 .fi-ta-text-item {
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}


/* --- 14. v4.22.0 §A — LE DÉFILEMENT MOBILE : PLUS AUCUN CONTENEUR DE TABLE NE CAPTE LE DOIGT --
 *
 * CE QUI EST PROUVÉ, ET CE QUI NE L'EST PAS. Le blocage du défilement est propre à Safari iOS :
 * il ne se reproduit dans AUCUN navigateur de bureau — Chrome mesure la page comme défilant
 * normalement, et c'est ce qui a fait échouer trois correctifs d'affilée. Sur l'écran réel, le
 * gérant est formel : le doigt se coince SUR LE TABLEAU, pas ailleurs sur la page. Donc un
 * conteneur du tableau capte le geste.
 *
 * LES DEUX CONTENEURS EN CAUSE, relevés au navigateur sur la v4.21.0 à 375 px :
 *
 *  - `.fi-ta-content-ctn` (celui qui porte le contexte de positionnement collant) calcule
 *    `overflow-x: auto` ET `overflow-y: auto`. Filament le pose sur TOUTES les tables, et il
 *    n'avait jamais été neutralisé nulle part ;
 *  - `.fi-ta-ctn` calcule `overflow-x: auto` (§2 de cette feuille). Il n'était neutralisé que là
 *    où il porte des cartes d'AO (§13) — donc PAS sur Opérations, PAS sur les trente-cinq autres.
 *
 * Règle CSS peu connue, et c'est le nœud : dès qu'UN seul axe d'`overflow` vaut `auto` ou
 * `scroll`, l'autre — laissé `visible` — est calculé `auto` lui aussi. Sur iOS, un conteneur à
 * `overflow: auto` capte le glissement vertical MÊME QUAND RIEN NE DÉBORDE, et ne le rend pas à
 * la page. Or, en dessous de `md`, Filament empile les colonnes en cartes : AUCUNE table n'a
 * besoin d'un défilement interne à cette largeur — c'est la page qui doit défiler.
 *
 * D'où la règle, GLOBALE et sans `:has()` : elle libère le geste sur les trente-sept tables du
 * socle, pas seulement sur les listes d'AO. Le bureau, lui, ne change pas : la règle de base
 * `.fi-ta-ctn { overflow-x: auto }` (§2) reste en vigueur au-dessus de 768 px, là où une table
 * large a vraiment besoin de son geste latéral.
 *
 * ⚠️ v4.22.1 §A — CETTE RÈGLE RESTE, ET ELLE RESTE GLOBALE : elle couvre les trente-sept tables
 * sous 768 px. Ce qu'elle ne couvrait pas, c'est le BUREAU, où `.fi-ta-content-ctn` demeurait un
 * conteneur à défilement — assez pour happer le geste au trackpad posé sur une liste d'AO. Le §13
 * neutralise désormais ce parent à toutes les largeurs, mais pour les SEULES listes d'AO
 * (`:has(.ao-ligne)`) : les tables à colonnes gardent leur défilement horizontal au bureau.
 *
 * ⚠️ HONNÊTETÉ. Ce remède est le standard pour ce comportement d'iOS, mais il ne se vérifie sur
 * AUCUN navigateur de bureau : ce qui est prouvé ici, c'est que plus aucun conteneur de table
 * n'a d'`overflow` interne sous 768 px. Que le doigt glisse, seul un iPhone réel le dira.
 *
 * ⚠️ On ne réintroduit JAMAIS `touch-action` ni `overscroll-behavior` : c'est le duo que la
 * v4.20.2 a retiré parce qu'il figeait le geste au lieu de le libérer.
 */
@media (max-width: 767px) {
    .fi-ta-ctn,
    .fi-ta-content-ctn {
        overflow: visible;
    }

    /* Les mentions que la LISTE a marquées secondaires quittent l'écran du téléphone — jamais le
       document, jamais la fiche, jamais le bureau. C'est à la liste d'en juger : la caution
       d'une soumission n'est pas une information de triage, l'attributaire d'un AO clôturé l'est,
       et la carte, partagée par les trois listes, ne peut pas en décider à leur place. */
    .ao-ligne .ao-n2 .ao-sec,
    .bloc-dense .bd-meta .bd-sec {
        display: none;
    }

    /* Au téléphone, la carte se resserre de deux pixels sur chaque bord : à 375 px, chaque pixel
       rendu au corps est un pixel que l'objet ne paie pas en troisième ligne coupée. */
    .fi-ta-record.ao-ligne {
        margin-inline: 8px;
    }
}

/* --- 15. v4.21.0 §A — LE DÉFILEMENT MOBILE : c'est le POIDS de la page, pas son CSS ----------
 *
 * CE QUE CE N'EST PAS, ET QU'IL NE FAUT PAS RE-CORRIGER. Mesuré sur la production v4.20.2, à
 * 375 px : aucun élément ne contraint `touch-action` ; la barre latérale est hors écran ;
 * `elementFromPoint` au milieu de la liste renvoie bien l'objet de l'AO, donc rien ne s'interpose ;
 * `.fi-ta-ctn:has(.ao-ligne)` calcule bien `overflow: visible` ; c'est bien le document qui défile.
 * Rien ne capte le geste. Les v4.20.1 §B et v4.20.2 ont traité un symptôme réel — le bureau —
 * mais pas la cause du téléphone.
 *
 * LA CAUSE, MESURÉE. Une veille de 25 AO faisait une page de 8 440 px, 4 177 nœuds et 179
 * composants Alpine ; et, sur les lignes d'AO SEULES, 600 éléments portaient une transition CSS
 * (`color, background-color, border-color, outline-color, text-decoration-color` — les utilitaires
 * `transition-colors` de Tailwind) et 125 une ombre portée. Sur iOS, poser le doigt applique les
 * états de survol et d'appui sous lui : ces centaines de transitions se déclenchent PENDANT le
 * glissement, et Safari doit repeindre. D'où l'accrochage — absent au bureau, où la souris laisse
 * un état stable et où la machine est plus puissante.
 *
 * ⚠️ On n'ajoute AUCUNE règle `touch-action` ni `overscroll-behavior` : c'est le duo que la
 * v4.20.2 a retiré parce qu'il figeait le geste. La règle se tient au POIDS, à rien d'autre.
 */

/* Contexte TACTILE seulement — jamais le bureau, où la transition est un agrément qui ne coûte
   rien. `hover: none` et `pointer: coarse` ensemble : c'est le doigt, et le doigt seul. */
@media (hover: none) and (pointer: coarse) {
    .ao-ligne,
    .ao-ligne *,
    .bloc-dense,
    .bloc-dense *,
    /* Les deux boutons du triage portent leur transition en propre (v4.20.1 §C), et leur
       sélecteur est plus spécifique que l'universel ci-dessus : sans cette ligne, deux éléments
       par AO restaient en transition — mesuré, 20 sur une page de dix. Au doigt, la bascule
       optimiste n'a d'ailleurs rien à gagner à un fondu de 120 ms : elle doit être INSTANTANÉE. */
    .ao-ligne .ao-triage-bouton {
        transition-property: none;
    }

    /* Les ombres du BLOC — des anneaux de Tailwind, transparents dans ce thème : rien ne se voit
       partir, et chacun coûtait une couche de peinture par ligne. La barre d'actions de la ligne
       n'est pas touchée : le panneau déroulant du menu, lui, a besoin de son ombre pour flotter. */
    .ao-ligne .ao-bloc,
    .ao-ligne .ao-bloc *,
    .bloc-dense,
    .bloc-dense * {
        box-shadow: none;
    }
}

/* Ne plus peindre ce qui est hors écran. `auto` en tête de `contain-intrinsic-size` fait retenir
   au navigateur la DERNIÈRE hauteur rendue : un bloc déjà vu reprend sa taille exacte, et la
   barre de défilement ne saute pas. La valeur de repli, 115 px, est le CONTENU mesuré de la carte
   de la veille à 375 px après la refonte de la v4.22.0 §B (129,8 px de carte, moins ses 15 px de
   gouttière haute) — un chiffre relevé, pas un chiffre choisi.

   ⚠️ ET IL DOIT ÊTRE JUSTE, PAS SEULEMENT PLAUSIBLE. `.fi-ta-content` est une grille, et la
   hauteur qu'un bloc SAUTÉ annonce est celle que sa rangée prend pour de bon. Un repli de 125
   (la carte entière au lieu de son contenu) faisait donc des rangées de 178 px là où le contenu
   n'en demandait que 168 — dix pixels de vide par AO, et une carte de moins par écran. Le repli
   se relève quand la carte change : à contenu, `contain-intrinsic-size`.

   ⚠️ DEUX PORTÉES, ET CHACUNE A SA RAISON.

   La règle porte sur `.ao-bloc`, PAS sur `.ao-ligne` : `content-visibility` applique la
   containment de PEINTURE, et posée sur la ligne entière elle rognerait le panneau déroulant du
   menu d'actions, qui est positionné dans la ligne et déborde d'elle. Le bloc, lui, ne contient
   aucun calque flottant — et c'est lui qui porte les vingt-quatre éléments à peindre.

   Et elle ne vaut qu'en dessous de 768 px, là où le problème est. La hauteur du bloc n'est pas la
   même aux deux largeurs — 129,8 px au téléphone, 116 px au bureau : un repli unique ferait
   mentir l'estimation de hauteur de page de l'autre côté (mesuré au bureau : 1 879 px annoncés
   pour 1 603 réels tant qu'on n'a pas fait défiler). Le bureau n'a pas d'accrochage à corriger ;
   il n'a donc rien à gagner à une estimation fausse. */
@media (max-width: 767px) {
    @supports (content-visibility: auto) {
        .ao-ligne .ao-bloc {
            content-visibility: auto;
            contain-intrinsic-size: auto 115px;
        }
    }
}

/* À l'impression, rien n'est « hors écran » : le contenu sauté doit revenir. */
@media print {
    .ao-ligne .ao-bloc {
        content-visibility: visible;
    }
}

/* --- 16. v4.22.0 §C — LA LIGNE DENSE GÉNÉRIQUE, ÉPURÉE, ET LE FILET DES AUTRES TABLES --------
 *
 * LE CONSTAT DE LA v4.21.0, QUI TIENT TOUJOURS. Sur les 36 tables de cinq colonnes ou plus de
 * l'admin, aucune ne déclarait de `visibleFrom` : en dessous de 640 px, Filament les replie
 * toutes en cartes, une colonne par rangée, son libellé au-dessus de sa valeur. Mesuré à 375 px :
 * une ligne d'Opérations faisait 522 px — une opération par écran, exactement ce que le gérant
 * décrivait.
 *
 * DEUX RÉPONSES, ET ELLES NE SE REMPLACENT PAS :
 *
 *  1. le BLOC DENSE ({@see App\Filament\Support\Tables\BlocDense}) pour les tables converties —
 *     Opérations ouvre la marche. Il est une COLONNE, pas un composant de disposition : la table
 *     reste une table, le tableau du bureau ne bouge pas d'un pixel, et c'est `hiddenFrom('sm')`
 *     qui le montre au téléphone pendant que `visibleFrom('sm')` y cache les colonnes ;
 *  2. le FILET, plus bas, pour les trente-cinq autres. Il ne masque rien : il range la paire
 *     libellé / valeur SUR UNE MÊME RANGÉE au lieu de l'une sous l'autre.
 *
 * CE QUE LA v4.22.0 CHANGE. Le bloc à deux niveaux était lisible et n'était pas beau — même
 * reproche que pour la liste d'AO, même remède. La ligne tient désormais sur UNE rangée, et elle
 * se lit sans lire un seul chiffre : une pastille ronde porte le SENS à gauche (flèche qui
 * descend pour une entrée, flèche qui monte pour une sortie), le libellé et sa méta occupent le
 * centre, le montant et son état sont calés à droite.
 *
 * Le seuil de tout ce qui suit est 639 px et non 767 px, et ce n'est pas un détail : c'est à
 * 640 px (`sm`) que Filament replie la table et cache sa rangée d'en-têtes. Une règle qui
 * viserait 767 px s'appliquerait, entre 640 et 767, à une VRAIE table — elle y désalignerait les
 * cellules de leurs en-têtes.
 */

/* L'EN-TÊTE DU BLOC NE DOIT JAMAIS PARAÎTRE AU BUREAU. `hiddenFrom('sm')` pose bien
   `sm:fi-hidden` sur l'en-tête, et Filament a la règle qui va avec — mais il en a une autre, plus
   spécifique, qui remet `display: table-cell` à toutes les en-têtes d'une table repliable dès
   `sm`. Mesuré à 1 280 px sans cette ligne : une colonne « Opération » VIDE de 119 px s'ouvrait
   dans le tableau du bureau. Il faut donc être plus spécifique qu'elle — d'où la tête complète.
   En dessous de `sm`, Filament cache la rangée d'en-têtes entière : aucune requête média ici. */
.fi-ta-table.fi-ta-table-stacked-on-mobile > thead > tr > .fi-ta-header-cell.entete-bloc-dense {
    display: none;
}

/* La ligne : la pastille, le corps, le chiffre. Une seule rangée, alignée au centre. */
.bloc-dense {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    color: var(--ep-encre);
    line-height: 1.35;
}

/* LE ROND DE GAUCHE, CELUI QUI PORTE LE SENS. 34 px, rayon 9 : un carré très arrondi plutôt
   qu'un cercle — c'est ce que la maquette dessine, et cela distingue la pastille d'un avatar. */
.bloc-dense .bd-rond {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background-color: var(--ep-bord);
    color: var(--ep-faible);
    font-size: 13px;
    font-weight: 650;
}

.bloc-dense .bd-rond-icone {
    width: 17px;
    height: 17px;
}

.bloc-dense .bd-rond--success {
    background-color: var(--ep-entree-fond);
    color: var(--ep-entree-encre);
}

.bloc-dense .bd-rond--danger {
    background-color: var(--ep-sortie-fond);
    color: var(--ep-sortie-encre);
}

/* Le centre prend la place. `min-width: 0` n'est pas décoratif : sans lui, un libellé long fixe
   la largeur minimale de la rangée, elle remonte toute la chaîne, et la ligne déborde de
   l'écran — puis se fait retailler sans une barre pour aller la chercher. */
.bloc-dense .bd-corps {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.bloc-dense .bd-titre {
    min-width: 0;
    font-size: 14px;
    font-weight: 550;
    color: var(--ep-encre);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* La ligne de méta : discrète, sur une seule ligne, coupée net. Ce qui n'y tient pas est sur la
   fiche — une liste qu'on parcourt au pouce n'est pas un formulaire. */
.bloc-dense .bd-meta {
    min-width: 0;
    font-size: 11.5px;
    color: var(--ep-faible);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bloc-dense .bd-repere {
    font-variant-numeric: tabular-nums;
}

.bloc-dense .bd-k {
    opacity: 0.75;
}

/* Un séparateur entre deux entrées de la méta : sans lui, « Fournitures Banque principale
   PRJ-5YTXY7 » se lit comme une seule phrase. Il est posé en `::before` — donc hors du document,
   hors de la sélection et hors de ce qu'un lecteur d'écran annonce. */
.bloc-dense .bd-meta > * + *::before {
    content: '·';
    margin-inline: 0.15rem 0.3rem;
    opacity: 0.55;
}

.bloc-dense .bd-item--danger { color: var(--ep-proche); }
.bloc-dense .bd-item--warning { color: var(--ep-moyen); }
.bloc-dense .bd-item--success { color: var(--ep-entree-encre); }

/* Le chiffre à droite, et l'état sous lui. */
.bloc-dense .bd-droite {
    flex: 0 0 auto;
    text-align: end;
    white-space: nowrap;
    line-height: 1.25;
}

.bloc-dense .bd-valeur {
    display: block;
    font-size: 14px;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--ep-encre);
}

.bloc-dense .bd-valeur--success { color: var(--ep-entree-encre); }
.bloc-dense .bd-valeur--danger { color: var(--ep-sortie-encre); }
.bloc-dense .bd-valeur--warning { color: var(--ep-moyen); }
.bloc-dense .bd-valeur--gray { color: var(--ep-faible); }
.bloc-dense .bd-valeur--info,
.bloc-dense .bd-valeur--primary { color: var(--ep-encre); }

/* L'état : « Payé », « En attente ». Une mention, pas une pastille — la refonte retire les
   badges partout où une encre suffit. */
.bloc-dense .bd-etat {
    display: block;
    font-size: 11px;
    color: var(--ep-faible);
}

.bloc-dense .bd-etat--warning { color: var(--ep-attente); }
.bloc-dense .bd-etat--danger { color: var(--ep-proche); }
.bloc-dense .bd-etat--success,
.bloc-dense .bd-etat--gray,
.bloc-dense .bd-etat--info,
.bloc-dense .bd-etat--primary { color: var(--ep-faible); }

@media (max-width: 639px) {
    /* LA LIGNE EST UNE CARTE, comme celle d'un AO — et pour la même raison : sans fond ni
       bordure, une liste dense n'est qu'un mur de texte. C'est la RANGÉE de la table repliée qui
       la porte, puisque c'est elle qui contient le bloc ET, le cas échéant, la case à cocher et
       la barre d'actions de la ligne. */
    .fi-ta-ctn:has(.bloc-dense) {
        background-color: var(--ep-fond);
    }

    .fi-ta-table-stacked-on-mobile > tbody > tr:has(> .cellule-bloc-dense) {
        background-color: var(--ep-carte);
        border: 1px solid var(--ep-bord);
        border-radius: 12px;
        margin: 5px 12px;
        padding-block: 0;
    }

    /* La cellule du bloc n'a pas de libellé à montrer : le bloc EST la ligne. */
    .fi-ta-table-stacked-on-mobile > tbody > tr > .cellule-bloc-dense > .fi-ta-cell-label {
        display: none;
    }

    .fi-ta-table-stacked-on-mobile > tbody > tr > .cellule-bloc-dense {
        padding: 13px 15px;
    }

    /* LE FILET — les trente-cinq tables qu'on ne convertit pas. Le libellé et la valeur se
       rangent sur une même rangée, le libellé à gauche en petit, la valeur à droite : une paire
       passe de 66 px à environ 25. Rien n'est masqué, rien n'est déplacé dans le document :
       c'est la même cellule, rangée autrement.

       ⚠️ LES TROIS EXCLUSIONS SONT LA RÈGLE, PAS UN DÉTAIL :
        - la cellule de sélection n'est pas une paire libellé / valeur ;
        - la cellule d'un bloc dense non plus — et un `text-align: end` y jetterait tout le bloc
          contre le bord droit ;
        - et surtout, une cellule qu'une bascule responsive a CACHÉE (`sm:fi-visible` et ses
          variantes `md:`, `lg:`, `xl:`, `2xl:`) doit le rester. Filament la cache avec un
          sélecteur à deux classes ; poser ici un `display: flex` plus spécifique la RAMÈNERAIT à
          l'écran. Mesuré sur Opérations avant cette exclusion : les sept colonnes du bureau
          revenaient sous le bloc, et la ligne faisait 335 px au lieu de 130. */
    .fi-ta-table-stacked-on-mobile > tbody > tr {
        padding-block: 0.2rem;
    }

    .fi-ta-table-stacked-on-mobile > tbody > tr > .fi-ta-cell:not(.fi-ta-selection-cell):not(.cellule-bloc-dense):not([class*='fi-visible']) {
        display: flex;
        align-items: baseline;
        gap: 0.5rem;
        padding-block: 0.1rem;
    }

    .fi-ta-table-stacked-on-mobile > tbody > tr > .fi-ta-cell:not(.fi-ta-selection-cell):not(.cellule-bloc-dense):not([class*='fi-visible']) > .fi-ta-cell-label {
        flex: 0 0 auto;
        min-width: 7rem;
        padding-top: 0;
        font-size: 0.6875rem;
        line-height: 1.35;
        font-weight: 500;
        /* Une colonne alignée à droite (`alignEnd`) pose `text-align: end` sur toute la cellule,
           et le libellé, rangé dans sa boîte de 7 rem, s'y décalait vers la droite — « TTC »
           flottait au milieu de la ligne. Le libellé lit toujours à gauche. */
        text-align: start;
    }

    .fi-ta-table-stacked-on-mobile > tbody > tr > .fi-ta-cell:not(.fi-ta-selection-cell):not(.cellule-bloc-dense):not([class*='fi-visible']) > .fi-ta-cell-content {
        display: flex;
        flex: 1 1 auto;
        min-width: 0;
        justify-content: flex-end;
        text-align: end;
    }

    /* LA CASE À COCHER FLOTTE AU-DESSUS DE LA PREMIÈRE PAIRE. En empilé, Filament la sort du
       flux (`position: absolute`, en haut à droite). Tant que la valeur s'écrivait SOUS son
       libellé, sur toute la largeur, elle passait dans le vide ; rangée à droite, elle passe
       DESSOUS. La première paire lui laisse donc la place — et elle seule : une gouttière posée
       sur les huit paires coûterait 40 px de largeur à chaque ligne. */
    .fi-ta-table-stacked-on-mobile > tbody > tr > .fi-ta-selection-cell + .fi-ta-cell:not(.cellule-bloc-dense):not([class*='fi-visible']) {
        padding-inline-end: 2.5rem;
    }

    /* Même égard pour le bloc dense : sa rangée laisse la place à la case, à droite. */
    .fi-ta-table-stacked-on-mobile > tbody > tr:has(> .fi-ta-selection-cell) > .cellule-bloc-dense {
        padding-inline-end: 2.25rem;
    }

    /* La valeur elle-même : elle ne s'étale plus sur toute la largeur de la cellule. */
    .fi-ta-table-stacked-on-mobile > tbody > tr > .fi-ta-cell:not(.fi-ta-selection-cell):not(.cellule-bloc-dense):not([class*='fi-visible']) > .fi-ta-cell-content .fi-ta-col {
        justify-content: flex-end;
        width: auto;
    }
}

/*
 * ─── v4.23.0 §A — LE MENU RANGÉ : LES PARENTS SE REPLIENT ─────────────────────────────────────
 *
 * Trois entrées du menu ne mènent nulle part : « Analyses & états », « Congés », « Paie & primes ».
 * Elles regroupent. Filament rend un parent SANS URL avec ses enfants toujours déployés — ce qui
 * rendrait au menu les vingt-quatre lignes qu'on vient de lui retirer. On les replie ici.
 *
 * Ces règles ne s'arment QUE si `public/js/socle-menu.js` a été lu : c'est lui qui pose
 * `socle-menu-prete` sur la racine, avant l'analyse du corps. Sans lui — script bloqué,
 * JavaScript coupé — rien ne se replie et tous les écrans restent au menu. On ne rend jamais un
 * écran inatteignable par une feuille de style.
 *
 * Le cas « je suis DANS la section » est traité sans script : Filament pose lui-même
 * `fi-sidebar-item-has-active-child-items` sur le parent, côté serveur. Le menu arrive donc déjà
 * ouvert au bon endroit, sans clignotement.
 */

.fi-sidebar-item[data-socle-repli] > .fi-sidebar-item-btn {
    cursor: pointer;
}

/* Le chevron, à droite du libellé. Dessiné à la bordure : aucune image, aucune police d'icônes. */
.fi-sidebar-item[data-socle-repli] > .fi-sidebar-item-btn::after {
    content: '';
    flex: 0 0 auto;
    margin-inline-start: auto;
    width: 0.45rem;
    height: 0.45rem;
    border-inline-end: 1.5px solid currentColor;
    border-block-end: 1.5px solid currentColor;
    opacity: 0.5;
    transform: rotate(45deg);
    transition: transform 150ms ease;
}

html.socle-menu-prete .fi-sidebar-item[data-socle-repli] > .fi-sidebar-sub-group-items {
    display: none;
}

/* Ouvert parce qu'on y est (Filament, côté serveur) … */
html.socle-menu-prete .fi-sidebar-item[data-socle-repli].fi-sidebar-item-has-active-child-items > .fi-sidebar-sub-group-items,
/* … ou parce que ce navigateur l'a ouvert (socle-menu.js). */
html.socle-menu-prete .fi-sidebar-item[data-socle-repli].socle-deplie > .fi-sidebar-sub-group-items {
    display: block;
}

html.socle-menu-prete .fi-sidebar-item[data-socle-repli].fi-sidebar-item-has-active-child-items > .fi-sidebar-item-btn::after,
html.socle-menu-prete .fi-sidebar-item[data-socle-repli].socle-deplie > .fi-sidebar-item-btn::after {
    transform: rotate(-135deg);
}

/* Le refermer À LA MAIN gagne sur « j'y suis » : ces deux règles viennent après, à spécificité
   égale — c'est l'ordre qui tranche. Sans elles, un parent dont un enfant est ouvert ne pourrait
   plus se replier, et le clic ne ferait rien. */
html.socle-menu-prete .fi-sidebar-item[data-socle-repli].socle-replie > .fi-sidebar-sub-group-items {
    display: none;
}

html.socle-menu-prete .fi-sidebar-item[data-socle-repli].socle-replie > .fi-sidebar-item-btn::after {
    transform: rotate(45deg);
}

/*
 * ─── v4.23.0 §B — LA BARRE D'ONGLETS DU BAS, SUR MOBILE ───────────────────────────────────────
 *
 * Quatre destinations à un doigt, façon application. Elle n'existe QUE sous 768 px : au bureau le
 * menu latéral est là, permanent, et une barre en plus serait une barre de trop.
 *
 * Tenue :
 *  - `z-index: 29`, soit UN CRAN SOUS la barre latérale mobile et son voile (30, relevés dans la
 *    feuille de Filament). « Plus » ouvre le menu : il doit passer PAR-DESSUS la barre, sans quoi
 *    on ne verrait pas ce qu'on vient d'ouvrir ;
 *  - la zone tactile fait 44 px au moins — la recommandation d'Apple, et la taille d'un pouce ;
 *  - `env(safe-area-inset-bottom)` : sur un iPhone sans bouton, les derniers pixels du bas sont
 *    à la barre d'accueil du système, pas à nous ;
 *  - le contenu reçoit la hauteur de la barre en marge basse, sinon la fin d'une liste vit
 *    dessous et devient inatteignable ;
 *  - clair ET sombre, mesurés : l'encre inactive est à 4,7 : 1 sur le fond de la barre dans les
 *    deux thèmes, l'onglet actif prend la couleur primaire du panneau.
 */

.socle-onglets {
    display: none;
}

@media (max-width: 767px) {
    .socle-onglets {
        position: fixed;
        inset-inline: 0;
        bottom: 0;
        z-index: 29;
        display: flex;
        align-items: stretch;
        justify-content: space-around;
        gap: 0.125rem;
        padding: 0.25rem 0.25rem calc(0.25rem + env(safe-area-inset-bottom));
        background-color: var(--socle-onglets-fond);
        border-top: 1px solid var(--socle-onglets-bord);
        box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.06);
    }

    .socle-onglet {
        display: flex;
        flex: 1 1 0;
        min-width: 0;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 0.125rem;
        /* 44 px de zone tactile, marges comprises. */
        min-height: 2.75rem;
        padding: 0.25rem 0.125rem;
        border-radius: 0.5rem;
        background: none;
        border: 0;
        color: var(--socle-onglets-encre);
        text-decoration: none;
        font: inherit;
        cursor: pointer;
    }

    .socle-onglet-icone {
        width: 1.375rem;
        height: 1.375rem;
        flex: 0 0 auto;
    }

    .socle-onglet-libelle {
        font-size: 0.625rem;
        line-height: 1.1;
        font-weight: 500;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .socle-onglet-actif {
        color: var(--socle-onglets-actif);
        background-color: var(--socle-onglets-actif-fond);
    }

    /* La fin d'une liste ne vit pas sous la barre. */
    .fi-panel-admin .fi-main {
        padding-bottom: calc(3.75rem + env(safe-area-inset-bottom));
    }
}

:root {
    --socle-onglets-fond: #ffffff;
    --socle-onglets-bord: #e5e3df;
    /* 4,71 : 1 sur le blanc de la barre. */
    --socle-onglets-encre: #6f6b63;
    --socle-onglets-actif: var(--primary-600, #4338ca);
    --socle-onglets-actif-fond: rgba(0, 0, 0, 0.045);
}

.dark {
    --socle-onglets-fond: #16181c;
    --socle-onglets-bord: #2c3038;
    /* 4,72 : 1 sur le fond sombre de la barre. */
    --socle-onglets-encre: #979289;
    --socle-onglets-actif: var(--primary-400, #a5b4fc);
    --socle-onglets-actif-fond: rgba(255, 255, 255, 0.07);
}

/*
 * ─── v4.23.0 §A2 — LE MENU TIENT EN UN ÉCRAN ──────────────────────────────────────────────────
 *
 * Le rangement (§A) a ramené le menu de 90 lignes à 21. Il défilait quand même : relevé à
 * 1728 × 963, 21 lignes + 6 intitulés de groupe faisaient 1 360 px pour une zone de 899. Ce qui
 * restait n'était plus de la structure mais de la DENSITÉ — 44 px par ligne (40 de bouton, 4 de
 * gouttière), 28 px entre deux groupes, 32 px de marge haute et basse. Aucun rangement
 * supplémentaire n'aurait rattrapé ces 461 px : il aurait fallu retirer neuf écrans du menu.
 *
 * ⚠️ BUREAU SEULEMENT, et c'est la condition de cette règle. `hover: hover` et `pointer: fine`
 * disent une souris ou un trackpad : là, une ligne de 32 px se vise sans effort (c'est la densité
 * de Notion et de Linear). Au doigt — le menu que « Plus » ouvre sur le téléphone (§B) — rien ne
 * change : les lignes y gardent leurs 40 px, parce qu'une cible de 32 px se manque une fois sur
 * trois. Même garde que la v4.21.0 §A, prise par le même bout.
 *
 * Réversible d'un bloc : supprimer ces lignes rend le menu aéré de Filament.
 */

@media (hover: hover) and (pointer: fine) {
    /* La marge haute et basse de la colonne : 32 px de vide avant la première ligne. */
    .fi-main-sidebar .fi-sidebar-nav {
        padding-block: 0.5rem;
        row-gap: 0.625rem;
    }

    /* L'espace entre deux lignes d'un même groupe. */
    .fi-main-sidebar .fi-sidebar-group-items {
        row-gap: 0.0625rem;
    }

    /* La ligne elle-même : l'icône fait 24 px, on ne touche qu'à ce qu'il y a autour. */
    .fi-main-sidebar .fi-sidebar-item-btn {
        padding-block: 0.25rem;
    }

    /* L'intitulé d'un groupe. */
    .fi-main-sidebar .fi-sidebar-group-btn {
        padding-block: 0.125rem;
    }
}
