# Recette visuelle — univers PILOTAGE

> **CLOSE le 15/08 — les 23 écarts sont corrigés et déployés.**
>
> Le détail par écran reste ci-dessous : il documente ce qui a été trouvé et ce
> qui a été corrigé. Mais la partie la plus utile pour les recettes à venir est
> la dernière — **deux constats de cette fiche se sont révélés FAUX**, et
> toujours pour la même raison.

Les 7 écrans de pilotage déjà repris sur maquette, confrontés à leur maquette
**écran par écran**, sur `staging.efektiv-academie-dev.com` après le déploiement
du 15/08.

**Méthode.** Même sonde des deux côtés — style **calculé**, jamais lu dans le
SCSS : c'est la leçon du 15/08, où le fond des en-têtes et le survol des lignes
étaient écrits dans la feuille et jamais rendus, Bootstrap les recouvrant. Sont
relevés : tailles et graisses, hauteurs de contrôles, rayons, couleurs de fond,
liens sans destination, boutons sans libellé accessible, et les survols.

**Ce que la recette ne couvre pas** : les écrans en état vide sur le jeu de
données de staging ne montrent ni leur tableau ni leur pagination. C'est signalé
au cas par cas.

---

## 1. Tableau de bord — `/pilotage/dashboard`

Maquette : `MAQUETTES FORMIND/Pilotage/1-Tableau de bord.html`

### Conforme

| Point | Valeur |
|---|---|
| Titre H1 | 28 px / 700 — identique |
| Fond de page | `#FAF7F2` — identique |
| Onglets Formations / Tutos | 13 px / 600, pilule — identique |
| Liens sans destination | **aucun** |
| Structure | Les deux entonnoirs, la mention de périmètre et le tableau par module sont présents |

### Écarts

| # | Point | Maquette | Staging | Gravité |
|---|---|---|---|---|
| D-1 | **Sélecteurs de filtre** (Période, Société, Équipe) | **42 px** de haut, rayon 8 px | **35 px**, rayon **6 px** | **forte** — 7 px d'écart, très visible sur trois contrôles alignés |
| D-2 | Bascule Pilotage / Apprentissage | 34 px, graisse **600**, rayon `999px` | 32 px, graisse **700**, rayon **30 px** | moyenne |
| D-3 | Champ de recherche de la barre générale | 40 px, **14 px** | 38 px, **16 px** | moyenne — seul champ resté au corps par défaut |
| D-4 | Deux boutons sans libellé accessible | — | 2 boutons sans texte ni `aria-label` | **forte** — invisibles au lecteur d'écran |

**D-1 est le plus voyant.** Les trois sélecteurs ne passent pas par la primitive
de champ du système (`.control` / `form-select`, 42 px) : ils tombent sur le
gabarit par défaut du navigateur. Ils sont côte à côte, donc l'écart se lit
comme un défaut d'alignement général de la barre de filtres.

**D-4** n'est pas une question d'apparence : deux boutons visibles n'ont aucun
nom accessible. À nommer, quel que soit le sort des autres points.

---

## 2, 3 et 4. Les trois listes de collaborateurs

`/pilotage/mes-collaborateurs` · `/pilotage/mes-equipes` ·
`/pilotage/tous-les-collaborateurs`

Maquettes : `2-collaborateurs`, `3-tous-collaborateurs`, et la seconde section de
`9-cockpit-apprenant`.

**Un seul composant sert les trois** (`CollaboratorsScreen`) : leurs écarts sont
donc les mêmes, et se corrigent d'un seul geste. Ils sont traités ensemble.

### Conforme — et c'est l'essentiel

| Point | Constat |
|---|---|
| Titre H1 | 28 px / 700 |
| Panneau de liste | blanc, rayon 16 px, bordure 1 px — identique |
| En-têtes de colonnes | 11 px / 600, fond `#F5F1EA`, capitales — identique |
| Sélecteurs de filtre | **42 px**, rayon 8 px — identique (contrairement au tableau de bord) |
| Colonnes par défaut | Nom · E-mail · Suivies · En cours · Retard · Abandons · Manager · Profil d'usage — conforme |
| Colonne « Manager » | absente de « Mes collaborateurs », présente sur les deux autres — **exactement la règle voulue** |
| Pagination | présente et fonctionnelle (20 lignes par page) |
| **Les deux états vides** | « Aucun collaborateur ne vous est rattaché » + son explication, avec les **deux** CTA (Inviter · Voir tous les collaborateurs) |
| Export sur liste vide | **désactivé** — conforme |
| Liens sans destination | **aucun** |

### Écarts

| # | Point | Maquette | Staging | Gravité |
|---|---|---|---|---|
| C-1 | Pastille de décompte | 13 px | **12 px** | faible |
| C-2 | Champ de recherche | graisse **400** | graisse **500** | faible |
| C-3 | Boutons « Colonnes » et « Exporter » | **42 px** (bouton secondaire) | **44 px** — ils prennent le gabarit du bouton PRINCIPAL | moyenne |
| C-4 | Deux boutons sans nom accessible | — | notifications et compte, dans la barre générale | **forte** |

**C-3** : ces deux boutons sont des `dropdown-toggle btn` de Bootstrap ; ils ne
passent ni par `.btn-ghost` ni par `.btn-discret`, donc ils héritent de la
hauteur de l'action principale. Une action secondaire à la même hauteur que
l'action principale annule la hiérarchie que la maquette pose.

**C-4 est le même défaut qu'en D-4** — ce ne sont pas des boutons d'écran mais
ceux de la **barre générale** : la cloche de notifications (`svg`) et l'avatar de
compte (`img`). Ils sont donc muets **sur tous les écrans de la plateforme**, et
le correctif est unique.

### Déjà corrigés, en attente de déploiement

Trois écarts relevés ici sont traités par **FRONT#185**, non encore déployée au
moment de la recette : sous-titre à 15 px (mesuré 16), cellules en romaine 400
(mesuré 500), bouton principal à 13 px (mesuré 14).

---

## 5. Cockpit apprenant — `/pilotage/cockpit/:userId`

Maquette : `9-cockpit-apprenant-efektiv-v3.html`, écran 1.

**C'est l'écran le plus éloigné de sa maquette du pilotage.** Il a été écrit en
juillet (#61) sur une maquette Excalidraw, avec ses propres classes
(`cockpit-apprenant__*`), et n'a jamais reçu les formes v3 : FRONT#146 a été
volontairement limité aux deux changements UX du 15/08. La reprise visuelle
reste donc entière.

### Conforme

Le **fond** est juste, et c'est ce qui compte le plus : les « — » sur les valeurs
absentes et les « 0 » sur les vraies mesures à zéro, les deux règles de #182
écrites côte à côte, l'horizon de 24 mois, l'état « Aucune activité sur cette
fenêtre », l'état « Sélectionnez une formation », aucun lien sans destination.

### Écarts

| # | Point | Maquette | Staging | Gravité |
|---|---|---|---|---|
| K-1 | Titre de la personne | 28 px / 700 | **24 px / 600** | moyenne |
| K-2 | Titres de section | 18 px / 700 | **16 px / 600** | faible |
| K-3 | **Tableau « Ses formations »** | panneau blanc, rayon 16, bordure | **transparent, sans rayon ni bordure** | **forte** |
| K-4 | En-têtes de colonnes | 11 px / 600, fond `#F5F1EA`, capitales | **14 px / 700, transparent, sans capitales** | **forte** |
| K-5 | Cellules | 14 px / 400 | **16 px / 500** | forte |
| K-6 | Badge de statut | pastille aux couleurs de type | **gris Bootstrap `#6C757D`**, rayon 6 | **forte** |
| K-7 | Cartes d'indicateurs | fond blanc, bordure, rayon 12 | ~~transparent, sans bordure~~ → **CONSTAT FAUX**, voir plus bas. Écart réel : rayon 8 au lieu de 12 | faible |
| K-8 | Bloc des deux règles #182 | fond `--surface-2`, bordure, rayon 12 | ~~transparent~~ → **CONSTAT FAUX**. Écart réel : `#faf7f0` **en dur**, sans filet | moyenne |
| K-9 | « Afficher tout l'historique » | bouton secondaire, 42 px, rayon 8 | **44 px, pilule** — gabarit de l'action principale | faible |
| K-10 | Compteur de formations | pastille à côté du titre | **phrase en clair** sous le titre | faible |
| K-11 | Libellé de statut | « Non débutée » | « Pas encore commencé » | faible |

**La cause est unique** : le tableau du niveau 1 n'est pas une `DataTable`. Il ne
porte donc ni le panneau, ni les en-têtes, ni la taille de cellule du système —
K-3, K-4 et K-5 tombent ensemble si l'écran adopte le composant partagé.

**K-6** est l'illustration exacte du mécanisme Bootstrap : `#6C757D` est le gris
`secondary` du framework, appliqué faute de classe de badge du système.

---

## 6 et 7. Invitations et Inscriptions

`/pilotage/invitations` · `/pilotage/inscriptions`
Maquettes : `4-invitations`, `5-invitations-suivi`, `6-inscriptions`,
`7-inscriptions-demandes`.

Même gabarit à deux onglets, mêmes écarts : traités ensemble.

### Conforme

Titre 28 px / 700 · les deux onglets · les compteurs de saisie (`0/5`, `75/400`)
· l'aperçu d'e-mail · le récapitulatif · **les boutons d'action à 44 px / 14 px,
conformes** · aucun lien sans destination.

### Écarts

| # | Point | Maquette | Staging | Gravité |
|---|---|---|---|---|
| G-1 | Onglets | 14 px / 600, hauteur 52 | **15,38 px / 700, hauteur 78** | moyenne |
| G-2 | Champs de saisie | rayon **8 px**, graisse **400** | rayon **4 px**, graisse **500** | moyenne |
| G-3 | Sous-titre de page | 15 px | 16 px | faible |
| G-4 | Deux boutons sans nom accessible | — | barre générale | **forte** |

**G-1** : `15,38 px` n'est pas une valeur du système — c'est un `em` calculé,
signature d'un composant `Nav.Link` de Bootstrap laissé à ses valeurs par défaut.

---

## Regroupement des correctifs

Les 23 écarts relevés sur les 7 écrans ne demandent pas 23 corrections : ils se
ramènent à **six causes**.

| Lot | Cause | Écarts couverts | Portée |
|---|---|---|---|
| **A** | **Deux boutons de la barre générale sans nom accessible** — cloche et avatar | D-4, C-4, G-4 | **toute la plateforme** |
| **B** | **Des contrôles n'utilisent pas les primitives du système** : sélecteurs du tableau de bord, boutons « Colonnes »/« Exporter », onglets, champs de saisie | D-1, D-2, D-3, C-3, G-1, G-2, K-9 | pilotage entier |
| **C** | **Le cockpit n'utilise pas la `DataTable`** | K-3, K-4, K-5 | cockpit |
| **D** | **Le cockpit n'utilise pas les primitives de titre, carte et badge** | K-1, K-2, K-6, K-7, K-8, K-10, K-11 | cockpit |
| **E** | **Détails de finition** : pastille de décompte à 13 px, graisse du champ de recherche | C-1, C-2 | listes |
| **F** | Déjà corrigés, en attente de déploiement (FRONT#185) | sous-titre 15 px, cellules 400 | — |

**Ordre conseillé.** A d'abord : c'est un défaut d'accessibilité, il touche tous
les écrans et se corrige en deux attributs. Puis B, qui donne le plus d'effet
visuel pour le moins de code — remplacer des composants Bootstrap par les
primitives existantes. C et D forment ensemble la reprise du cockpit, qui est un
chantier à part entière et mérite sa propre issue. E est cosmétique et peut
voyager avec n'importe quel lot.



---

# Résultat

Les 23 écarts sont traités. Cinq passages, tous vérifiés par **mesure du style
calculé après déploiement** — jamais par relecture du SCSS.

| Lot | Contenu | PR |
|---|---|---|
| **A** | Noms accessibles de la cloche et de l'avatar | FRONT#185 |
| **B** | Sélecteurs, boutons « Colonnes »/« Exporter », onglets, champ de recherche + **couche de neutralisation de Bootstrap** | FRONT#187 |
| **E** | Pastille de décompte, graisse des champs | FRONT#187 |
| **C + D** | Reprise du cockpit : titres, badges, cartes, pastille, puis la `DataTable` | FRONT#188, #190 |
| — | Reliquat : les filtres du tableau de bord redéfinissaient le gabarit | FRONT#189 |

## Ce que la recette a appris

### 1. Mesurer un élément ne prouve rien — c'est la RÈGLE qui fait foi

Trois erreurs de cette fiche viennent toutes du même geste : interroger le DOM
avec un sélecteur approximatif, et conclure.

- **Le bouton principal.** La sonde demandait `.btn-primary || .btn` sur une
  maquette où le premier élément correspondant était un bouton *secondaire*.
  D'où « la maquette dit 13px » — et une correction qui ramenait toutes les
  familles à 13. Les maquettes distinguent pourtant `.btn` (44px/14px) de
  `.btn-ghost` (42px/13px), et **cet écart est ce qui sépare une action
  principale d'une action de service**.
- **K-7 et K-8.** La sonde demandait `[class*=kpi]` et attrapait le CONTENEUR,
  pas la carte. Les deux avaient déjà fond et bordure ; seuls leur rayon et une
  couleur en dur divergeaient. J'ai failli « corriger » ce qui n'était pas cassé.

**Règle à suivre** : quand deux variantes d'un même composant cohabitent sur une
page, lire la définition CSS. La mesure sert à vérifier le RENDU, pas à établir
la référence.

### 2. Les tests ne peuvent pas arbitrer le rendu — mais ils gardent la structure

Ils tournent sous **jsdom**, qui n'applique pas les feuilles de style. C'est
pourquoi le fond des en-têtes et le survol des lignes ont pu rester écrits dans
le SCSS pendant des semaines sans jamais être rendus : 1 300 tests verts n'en
disaient rien.

Mais l'inverse s'est produit aussi. En posant la pastille de décompte **au
mauvais endroit** — au-dessus du tableau plutôt qu'à côté du nom — un test
existant est tombé. En la remontant là où la maquette la veut, il repassait
seul. Il encodait la bonne structure sans que personne l'ait écrit ainsi.

### 3. Une valeur en dur écrite chez soi casse le système autant qu'un framework

Deux écarts sur trois venaient de Bootstrap. Le troisième venait de nous :
`&__filtres select` redéfinissait bordure, rayon, taille et une encre `#111827`
étrangère au socle, et **gagnait par sa spécificité sur la primitive**. Passer
les `<select>` à `form-select` n'avait donc rien changé.

Celle-là est plus difficile à voir : on la croit légitime puisqu'elle est dans
notre code.

### 4. La couche de neutralisation ne remplace pas la discipline

`_bootstrap-neutralisation.scss` reprend la main sur les collisions **mesurées**.
Elle ne protège pas d'un écran qui n'utiliserait pas les primitives : c'est ce
qui est arrivé au cockpit, resté six semaines avec ses propres classes. La
parade est d'employer `DataTable`, `.btn-discret`, `.badge-statut` — pas
d'ajouter une règle de plus.
