/* ============================================================================
   EASYPURCHASE — feuille de MODULE, préfixe .ap-* (« achat »).

   MÊME PLACE ET MÊME RAISON QU'easypaie.css ET easyconso.css : chargée dans
   App.razor APRÈS modele-erp.css (dont elle consomme le vocabulaire .mx-*) et
   AVANT les feuilles d'écran. Elle existe parce que les trente écrans du module
   partagent quelques motifs que le gabarit ne nomme pas ; trente feuilles
   d'écran en auraient fait trente copies, ce que la règle « une classe employée
   par deux écrans monte d'un cran » existe précisément pour éviter.

   CE QU'ELLE NE CONTIENT PAS
   Aucune valeur de couleur, aucune police, aucune taille de la charte : tout
   passe par les jetons --et-* d'easytech-theme.css. Aucune redite du gabarit
   non plus — un écran d'achat écrit .mx-carte, .mx-tbl, .mx-form, .mx-ind,
   .mx-blocage, .mx-seg, .mx-btn comme n'importe quel autre écran du produit.

   CE QU'ELLE CONTIENT, ET POURQUOI CHAQUE BLOC EST LÀ
     .ap-filtres  la barre de critères d'un écran d'analyse (dates, fournisseur,
                  seuil). Dix-neuf écrans du module en portent une.
     .ap-sig      l'ENCRE d'un chiffre qui signale — un écart, un dépassement,
                  une variation. Elle remplace les `style="color:var(--et-…)"`
                  que les pages écrivaient une à une.
     .ap-cols     deux ou trois cartes côte à côte, aux paliers du dépôt.
     .ap-mini     une paire libellé/valeur dans une carte, quand la grille
                  dense du formulaire serait trop lourde pour trois chiffres.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. BARRE DE CRITÈRES (.ap-filtres)

   Une rangée de champs étiquetés, posée sous l'en-tête d'écran et au-dessus de
   ce qu'elle filtre. Le libellé va AU-DESSUS du champ et non à sa gauche : la
   grille dense du gabarit (colonne de libellés de 158 px) est faite pour une
   fiche en colonne, pas pour cinq critères en rangée — elle y consommerait la
   moitié de la largeur en intitulés.

   Les champs sont des .mx-input / .mx-select du gabarit, en version 32 px : on
   règle un périmètre, on ne saisit pas une pièce.
   --------------------------------------------------------------------------- */
.ap-filtres {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px;
    padding: 12px 14px;
    background: var(--et-surface); border: 1px solid var(--et-hairline);
    margin-bottom: 14px;
}
.ap-filtres > label { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ap-filtres > label > span {
    font-family: var(--et-font-mono); font-size: 12px; font-weight: 600;
    letter-spacing: .12em; text-transform: uppercase; color: var(--et-table-head-encre);
}
.ap-filtres .mx-input, .ap-filtres .mx-select { height: 32px; }
/* Un critère qui a besoin de place — une recherche libre, un numéro de pièce —
   plutôt qu'une largeur écrite dans la page. */
.ap-filtres > label.est-large { flex: 1 1 260px; }
/* Les raccourcis de période (« Ce mois », « Année en cours ») : un groupe de
   boutons qui suit les champs, aligné sur leur ligne de base. */
.ap-filtres-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Ce qui pousse un bouton à droite de la barre — « Recalculer » d'un écran qui
   n'applique pas ses critères à la frappe. */
.ap-filtres-fin { margin-left: auto; }

@media (max-width: 720px) {
    .ap-filtres { padding: 10px 12px; }
    .ap-filtres > label { flex: 1 1 100%; }
    .ap-filtres-fin { margin-left: 0; }
}

/* RÈGLE TACTILE (docs/cibles-tactiles.md) : sous 1024 px, aucune cible sous
   44 px, et une cible ne rétrécit jamais. */
@media (max-width: 1024px) {
    .ap-filtres .mx-input, .ap-filtres .mx-select { height: 44px; }
    .ap-filtres .mx-btn { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   2. ENCRE DE SIGNALEMENT (.ap-sig)

   Un chiffre qui dit quelque chose de plus que sa valeur : une variation en
   hausse sur une dépense, un disponible budgétaire négatif, un écart de prix
   hors tolérance. Les pages l'écrivaient en ligne — `style="color:var(--et-
   danger-ink)"`, vingt-huit fois — ce que la charte refuse : « jamais de
   couleur codée en dur dans une page » vaut aussi pour un var(--et-*) recopié
   dans un attribut style.

   TROIS RANGS, ET CE SONT LES RANGS D'ENCRE, PAS LES COULEURS D'ÉTAT.
   docs/couleurs-en-dur.md : --et-danger rend 4,13:1 sur --et-rang, la ligne
   survolée — un chiffre de tableau y perdrait AA sous le curseur. C'est donc
   --et-danger-ink / --et-succes-ink / --et-avertissement-ink, mesurés contre le
   fond le moins favorable et non contre le blanc.

   LA COULEUR NE PORTE JAMAIS SEULE : partout où .ap-sig sert, le signe (+/-),
   le mot ou la colonne disent déjà la même chose.
   --------------------------------------------------------------------------- */
.ap-sig.est-negatif  { color: var(--et-danger-ink); }
.ap-sig.est-critique { color: var(--et-avertissement-ink); }
.ap-sig.est-positif  { color: var(--et-succes-ink); }
.ap-sig.est-neutre   { color: var(--et-muted); }

/* ---------------------------------------------------------------------------
   3. COLONNES DE CARTES (.ap-cols)

   Deux ou trois .mx-carte côte à côte. Aux PALIERS DU DÉPÔT (1024 px,
   docs/conventions-responsive.md) et non à ceux de Bootstrap (992/1200) : le
   module n'a aucune raison d'introduire deux échelles de rupture dans le
   produit, et « col-xl-6 » en introduisait une.
   --------------------------------------------------------------------------- */
.ap-cols { display: grid; gap: 14px; align-items: start; }
.ap-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ap-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (max-width: 1024px) {
    .ap-cols-2, .ap-cols-3 { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------------------------
   4. PAIRE LIBELLÉ/VALEUR (.ap-mini)

   Trois ou quatre chiffres dans une carte, sans en faire un formulaire. La
   grille dense (.mx-champ) est faite pour une fiche qu'on SAISIT ; posée sur
   trois valeurs de lecture, sa colonne de 158 px les repousse au milieu de la
   carte. Même vocabulaire que .mx-inerte du gabarit, en rangée plutôt qu'en
   colonne.
   --------------------------------------------------------------------------- */
.ap-mini { display: flex; flex-wrap: wrap; gap: 10px 22px; }
.ap-mini > div { min-width: 0; }
.ap-mini-lbl {
    display: block;
    font-family: var(--et-font-mono); font-size: 11px; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase; color: var(--et-muted);
}
.ap-mini-val {
    display: block; margin-top: 2px;
    font-family: var(--et-font-mono); font-size: 14px; font-weight: 600;
    color: var(--et-ink); font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   5. TABLE DANS UNE CARTE (.ap-tbl-carte)

   .mx-tbl-cadre du gabarit fait DEUX choses : il porte le filet, et il porte le
   défilement horizontal. Posé dans une .mx-carte, qui a déjà son filet, il en
   dessine un second à un pixel du premier. Ce conteneur-ci ne garde que la
   seconde moitié — le défilement — et rend le filet à la carte.

   IL NE REMPLACE PAS .mx-tbl-cadre : une table posée à même le fond de page
   garde le cadre du gabarit, qui est alors ce qui la délimite.
   --------------------------------------------------------------------------- */
.ap-tbl-carte { overflow-x: auto; }

/* ---------------------------------------------------------------------------
   6. PUCE D'IDENTITÉ (.ap-puce)

   Le rond de 8 px qui relie une ligne de table à sa série dans un graphique.
   Sa TEINTE vient de Services/PaletteCategorielle.cs, posée en style="background:…"
   parce que la palette d'identité est choisie en C# — la même valeur sert au
   `fill=` du point SVG, qui n'accepte pas var() (docs/couleurs-en-dur.md). La
   géométrie, elle, n'a aucune raison d'être écrite dans trente pages.
   --------------------------------------------------------------------------- */
.ap-puce {
    display: inline-block; width: 8px; height: 8px; border-radius: 50%;
    margin-right: 6px; vertical-align: baseline; flex: none;
}

/* ---------------------------------------------------------------------------
   7. TABLE DÉFILANTE DANS UNE CARTE (.ap-tbl-carte.est-defilante)

   Un bloc de tableau de bord qui montre les vingt premières lignes d'une liste
   qui en compte deux cents : la carte garde une hauteur lisible, la table défile
   dedans, et SA TÊTE RESTE. Une colonne de montants qu'on fait défiler sans son
   intitulé est une colonne de nombres.

   La hauteur est ici et non dans les pages : « jamais de largeur ni de hauteur
   codée en dur dans une page » (docs/conventions-responsive.md) — six blocs
   l'écrivaient chacun la sienne, en rem, de 18 à 22.
   --------------------------------------------------------------------------- */
.ap-tbl-carte.est-defilante { max-height: 21rem; overflow-y: auto; }
.ap-tbl-carte.est-defilante thead th { position: sticky; top: 0; z-index: 1; }

/* ---------------------------------------------------------------------------
   8. CHIFFRE DE PHARE (.ap-phare)

   LE chiffre d'un écran, celui qu'on vient lire avant tout le reste — le passif
   reçu-non-facturé du tableau de bord (compte 408 SYSCOHADA). Il ne rentre pas
   dans .mx-ind : une vignette d'indicateur est faite pour une bande de quatre,
   et ce chiffre-ci en vaut quatre à lui seul.

   IL PORTE SA CONSÉQUENCE À CÔTÉ DE LUI, et non dessous : un montant qui n'est
   pas au bilan doit se lire avec la phrase qui le dit, dans le même regard.
   --------------------------------------------------------------------------- */
.ap-phare { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 28px; padding: 14px; }
.ap-phare-txt { flex: 1 1 260px; min-width: 0; }
.ap-phare-dit { flex: 1 1 320px; min-width: 0; }
.ap-phare-dit > .mx-blocage { margin: 0; }
.ap-phare-lbl {
    display: block;
    font-family: var(--et-font-mono); font-size: 11px; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase; color: var(--et-muted);
}
.ap-phare-val {
    display: block; margin-top: 3px;
    font-family: var(--et-font-mono); font-size: 30px; font-weight: 600; line-height: 1.1;
    color: var(--et-ink); font-variant-numeric: tabular-nums;
}
.ap-phare-val .unite { font-size: 14px; font-weight: 400; color: var(--et-muted); }
.ap-phare-note { display: block; margin-top: 4px; font-size: 12px; color: var(--et-muted); }

@media (max-width: 720px) {
    .ap-phare-val { font-size: 24px; }
}

/* ---------------------------------------------------------------------------
   9. FENÊTRE LARGE — .est-tres-large DEPUIS LE 2026-09-10, ET CETTE SECTION
      N'A PLUS RIEN À DÉCLARER

   Le raisonnement tient toujours : la fenêtre du gabarit plafonne à 660 px, ce
   qui est la bonne mesure pour un formulaire en colonne, et cinq fenêtres du
   module montrent autre chose — un aperçu de réappro groupé par fournisseur, un
   comparatif d'offres, la ventilation d'un dossier d'import : des TABLES, qu'un
   plafond de 660 px ferait défiler horizontalement alors que la fenêtre du
   navigateur a la place. Elle plafonne quand même, parce qu'au-delà une rangée
   de table sépare tellement son article de son montant qu'il faut suivre la
   ligne du doigt.

   C'est exactement le cran .est-tres-large de la charte (1120 px), posé dans la
   page. Les 1080 px que cette section écrivait disaient la même chose.

   ET LE PLAFOND DU CORPS AUSSI EST PARTI, celui-là pour une raison de fond.
   Cette feuille posait « max-height: 68vh » sur .mx-modale-corps, avec la bonne
   intention — « le bouton qui engage ne doit jamais être au-delà du
   défilement » — et la mauvaise méthode : 68 vh est une FRACTION D'ÉCRAN
   DEVINÉE, qui ignore ce qu'il y a autour du corps. Une tête d'une ligne, une
   bande de faits et un pied à deux lignes ne font pas la même hauteur qu'une
   tête à deux lignes sans bande ; à 32 % restants, tantôt il manque de la place,
   tantôt il en reste. Le gabarit ne devine plus rien depuis le 2026-09-10 : la
   tête et le pied gardent leur hauteur, le corps prend CE QUI RESTE, et le
   plafond de la fenêtre est celui de l'écran moins les deux retraits du voile.
   C'est la même correction que celle qu'ecran-terminaux.css avait déjà dû faire
   sur son propre calcul (56 px de retrait au lieu de 96).
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   10. LISTE DE CASES À DÉFILEMENT (.ap-cases)

   Un panel de fournisseurs, une liste de dépôts, un jeu de taxes : trente cases
   à cocher dans une fenêtre. Sans plafond de hauteur, la fenêtre part au-delà de
   l'écran et son bouton d'engagement avec elle ; sans filet, la liste se confond
   avec le formulaire qui la précède.
   --------------------------------------------------------------------------- */
.ap-cases {
    max-height: 10rem; overflow-y: auto;
    padding: 8px 10px;
    border: 1px solid var(--et-form-border); background: var(--et-surface);
    display: flex; flex-direction: column; gap: 5px;
}

/* ---------------------------------------------------------------------------
   11. CELLULE MARQUÉE D'UN TABLEAU CROISÉ (.ap-cell-*)

   Un comparatif d'offres est une matrice ligne × fournisseur : ce n'est pas la
   RANGÉE qui porte le verdict — `est-alerte` du gabarit ne convient donc pas —
   mais la CELLULE, une par croisement.

   DEUX MARQUES, ET ELLES NE DISENT PAS LA MÊME CHOSE
     · `ap-cell-mieux`  — le moins cher disponible sur cette ligne. Un CONSTAT :
       il se calcule, personne ne l'a décidé.
     · `ap-cell-retenu` — celui qu'on retient. Une DÉCISION, et rien n'oblige à
       retenir le moins cher : un délai, une garantie, un historique de litiges
       valent parfois l'écart. La marque est donc plus forte — un liseré, pas un
       aplat — et elle est doublée d'une coche, parce qu'un aplat pâle ne survit
       pas à l'impression.

   La cellule retenue emprunte --et-tint et --et-form-blue : c'est du BLEU DE
   PAGE, la couleur de l'interactif, et non une couleur d'état. Retenir une offre
   n'est ni bien ni mal.
   --------------------------------------------------------------------------- */
.mx-tbl td.ap-cell-mieux { background: var(--et-succes-bg); }
.mx-tbl td.ap-cell-retenu { background: var(--et-tint); box-shadow: inset 0 0 0 2px var(--et-form-blue); }
.ap-retenu { color: var(--et-form-blue-d); font-weight: 700; }

/* ---------------------------------------------------------------------------
   12. RANGÉE D'ACTIONS DANS UNE CARTE (.ap-actions)

   .mx-outils du gabarit est la barre d'outils de l'EN-TÊTE D'ÉCRAN : les actions
   qui valent pour l'écran entier. Les actions d'un OBJET ouvert dans une carte —
   activer cet accord, le suspendre, le clore — n'en sont pas, et le commentaire
   du gabarit est net là-dessus. Elles ont donc leur rangée, même géométrie et
   même gouttière, sans prétendre au même rôle.
   --------------------------------------------------------------------------- */
.ap-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* ---------------------------------------------------------------------------
   13. LISTE DE CHOIX (.ap-choix)

   Le résultat d'une recherche dans une fenêtre : quelques lignes dont on retient
   une. Ce n'est pas une table — une seule information par ligne, et la ligne
   ENTIÈRE est la cible, pas un bouton en bout de rangée.

   Chaque ligne est donc un <button>, ce qui interdit d'y mettre un <input> : la
   règle du gabarit est la même pour .mx-case (modele-erp.css §5).
   --------------------------------------------------------------------------- */
.ap-choix {
    max-height: 12rem; overflow-y: auto;
    border: 1px solid var(--et-form-border); background: var(--et-surface);
}
.ap-choix > button {
    display: block; width: 100%; text-align: left;
    padding: 8px 11px;
    border: 0; border-bottom: 1px solid var(--et-hairline);
    background: var(--et-surface); color: var(--et-ink);
    font-family: inherit; font-size: 13px; cursor: pointer;
}
.ap-choix > button:last-child { border-bottom: 0; }
.ap-choix > button:hover { background: var(--et-rang); }
.ap-choix > button:focus-visible { outline: 2px solid var(--et-form-blue); outline-offset: -2px; }

/* RÈGLE TACTILE (docs/cibles-tactiles.md) : sous 1024 px, aucune cible sous 44 px. */
@media (max-width: 1024px) {
    .ap-choix > button { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   14. BARRE D'ÉTAPES D'UN DOSSIER (.ap-etapes)

   L'ORDRE DES OPÉRATIONS EST MONTRÉ, et ce n'est pas une décoration : calculer un
   dossier d'import avant d'avoir saisi le fret donne un coefficient de 1,0 et
   l'apparence du travail fini. La barre dit où l'on en est et ce qui vient après.

   POURQUOI PAS FilEtapes.razor (.mx-fil du gabarit) : ce fil-là est un assistant
   — une étape à la fois, on y navigue. Celui-ci est un ÉTAT : les cinq étapes
   sont visibles ensemble, chacune porte son propre bouton, et rien n'oblige à les
   franchir dans l'ordre. Ce sont deux objets différents sous un nom voisin.

   L'ÉTAT SE DIT PAR LE GLYPHE ET PAR L'INTITULÉ, pas par la seule teinte : une
   étape faite porte une coche, une étape actionnable porte son verbe. La couleur
   ne fait que redire ce qui est déjà écrit.
   --------------------------------------------------------------------------- */
.ap-etapes { display: flex; flex-wrap: wrap; gap: 10px; }
.ap-etape {
    flex: 1 1 9rem; min-width: 0;
    padding: 8px 10px;
    background: var(--et-surface); border: 1px solid var(--et-hairline);
}
.ap-etape.est-faite { background: var(--et-succes-bg); border-color: var(--et-succes); }
.ap-etape.est-a-faire { border-color: var(--et-form-blue); }
.ap-etape-titre { font-size: 12px; font-weight: 600; color: var(--et-ink); }
.ap-etape.est-faite .ap-etape-titre { color: var(--et-succes-ink); }
.ap-etape-etat { margin-top: 1px; font-size: 12px; color: var(--et-muted); }
.ap-etape .mx-btn { width: 100%; margin-top: 7px; }

@media (max-width: 720px) {
    .ap-etape { flex: 1 1 100%; }
}

/* ---------------------------------------------------------------------------
   15. BARRE DE PART (.ap-part)

   « 89 % du volume pour 6 % de la valeur » : la ligne qui explique un coefficient.
   .mx-barre du gabarit conviendrait, mais son libellé fait 168 px — la moitié de
   la largeur disponible dans une rangée dépliée de table. Celui-ci en fait 5rem,
   et la valeur se pose à droite, comme dans le gabarit.

   DEUX SÉRIES SEULEMENT, et elles ne sont pas des états : la valeur d'un côté, la
   clé physique (poids ou volume) de l'autre. Les teintes viennent donc des
   couleurs d'identité de la charte, jamais de --et-succes / --et-danger.
   --------------------------------------------------------------------------- */
.ap-part { display: flex; align-items: center; gap: 8px; padding: 2px 0; }
.ap-part-lbl { flex: 0 0 5rem; font-size: 12px; color: var(--et-ink); }
.ap-part-piste { position: relative; flex: 1 1 auto; min-width: 40px; height: 12px; background: var(--et-piste); }
.ap-part-jauge { height: 100%; background: var(--et-cat-1); }
.ap-part-jauge.est-physique { background: var(--et-cat-2); }
.ap-part-val {
    flex: 0 0 3.5rem; text-align: right;
    font-family: var(--et-font-mono); font-size: 12px; color: var(--et-ink);
    font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   16. COLONNE D'ANCRAGE SUR UNE TABLE DU GABARIT (.mx-tbl.tbl-ancree)

   POURQUOI CE BLOC EXISTE : le lot 03 (wwwroot/css/lot03-tables-larges.css,
   docs/tables-larges.md) a été écrit pour les familles de table dont l'EN-TÊTE
   EST DÉJÀ UN APLAT ARDOISE À ENCRE CLAIRE — .tbl, .table, .cso-etat, .rh-table.
   Il repeint donc la cellule d'en-tête ancrée en var(--et-table-head) pour la
   rendre opaque pendant le défilement, et l'encre claire de ces tables suit.

   .mx-tbl, lui, a fait le choix inverse et le dit : « Le fond reste CLAIR — le
   gris foncé de .tbl ancre une liste de douze colonnes, il ferait un bandeau
   dans un formulaire » (modele-erp.css §11). Son encre est donc
   --et-table-head-encre, qui vaut #354A5F en thème clair — la MÊME valeur que
   --et-table-head. Croisés, les deux rendent #354A5F sur #354A5F : l'intitulé
   de la colonne d'ancrage disparaît, précisément la colonne que le lot existe
   pour garder lisible.

   Ces trois tables sont les premières du dépôt à croiser les deux familles.
   La correction rend à .mx-tbl le fond clair de sa propre tête — opaque, donc
   le défilement reste couvert — plutôt que de lui imposer une encre qui n'est
   pas la sienne.

   MÊME CAUSE, DEUXIÈME EFFET : le lot 03 pose var(--et-surface) sur la cellule
   ancrée du CORPS, ce qui efface, sur une rangée en anomalie, l'aplat ambre ET
   le liseré de 3 px — le seul marqueur qui, dit le gabarit, survit au thème
   sombre. La rangée en alerte les reprend ici.
   --------------------------------------------------------------------------- */
.mx-tbl.tbl-ancree[data-ancre="1"] > thead > tr > :nth-child(1),
.mx-tbl.tbl-ancree[data-ancre="2"] > thead > tr > :nth-child(2),
.mx-tbl.tbl-ancree[data-ancre="3"] > thead > tr > :nth-child(3),
.mx-tbl.tbl-ancree[data-ancre="4"] > thead > tr > :nth-child(4) {
    background: var(--et-surface-2);
}

.mx-tbl.tbl-ancree[data-ancre="1"] > tbody > tr.est-alerte > :nth-child(1):not([colspan]),
.mx-tbl.tbl-ancree[data-ancre="2"] > tbody > tr.est-alerte > :nth-child(2):not([colspan]),
.mx-tbl.tbl-ancree[data-ancre="3"] > tbody > tr.est-alerte > :nth-child(3):not([colspan]),
.mx-tbl.tbl-ancree[data-ancre="4"] > tbody > tr.est-alerte > :nth-child(4):not([colspan]) {
    background: var(--et-avertissement-bg);
}
/* Le liseré de la rangée en alerte est porté par sa PREMIÈRE cellule ; quand
   c'est elle qui est ancrée, le lot 03 lui substitue son filet de séparation.
   Les deux ombres cohabitent — le liseré à gauche, le filet à droite. */
.mx-tbl.tbl-ancree[data-ancre="1"] > tbody > tr.est-alerte > :nth-child(1):not([colspan]) {
    box-shadow: inset 3px 0 0 var(--et-avertissement), 1px 0 0 var(--et-hairline);
}
