@zevra/ui 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DECISIONS.md +264 -208
- package/README.md +21 -21
- package/demo/app.html +6 -6
- package/demo/index.html +3 -3
- package/dist/actions.d.ts +8 -8
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/catalogue.d.ts +2 -2
- package/dist/catalogue.js +67 -67
- package/dist/catalogue.js.map +1 -1
- package/dist/content.d.ts +23 -23
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +16 -16
- package/dist/content.js.map +1 -1
- package/dist/css-inline.d.ts +1 -1
- package/dist/css-inline.d.ts.map +1 -1
- package/dist/css-inline.js +4 -4
- package/dist/css-inline.js.map +1 -1
- package/dist/data-table.d.ts +1 -1
- package/dist/data.d.ts +7 -7
- package/dist/data.js +5 -5
- package/dist/email-tokens.js +1 -1
- package/dist/email.d.ts +6 -6
- package/dist/email.js +8 -8
- package/dist/email.js.map +1 -1
- package/dist/feedback.d.ts +10 -10
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +3 -3
- package/dist/forms.d.ts +12 -12
- package/dist/forms.js +5 -5
- package/dist/glyph-data.d.ts +2 -2
- package/dist/glyph-data.js +3 -3
- package/dist/glyph-urls.js +1 -1
- package/dist/glyphes.d.ts +2 -2
- package/dist/glyphes.js +4 -4
- package/dist/icon-data.d.ts +1 -1
- package/dist/icon-data.js +2 -2
- package/dist/icon.d.ts +5 -5
- package/dist/icon.js +1 -1
- package/dist/index.js +4 -4
- package/dist/layout.d.ts +21 -21
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +15 -15
- package/dist/layout.js.map +1 -1
- package/dist/navigation.d.ts +16 -16
- package/dist/navigation.d.ts.map +1 -1
- package/dist/navigation.js +9 -9
- package/dist/navigation.js.map +1 -1
- package/dist/overlays.d.ts +6 -6
- package/dist/overlays.d.ts.map +1 -1
- package/dist/overlays.js +5 -5
- package/dist/select-menu.d.ts +1 -1
- package/dist/select-menu.js +2 -2
- package/dist/surfaces.d.ts +8 -8
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +6 -6
- package/dist/surfaces.js.map +1 -1
- package/dist/typography.d.ts +4 -4
- package/dist/typography.d.ts.map +1 -1
- package/dist/typography.js +3 -3
- package/dist/typography.js.map +1 -1
- package/icons/index.json +1 -1
- package/package.json +2 -2
- package/react/actions.tsx +9 -9
- package/react/catalogue.tsx +68 -68
- package/react/content.tsx +28 -28
- package/react/css-inline.ts +4 -4
- package/react/data-table.tsx +3 -3
- package/react/data.tsx +9 -9
- package/react/email-tokens.ts +1 -1
- package/react/email.ts +10 -10
- package/react/feedback.tsx +12 -12
- package/react/forms.tsx +15 -15
- package/react/glyph-data.ts +3 -3
- package/react/glyph-urls.ts +1 -1
- package/react/glyphes.ts +4 -4
- package/react/icon-data.ts +2 -2
- package/react/icon.tsx +6 -6
- package/react/index.ts +4 -4
- package/react/layout.tsx +22 -22
- package/react/navigation.tsx +18 -18
- package/react/overlays.tsx +9 -9
- package/react/select-menu.tsx +3 -3
- package/react/surfaces.tsx +10 -10
- package/react/typography.tsx +6 -6
- package/src/base.css +10 -10
- package/src/components.css +49 -49
- package/src/data.css +41 -41
- package/src/feedback.css +55 -55
- package/src/fonts.css +2 -2
- package/src/forms.css +50 -50
- package/src/icons.css +10 -10
- package/src/index.css +1 -1
- package/src/layout.css +27 -27
- package/src/motion.css +16 -16
- package/src/motion.js +4 -4
- package/src/nav.js +5 -5
- package/src/navigation.css +62 -62
- package/src/overlays.css +14 -14
- package/src/rail.js +6 -6
- package/src/surfaces.css +11 -11
- package/src/tokens.css +14 -14
- package/tokens/index.js +8 -8
package/DECISIONS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Arbitrages de relevé
|
|
2
2
|
|
|
3
3
|
Les cinq maquettes de la passation ne s'accordent pas toujours. Ce fichier
|
|
4
|
-
liste chaque désaccord, la valeur retenue et pourquoi
|
|
4
|
+
liste chaque désaccord, la valeur retenue et pourquoi : pour qu'aucun écart ne
|
|
5
5
|
soit tranché en silence, et que la DA puisse rejuger sur pièces.
|
|
6
6
|
|
|
7
7
|
Sources : les dix planches de `reference/maquettes/` et
|
|
@@ -17,7 +17,7 @@ Les deux questions laissées ouvertes à la première livraison sont **closes**,
|
|
|
17
17
|
et dans le sens qui avait été retenu. Les cinq planches ajoutées le
|
|
18
18
|
confirment à l'unanimité.
|
|
19
19
|
|
|
20
|
-
### 1. Le sens du dégradé de signature
|
|
20
|
+
### 1. Le sens du dégradé de signature : clos
|
|
21
21
|
|
|
22
22
|
| Source | Valeur |
|
|
23
23
|
|---|---|
|
|
@@ -30,7 +30,7 @@ Les cinq nouvelles planches posent toutes `linear-gradient(90deg, #8a3af8,
|
|
|
30
30
|
token est donc la bonne ; les trois planches historiques sont en retard, pas
|
|
31
31
|
en désaccord.
|
|
32
32
|
|
|
33
|
-
### 2. Le rayon des cartes
|
|
33
|
+
### 2. Le rayon des cartes : clos
|
|
34
34
|
|
|
35
35
|
Les cinq nouvelles planches codent `border-radius: 16px` sur `.panel`, soit
|
|
36
36
|
`--r-card`. Le `14px` de DesignSystem et Logos et le `12px` du prototype
|
|
@@ -40,20 +40,20 @@ appartiennent à l'état antérieur.
|
|
|
40
40
|
|
|
41
41
|
## Tranché sans ambiguïté
|
|
42
42
|
|
|
43
|
-
**Hauteur des boutons
|
|
43
|
+
**Hauteur des boutons : 48px.** Main, Mobile et le prototype s'accordent ;
|
|
44
44
|
DesignSystem est seule à 46px.
|
|
45
45
|
|
|
46
|
-
**Icône du lien fléché
|
|
46
|
+
**Icône du lien fléché : 15×15.** Quatre occurrences dans Main contre une à
|
|
47
47
|
16px dans DesignSystem.
|
|
48
48
|
|
|
49
|
-
**Pastille
|
|
49
|
+
**Pastille (28px de haut, 10px de texte, 0.18em.** Main et le prototype
|
|
50
50
|
s'accordent ; DesignSystem est plus grande (30/11), Mobile plus petite
|
|
51
|
-
(26/0.16em
|
|
51
|
+
(26/0.16em) repris dans la déclinaison mobile).
|
|
52
52
|
|
|
53
|
-
**Puce de source
|
|
53
|
+
**Puce de source : `--accent-deep`.** Main et le prototype ; DesignSystem pose
|
|
54
54
|
`--accent`.
|
|
55
55
|
|
|
56
|
-
**Entité pseudonymisée
|
|
56
|
+
**Entité pseudonymisée : 10px, `1px 6px`.** Main et DesignSystem ; le
|
|
57
57
|
prototype est plus grand (11px, `2px 7px`).
|
|
58
58
|
|
|
59
59
|
**Les deux encarts ne sont pas le même composant.** `.zv-inset` (blanc,
|
|
@@ -77,17 +77,17 @@ Deux choix d'implémentation méritent d'être dits :
|
|
|
77
77
|
view())`. Un navigateur sans support affiche la page complète, jamais un
|
|
78
78
|
écran vide en attente d'une animation qui ne viendra pas ;
|
|
79
79
|
- les deux boucles animent les propriétés `translate` et `scale`
|
|
80
|
-
indépendantes, jamais `transform`
|
|
80
|
+
indépendantes, jamais `transform` : le halo est centré par
|
|
81
81
|
`translateX(-50%)`, qu'une animation sur `transform` écraserait. La
|
|
82
82
|
maquette contournait le problème en recopiant le `translateX(-50%)` dans
|
|
83
83
|
chaque image-clé ; la propriété indépendante compose proprement.
|
|
84
84
|
|
|
85
85
|
**Six blocs de plus.** Citation, carte de tarif, FAQ, aperçu d'interface,
|
|
86
|
-
bande de preuve sociale, pied de page réduit
|
|
86
|
+
bande de preuve sociale, pied de page réduit : relevés dans `Blocks.html`,
|
|
87
87
|
qui liste les composants du site. Deux d'entre eux portent une règle
|
|
88
88
|
éditoriale que le CSS ne peut pas faire respecter et qui est donc écrite en
|
|
89
89
|
commentaire : **jamais de fausse citation**, et **jamais de lorem dans un
|
|
90
|
-
aperçu d'interface
|
|
90
|
+
aperçu d'interface**, c'est ce bloc qui porte la crédibilité de la page.
|
|
91
91
|
|
|
92
92
|
**Un palier typographique et une accroche.** `.zv-note` (12,5px) et
|
|
93
93
|
`.zv-tagline`, la phrase d'accroche posée sous le nom d'un glyphe, moins
|
|
@@ -105,7 +105,7 @@ n'a été inventé pour combler l'écart.
|
|
|
105
105
|
## Ajouts assumés, hors relevé
|
|
106
106
|
|
|
107
107
|
**Le point de rupture à 768px.** Les cinq maquettes sont à largeur fixe, sans
|
|
108
|
-
une seule media query
|
|
108
|
+
une seule media query : Mobile.html est un rendu figé à 390px. Le seuil vient
|
|
109
109
|
de la convention `md` du projet ; les valeurs mobiles, elles, sont toutes
|
|
110
110
|
relevées dans Mobile.html. Un test vérifie qu'il reste unique.
|
|
111
111
|
|
|
@@ -135,20 +135,20 @@ production, qui emploie les mêmes tokens de charte. Trois arbitrages de fond
|
|
|
135
135
|
ont été rendus :
|
|
136
136
|
|
|
137
137
|
**Les neutres.** Mémoire emploie six niveaux de gris là où la charte en a
|
|
138
|
-
trois, et deux d'entre eux
|
|
138
|
+
trois, et deux d'entre eux, #6B7488 et #727C93, **échouent au contraste AA**
|
|
139
139
|
sur texte normal (4,34 et 3,87), alors qu'ils portent justement le texte mono
|
|
140
140
|
de 10,5px : latences, horodatages, compteurs. Les adopter aurait gravé une
|
|
141
141
|
régression d'accessibilité. Ils se rabattent sur `--muted` (5,55). Un seul
|
|
142
142
|
niveau intermédiaire est ajouté, `--ink-2` (#4a5468, contraste 7,05).
|
|
143
143
|
|
|
144
144
|
**L'échelle de texte.** Le relevé compte huit paliers répartis dans 5,5px,
|
|
145
|
-
avec des demi-pixels et des écarts d'un pixel
|
|
145
|
+
avec des demi-pixels et des écarts d'un pixel : de l'entropie d'utilitaires,
|
|
146
146
|
pas une échelle dessinée. Ils se regroupent en trois paliers de texte
|
|
147
147
|
(`--app-lg`, `--app`, `--app-sm`) et trois de labels (`--mono-lg`, `--mono`,
|
|
148
148
|
`--mono-sm`).
|
|
149
149
|
|
|
150
150
|
**Les filets et surfaces.** Cinq « nouveaux » tokens étaient des doublons
|
|
151
|
-
imperceptibles de tokens existants
|
|
151
|
+
imperceptibles de tokens existants : écart RVB de 1,4 à 6,8, sous le seuil de
|
|
152
152
|
perception. `--line-inner` → `--hairline`, `--line-soft` → `--line`,
|
|
153
153
|
`--row-hover` / `--paper-hover` / `--paper-warm` → `--panel`.
|
|
154
154
|
|
|
@@ -159,7 +159,7 @@ Au total, 32 tokens proposés se réduisent à 14.
|
|
|
159
159
|
**La barre supérieure.** La production pose `top: 53px` pour une barre de
|
|
160
160
|
52px, en supposant que son filet s'ajoute à la hauteur. Il ne s'y ajoute
|
|
161
161
|
pas : `box-sizing: border-box` le peint à l'intérieur. Ce pixel n'empilait
|
|
162
|
-
rien, il ouvrait une couture
|
|
162
|
+
rien, il ouvrait une couture : et la feuille portant son propre filet haut,
|
|
163
163
|
le trait apparaissait doublé. Corrigé : la feuille se cale à ras, sans filet
|
|
164
164
|
propre.
|
|
165
165
|
|
|
@@ -173,7 +173,7 @@ n'importe quelle police.
|
|
|
173
173
|
`--muted`. La nuance de température disparaît ; elle n'était reconductible
|
|
174
174
|
nulle part ailleurs.
|
|
175
175
|
|
|
176
|
-
### Enrobages
|
|
176
|
+
### Enrobages : hors relevé, assumés
|
|
177
177
|
|
|
178
178
|
Trois composants n'existent dans aucune source et sont pourtant livrés, car
|
|
179
179
|
leur absence rend le système inutilisable :
|
|
@@ -186,7 +186,7 @@ d'atteindre sa navigation. Le tracé du burger est dérivé ; les mesures
|
|
|
186
186
|
|
|
187
187
|
**La modale.** Mémoire n'en emploie aucune. Celle-ci est dérivée de la carte
|
|
188
188
|
et du tiroir, sans une valeur nouvelle. Elle existe parce que la règle du
|
|
189
|
-
projet en impose la forme
|
|
189
|
+
projet en impose la forme, panneau plafonné à 92vh qui défile en son sein,
|
|
190
190
|
et qu'à défaut chaque app en réinventerait une.
|
|
191
191
|
|
|
192
192
|
**La notification flottante.** Mémoire signale tout en place, par une alerte
|
|
@@ -207,7 +207,7 @@ des puces de filtre ou un interrupteur. Ces trois contrôles sont livrés,
|
|
|
207
207
|
dérivés strictement de `.zv-input`, et signalés comme tels dans le CSS.
|
|
208
208
|
|
|
209
209
|
Aucun jeu d'onglets non plus : une rangée d'onglets se construit avec
|
|
210
|
-
`.zv-seg-group` et `.zv-seg`. Un onglet **souligné** reste à faire
|
|
210
|
+
`.zv-seg-group` et `.zv-seg`. Un onglet **souligné** reste à faire : il
|
|
211
211
|
suppose d'arbitrer la couleur et l'épaisseur du trait actif.
|
|
212
212
|
|
|
213
213
|
## Les logos, ramenés à cinq
|
|
@@ -218,8 +218,8 @@ Mémoire et de la marque Zevra.
|
|
|
218
218
|
|
|
219
219
|
Les déclinaisons ont été retirées parce qu'elles ne suivaient plus les
|
|
220
220
|
marques. Le cas de Mémoire le montrait sans discussion : `memoire-glyph-navy`
|
|
221
|
-
et ses quatre lockups portaient encore un logo
|
|
222
|
-
|
|
221
|
+
et ses quatre lockups portaient encore un logo abandonné, une forme de ruban
|
|
222
|
+
plié, quand `ink`, `white` et `orig` portaient déjà le M actuel. Deux
|
|
223
223
|
marques cohabitaient dans la même galerie, et rien ne disait laquelle était
|
|
224
224
|
la bonne.
|
|
225
225
|
|
|
@@ -229,7 +229,7 @@ Ce que cela coûte, et qui reste à refaire :
|
|
|
229
229
|
24 px ;
|
|
230
230
|
- **les lockups** avec wordmark, pour les barres de navigation et les pieds
|
|
231
231
|
de page ;
|
|
232
|
-
- **l'inlinage vectoriel**. Un PNG s'inline en data-URI
|
|
232
|
+
- **l'inlinage vectoriel**. Un PNG s'inline en data-URI, l'admin la donne,
|
|
233
233
|
mais c'est 150 ko de texte là où un SVG en faisait 4.
|
|
234
234
|
|
|
235
235
|
Les fichiers retirés restent dans l'historique du dépôt : rien n'est perdu,
|
|
@@ -253,7 +253,7 @@ Ces éléments restent consultables dans `reference/`.
|
|
|
253
253
|
dur. Même chose pour `#8fd3a8` / `#f0a5ad`, les états sur fond sombre.
|
|
254
254
|
|
|
255
255
|
Trois rayons de surface pour un seul token : `--r-card` (16), la puce de
|
|
256
|
-
source (4px) et le rayon 18px de la carte verre de DesignSystem
|
|
256
|
+
source (4px) et le rayon 18px de la carte verre de DesignSystem, ce dernier
|
|
257
257
|
ramené à `--r-card`, comme le fait Mobile.html.
|
|
258
258
|
|
|
259
259
|
|
|
@@ -274,7 +274,7 @@ spectre. À rejuger sur pièces si la DA en décide autrement.
|
|
|
274
274
|
|
|
275
275
|
### Colonnes 5 et 7 (0.5.0)
|
|
276
276
|
|
|
277
|
-
Le commentaire de `layout.css` relevait « 3+9, 8+4, 6+6 »
|
|
277
|
+
Le commentaire de `layout.css` relevait « 3+9, 8+4, 6+6 » : mais le
|
|
278
278
|
prototype `experience.html` compose toutes ses scènes produit en `span 5`
|
|
279
279
|
(glyphe) + `span 7` (discours), et c'est cette répartition qui équilibre
|
|
280
280
|
l'air entre le visuel et le texte. `zv-col-5` et `zv-col-7` complètent donc
|
|
@@ -284,46 +284,46 @@ le relevé ; en 4+8, le texte nage et le glyphe s'exile au bord.
|
|
|
284
284
|
|
|
285
285
|
## L'angle vif (25/08/2026)
|
|
286
286
|
|
|
287
|
-
« Très carré, ça fait pro et inspire confiance »
|
|
287
|
+
« Très carré, ça fait pro et inspire confiance » : arbitrage DA rendu sur
|
|
288
288
|
pièces. Les quatre tokens de rayon (`--r-btn`, `--r-pill`, `--r-panel`,
|
|
289
289
|
`--r-card`) sont ramenés à `0` et RESTENT nommés : rendre de la rondeur à
|
|
290
290
|
l'une des quatre intentions doit rester une ligne à changer, pas une chasse
|
|
291
|
-
dans douze fichiers. Seul survit le rond de FORME
|
|
292
|
-
halo, bouton d'interrupteur exclu (passé au carré), roue incluse
|
|
291
|
+
dans douze fichiers. Seul survit le rond de FORME (pastille d'état, radio,
|
|
292
|
+
halo, bouton d'interrupteur exclu (passé au carré), roue incluse) parce
|
|
293
293
|
qu'il porte du sens là où le rayon ne portait que du style.
|
|
294
294
|
|
|
295
|
-
Cet arbitrage SUCCÈDE au « rayon des cartes
|
|
295
|
+
Cet arbitrage SUCCÈDE au « rayon des cartes, clos » ci-dessus : la
|
|
296
296
|
question tranchée là était la fidélité au relevé (16px contre 14 et 12),
|
|
297
297
|
celle-ci est une décision de DA qui lui passe devant.
|
|
298
298
|
|
|
299
299
|
---
|
|
300
300
|
|
|
301
|
-
## Compléments du 25/08/2026 (0.9.0)
|
|
301
|
+
## Compléments du 25/08/2026 (0.9.0) : les manques comblés, hors relevé
|
|
302
302
|
|
|
303
303
|
La demande : compléter le système au niveau d'une bibliothèque de référence
|
|
304
304
|
(états d'interaction, contrôles absents, formats), en restant dans la charte.
|
|
305
|
-
Tout ce qui suit est **HORS RELEVÉ**
|
|
306
|
-
chaque écart dit
|
|
305
|
+
Tout ce qui suit est **HORS RELEVÉ** (dessiné dans les tokens existants,
|
|
306
|
+
chaque écart dit) et se rejuge sur pièces avec la DA. Un seul token entre
|
|
307
307
|
(`--font-code`, voir « Bloc de code ») ; aucune couleur nouvelle.
|
|
308
308
|
|
|
309
309
|
### Les états de survol et d'appui des boutons
|
|
310
310
|
|
|
311
|
-
Aucune maquette ne donne d'état `:hover` ni `:active` aux trois boutons
|
|
311
|
+
Aucune maquette ne donne d'état `:hover` ni `:active` aux trois boutons :
|
|
312
312
|
elles sont figées. Un bouton sans réaction se lit comme un décor (l'argument
|
|
313
313
|
qui a déjà tranché pour `.zv-chrome-btn`). Arbitrages :
|
|
314
314
|
|
|
315
315
|
- **le survol assombrit, l'appui assombrit davantage et rassoit** : les
|
|
316
316
|
teintes sont dérivées par `color-mix` (l'idiome que le voile emploie
|
|
317
|
-
déjà) des couleurs que le bouton porte
|
|
317
|
+
déjà) des couleurs que le bouton porte déjà, le sommet de dégradé relevé
|
|
318
318
|
(`--zv-btn-haut`, #2b2bb4, sans token) et `--accent-deep`. Aucune teinte
|
|
319
319
|
nouvelle n'entre ;
|
|
320
320
|
- à l'appui, l'ombre TOMBE et le liseré s'éteint : le bouton se rassoit sur
|
|
321
|
-
la page au lieu de flotter
|
|
321
|
+
la page au lieu de flotter (aucun déplacement, c'est la lumière qui dit
|
|
322
322
|
l'enfoncement ;
|
|
323
323
|
- le fantôme prend le filet `--accent` et l'appui pose `--accent-soft` en
|
|
324
324
|
fond ; l'encre s'éclaircit d'un cran (un aplat sombre ne peut pas
|
|
325
325
|
s'assombrir visiblement) ;
|
|
326
|
-
- une seule transition, la courbe maison, 160 ms
|
|
326
|
+
- une seule transition, la courbe maison, 160 ms) coupée par
|
|
327
327
|
`prefers-reduced-motion` (base.css) ;
|
|
328
328
|
- **aucun déplacement** : pas de translateY. Les entrées du système montent
|
|
329
329
|
au défilement ; un bouton qui saute au survol raconterait autre chose.
|
|
@@ -333,7 +333,7 @@ qui a déjà tranché pour `.zv-chrome-btn`). Arbitrages :
|
|
|
333
333
|
La modale destructive porte son filet `--err`, mais son action de
|
|
334
334
|
confirmation restait un plein indigo : « Supprimer » s'y lisait comme
|
|
335
335
|
n'importe quelle action. `zv-btn--danger` pose l'aplat `--err`, sans
|
|
336
|
-
dégradé ni ombre indigo. **Il compte comme LE bouton plein de l'écran**
|
|
336
|
+
dégradé ni ombre indigo. **Il compte comme LE bouton plein de l'écran** : la
|
|
337
337
|
règle « un seul plein par page » ne distingue pas les couleurs, elle compte
|
|
338
338
|
les aplats.
|
|
339
339
|
|
|
@@ -341,15 +341,15 @@ les aplats.
|
|
|
341
341
|
|
|
342
342
|
Relevé de Mémoire, cette fois (le motif de balisage documenté dans
|
|
343
343
|
feedback.css) : pendant l'action, le libellé change (« Connexion… ») et le
|
|
344
|
-
bouton passe en `cursor-wait; opacity: .7`
|
|
345
|
-
quelles. Le paquet le code sur `[aria-busy="true"]
|
|
346
|
-
l'attente audible ne coûte alors rien
|
|
344
|
+
bouton passe en `cursor-wait; opacity: .7` : valeurs reprises telles
|
|
345
|
+
quelles. Le paquet le code sur `[aria-busy="true"]`, l'attribut qui rend
|
|
346
|
+
l'attente audible ne coûte alors rien, et la façade React l'expose en prop
|
|
347
347
|
`occupe`, qui pose `aria-disabled` et AVALE le clic plutôt que de poser
|
|
348
348
|
`disabled` : un `disabled` sortirait le bouton du parcours clavier au
|
|
349
349
|
moment précis où l'attente doit s'annoncer. Mémoire, elle, désactive ; cet
|
|
350
350
|
écart-là est assumé.
|
|
351
351
|
|
|
352
|
-
### L'onglet souligné
|
|
352
|
+
### L'onglet souligné : l'arbitrage attendu
|
|
353
353
|
|
|
354
354
|
La question ouverte depuis le relevé Mémoire est tranchée ainsi :
|
|
355
355
|
|
|
@@ -358,7 +358,7 @@ La question ouverte depuis le relevé Mémoire est tranchée ainsi :
|
|
|
358
358
|
couleur de l'action, comme l'entrée de nav courante. PAS le spectre : un
|
|
359
359
|
quatrième emploi n'existe pas.
|
|
360
360
|
- l'onglet inactif est `--ink-2` graisse 500, l'actif `--accent` graisse
|
|
361
|
-
600
|
|
361
|
+
600, la grammaire exacte de `.zv-seg` ;
|
|
362
362
|
- la rangée porte un filet bas `--line` d'un pixel que le trait actif
|
|
363
363
|
recouvre : l'onglet se lit comme posé SUR une ligne, pas souligné en l'air.
|
|
364
364
|
|
|
@@ -367,39 +367,39 @@ module ne livre rien ici » réservait. La rangée de puces (`Tabs` en variante
|
|
|
367
367
|
par défaut) reste le motif des filtres ; l'onglet souligné est celui des
|
|
368
368
|
VUES d'un même objet (Aperçu / Sources).
|
|
369
369
|
|
|
370
|
-
### Roue, squelette, infobulle
|
|
370
|
+
### Roue, squelette, infobulle : les trois manques assumés, livrés
|
|
371
371
|
|
|
372
372
|
feedback.css les refusait faute de matière première, et posait les
|
|
373
373
|
contraintes à respecter « le jour où la DA les tranche ». Ce jour : les
|
|
374
374
|
contraintes sont reprises telles quelles, les valeurs restantes sont
|
|
375
375
|
arbitrées ici.
|
|
376
376
|
|
|
377
|
-
- **La roue** (`zv-spinner`) : anneau de 16 px
|
|
377
|
+
- **La roue** (`zv-spinner`) : anneau de 16 px, la taille de `.zv-icon`,
|
|
378
378
|
trait de 2 (l'épaisseur du jeu d'icônes), piste `--accent-line`, secteur
|
|
379
379
|
`--accent`, rotation 0,8 s linéaire. La variante `--lg` fait 24 px, la
|
|
380
380
|
grille du jeu d'icônes. Elle ne REMPLACE pas `.zv-loading` : la phrase
|
|
381
381
|
qui dit le travail reste le motif par défaut, la roue est pour l'attente
|
|
382
382
|
courte et locale (un bouton, une cellule). `prefers-reduced-motion` la
|
|
383
|
-
fige
|
|
383
|
+
fige : l'anneau interrompu reste lisible immobile. Son libellé d'annonce
|
|
384
384
|
est un texte masqué (`.zv-sr-only`, base.css), pas un `aria-label` sur un
|
|
385
385
|
span vide, que tous les lecteurs n'annoncent pas.
|
|
386
|
-
- **Le squelette** (`zv-skeleton`) : `--hairline`, comme
|
|
386
|
+
- **Le squelette** (`zv-skeleton`) : `--hairline`, comme exigé, pas de
|
|
387
387
|
balayage spectral. Pulsation d'OPACITÉ (1 → 0,55, 1,8 s) : animer la
|
|
388
388
|
couleur ferait un dégradé de gris que la charte n'a pas. La géométrie
|
|
389
389
|
vient du consommateur (largeur/hauteur en style) ; seule la variante
|
|
390
390
|
`--text` fixe une hauteur d'un cadratin de texte courant.
|
|
391
|
-
- **L'infobulle** (`zv-tooltip`) : la combinaison imposée
|
|
392
|
-
filet `--line`, ombre `--shadow-menu`, texte `--app-sm`/`--ink-2`
|
|
391
|
+
- **L'infobulle** (`zv-tooltip`) : la combinaison imposée (panneau blanc,
|
|
392
|
+
filet `--line`, ombre `--shadow-menu`, texte `--app-sm`/`--ink-2`)
|
|
393
393
|
posée AU-DESSUS de la cible, centrée, à 6 px (le pointeur vient d'en bas
|
|
394
394
|
et la masquerait dessous ; `--bas` existe pour le rare cas inverse),
|
|
395
395
|
plafonnée à 240 px et, sous le seuil, à l'écran. L'apparition attend
|
|
396
|
-
300 ms
|
|
397
|
-
par icône
|
|
396
|
+
300 ms, sans quoi traverser une rangée d'icônes fait clignoter une bulle
|
|
397
|
+
par icône, la disparition est immédiate. Trois exigences de WCAG 1.4.13
|
|
398
398
|
sont tenues : elle reste tant que le pointeur ou le focus y sont, elle
|
|
399
399
|
est survolable (le masquage par `visibility` évite les zones fantômes),
|
|
400
|
-
et Échap la ferme
|
|
400
|
+
et Échap la ferme, la seule ligne de script du composant, posée sans
|
|
401
401
|
état. L'annonce passe par `aria-describedby`, câblée en identifiants
|
|
402
|
-
EXPLICITES comme le couple `htmlFor`/`id` de `Field`
|
|
402
|
+
EXPLICITES comme le couple `htmlFor`/`id` de `Field` : pas de `useId`,
|
|
403
403
|
qui interdirait le rendu en composant serveur. Réservée à un COMPLÉMENT
|
|
404
404
|
dispensable : une commande n'a pas le droit de cacher son nom dans une
|
|
405
405
|
infobulle.
|
|
@@ -411,7 +411,7 @@ Aucune source. Dérivé de l'interrupteur redessiné : bouton CARRÉ de 14 px
|
|
|
411
411
|
`--accent-deep` au survol ; piste de 3 px (la hauteur de `.zv-progress`),
|
|
412
412
|
`--line`, remplie en `--accent` jusqu'au curseur. **Pas le spectre** : la
|
|
413
413
|
barre de progression est un des trois emplois, le curseur n'en est pas un.
|
|
414
|
-
Le remplissage se calcule dans la façade (pourcentage de position
|
|
414
|
+
Le remplissage se calcule dans la façade (pourcentage de position : une
|
|
415
415
|
géométrie, comme la largeur de `Progress`, pas une valeur de charte).
|
|
416
416
|
|
|
417
417
|
### L'affixe de champ (`zv-affix`)
|
|
@@ -419,14 +419,14 @@ géométrie, comme la largeur de `Progress`, pas une valeur de charte).
|
|
|
419
419
|
« 30 », seul dans un champ, ne dit pas s'il s'agit de jours ou d'euros. La
|
|
420
420
|
grammaire est celle de `.zv-search`, le seul cadre-à-champ-nu du relevé :
|
|
421
421
|
cadre `--line`, champ nu dedans, allumage `:focus-within` identique.
|
|
422
|
-
L'affixe est en mono `--label`
|
|
422
|
+
L'affixe est en mono `--label` : une unité est un libellé, pas une donnée.
|
|
423
423
|
|
|
424
424
|
### Le dépliant (`zv-fold`)
|
|
425
425
|
|
|
426
426
|
La FAQ est le pliage de la vitrine ; l'applicatif n'en avait aucun (options
|
|
427
427
|
avancées, détail d'une ligne de journal). Construit sur `<details>` natif :
|
|
428
428
|
clavier et annonce viennent du navigateur, aucun JavaScript. Rangé dans
|
|
429
|
-
data.css
|
|
429
|
+
data.css : c'est du contenu qui se déplie, pas de la navigation. Le chevron
|
|
430
430
|
tourne, seule rotation du module, coupée par `prefers-reduced-motion`.
|
|
431
431
|
|
|
432
432
|
### La touche (`zv-kbd`) et le bloc de code (`zv-codeblock`)
|
|
@@ -435,11 +435,11 @@ Une documentation d'interface cite des raccourcis et des commandes ; le
|
|
|
435
435
|
paquet n'avait ni l'un ni l'autre.
|
|
436
436
|
|
|
437
437
|
- La touche : `--panel`, filet `--line` avec un bas de 2 px qui fait le
|
|
438
|
-
relief de la touche
|
|
438
|
+
relief de la touche, géométrie, pas ombre.
|
|
439
439
|
- **Le bloc de code introduit le seul token nouveau, `--font-code`**
|
|
440
440
|
(`ui-monospace / SF Mono / Menlo`). La raison est déjà écrite deux fois
|
|
441
441
|
dans le paquet : `--font-mono` (Space Grotesk) n'est PAS à chasse fixe, et
|
|
442
|
-
`tabular-nums` n'aligne que les chiffres
|
|
442
|
+
`tabular-nums` n'aligne que les chiffres, du code exige la chasse fixe
|
|
443
443
|
entière. Détourner `--font-mono` aurait menti ; un hexadécimal de pile de
|
|
444
444
|
polices en dur dans data.css aurait été la première valeur de charte hors
|
|
445
445
|
tokens. Le token est reflété dans le miroir JS, comme les autres.
|
|
@@ -454,7 +454,7 @@ extérieur et Échap : au composant, comme pour le menu.
|
|
|
454
454
|
|
|
455
455
|
### Le carrousel (`zv-carousel`)
|
|
456
456
|
|
|
457
|
-
La bande de logos de la landing défile déjà
|
|
457
|
+
La bande de logos de la landing défile déjà : sans composant, chaque page
|
|
458
458
|
réinvente le sien. Défilement natif `scroll-snap`, AUCUN JavaScript : pas de
|
|
459
459
|
flèches (elles exigeraient un script et un arbitrage de dessin), pas de
|
|
460
460
|
points. La barre de défilement est masquée, le clavier passe par le focus du
|
|
@@ -464,7 +464,7 @@ préfère une grille tant que le contenu tient.
|
|
|
464
464
|
### Le bandeau d'annonce (`zv-banner`)
|
|
465
465
|
|
|
466
466
|
La bande au-dessus de la barre de navigation (annonce de version,
|
|
467
|
-
information réglementaire). `--accent-soft` sur filet `--accent-line`
|
|
467
|
+
information réglementaire). `--accent-soft` sur filet `--accent-line` : le
|
|
468
468
|
ton information de l'alerte, en pleine largeur. Un seul par page, et
|
|
469
469
|
JAMAIS pour du marketing permanent : un bandeau qui ne part pas devient un
|
|
470
470
|
bourrelet de chrome.
|
|
@@ -475,13 +475,13 @@ Mémoire navigue au tiroir ; une application à trois ou quatre sections
|
|
|
475
475
|
navigue plus vite par une barre basse. N'existe que SOUS le point de
|
|
476
476
|
rupture (au-dessus, la colonne latérale est là), cibles `--tap`, icône +
|
|
477
477
|
micro-label, état courant `--accent` sur `aria-current="page"`. Cinq
|
|
478
|
-
entrées au maximum
|
|
478
|
+
entrées au maximum : au-delà, c'est le tiroir.
|
|
479
479
|
|
|
480
480
|
### Les formats sociaux (`zv-social`)
|
|
481
481
|
|
|
482
482
|
Les visuels LinkedIn/OpenGraph se refaisaient à la main, hors charte. Trois
|
|
483
|
-
gabarits FIGÉS en pixels
|
|
484
|
-
carré 1080×1080 (post), story 1080×1920
|
|
483
|
+
gabarits FIGÉS en pixels (paysage 1200×630 (OpenGraph et lien LinkedIn),
|
|
484
|
+
carré 1080×1080 (post), story 1080×1920) qui ne répondent à aucun point de
|
|
485
485
|
rupture : ce sont des planches d'export, pas des pages. Ils composent les
|
|
486
486
|
pièces existantes (bande manifeste, kicker, halo) et portent un pied
|
|
487
487
|
wordmark + adresse. La règle « jamais de faux contenu » s'y applique au
|
|
@@ -491,19 +491,19 @@ premier chef : un visuel social EST une publication.
|
|
|
491
491
|
|
|
492
492
|
Le jeu passe de 34 à 55. Les règles du jeu ne bougent pas : trait 2, bouts
|
|
493
493
|
et jonctions arrondis, grille 24, `currentColor`. Les ajouts comblent les
|
|
494
|
-
trous les plus fréquents
|
|
495
|
-
catalogue citait `telecharger` en exemple sans qu'elle existe
|
|
494
|
+
trous les plus fréquents (`chevron-haut` manquait au chevron près, et le
|
|
495
|
+
catalogue citait `telecharger` en exemple sans qu'elle existe) plus le
|
|
496
496
|
vocabulaire du métier : balance, livre-ouvert, diplome. Aucune icône
|
|
497
497
|
pleine, aucune couleur.
|
|
498
498
|
|
|
499
499
|
### La micro-entrée des blocs
|
|
500
500
|
|
|
501
501
|
Demande DA du 25/08 au soir : les blocs des pages INTÉRIEURES doivent
|
|
502
|
-
entrer en mouvement, « pas aussi poussé que sur la home
|
|
502
|
+
entrer en mouvement, « pas aussi poussé que sur la home, ça peut être
|
|
503
503
|
vite chiant à la longue ». Ce n'est PAS un dixième mouvement, c'est un
|
|
504
504
|
DOSAGE du premier : `zv-anim-rise--doux` reprend `zv-rise` à douze pixels
|
|
505
505
|
au lieu de trente-deux, sur une plage plus courte (5 → 30 % au lieu de
|
|
506
|
-
10 → 45 %)
|
|
506
|
+
10 → 45 %), le bloc est posé avant que l'œil ait fini d'arriver, et une
|
|
507
507
|
visite répétée ne le remarque plus. Mêmes règles que les neuf : la courbe
|
|
508
508
|
unique, l'état au repos est l'état final, rien hors du bloc `@supports`,
|
|
509
509
|
coupé par `prefers-reduced-motion`. La home garde l'entrée pleine ; c'est
|
|
@@ -511,7 +511,7 @@ elle la signature, le doux est le quotidien.
|
|
|
511
511
|
|
|
512
512
|
- **Le code de vérification (OTP)** : aucun écran du groupe n'en pose. Le
|
|
513
513
|
livrer supposerait d'inventer la gestion de focus inter-cases sans aucune
|
|
514
|
-
source
|
|
514
|
+
source : le jour où un écran d'authentification à code existe, c'est lui
|
|
515
515
|
qui tranche.
|
|
516
516
|
- **Le sélecteur de date** : le natif (`.zv-input` sur `type="date"`) reste
|
|
517
517
|
le motif ; un calendrier maison est un projet, pas un complément.
|
|
@@ -525,32 +525,32 @@ elle la signature, le doux est le quotidien.
|
|
|
525
525
|
### Le jeu d'icônes prend la signature de la charte
|
|
526
526
|
|
|
527
527
|
L'angle vif du 25/08 s'était arrêté aux surfaces : le TRAIT des icônes
|
|
528
|
-
restait « bouts et jonctions arrondis
|
|
528
|
+
restait « bouts et jonctions arrondis », le dialecte de toutes les
|
|
529
529
|
bibliothèques génériques. Un système qui vend le carré ne peut pas parler
|
|
530
530
|
rond dans ses pictogrammes. Arbitrage :
|
|
531
531
|
|
|
532
532
|
- **bouts FRANCS** (`square` : même emprise optique que le rond, la
|
|
533
533
|
silhouette change sans redessiner un seul tracé) et **jonctions VIVES**
|
|
534
|
-
(`miter`)
|
|
534
|
+
(`miter`), le réglage vit dans icons.css, les 55 tracés le suivent d'un
|
|
535
535
|
coup ;
|
|
536
536
|
- **les points d'encre passent au carré** : trois-points, ponctuation
|
|
537
537
|
d'info/aide/attention, taquets du registre. Dans une icône, le point est
|
|
538
|
-
une ponctuation, pas un état
|
|
538
|
+
une ponctuation, pas un état (le rond de FORME (pastille, radio) n'est
|
|
539
539
|
pas concerné ;
|
|
540
540
|
- **les coins de rectangles tombent à zéro** (rx=0) : archiver, cadenas,
|
|
541
541
|
calendrier, copier, courriel, imprimante, registre ;
|
|
542
|
-
- ce qui ne change PAS : les courbes de DESSIN
|
|
542
|
+
- ce qui ne change PAS : les courbes de DESSIN) l'épaule du dossier, la
|
|
543
543
|
panse de la base de données, les cercles d'objet (horloge, globe,
|
|
544
544
|
cocarde d'info). Le carré est un style de trait, pas une interdiction de
|
|
545
545
|
courbe.
|
|
546
546
|
|
|
547
|
-
Portée : tout ce qui trace dans le paquet suit
|
|
547
|
+
Portée : tout ce qui trace dans le paquet suit, le chevron du dépliant,
|
|
548
548
|
l'icône de dépôt, la coche de la pastille et celle de la case, le burger de
|
|
549
549
|
la vitrine. Le burger applicatif, relevé « extrémités franches », y était
|
|
550
550
|
déjà : le relevé avait la bonne intuition avant l'arbitrage.
|
|
551
551
|
|
|
552
552
|
**Correction embarquée** : `.zv-link-arrow svg` n'avait jamais déclaré son
|
|
553
|
-
trait
|
|
553
|
+
trait, ni `fill: none`, ni `stroke`. La flèche se rendait en TRIANGLE
|
|
554
554
|
PLEIN noir (le fût, aire nulle, disparaissait), pas dans la couleur du
|
|
555
555
|
lien. Le commentaire promettait le tracé depuis le premier jour ; le CSS le
|
|
556
556
|
pose enfin, au trait carré.
|
|
@@ -558,13 +558,13 @@ pose enfin, au trait carré.
|
|
|
558
558
|
### Les boutons à icône
|
|
559
559
|
|
|
560
560
|
`icone` / `iconeApres` sur Button et ButtonLink : l'icône vient du jeu, à
|
|
561
|
-
16 px, héritant de la couleur du
|
|
561
|
+
16 px, héritant de la couleur du libellé, la fournir en prop évite les
|
|
562
562
|
tracés recopiés à la main (la faute qui avait produit trois flèches
|
|
563
|
-
différentes). `carre` est le bouton d'action à icône SEULE
|
|
564
|
-
en compact
|
|
563
|
+
différentes). `carre` est le bouton d'action à icône SEULE (48×48, 40×40
|
|
564
|
+
en compact) pour l'envoi d'un composeur ou l'action unique d'une barre.
|
|
565
565
|
Le libellé accessible y est OBLIGATOIRE et s'écrit pour l'ACTION. Ne pas
|
|
566
566
|
confondre : `IconButton` est le chrome nu (40 px, sans cadre),
|
|
567
|
-
`ChromeButton` la croix bordée (26 px)
|
|
567
|
+
`ChromeButton` la croix bordée (26 px), le carré est une action, il en a
|
|
568
568
|
le poids et l'aplat.
|
|
569
569
|
|
|
570
570
|
### La tuile d'icône (`zv-icon-tile`)
|
|
@@ -572,13 +572,13 @@ le poids et l'aplat.
|
|
|
572
572
|
La pastille carrée qui porte une icône devant un argument de la vitrine
|
|
573
573
|
(liste de garanties, grille d'atouts) : 40 px, fond `--accent-soft`, filet
|
|
574
574
|
`--accent-line`, icône `--accent`. HORS RELEVÉ, dessinée dans les tokens.
|
|
575
|
-
Décorative par défaut
|
|
575
|
+
Décorative par défaut : c'est le libellé voisin qui nomme. Une par
|
|
576
576
|
argument, jamais en décor isolé.
|
|
577
577
|
|
|
578
578
|
### L'icône dans la colonne latérale
|
|
579
579
|
|
|
580
580
|
Aucune prop nouvelle : `num` sur SideLink accepte déjà « rang mono ou
|
|
581
|
-
glyphe
|
|
581
|
+
glyphe », le relevé Mémoire y posait le ⚙ du panneau admin, et la colonne
|
|
582
582
|
fixe de 16 px tient l'alignement. Ce qui manquait, c'était l'EXEMPLE : le
|
|
583
583
|
catalogue montre désormais `num={<Icon nom="reglages" />}`. Rang OU icône,
|
|
584
584
|
jamais les deux.
|
|
@@ -593,7 +593,7 @@ refus est argumenté et écrit : il tient, la fournée ne le rouvre pas.
|
|
|
593
593
|
|
|
594
594
|
Constat d'usage sur le site vitrine : les entrées pilotées par
|
|
595
595
|
`animation-timeline: view()` rejouaient À L'ENVERS dès que le lecteur
|
|
596
|
-
remontait
|
|
596
|
+
remontait, les vidéos, les cartes d'articles, les grilles entières
|
|
597
597
|
disparaissaient sous ses yeux, y compris en pleine lecture d'un article. Et
|
|
598
598
|
une grille haute, jamais « contenue » dans le viewport, n'atteignait jamais
|
|
599
599
|
son état posé : la section paraissait vide.
|
|
@@ -601,7 +601,7 @@ son état posé : la section paraissait vide.
|
|
|
601
601
|
Arbitrage : **une révélation par visite**. Les sept entrées deviennent des
|
|
602
602
|
animations temporelles courtes, armées par `html.zv-motion` (posé par
|
|
603
603
|
`motion.js`, importable en `@zevra/ui/motion.js`) et libérées par `.zv-in`
|
|
604
|
-
à l'entrée au viewport
|
|
604
|
+
à l'entrée au viewport : une fois, puis plus jamais. Sans JavaScript, rien
|
|
605
605
|
n'est armé : la page s'affiche complète, même dégradation douce qu'avant.
|
|
606
606
|
Les @keyframes remontent au niveau racine pour qu'un échafaudage de scènes
|
|
607
607
|
(l'expérience épinglée d'une home) puisse les re-brancher sur ses timelines
|
|
@@ -609,12 +609,12 @@ nommées : il pose `data-zv-motion-skip` sur ses scènes et motion.js n'y
|
|
|
609
609
|
touche pas.
|
|
610
610
|
|
|
611
611
|
Ce qui RESTE scroll-piloté, et doit le rester : la barre de progression
|
|
612
|
-
(`zv-anim-progress`) et le point d'étape (`zv-anim-dot-active`)
|
|
612
|
+
(`zv-anim-progress`) et le point d'étape (`zv-anim-dot-active`), suivre la
|
|
613
613
|
position de lecture est leur raison d'être, avancer et reculer avec elle
|
|
614
614
|
est leur contrat.
|
|
615
615
|
|
|
616
616
|
Corrigé du même mouvement : dans `.zv-band`, l'emphase `strong` de
|
|
617
|
-
zv-body/zv-lead posait l'encre (--ink) sur le navy
|
|
617
|
+
zv-body/zv-lead posait l'encre (--ink) sur le navy, invisible. Elle hérite
|
|
618
618
|
désormais de la couleur ambiante, la graisse seule la distingue.
|
|
619
619
|
|
|
620
620
|
## La page a une largeur (27/08/2026, 0.12.4)
|
|
@@ -622,22 +622,22 @@ désormais de la couleur ambiante, la graisse seule la distingue.
|
|
|
622
622
|
Le relevé de la passation vivait sur une trame de 1440 et les enveloppes
|
|
623
623
|
n'étaient que du retrait : `zv-gutter` posait 72 px de padding et laissait
|
|
624
624
|
le contenu suivre l'écran. Sur un moniteur large, le hero collait au bord
|
|
625
|
-
gauche pendant que la nav
|
|
625
|
+
gauche pendant que la nav, bornée localement par le site vitrine, restait
|
|
626
626
|
centrée : deux largeurs de vérité sur la même page.
|
|
627
627
|
|
|
628
628
|
Arbitrage : un token `--page-max` (1440px, la trame du relevé) et les trois
|
|
629
629
|
enveloppes de gutter se centrent au-delà ; `zv-inset-x` garde ses 72 px de
|
|
630
630
|
marge minimale ET se centre dès que l'écran offre plus (max()). En dessous
|
|
631
|
-
de 1440, rien ne bouge
|
|
631
|
+
de 1440, rien ne bouge : le rendu du relevé est inchangé au pixel. La
|
|
632
632
|
rustine locale du site vitrine devient inutile.
|
|
633
633
|
|
|
634
634
|
## Le mouvement baisse d'un ton (27/08/2026, 0.12.5)
|
|
635
635
|
|
|
636
|
-
Retour d'usage : au défilement, les entrées « poussaient » trop
|
|
636
|
+
Retour d'usage : au défilement, les entrées « poussaient » trop, l'effet
|
|
637
637
|
de parallaxe prenait le pas sur la lecture. Les amplitudes sont divisées
|
|
638
638
|
par deux, les intentions conservées : zv-rise 32 → 16 px, son dosage doux
|
|
639
639
|
12 → 8 px, le glyphe 40 px/0,70 → 24 px/0,85, le pop 0,60 → 0,80. La
|
|
640
|
-
convergence de la home et le filet ne bougent pas
|
|
640
|
+
convergence de la home et le filet ne bougent pas : l'une est la signature,
|
|
641
641
|
l'autre ne translate rien. Les durées et la courbe restent celles de la
|
|
642
642
|
passation : c'est la distance qui fatiguait, pas le tempo.
|
|
643
643
|
|
|
@@ -645,8 +645,8 @@ passation : c'est la distance qui fatiguait, pas le tempo.
|
|
|
645
645
|
|
|
646
646
|
Deux produits à venir reçoivent leur glyphe : le P de Plume (l'éditeur
|
|
647
647
|
juridique) et le S de Supernovia (la création de contenu sourcée). Même
|
|
648
|
-
facture que les cinq autres
|
|
649
|
-
détouré remonté à 512px sur le grand côté
|
|
648
|
+
facture que les cinq autres (le ruban de la charte, rendu couleur, PNG
|
|
649
|
+
détouré remonté à 512px sur le grand côté) et même convention de nommage
|
|
650
650
|
`<produit>-<forme>-<nuance>.png`.
|
|
651
651
|
|
|
652
652
|
Le registre des produits du script d'index les connaît désormais : ajouter
|
|
@@ -660,7 +660,7 @@ monochrome, pas de lockup. Sur navy ou sous 24px, ils ne conviennent pas.
|
|
|
660
660
|
|
|
661
661
|
Un lockup ne se réduit pas. Celui de Zevra mesure 555×200, sa capitale
|
|
662
662
|
70px, et le site l'affichait à **14,7px de capitale** dans la barre de
|
|
663
|
-
navigation, 10,5 sur téléphone, 9,8 dans le pied de page
|
|
663
|
+
navigation, 10,5 sur téléphone, 9,8 dans le pied de page : une réduction
|
|
664
664
|
de près de cinq fois. Chaque fût tombait alors sur une fraction de pixel
|
|
665
665
|
et recevait sa propre dose de lissage : le mot virait au gris, et le V,
|
|
666
666
|
seul à n'avoir aucun fût vertical sur quoi s'aligner, semblait flotter.
|
|
@@ -683,7 +683,7 @@ le registre décrivait sans qu'aucun fichier ne les fournisse. La nuance
|
|
|
683
683
|
|
|
684
684
|
Relevées au pixel sur le lockup d'origine : la marque vaut **2,86 fois**
|
|
685
685
|
la capitale, l'écart entre les deux **0,64 fois**, et les deux pièces se
|
|
686
|
-
**centrent l'une sur l'autre
|
|
686
|
+
**centrent l'une sur l'autre**, elles ne partagent pas de ligne de base.
|
|
687
687
|
Tout se pilote par `--zv-cap`, qui EST la hauteur de capitale : le viewBox
|
|
688
688
|
du SVG a 100 unités de haut pour la capitale, si bien qu'une hauteur CSS
|
|
689
689
|
posée dessus se lit directement.
|
|
@@ -701,16 +701,16 @@ Le fichier vectoriel d'origine n'a pas été retrouvé : le tracé est
|
|
|
701
701
|
reconstruit depuis le bitmap, par ajustement de droites sur le contour
|
|
702
702
|
(les lettres sont géométriques, leurs côtés sont des segments). Il est
|
|
703
703
|
fidèle à **0,1 % en largeur** et mesurablement plus lisible que le bitmap
|
|
704
|
-
partout où le site le pose
|
|
704
|
+
partout où le site le pose : mais il porte les approximations du relevé.
|
|
705
705
|
|
|
706
|
-
**Réservé à l'écran, jusqu'à 120px de capitale.** Au-delà
|
|
707
|
-
impression
|
|
706
|
+
**Réservé à l'écran, jusqu'à 120px de capitale.** Au-delà (grand format,
|
|
707
|
+
impression) exiger le fichier d'origine, qui remplacera celui-ci sans
|
|
708
708
|
changer une ligne de code.
|
|
709
709
|
|
|
710
710
|
### Au passage : le commentaire du token était faux
|
|
711
711
|
|
|
712
712
|
`--font-display` annonçait « titres 200-400, wordmarks 600 ». Mesure faite,
|
|
713
|
-
le mot du lockup a un rapport fût/capitale de 0,129, soit du **400
|
|
713
|
+
le mot du lockup a un rapport fût/capitale de 0,129, soit du **400**, et
|
|
714
714
|
surtout il n'est PAS dessiné en Outfit : à capitale égale, son E est 20 %
|
|
715
715
|
plus étroit, son V 24 %, son A 26 %. Seul le Z coïncide. La mention a été
|
|
716
716
|
retirée plutôt que corrigée : le mot n'est pas de la typographie, c'est un
|
|
@@ -720,7 +720,7 @@ tracé.
|
|
|
720
720
|
|
|
721
721
|
La nav du site Zevra portait, dans son propre dépôt, cent lignes de CSS et
|
|
722
722
|
un script que le paquet ne connaissait pas : menus déroulants, sélecteur de
|
|
723
|
-
langue, tiroir groupé, chrome givré. Tout cela n'a rien de propre à Zevra
|
|
723
|
+
langue, tiroir groupé, chrome givré. Tout cela n'a rien de propre à Zevra :
|
|
724
724
|
c'est ce que demande n'importe quelle vitrine dès qu'elle a plus de quatre
|
|
725
725
|
liens. Le paquet le reprend.
|
|
726
726
|
|
|
@@ -736,7 +736,7 @@ Son voile était écrit en `rgba(245, 246, 250, …)`, c'est-à-dire hors token
|
|
|
736
736
|
`color-mix` sur le token.
|
|
737
737
|
|
|
738
738
|
⚠️ `backdrop-filter` fait du chrome le bloc conteneur de tout descendant en
|
|
739
|
-
position fixe. Le tiroir doit donc vivre EN DEHORS, en frère
|
|
739
|
+
position fixe. Le tiroir doit donc vivre EN DEHORS, en frère : dedans, il
|
|
740
740
|
serait rogné à la hauteur de la barre. C'est écrit dans le CSS, à l'endroit
|
|
741
741
|
où l'on se tromperait.
|
|
742
742
|
|
|
@@ -744,12 +744,12 @@ où l'on se tromperait.
|
|
|
744
744
|
|
|
745
745
|
`:hover` et `:focus-within` : accessible au clavier, rien à hydrater, la
|
|
746
746
|
barre reste rendue au serveur. Un pont invisible couvre l'interstice entre
|
|
747
|
-
l'entrée et son panneau
|
|
747
|
+
l'entrée et son panneau : sans lui le survol se rompt en descendant, et le
|
|
748
748
|
menu se referme sous le curseur.
|
|
749
749
|
|
|
750
750
|
Piège consigné : le déclencheur porte `.zv-navlink` pour se rendre comme un
|
|
751
751
|
lien simple. Un `font: inherit`, réflexe habituel pour dénuder un bouton,
|
|
752
|
-
remet la fonte du conteneur (16px/400) là où `.zv-navlink` pose 14px/500
|
|
752
|
+
remet la fonte du conteneur (16px/400) là où `.zv-navlink` pose 14px/500 :
|
|
753
753
|
les entrées à menu deviennent alors plus grosses que les autres. C'est
|
|
754
754
|
arrivé, et ça s'est vu.
|
|
755
755
|
|
|
@@ -757,21 +757,21 @@ arrivé, et ça s'est vu.
|
|
|
757
757
|
|
|
758
758
|
Le seuil de bascule vers le tiroir est à 767px, réglé sur la nav de
|
|
759
759
|
référence : quatre liens simples. Une nav qui porte cinq familles à menu,
|
|
760
|
-
un sélecteur de langue et un appel à l'action déborde bien avant
|
|
760
|
+
un sélecteur de langue et un appel à l'action déborde bien avant, mesuré :
|
|
761
761
|
entre 768 et 1150px, le logo passe SOUS la première entrée.
|
|
762
762
|
|
|
763
763
|
`.zv-nav--riche` déplace le seuil à 1150px, **pour la barre seulement**. Ce
|
|
764
764
|
n'est pas un second gabarit : le reste de la page garde l'unique frontière
|
|
765
765
|
de la charte. Le test d'intégrité l'accepte désormais, et un second test
|
|
766
|
-
vérifie qu'aucun sélecteur étranger ne se glisse dans ces blocs
|
|
766
|
+
vérifie qu'aucun sélecteur étranger ne se glisse dans ces blocs : une
|
|
767
767
|
frontière arbitrée pour un composant ne doit pas devenir, par commodité, le
|
|
768
768
|
gabarit de tout le monde.
|
|
769
769
|
|
|
770
770
|
### Le tiroir a son module
|
|
771
771
|
|
|
772
772
|
`@zevra/ui/nav.js`, sur le modèle de `motion.js` : il pose et retire
|
|
773
|
-
`data-open`, tient `aria-expanded`, ferme sur Échap. Le reste
|
|
774
|
-
glissade, verrouillage du défilement
|
|
773
|
+
`data-open`, tient `aria-expanded`, ferme sur Échap. Le reste (voile,
|
|
774
|
+
glissade, verrouillage du défilement) était déjà dans `overlays.css` et se
|
|
775
775
|
joue sur cet attribut seul.
|
|
776
776
|
|
|
777
777
|
Il travaille par délégation sur le document plutôt qu'en câblant chaque
|
|
@@ -781,14 +781,14 @@ client.
|
|
|
781
781
|
|
|
782
782
|
Déclaré dans `sideEffects`. C'est la panne de la 0.12.0 : `motion.js` était
|
|
783
783
|
exporté et correct, mais `sideEffects: ["*.css"]` autorisait le bundler à
|
|
784
|
-
l'élaguer
|
|
784
|
+
l'élaguer, tout paraissait câblé et rien ne s'animait. Un test le garde
|
|
785
785
|
maintenant pour tout module JS livré.
|
|
786
786
|
|
|
787
787
|
### Le piège de l'ordre, trouvé à la première intégration (0.15.1)
|
|
788
788
|
|
|
789
789
|
Le bloc des menus déroulants était dans `layout.css`. Le panneau d'une
|
|
790
|
-
entrée porte DEUX classes
|
|
791
|
-
la surcharge
|
|
790
|
+
entrée porte DEUX classes, `.zv-menu` du paquet et `.zv-navdd__menu` qui
|
|
791
|
+
la surcharge, et elles ont la même spécificité : c'est l'ordre de
|
|
792
792
|
chargement qui tranche. `index.css` importe `layout.css` AVANT
|
|
793
793
|
`navigation.css`, donc `.zv-menu { display: flex }` gagnait et les trois
|
|
794
794
|
menus de la barre restaient ouverts en permanence.
|
|
@@ -803,7 +803,7 @@ après elle.
|
|
|
803
803
|
La table des matières d'une page longue, posée sur le côté : un libellé, un
|
|
804
804
|
point, et le point courant qui s'allume. Elle vivait dans le site Zevra,
|
|
805
805
|
sous le nom de son échafaudage de scènes. C'est le manque qui avait déjà
|
|
806
|
-
été signalé pour les longues lectures
|
|
806
|
+
été signalé pour les longues lectures : il est comblé.
|
|
807
807
|
|
|
808
808
|
Elle NAVIGUE et elle SUIT, et il faut les deux. Un rail qui suit sans
|
|
809
809
|
naviguer est un décor qui occupe la marge ; un rail qui navigue sans suivre
|
|
@@ -812,7 +812,7 @@ oblige à se demander où l'on en est.
|
|
|
812
812
|
### Le suivi lit la position, il n'observe pas les intersections
|
|
813
813
|
|
|
814
814
|
Premier réflexe : un IntersectionObserver réduit à la bande centrale du
|
|
815
|
-
viewport. Il tombe sur les rails réels
|
|
815
|
+
viewport. Il tombe sur les rails réels : leurs ancres sont souvent des
|
|
816
816
|
points MATÉRIELS de 1 px posés en tête de section, et un point de 1 px ne
|
|
817
817
|
traverse une bande de 10 % que pendant quelques images. Un défilement
|
|
818
818
|
rapide saute la bande entière, et l'entrée ne s'allume jamais.
|
|
@@ -820,7 +820,7 @@ rapide saute la bande entière, et l'entrée ne s'allume jamais.
|
|
|
820
820
|
`rail.js` lit donc la position : l'entrée courante est la DERNIÈRE dont
|
|
821
821
|
l'ancre a passé la ligne de lecture (45 % de la hauteur, un peu au-dessus
|
|
822
822
|
du milieu, là où l'œil se pose). Déterministe, quelle que soit la vitesse.
|
|
823
|
-
Une lecture par image au plus
|
|
823
|
+
Une lecture par image au plus : le défilement émet bien plus souvent que
|
|
824
824
|
l'écran ne se rafraîchit, et chaque lecture coûte un reflow.
|
|
825
825
|
|
|
826
826
|
### Le balisage fait foi
|
|
@@ -828,7 +828,7 @@ l'écran ne se rafraîchit, et chaque lecture coûte un reflow.
|
|
|
828
828
|
Le module ne prend aucune liste : il lit les `<a href="#…">` du rail et
|
|
829
829
|
résout chaque cible. Rien à tenir à jour en double, donc rien à faire
|
|
830
830
|
diverger. Une ancre qui ne résout pas laisse son entrée cliquable et sort
|
|
831
|
-
du suivi, plutôt que de décaler toutes les suivantes
|
|
831
|
+
du suivi, plutôt que de décaler toutes les suivantes : c'est le décalage
|
|
832
832
|
silencieux qui coûte cher.
|
|
833
833
|
|
|
834
834
|
Sans le module, le rail navigue toujours : ce sont des ancres HTML. La
|
|
@@ -836,7 +836,7 @@ dégradation est douce, la page n'est jamais cassée.
|
|
|
836
836
|
|
|
837
837
|
### Il demande de la place
|
|
838
838
|
|
|
839
|
-
Sous le point de rupture il disparaît
|
|
839
|
+
Sous le point de rupture il disparaît : un rail fixe sur un téléphone se
|
|
840
840
|
pose sur la lecture. Au-dessus, c'est la mesure de la page qui décide, et
|
|
841
841
|
le paquet ne peut pas la connaître : une page dont le contenu court d'un
|
|
842
842
|
bord à l'autre jusqu'à 1100px gagnera à relever le seuil chez elle. C'est
|
|
@@ -852,13 +852,13 @@ constat vient du ruban de la home, qui passait derrière et le délavait.
|
|
|
852
852
|
## Les favicons (26/08/2026)
|
|
853
853
|
|
|
854
854
|
Chaque produit reçoit son jeu de favicons, composé depuis le glyphe couleur
|
|
855
|
-
du registre
|
|
855
|
+
du registre : `logos/favicon/<produit>/`, publié avec le paquet comme le
|
|
856
856
|
reste de `logos/`.
|
|
857
857
|
|
|
858
858
|
**Dérogation assumée à la règle « mono sous 24 px ».** Cette règle existe
|
|
859
859
|
pour l'encre posée SUR une page de charte, dont on maîtrise le fond. Un
|
|
860
860
|
favicon vit ailleurs : sur un onglet au fond inconnu (clair ou sombre selon
|
|
861
|
-
le navigateur), au milieu des favicons couleur de tous les autres sites
|
|
861
|
+
le navigateur), au milieu des favicons couleur de tous les autres sites,
|
|
862
862
|
c'est la couleur qui y est l'identifiant, et une version encre y disparaît
|
|
863
863
|
un onglet sur deux. Le glyphe couleur reste donc couleur, à toutes les
|
|
864
864
|
tailles.
|
|
@@ -867,14 +867,14 @@ tailles.
|
|
|
867
867
|
foi), puis centré sur un canevas carré :
|
|
868
868
|
|
|
869
869
|
- `favicon.ico` (16, 32, 48 en PNG embarqués), `icon-192.png` et
|
|
870
|
-
`icon-512.png` : fond TRANSPARENT, glyphe à 86 % du canevas
|
|
870
|
+
`icon-512.png` : fond TRANSPARENT, glyphe à 86 % du canevas, la marge
|
|
871
871
|
évite que les pointes touchent le bord de l'onglet ;
|
|
872
|
-
- `apple-touch-icon.png` (180) : fond OPAQUE `--paper` et glyphe à 64
|
|
872
|
+
- `apple-touch-icon.png` (180) : fond OPAQUE `--paper` et glyphe à 64 %,
|
|
873
873
|
Apple aplatit la transparence en noir et arrondit les coins lui-même,
|
|
874
874
|
l'icône doit donc apporter son fond et laisser l'air que le masque
|
|
875
875
|
mangera.
|
|
876
876
|
|
|
877
|
-
Le script est `scripts/build-favicons.py
|
|
877
|
+
Le script est `scripts/build-favicons.py`, Python et non Node comme les
|
|
878
878
|
autres : la composition raster exige un canal alpha que `sips` ne sait pas
|
|
879
879
|
préserver au recadrage, et Pillow est le seul outil d'image du poste. Les
|
|
880
880
|
fichiers produits sont COMMITTÉS, comme le sprite : un consommateur n'a
|
|
@@ -886,7 +886,7 @@ aucune étape de build à exécuter. Relancer après tout changement de glyphe.
|
|
|
886
886
|
|
|
887
887
|
Jusqu'ici le système ne savait afficher aucune image. Pas une déclaration
|
|
888
888
|
`aspect-ratio`, pas un `object-fit`, pas un sélecteur `img` dans les quatorze
|
|
889
|
-
modules
|
|
889
|
+
modules : les seules images qu'il connaissait étaient ses propres logos et la
|
|
890
890
|
planche d'export social, figée en pixels. Chaque produit a donc réécrit le
|
|
891
891
|
même cadre : campus quatre fois (couverture de parcours, carte scindée, attente
|
|
892
892
|
de vidéo, grille du fil), la vitrine autant.
|
|
@@ -906,8 +906,8 @@ ainsi qu'une bibliothèque finit avec dix-sept rapports dont trois servent.
|
|
|
906
906
|
**L'image RECOUVRE par défaut** (`object-fit: cover`) : c'est le seul
|
|
907
907
|
comportement qui garantisse un cadre plein quelle que soit la source, et une
|
|
908
908
|
grille de cartes dont les couvertures ne s'alignent pas se voit
|
|
909
|
-
immédiatement. `.zv-media--contient` existe pour le cas inverse
|
|
910
|
-
schéma, une pièce qu'on ne peut pas rogner
|
|
909
|
+
immédiatement. `.zv-media--contient` existe pour le cas inverse (un logo, un
|
|
910
|
+
schéma, une pièce qu'on ne peut pas rogner) et pose alors le papier derrière,
|
|
911
911
|
puisqu'il restera du vide.
|
|
912
912
|
|
|
913
913
|
**Le fond est posé, pas laissé transparent.** Une image qui tarde, échoue ou
|
|
@@ -932,7 +932,7 @@ Quatorze icônes entrent : `lecture`, `pause`, `rembobiner`, `avancer`,
|
|
|
932
932
|
Le jeu en comptait cinquante-cinq et n'en portait aucune de lecture ni
|
|
933
933
|
d'édition. Conséquence directe : tout produit qui pose un lecteur ou un
|
|
934
934
|
éditeur recopie des tracés d'une autre bibliothèque, avec une graisse et des
|
|
935
|
-
bouts de trait qui ne sont pas les nôtres
|
|
935
|
+
bouts de trait qui ne sont pas les nôtres, campus en avait une quarantaine.
|
|
936
936
|
Les nouvelles suivent la signature du jeu : grille de 24, trait de 2, bouts
|
|
937
937
|
francs. `lecture` et `pause` sont pleines plutôt que filaires, parce qu'à
|
|
938
938
|
16 px un triangle en fil de fer se lit mal sur un fond d'image.
|
|
@@ -952,7 +952,7 @@ l'entoure et l'anneau de mise au point du groupe existaient déjà. Un second
|
|
|
952
952
|
cadre aurait dérivé au premier réglage.
|
|
953
953
|
|
|
954
954
|
**Le bouton est un vrai `<button type="button">`.** Posé sur un `<span>`, il
|
|
955
|
-
n'est ni atteignable au clavier ni annoncé
|
|
955
|
+
n'est ni atteignable au clavier ni annoncé : et sans le `type`, il envoie le
|
|
956
956
|
formulaire. Son libellé change avec l'état (« Afficher » / « Masquer »)
|
|
957
957
|
plutôt que de rester fixe : une icône seule ne dit pas ce qui va se passer.
|
|
958
958
|
`aria-pressed` porte l'état pour les lecteurs d'écran.
|
|
@@ -964,13 +964,13 @@ côté navigateur pour un champ de saisie.
|
|
|
964
964
|
**L'œil natif du navigateur est masqué** (`::-ms-reveal`) : sinon deux boutons
|
|
965
965
|
voisins font la même chose, dont un seul suit la charte.
|
|
966
966
|
|
|
967
|
-
Vient avec l'icône `oeil-barre`, le pendant qui manquait à `oeil`
|
|
967
|
+
Vient avec l'icône `oeil-barre`, le pendant qui manquait à `oeil` : sans elle,
|
|
968
968
|
la bascule n'a pas de second état à montrer.
|
|
969
969
|
|
|
970
970
|
## Ce que l'intégration de mcp-factory a révélé (27/08/2026, 0.19.0)
|
|
971
971
|
|
|
972
|
-
Six défauts trouvés en migrant une application entière
|
|
973
|
-
zones
|
|
972
|
+
Six défauts trouvés en migrant une application entière (trente pages, six
|
|
973
|
+
zones) vers le paquet. Aucun n'était visible en planche : tous se voient à
|
|
974
974
|
l'usage, et plusieurs ne se voient qu'à un ÉTAT. Ils avaient tous été
|
|
975
975
|
rattrapés dans le `globals.css` de l'app, et memoire en portait déjà trois
|
|
976
976
|
des siens : un correctif recopié dans deux apps est un défaut du paquet qui
|
|
@@ -979,14 +979,14 @@ s'ignore.
|
|
|
979
979
|
### `.zv-em` penchait
|
|
980
980
|
|
|
981
981
|
`Em` rend un vrai `<em>`, et `.zv-em` ne déclarait que la couleur et la
|
|
982
|
-
graisse
|
|
982
|
+
graisse, c'est bien ce que demande la charte : « la deuxième moitié de
|
|
983
983
|
phrase d'un titre bascule en indigo et prend un cran de graisse ». Mais le
|
|
984
984
|
navigateur, lui, penche les `<em>` par défaut, et Outfit n'a **aucune
|
|
985
985
|
italique** chargée : il en fabriquait donc une oblique de synthèse. Sur la
|
|
986
986
|
page pilier de mcp-factory, la seconde moitié du `<h1>` partait en faux
|
|
987
987
|
italique à 76 px, sur le premier écran.
|
|
988
988
|
|
|
989
|
-
`.zv-inset em` remettait déjà `font-style: normal`
|
|
989
|
+
`.zv-inset em` remettait déjà `font-style: normal` : la règle existait donc
|
|
990
990
|
au paquet, mais seulement là où l'on avait rencontré le problème. Elle passe
|
|
991
991
|
sur `.zv-em`, qui est l'endroit qui en a besoin par construction.
|
|
992
992
|
|
|
@@ -995,11 +995,11 @@ sur `.zv-em`, qui est l'endroit qui en a besoin par construction.
|
|
|
995
995
|
C'était la **seule** classe interactive du paquet sans état désactivé.
|
|
996
996
|
`.zv-btn`, `.zv-chrome-btn`, `.zv-menu__item`, `.zv-pager__arrow`,
|
|
997
997
|
`.zv-range` et tous les champs en ont un, et plusieurs neutralisent
|
|
998
|
-
explicitement le survol
|
|
998
|
+
explicitement le survol : leurs auteurs savaient donc que `:hover`
|
|
999
999
|
s'applique encore à un bouton désactivé.
|
|
1000
1000
|
|
|
1001
|
-
Conséquence à l'usage : la corbeille de révocation d'une clé API unique
|
|
1002
|
-
cas de tout compte à sa première visite
|
|
1001
|
+
Conséquence à l'usage : la corbeille de révocation d'une clé API unique, le
|
|
1002
|
+
cas de tout compte à sa première visite, se rendait exactement comme une
|
|
1003
1003
|
corbeille active, curseur main compris, et s'allumait au survol comme si
|
|
1004
1004
|
elle allait agir. Rien dans le rendu ne disait que l'action était fermée.
|
|
1005
1005
|
|
|
@@ -1016,13 +1016,13 @@ couleur. memoire le rattrapait déjà.
|
|
|
1016
1016
|
|
|
1017
1017
|
**On dérive donc le sommet de `--accent`.** C'est un écart assumé au relevé :
|
|
1018
1018
|
pour la charte par défaut, l'écart entre `#2b2bb4` et `#2a2aa8` est d'un
|
|
1019
|
-
point de bleu
|
|
1019
|
+
point de bleu, invisible. La valeur relevée reste écrite en commentaire,
|
|
1020
1020
|
pour que l'arbitrage se relise.
|
|
1021
1021
|
|
|
1022
|
-
### `.zv-header` perdait son flou
|
|
1022
|
+
### `.zv-header` perdait son flou : et le diagnostic d'origine était faux
|
|
1023
1023
|
|
|
1024
|
-
**Le défaut réel : l'ordre des deux `backdrop-filter`.** Lightning CSS
|
|
1025
|
-
compilateur de Tailwind v4, donc celui de toutes nos applications Next
|
|
1024
|
+
**Le défaut réel : l'ordre des deux `backdrop-filter`.** Lightning CSS (le
|
|
1025
|
+
compilateur de Tailwind v4, donc celui de toutes nos applications Next)
|
|
1026
1026
|
SUPPRIME la déclaration non préfixée quand elle précède la forme `-webkit-`.
|
|
1027
1027
|
Or Firefox ne connaît QUE la forme non préfixée. La barre y perdait son flou.
|
|
1028
1028
|
Reproduit avec la chaîne exacte des apps, dans les deux ordres : l'inversion
|
|
@@ -1037,40 +1037,40 @@ repli, écrasé juste après par une règle de spécificité égale et postérie
|
|
|
1037
1037
|
|
|
1038
1038
|
Ce paquet a d'abord repris cette prémisse et remplacé le voile par
|
|
1039
1039
|
`rgb(from var(--paper) r g b / 0.92)`. **C'était une régression**, trouvée
|
|
1040
|
-
avant publication : cette syntaxe sort du compilateur NUE
|
|
1040
|
+
avant publication : cette syntaxe sort du compilateur NUE, ni `@supports`,
|
|
1041
1041
|
ni repli. Sur un navigateur sans couleurs relatives, la valeur devient
|
|
1042
1042
|
invalide au calcul, le raccourci `background` retombe à sa valeur initiale,
|
|
1043
1043
|
et une barre FIXE se retrouve sans aucun fond au-dessus du texte qui défile.
|
|
1044
1044
|
Soit 3,5 % d'usage qui voyaient le voile correctement et ne verraient plus
|
|
1045
|
-
rien
|
|
1045
|
+
rien : Chrome ≤ 118, Firefox ≤ 127, Safari ≤ 16.3.
|
|
1046
1046
|
|
|
1047
1047
|
Le voile reste donc en `color-mix`, et le commentaire sur place dit
|
|
1048
1048
|
maintenant pourquoi il ne faut PAS le « corriger ».
|
|
1049
1049
|
|
|
1050
1050
|
**La leçon, plus large que ce correctif** : un correctif recopié dans deux
|
|
1051
|
-
apps est un signal fort
|
|
1051
|
+
apps est un signal fort, c'est ce qui a motivé cette fournée. Mais ce peut
|
|
1052
1052
|
aussi être une ERREUR recopiée dans deux apps. Le nombre d'occurrences dit
|
|
1053
1053
|
qu'il faut regarder ; il ne dit pas que le diagnostic est juste. Ici, la
|
|
1054
1054
|
seconde app avait copié le commentaire de la première sans revérifier.
|
|
1055
1055
|
|
|
1056
1056
|
### Le mobile zoomait encore, et deux cibles restaient sous le doigt
|
|
1057
1057
|
|
|
1058
|
-
Le module `forms` pose la règle des 16 px lui-même
|
|
1059
|
-
iOS zoome à la mise au point du champ et décale toute la page »
|
|
1058
|
+
Le module `forms` pose la règle des 16 px lui-même (« en dessous, Safari
|
|
1059
|
+
iOS zoome à la mise au point du champ et décale toute la page ») mais
|
|
1060
1060
|
`.zv-input--bare` y échappait : son bloc mobile le redescend à `--app-lg`,
|
|
1061
1061
|
soit 14 px. `.zv-search__input` n'était visé par aucune des deux règles.
|
|
1062
1062
|
Ce sont précisément les deux champs les plus saisis d'une application.
|
|
1063
1063
|
|
|
1064
1064
|
Trois cibles restaient par ailleurs sous `--tap` : les deux commandes de
|
|
1065
|
-
pagination et le fil d'Ariane
|
|
1065
|
+
pagination et le fil d'Ariane, qui est un seul lien pour tout le fil.
|
|
1066
1066
|
Et `.zv-rows__val` gardait son `min-width: 260px` sous le seuil, alors que
|
|
1067
1067
|
le module libérait déjà la CLÉ : dans une carte de 215 px, la valeur
|
|
1068
1068
|
débordait de 45 px.
|
|
1069
1069
|
|
|
1070
1070
|
### Cinq composants d'ancre refusaient `target` et `rel`
|
|
1071
1071
|
|
|
1072
|
-
`ButtonLink`, `LinkArrow` et tout le module `navigation
|
|
1073
|
-
compris
|
|
1072
|
+
`ButtonLink`, `LinkArrow` et tout le module `navigation`, `SideLink`
|
|
1073
|
+
compris, étaient déjà typés sur `AnchorHTMLAttributes`. Cinq autres ne
|
|
1074
1074
|
l'étaient pas : `Link` (typography), et `NavLink`, `NavDrawerLink`, `Langue`
|
|
1075
1075
|
et `RailItem` (layout). Ils portaient `HTMLAttributes<HTMLAnchorElement>`,
|
|
1076
1076
|
qui ne connaît ni `target`, ni `rel`, ni `download`, ni `hreflang`.
|
|
@@ -1078,7 +1078,7 @@ qui ne connaît ni `target`, ni `rel`, ni `download`, ni `hreflang`.
|
|
|
1078
1078
|
Ce n'est pas une nuance de typage : un lien sortant ne peut pas porter
|
|
1079
1079
|
`rel="noopener"`, et un lien qui doit s'ouvrir à côté ne le peut pas non
|
|
1080
1080
|
plus. mcp-factory a dû garder deux `className="zv-link"` écrits à la main
|
|
1081
|
-
pour cette seule raison
|
|
1081
|
+
pour cette seule raison : dont un dans un formulaire à moitié rempli, où
|
|
1082
1082
|
suivre le lien sans `target="_blank"` aurait vidé la saisie.
|
|
1083
1083
|
|
|
1084
1084
|
L'incohérence n'était pas un choix : `navigation` avait la bonne base depuis
|
|
@@ -1091,20 +1091,20 @@ appel existant ne casse.
|
|
|
1091
1091
|
### Les quatre variantes de bouton s'excluent, et le CSS le dit enfin
|
|
1092
1092
|
|
|
1093
1093
|
Le défaut ci-dessus a une cause structurelle, et c'est elle qu'il fallait
|
|
1094
|
-
traiter
|
|
1094
|
+
traiter : sans quoi la prochaine app le refait.
|
|
1095
1095
|
|
|
1096
1096
|
`zv-btn`, `zv-btn--ghost`, `zv-btn--ink` et `zv-btn--danger` sont quatre
|
|
1097
1097
|
classes **autonomes et mutuellement exclusives**. Mais le socle commun les
|
|
1098
|
-
groupe dans un même sélecteur
|
|
1098
|
+
groupe dans un même sélecteur : ce qui leur donne exactement l'air d'une base
|
|
1099
1099
|
et de ses modificateurs. `Button` n'en rend jamais qu'une ; une app qui écrit
|
|
1100
1100
|
ses classes à la main, elle, lit du BEM et compose les deux. C'est arrivé.
|
|
1101
1101
|
|
|
1102
1102
|
Le résultat était vicieux : `.zv-btn:hover` (0,2,0) l'emportait sur
|
|
1103
|
-
`.zv-btn--ghost` (0,1,0). Un fond indigo apparaissait sous un texte encre
|
|
1103
|
+
`.zv-btn--ghost` (0,1,0). Un fond indigo apparaissait sous un texte encre,
|
|
1104
1104
|
illisible, et **seulement au survol** : invisible en relecture de code comme
|
|
1105
1105
|
en capture d'écran. Aucun outil ne pouvait l'attraper. Ni le compilateur, qui
|
|
1106
1106
|
ne lit pas les chaînes de classes ; ni les tests du paquet, qui vérifient ce
|
|
1107
|
-
que les composants émettent
|
|
1107
|
+
que les composants émettent : or ils émettaient juste.
|
|
1108
1108
|
|
|
1109
1109
|
Les règles qui peignent le plein portent donc désormais
|
|
1110
1110
|
`:not(:where(.zv-btn--ghost, .zv-btn--ink, .zv-btn--danger))`. Le CSS dit
|
|
@@ -1121,8 +1121,8 @@ d'autres.
|
|
|
1121
1121
|
commentaire est sur place, au-dessus de la première.
|
|
1122
1122
|
|
|
1123
1123
|
**Ce qui a été écarté** : rendre la combinaison visiblement fautive (un
|
|
1124
|
-
liseré d'alerte)
|
|
1125
|
-
production ; et renommer `zv-btn` en `zv-btn--plein
|
|
1124
|
+
liseré d'alerte), on ne met pas de piège de développement dans du CSS de
|
|
1125
|
+
production ; et renommer `zv-btn` en `zv-btn--plein`, c'est une rupture pour
|
|
1126
1126
|
les quatre consommateurs, dont la landing qui écrit toutes ses classes à la
|
|
1127
1127
|
main, pour un gain de lisibilité seul.
|
|
1128
1128
|
|
|
@@ -1130,7 +1130,7 @@ main, pour un gain de lisibilité seul.
|
|
|
1130
1130
|
|
|
1131
1131
|
Deux retours de recette sur mcp-factory, sur la même page.
|
|
1132
1132
|
|
|
1133
|
-
### La FAQ se replie enfin
|
|
1133
|
+
### La FAQ se replie enfin : et le CSS l'attendait
|
|
1134
1134
|
|
|
1135
1135
|
`FaqItem` rendait deux `<p>`, tout ouvert, avec ce commentaire : « la cacher
|
|
1136
1136
|
derrière un clic n'ajoute rien à cinq questions ». L'argument tient à cinq
|
|
@@ -1141,7 +1141,7 @@ qu'on n'a pas demandées.
|
|
|
1141
1141
|
Surtout, **le CSS prévoyait déjà l'accordéon** : `.zv-faq__q` portait
|
|
1142
1142
|
`cursor: pointer` et un `svg` de chevron stylé en `--accent`. La façade React
|
|
1143
1143
|
ne les a jamais servis. Le curseur promettait donc un clic qui ne faisait
|
|
1144
|
-
rien
|
|
1144
|
+
rien : l'affordance était un mensonge.
|
|
1145
1145
|
|
|
1146
1146
|
`FaqItem` rend maintenant un `<details>`, comme `Fold`. Donc **aucun
|
|
1147
1147
|
JavaScript** : ouverture au clic, à Entrée et à Espace, annonce native de
|
|
@@ -1155,26 +1155,26 @@ peut ouvrir. Une app avait dû rendre ses réponses ouvertes pour cette raison
|
|
|
1155
1155
|
précise, son accordéon maison démontant son contenu.
|
|
1156
1156
|
|
|
1157
1157
|
L'API ne bouge pas : `<FaqItem question={…}>réponse</FaqItem>`. Une prop
|
|
1158
|
-
`ouvert` s'ajoute, pour la question qu'on veut dépliée d'entrée
|
|
1158
|
+
`ouvert` s'ajoute, pour la question qu'on veut dépliée d'entrée : **une par
|
|
1159
1159
|
page au plus**, sinon le repli ne sert plus à rien.
|
|
1160
1160
|
|
|
1161
1161
|
**Et le bloc reçoit son filet.** `.zv-faq` était un aplat blanc posé sur le
|
|
1162
1162
|
papier, sans début ni fin, là où toutes les autres surfaces blanches de la
|
|
1163
|
-
vitrine
|
|
1163
|
+
vitrine (carte, encart, tarif, dépliant) en portent un. Il faisait tache.
|
|
1164
1164
|
C'est le même filet que `.zv-fold`.
|
|
1165
1165
|
|
|
1166
1166
|
### La barre coupait les titres en deux
|
|
1167
1167
|
|
|
1168
1168
|
Le voile de `.zv-header` se dégradait sur TOUTE sa hauteur : à sa base il ne
|
|
1169
1169
|
restait presque rien. Un titre de 38 ou 56 px qui passait dessous se
|
|
1170
|
-
retrouvait donc coupé en deux
|
|
1170
|
+
retrouvait donc coupé en deux (moitié voilée, moitié nette) avec les
|
|
1171
1171
|
entrées de navigation posées sur ses lettres. Deux textes superposés, aucun
|
|
1172
1172
|
lisible.
|
|
1173
1173
|
|
|
1174
1174
|
Le voile est désormais PLEIN derrière la barre, et le dégradé descend SOUS
|
|
1175
1175
|
elle, dans un `::after` de 24 px. Le dégradé n'est pas perdu : il adoucit le
|
|
1176
1176
|
passage là où il ne se dispute plus la place avec la navigation. La frange
|
|
1177
|
-
porte `pointer-events: none`
|
|
1177
|
+
porte `pointer-events: none` : elle couvre le haut du contenu, elle ne doit
|
|
1178
1178
|
rien intercepter.
|
|
1179
1179
|
|
|
1180
1180
|
Aucun changement de gabarit : le `::after` est en absolu sous une barre déjà
|
|
@@ -1185,13 +1185,13 @@ fixée, il ne prend pas de place dans le flux.
|
|
|
1185
1185
|
## Les e-mails (27/08/2026)
|
|
1186
1186
|
|
|
1187
1187
|
Le paquet gagne des gabarits d'e-mail (`@zevra/ui/email`). Ils étaient
|
|
1188
|
-
jusqu'ici refaits par chaque produit, hors charte
|
|
1188
|
+
jusqu'ici refaits par chaque produit, hors charte, fond crème, angles
|
|
1189
1189
|
ronds, surligné jaune, titres en serif : rien de tout cela n'est dans le
|
|
1190
1190
|
système.
|
|
1191
1191
|
|
|
1192
1192
|
### La dérogation à la règle première, et pourquoi elle est imposée
|
|
1193
1193
|
|
|
1194
|
-
« Le CSS est la source de vérité, les composants n'en sont qu'une façade »
|
|
1194
|
+
« Le CSS est la source de vérité, les composants n'en sont qu'une façade » :
|
|
1195
1195
|
sauf ici. Ce n'est pas un choix, c'est le support :
|
|
1196
1196
|
|
|
1197
1197
|
- il n'y a **aucune feuille de style** à charger dans un e-mail ;
|
|
@@ -1201,7 +1201,7 @@ sauf ici. Ce n'est pas un choix, c'est le support :
|
|
|
1201
1201
|
- ni flexbox ni grid ne sont fiables : la mise en page est en **tables** ;
|
|
1202
1202
|
- les **dégradés** ne se rendent pas dans Outlook.
|
|
1203
1203
|
|
|
1204
|
-
Les valeurs sont donc écrites en clair
|
|
1204
|
+
Les valeurs sont donc écrites en clair : mais tirées du **miroir JS des
|
|
1205
1205
|
tokens**, que `tokens/index.js` destinait déjà explicitement à cet usage
|
|
1206
1206
|
(« couleurs de thème d'un e-mail ») et que `tests/tokens.test.js` tient
|
|
1207
1207
|
aligné sur le CSS. Aucune seconde source n'apparaît. Le détour par
|
|
@@ -1212,12 +1212,12 @@ aligné sur le CSS. Aucune seconde source n'apparaît. Le détour par
|
|
|
1212
1212
|
| Dans le système | Dans l'e-mail | Pourquoi |
|
|
1213
1213
|
|---|---|---|
|
|
1214
1214
|
| Bouton plein en dégradé indigo | Aplat `--accent-deep` | Les dégradés ne se rendent pas dans Outlook |
|
|
1215
|
-
| Filet de spectre en `linear-gradient` | Trois aplats de 19 px | Idem
|
|
1215
|
+
| Filet de spectre en `linear-gradient` | Trois aplats de 19 px | Idem : une bande vide sinon |
|
|
1216
1216
|
| `padding` sur le `<a>` du bouton | Table + `bgcolor` | Outlook ignore le padding d'un `<a>` |
|
|
1217
1217
|
| Largeur `--page-max` | 600 px | Le volet de lecture d'Outlook |
|
|
1218
1218
|
|
|
1219
1219
|
Ce qui NE change pas : l'angle vif, le papier, l'encre, les trois familles,
|
|
1220
|
-
un seul bouton plein par message, et le filet de spectre comme signature
|
|
1220
|
+
un seul bouton plein par message, et le filet de spectre comme signature,
|
|
1221
1221
|
premier de ses trois emplois autorisés.
|
|
1222
1222
|
|
|
1223
1223
|
### Le mode sombre est refusé
|
|
@@ -1225,7 +1225,7 @@ premier de ses trois emplois autorisés.
|
|
|
1225
1225
|
`color-scheme: light`, explicitement. La charte est claire par nature :
|
|
1226
1226
|
l'inversion automatique d'Apple Mail retourne les neutres **sans toucher aux
|
|
1227
1227
|
aplats**, et l'indigo du bouton se retrouverait sur un fond devenu noir. Même
|
|
1228
|
-
règle que pour les surfaces sombres du système
|
|
1228
|
+
règle que pour les surfaces sombres du système : elles se font avec la bande
|
|
1229
1229
|
manifeste, jamais en inversant les neutres.
|
|
1230
1230
|
|
|
1231
1231
|
### Deux règles qui ne sont pas décoratives
|
|
@@ -1235,7 +1235,7 @@ deux est bloquée par défaut ; un e-mail qui ne dit pas de qui il vient part à
|
|
|
1235
1235
|
la corbeille. D'où `marque` obligatoire, et le logo en option.
|
|
1236
1236
|
|
|
1237
1237
|
**Le preheader est un contenu, pas un détail.** Sans lui, le client affiche
|
|
1238
|
-
les premiers mots du HTML dans la liste des messages
|
|
1238
|
+
les premiers mots du HTML dans la liste des messages : c'est la seule ligne
|
|
1239
1239
|
dont on dispose pour convaincre d'ouvrir.
|
|
1240
1240
|
|
|
1241
1241
|
### Un piège rencontré, et gardé
|
|
@@ -1245,7 +1245,7 @@ Les piles de polices du paquet contiennent des **guillemets doubles**
|
|
|
1245
1245
|
mêmes guillemets : l'attribut se referme au premier guillemet interne et le
|
|
1246
1246
|
nœud perd **tout** son style. L'e-mail entier repassait en Times, sans
|
|
1247
1247
|
couleurs, avec un libellé de bouton blanc devenu illisible sur l'aplat
|
|
1248
|
-
indigo. Cela ne se voit pas à la relecture
|
|
1248
|
+
indigo. Cela ne se voit pas à la relecture : cela s'est vu au rendu. Les
|
|
1249
1249
|
piles sont converties en guillemets simples, et un test refuse désormais
|
|
1250
1250
|
tout attribut `style` contenant un guillemet double.
|
|
1251
1251
|
|
|
@@ -1255,14 +1255,14 @@ tout attribut `style` contenant un guillemet double.
|
|
|
1255
1255
|
|
|
1256
1256
|
La barre gagne, à DROITE, deux pièces que toute suite de produits finit par
|
|
1257
1257
|
avoir : le **lanceur** pour passer d'un produit à l'autre, et la **zone de
|
|
1258
|
-
compte** pour savoir qui l'on est. HORS RELEVÉ
|
|
1258
|
+
compte** pour savoir qui l'on est. HORS RELEVÉ : aucune planche n'en montre.
|
|
1259
1259
|
|
|
1260
1260
|
### Quatre carrés, pas neuf points
|
|
1261
1261
|
|
|
1262
1262
|
L'icône du lanceur est une grille de **quatre carrés pleins** (icône
|
|
1263
1263
|
`applications`), là où la convention du web est neuf points ronds. Deux
|
|
1264
|
-
raisons : la charte est carrée depuis l'arbitrage du 25/08
|
|
1265
|
-
d'encre du jeu d'icônes sont d'ailleurs déjà des carrés
|
|
1264
|
+
raisons : la charte est carrée depuis l'arbitrage du 25/08, les points
|
|
1265
|
+
d'encre du jeu d'icônes sont d'ailleurs déjà des carrés, et quatre carrés
|
|
1266
1266
|
se lisent mieux que neuf points à 20 px. L'affordance reste immédiate : un
|
|
1267
1267
|
pavé de formes régulières au bord droit d'une barre ne se confond avec rien.
|
|
1268
1268
|
|
|
@@ -1278,19 +1278,19 @@ composant.
|
|
|
1278
1278
|
|
|
1279
1279
|
`.zv-nav__links` disparaît sous le point de rupture (et sous 1150px en
|
|
1280
1280
|
`nav--riche`), remplacée par le burger. Un compte placé dedans s'évanouit
|
|
1281
|
-
sur téléphone
|
|
1281
|
+
sur téléphone : et se connecter est justement la première chose qu'on y
|
|
1282
1282
|
fait. D'où `.zv-nav__actions`, une zone sœur qui survit au seuil.
|
|
1283
1283
|
|
|
1284
1284
|
### L'état : CSS d'abord, prop ensuite
|
|
1285
1285
|
|
|
1286
|
-
Ouverture au survol ET au focus, en CSS seul
|
|
1286
|
+
Ouverture au survol ET au focus, en CSS seul : la barre reste rendue au
|
|
1287
1287
|
serveur, sans rien à hydrater, comme `.zv-navdd`. Une app qui préfère
|
|
1288
1288
|
l'ouverture au CLIC (la convention des lanceurs) tient l'état et passe
|
|
1289
1289
|
`ouvert` : un état se dit en PROP, il ne se peint pas depuis l'app.
|
|
1290
1290
|
|
|
1291
1291
|
Le panneau n'est pas un `role="menu"` : ce rôle promet une navigation aux
|
|
1292
1292
|
flèches que le CSS seul ne peut pas tenir. Ce sont des liens dans un
|
|
1293
|
-
panneau, atteignables à la tabulation
|
|
1293
|
+
panneau, atteignables à la tabulation : une promesse tenue vaut mieux qu'un
|
|
1294
1294
|
rôle exact et menteur.
|
|
1295
1295
|
|
|
1296
1296
|
### Deux défauts trouvés au rendu, pas à la relecture
|
|
@@ -1298,7 +1298,7 @@ rôle exact et menteur.
|
|
|
1298
1298
|
**Le double ancrage.** Le `.zv-menu` du paquet est lui-même en position
|
|
1299
1299
|
absolue : imbriqué dans un panneau qui porte déjà l'ancrage, il se
|
|
1300
1300
|
positionnait une seconde fois, à partir du bord droit, et la grille sortait
|
|
1301
|
-
de l'écran. Sur grand écran la place restante le masquait
|
|
1301
|
+
de l'écran. Sur grand écran la place restante le masquait : c'est le rendu à
|
|
1302
1302
|
390 px qui l'a montré. Le panneau ancre, le menu ne fournit plus que sa
|
|
1303
1303
|
surface.
|
|
1304
1304
|
|
|
@@ -1311,40 +1311,40 @@ déconnecter » non. C'est la BALISE qui change, pas l'apparence.
|
|
|
1311
1311
|
|
|
1312
1312
|
Le lanceur montrait l'initiale des produits faute de pouvoir charger leur
|
|
1313
1313
|
glyphe : le catalogue est compilé par `tsc`, qui ne sait pas importer un
|
|
1314
|
-
PNG, et il est rendu hors du dépôt
|
|
1314
|
+
PNG, et il est rendu hors du dépôt (planche, kit de canvas, page d'admin)
|
|
1315
1315
|
où un chemin relatif ne résout pas. Deux « M » (Mémoire, MCP) se
|
|
1316
1316
|
retrouvaient côte à côte.
|
|
1317
1317
|
|
|
1318
1318
|
Même arbitrage que pour les icônes : **inliner**. Ce qui l'empêchait, c'est
|
|
1319
|
-
le poids
|
|
1319
|
+
le poids, DECISIONS le notait déjà : « un PNG s'inline en data-URI, mais
|
|
1320
1320
|
c'est 150 ko de texte là où un SVG en faisait 4 ». Les originaux sont du
|
|
1321
1321
|
matériel de charte (512 px, 900 Ko à eux sept) ; une tuile les affiche à
|
|
1322
|
-
28 px. Réduits à 96 px
|
|
1323
|
-
pour les écrans à densité
|
|
1322
|
+
28 px. Réduits à 96 px (le double de la plus grande taille d'affichage,
|
|
1323
|
+
pour les écrans à densité) ils tombent à **60 Ko**, soit ~80 Ko en base64.
|
|
1324
1324
|
L'inlinage redevient tenable.
|
|
1325
1325
|
|
|
1326
1326
|
Deux étapes, chacune sur un précédent du dépôt :
|
|
1327
1327
|
|
|
1328
1328
|
- `scripts/build-glyphes.py` réduit et **committe** `logos/glyphes/*.png`,
|
|
1329
|
-
comme `logos/favicon/`
|
|
1329
|
+
comme `logos/favicon/` (la réduction demande Pillow, le build n'a pas à
|
|
1330
1330
|
en dépendre ;
|
|
1331
1331
|
- `scripts/build-glyph-data.mjs` les inline dans `react/glyph-data.ts`,
|
|
1332
|
-
comme `react/icon-data.ts`
|
|
1332
|
+
comme `react/icon-data.ts`) généré, ignoré par git, dans la chaîne Node.
|
|
1333
1333
|
|
|
1334
1334
|
⚠️ **Entrée SÉPARÉE** (`@zevra/ui/glyphes`) : 80 Ko n'ont rien à faire dans
|
|
1335
1335
|
le barrel React, que toute app importe. Seule celle qui affiche des logos
|
|
1336
1336
|
la charge. `LanceurApp` garde donc `glyphe` en prop plutôt que de résoudre
|
|
1337
|
-
un identifiant lui-même
|
|
1337
|
+
un identifiant lui-même : sinon `layout.tsx`, qui est dans le barrel,
|
|
1338
1338
|
tirerait les 80 Ko derrière lui.
|
|
1339
1339
|
|
|
1340
|
-
⚠️ Réduction SEULE : aucune recoloration, aucune resaturation
|
|
1340
|
+
⚠️ Réduction SEULE : aucune recoloration, aucune resaturation, la charte
|
|
1341
1341
|
l'interdit sur les glyphes couleur. Et ils ne descendent pas sous 24 px :
|
|
1342
1342
|
la charte y demande une version monochrome, qui n'existe pas encore.
|
|
1343
1343
|
|
|
1344
1344
|
### Les logos dans les e-mails (27/08/2026)
|
|
1345
1345
|
|
|
1346
1346
|
Un e-mail ne peut afficher un glyphe ni par chemin relatif, ni par data-URI
|
|
1347
|
-
|
|
1347
|
+
- Gmail bloque les secondes. Il lui faut une **URL absolue et publique**.
|
|
1348
1348
|
|
|
1349
1349
|
Retenu : la planche les publie. `design.zevra.tech` est déployé depuis ce
|
|
1350
1350
|
dépôt, à chaque version : c'est le seul endroit où l'image ne peut pas
|
|
@@ -1354,18 +1354,18 @@ les adresses. `email({ produit: 'memoire' })` suffit.
|
|
|
1354
1354
|
|
|
1355
1355
|
⚠️ Ce que cela suppose, et qu'il faut savoir : les e-mails déjà partis
|
|
1356
1356
|
pointent vers cette adresse pour toujours. **Le chemin `/logos/glyphes/` ne
|
|
1357
|
-
se renomme pas**
|
|
1357
|
+
se renomme pas** : un e-mail d'il y a deux ans doit continuer d'afficher son
|
|
1358
1358
|
logo. Si la planche devait changer d'hôte, l'ancien devrait redirigier.
|
|
1359
1359
|
|
|
1360
1360
|
Et si l'adresse tombe, le repli est déjà en place : `alt` porte le nom de la
|
|
1361
1361
|
marque, et `marque` reste obligatoire. Une image sur deux est bloquée de
|
|
1362
|
-
toute façon
|
|
1362
|
+
toute façon : c'est le texte qui identifie l'expéditeur, jamais l'image.
|
|
1363
1363
|
|
|
1364
1364
|
## Le lanceur d'applications devient lisible (27/08/2026, 0.29.0)
|
|
1365
1365
|
|
|
1366
1366
|
Le panneau du lanceur montrait sept glyphes et sept noms de marque. Pour
|
|
1367
1367
|
qui travaille chez Zevra, c'est suffisant. Pour un client qui découvre la
|
|
1368
|
-
suite
|
|
1368
|
+
suite, et c'est lui qui ouvre ce panneau, « Lexform » et « Plume » ne
|
|
1369
1369
|
disent **rien**. Une grille de marques n'est pas une liste d'applications :
|
|
1370
1370
|
c'est un test de mémoire.
|
|
1371
1371
|
|
|
@@ -1385,19 +1385,19 @@ aplat : le filet passe à `--accent-line`, l'application courante le porte
|
|
|
1385
1385
|
déjà. Sans lui, sept PNG flottaient sur du blanc.
|
|
1386
1386
|
|
|
1387
1387
|
**Un en-tête, et des groupes.** Le titre « Applications » précédé du filet
|
|
1388
|
-
de spectre
|
|
1388
|
+
de spectre : deuxième emploi de la signature, celui qui fait qu'un panneau
|
|
1389
1389
|
d'apps ressemble à Zevra et pas à n'importe quel lanceur. Le groupe
|
|
1390
1390
|
(« Suite Zevra ») est facultatif : avec une seule famille il n'apporte rien.
|
|
1391
1391
|
|
|
1392
1392
|
**Quatre colonnes, plus trois.** Sept produits en trois colonnes laissaient
|
|
1393
1393
|
une dernière rangée d'une seule tuile ; en quatre, ils tiennent en 4 + 3.
|
|
1394
|
-
Sur téléphone, trois colonnes souples
|
|
1394
|
+
Sur téléphone, trois colonnes souples : quatre tuiles de 104px ne tiennent
|
|
1395
1395
|
pas dans les 358px qui restent.
|
|
1396
1396
|
|
|
1397
1397
|
⚠️ **PAS DE CHAMP DE RECHERCHE**, et c'est délibéré. La maquette d'origine
|
|
1398
1398
|
en portait un. Sept produits se lisent d'un coup d'œil : une recherche y
|
|
1399
1399
|
ajouterait un contrôle à servir, un état à tenir, un focus à gérer et un
|
|
1400
|
-
clavier qui s'ouvre sur téléphone
|
|
1400
|
+
clavier qui s'ouvre sur téléphone, pour trouver ce qui est déjà à l'écran.
|
|
1401
1401
|
Le jour où la suite dépasse la douzaine, c'est une autre conversation.
|
|
1402
1402
|
|
|
1403
1403
|
Ce qui n'a **pas** été repris de la maquette : les angles arrondis des
|
|
@@ -1406,13 +1406,13 @@ d'applications n'est pas une exception.
|
|
|
1406
1406
|
|
|
1407
1407
|
## Le drapeau qui se prenait pour un composant (28/08/2026, 0.29.1)
|
|
1408
1408
|
|
|
1409
|
-
`rail.js` marquait « déjà armé » en posant `data-zv-rail` sur `<html>`
|
|
1409
|
+
`rail.js` marquait « déjà armé » en posant `data-zv-rail` sur `<html>` :
|
|
1410
1410
|
le nom même de l'attribut qui DÉSIGNE un rail. Son propre sélecteur,
|
|
1411
1411
|
`[data-zv-rail]`, ramassait donc `<html>` : **la page entière devenait un
|
|
1412
1412
|
rail**.
|
|
1413
1413
|
|
|
1414
1414
|
Sur une page qui a un vrai rail, cela ne se voyait pas. Sur une page qui
|
|
1415
|
-
n'en a pas
|
|
1415
|
+
n'en a pas, la seule où ça compte, `a[href^="#"]` ramassait tous les
|
|
1416
1416
|
liens d'ancre, boutons compris, et le premier recevait
|
|
1417
1417
|
`.zv-rail__item--on`. Or cette classe pose `color: var(--accent-deep)` :
|
|
1418
1418
|
un appel à l'action indigo sur fond indigo, illisible.
|
|
@@ -1421,7 +1421,7 @@ Constaté sur `/bootcamp` : « Candidater pour octobre » était le premier
|
|
|
1421
1421
|
lien d'ancre de la page.
|
|
1422
1422
|
|
|
1423
1423
|
Le drapeau s'appelle désormais `data-zv-rail-arme`, et `rails()` écarte
|
|
1424
|
-
explicitement `<html>` et `<body>`
|
|
1424
|
+
explicitement `<html>` et `<body>` : ceinture et bretelles, parce qu'un
|
|
1425
1425
|
consommateur peut écrire ce qu'il veut sur la racine.
|
|
1426
1426
|
|
|
1427
1427
|
Un test garde la classe entière de fautes : dans tout module livré, aucun
|
|
@@ -1447,13 +1447,13 @@ ne fait que doser ce qu'on en voit.
|
|
|
1447
1447
|
|
|
1448
1448
|
Le prolongement sous la barre (`::after`) part désormais de 72 % lui
|
|
1449
1449
|
aussi. Son sommet doit valoir exactement l'opacité de la barre, sinon la
|
|
1450
|
-
jointure fait une marche
|
|
1450
|
+
jointure fait une marche : d'autant plus visible que la barre est
|
|
1451
1451
|
translucide.
|
|
1452
1452
|
|
|
1453
1453
|
### Ce qui n'est PAS revenu
|
|
1454
1454
|
|
|
1455
1455
|
Le dégradé sur toute la hauteur de la barre. C'est lui qui coupait un
|
|
1456
|
-
grand titre en deux
|
|
1456
|
+
grand titre en deux : moitié voilée, moitié nette, avec les entrées de
|
|
1457
1457
|
nav posées sur ses lettres. Le voile reste PLAT derrière la barre : c'est
|
|
1458
1458
|
l'uniformité qui règle ce défaut, pas l'opacité. On récupère donc le
|
|
1459
1459
|
verre sans rouvrir la panne.
|
|
@@ -1471,7 +1471,7 @@ l'exemple de référence.
|
|
|
1471
1471
|
|
|
1472
1472
|
**Elle vit dans `components.css`, et c'est un choix.** Le découpage du paquet
|
|
1473
1473
|
oppose une couche vitrine (`layout`, `surfaces`, `motion`) à une couche
|
|
1474
|
-
applicative (`forms`, `feedback`, `navigation`, `data`)
|
|
1474
|
+
applicative (`forms`, `feedback`, `navigation`, `data`), or une page
|
|
1475
1475
|
d'erreur est réclamée par les DEUX : la landing Astro comme l'app Next.
|
|
1476
1476
|
`feedback.css` en aurait privé la landing, `layout.css` en aurait privé les
|
|
1477
1477
|
apps, et la dupliquer est exclu. `components.css` ne dépend que de `tokens`
|
|
@@ -1480,13 +1480,13 @@ C'est le seul module que les deux couches chargent réellement.
|
|
|
1480
1480
|
|
|
1481
1481
|
**Le composant ne porte AUCUN texte.** C'est la décision qui compte. Une
|
|
1482
1482
|
plaisanterie câblée dans un design system part dans les sept apps, dans une
|
|
1483
|
-
seule langue, et n'en revient jamais
|
|
1483
|
+
seule langue, et n'en revient jamais : et elle vieillit vite. Le composant
|
|
1484
1484
|
n'expose que des emplacements ; la copie de référence vit dans l'exemple du
|
|
1485
1485
|
catalogue, là où on la lit avant de la copier, et où la changer n'oblige
|
|
1486
1486
|
personne.
|
|
1487
1487
|
|
|
1488
1488
|
**Drôle par le VOCABULAIRE, pas par le ton.** La copie de référence
|
|
1489
|
-
plaisante en droit
|
|
1489
|
+
plaisante en droit : « elle a peut-être exercé son droit à l'effacement »
|
|
1490
1490
|
(art. 17 RGPD), « vous n'avez pas qualité pour agir » pour un 403. Ça
|
|
1491
1491
|
fonctionne parce que le lecteur est un juriste : c'est un mot juste employé
|
|
1492
1492
|
de travers, pas une blague sur un ton qu'Encre & Papier n'a pas. Et
|
|
@@ -1494,7 +1494,7 @@ l'ordre est fixe : **le titre dit la panne en clair**, l'esprit vient
|
|
|
1494
1494
|
ensuite et se dédit lui-même (« Plus sérieusement : … »). Une page d'erreur
|
|
1495
1495
|
qui fait rire avant d'informer est une page d'erreur ratée.
|
|
1496
1496
|
|
|
1497
|
-
**La ligne de référence en bas**
|
|
1497
|
+
**La ligne de référence en bas** : `RÉF. 404 · GET /dossier/2019` : n'est pas
|
|
1498
1498
|
un ornement. Elle donne au visiteur de quoi signaler l'incident et au support
|
|
1499
1499
|
de quoi le retrouver, et elle a la forme d'une cote de dossier, ce qui est la
|
|
1500
1500
|
seule illustration dont cette maison ait besoin.
|
|
@@ -1512,8 +1512,8 @@ Mémoire, et **aucune prop ne permettait de le corriger**. Le même composant
|
|
|
1512
1512
|
« Erreur 404 ». Son propre arbitrage, écrit dans le même commit, disait
|
|
1513
1513
|
pourtant qu'elle « ne porte AUCUN texte ».
|
|
1514
1514
|
|
|
1515
|
-
C'est la faute déjà relevée pour `.zv-btn` et `.zv-meta
|
|
1516
|
-
app aura légitimement besoin d'ajuster ne se pose pas en dur
|
|
1515
|
+
C'est la faute déjà relevée pour `.zv-btn` et `.zv-meta`, une valeur qu'une
|
|
1516
|
+
app aura légitimement besoin d'ajuster ne se pose pas en dur, mais vue d'un
|
|
1517
1517
|
angle qui la rend **pire**. Une couleur posée en dur, l'app peut au moins
|
|
1518
1518
|
tenter un `className` et constater que rien ne bouge. Un `alt`, le CSS ne le
|
|
1519
1519
|
peint pas : l'app n'a **aucun recours**. Et le défaut est invisible à
|
|
@@ -1524,19 +1524,19 @@ Deux règles en sortent.
|
|
|
1524
1524
|
|
|
1525
1525
|
**Le glyphe d'une page d'erreur est DÉCORATIF par défaut** (`glypheAlt=""`).
|
|
1526
1526
|
Sur une page qui annonce déjà « Erreur 404 » et « Page introuvable », la
|
|
1527
|
-
marque n'ajoute rien
|
|
1527
|
+
marque n'ajoute rien : l'annoncer place un nom de produit devant
|
|
1528
1528
|
l'information que le lecteur est venu chercher. La prop existe pour l'app
|
|
1529
1529
|
qui a une raison de la nommer.
|
|
1530
1530
|
|
|
1531
1531
|
**Et un garde, parce qu'un correctif ponctuel ne protège que ce cas-là.**
|
|
1532
1532
|
`tests/react.test.js` refuse désormais toute littérale dans un `alt` ou un
|
|
1533
|
-
`aria-label` de la couche React
|
|
1534
|
-
l'exemple à recopier
|
|
1533
|
+
`aria-label` de la couche React (le catalogue excepté, puisque sa copie EST
|
|
1534
|
+
l'exemple à recopier) et exige qu'un `<img>` porte un `alt`, fût-il vide :
|
|
1535
1535
|
sans attribut du tout, un lecteur d'écran annonce le nom du fichier, souvent
|
|
1536
1536
|
un data-URI de 60 Ko. Le garde a été vérifié en réintroduisant la faute : il
|
|
1537
1537
|
la signale à la ligne près.
|
|
1538
1538
|
|
|
1539
|
-
Il a aussi attrapé son propre défaut au premier jet
|
|
1539
|
+
Il a aussi attrapé son propre défaut au premier jet : un quantificateur
|
|
1540
1540
|
paresseux traversait `alt=""` et attrapait l'attribut suivant.
|
|
1541
1541
|
|
|
1542
1542
|
## Le lanceur ne liste que ce qui s'ouvre (28/08/2026, 0.34.0)
|
|
@@ -1548,18 +1548,18 @@ correction descend dans les sept apps, aucune n'a de liste à tenir.
|
|
|
1548
1548
|
**Un produit sans adresse n'entre pas dans le lanceur.** Plume et Supernovia
|
|
1549
1549
|
ont leur glyphe depuis le 26/08 et rien à ouvrir. Une tuile qui mène à rien
|
|
1550
1550
|
est pire qu'une absence : elle promet un produit, le visiteur clique, et il
|
|
1551
|
-
tombe. Le lanceur se construit donc sur `APPS
|
|
1552
|
-
adresse
|
|
1551
|
+
tombe. Le lanceur se construit donc sur `APPS`, les produits qui ont une
|
|
1552
|
+
adresse, et non sur `PRODUITS`. La liste se DÉDUIT du registre : le jour où
|
|
1553
1553
|
Plume ouvre, une ligne l'y fait apparaître partout.
|
|
1554
1554
|
|
|
1555
1555
|
**https, toujours.** `memoire.zevra.tech` avait été communiqué en `http` :
|
|
1556
1556
|
cette adresse-là répond **404** (vérifié au curl), la version chiffrée répond
|
|
1557
|
-
200. Un test refuse désormais toute adresse non chiffrée
|
|
1557
|
+
200. Un test refuse désormais toute adresse non chiffrée : l'erreur ne se
|
|
1558
1558
|
serait pas vue en relecture, et elle aurait été le même lien mort dans les
|
|
1559
1559
|
sept apps.
|
|
1560
1560
|
|
|
1561
1561
|
**Et une conséquence de mise en page, qui n'était pas dans la demande.** À
|
|
1562
|
-
cinq tuiles, la grille à quatre colonnes redonnait 4 + 1
|
|
1562
|
+
cinq tuiles, la grille à quatre colonnes redonnait 4 + 1 : la dernière rangée
|
|
1563
1563
|
d'une seule tuile que le passage à quatre colonnes avait justement servi à
|
|
1564
1564
|
supprimer pour sept. Une requête de quantité (`:has(> :nth-child(5):last-child)`)
|
|
1565
1565
|
repasse à trois colonnes pour ce compte-là seulement, et **se désarme
|
|
@@ -1568,13 +1568,13 @@ en a 6 ou 7. Personne n'aura à y penser quand la suite s'agrandira.
|
|
|
1568
1568
|
|
|
1569
1569
|
## Les panneaux de la barre débordaient de l'écran par la gauche (28/08/2026, 0.35.0)
|
|
1570
1570
|
|
|
1571
|
-
Trouvé en mesurant mcp-factory dans une iframe de 375 px
|
|
1571
|
+
Trouvé en mesurant mcp-factory dans une iframe de 375 px : la seule façon de
|
|
1572
1572
|
juger un téléphone quand la fenêtre du navigateur ne redimensionne pas le
|
|
1573
1573
|
viewport.
|
|
1574
1574
|
|
|
1575
1575
|
`.zv-lanceur__panneau` et `.zv-compte__panneau` sont en `position: absolute;
|
|
1576
1576
|
right: 0` : ils se calent sur le bord droit de LEUR DÉCLENCHEUR. Or le
|
|
1577
|
-
lanceur n'est pas au bord de l'écran
|
|
1577
|
+
lanceur n'est pas au bord de l'écran : le compte et le burger le suivent,
|
|
1578
1578
|
soit une soixantaine de pixels. Le plafond `max-width: calc(100vw - 32px)`,
|
|
1579
1579
|
lui, a été écrit en pensant un panneau ancré au bord de l'écran : son
|
|
1580
1580
|
commentaire dit « au bord droit d'un téléphone ».
|
|
@@ -1585,17 +1585,73 @@ gauche à **−65**. Deux tuiles sur cinq étaient coupées, et la partie hors
|
|
|
1585
1585
|
écran était inatteignable.
|
|
1586
1586
|
|
|
1587
1587
|
⚠️ ET C'EST SILENCIEUX. Un débordement par la GAUCHE n'engendre aucun
|
|
1588
|
-
défilement horizontal
|
|
1588
|
+
défilement horizontal : le navigateur le rogne, sans rien signaler. Le
|
|
1589
1589
|
contrôle « la page ne déborde pas » que l'on fait spontanément répondait donc
|
|
1590
1590
|
OUI pendant que deux produits étaient hors de portée.
|
|
1591
1591
|
|
|
1592
1592
|
Sous le point de rupture, les panneaux s'ancrent désormais à l'ÉCRAN et non à
|
|
1593
1593
|
leur déclencheur : `left: 16px; right: 16px`, largeur pleine. C'est le motif
|
|
1594
1594
|
que tout le monde connaît sur téléphone, et il ne dépend plus de ce qui est
|
|
1595
|
-
posé à droite du déclencheur
|
|
1595
|
+
posé à droite du déclencheur : un jour où la barre gagnera une entrée, rien
|
|
1596
1596
|
ne sera à recalculer. Le plafond en `100vw` devient alors redondant : il
|
|
1597
1597
|
reste, il ne coûte rien et il protège un panneau posé ailleurs.
|
|
1598
1598
|
|
|
1599
1599
|
**Ce qui a été écarté** : réduire le plafond de la largeur du burger et du
|
|
1600
1600
|
compte. Ça marche tant que personne ne touche à la barre, et ça casse au
|
|
1601
|
-
premier ajout
|
|
1601
|
+
premier ajout : une constante qui encode la mise en page d'à côté.
|
|
1602
|
+
|
|
1603
|
+
## Le tiret cadratin est banni (29/08/2026, 0.35.0)
|
|
1604
|
+
|
|
1605
|
+
Règle impérative, inscrite dans AGENTS.md avec celles qui ne se négocient
|
|
1606
|
+
pas : le signe U+2014 ne paraît plus dans le dépôt. Ni le code, ni les
|
|
1607
|
+
commentaires, ni la documentation, ni la copie rendue.
|
|
1608
|
+
|
|
1609
|
+
Pourquoi c'est une règle et pas un goût : le tiret cadratin est le signe
|
|
1610
|
+
qu'on pose quand on n'a pas tranché. Le français en a de plus précis, et il
|
|
1611
|
+
faut choisir lequel. **Deux-points** quand ce qui suit explique ce qui
|
|
1612
|
+
précède, **virgule** quand la phrase porte déjà un « : », **parenthèses**
|
|
1613
|
+
pour une incise qui contient elle-même des virgules, **trait d'union** pour
|
|
1614
|
+
une puce de liste. C'est la répartition qu'a suivie le passage : 600
|
|
1615
|
+
deux-points, 222 virgules, 132 parenthèses, 87 incises, 12 puces.
|
|
1616
|
+
|
|
1617
|
+
Le **demi-cadratin** U+2013 reste autorisé dans son seul emploi légitime,
|
|
1618
|
+
l'intervalle (« 1 – 25 sur 128 », « 0,14–0,2em »). Autre signe, autre
|
|
1619
|
+
travail.
|
|
1620
|
+
|
|
1621
|
+
### Ce que ce nettoyage a failli casser
|
|
1622
|
+
|
|
1623
|
+
Un premier transformateur appliquait des expressions régulières de nettoyage
|
|
1624
|
+
sur le fichier ENTIER. Il a fusionné
|
|
1625
|
+
|
|
1626
|
+
.zv-sidelink--on,
|
|
1627
|
+
.zv-sidelink[aria-current="page"] {
|
|
1628
|
+
|
|
1629
|
+
en un seul sélecteur. Deux règles CSS devenues une, en silence, et aucun
|
|
1630
|
+
test du dépôt n'aurait pu le voir : les classes existaient toujours. La
|
|
1631
|
+
règle qui en sort vaut au-delà de ce cas : **un tiret cadratin ne vit que
|
|
1632
|
+
dans de la prose**, donc on n'ouvre jamais le reste du fichier. Le second
|
|
1633
|
+
transformateur ne touche qu'aux commentaires, aux chaînes et au markdown, et
|
|
1634
|
+
un script de preuve compare le squelette de chaque fichier (code sans
|
|
1635
|
+
commentaires ni contenu de chaînes) avant et après. Il est resté identique.
|
|
1636
|
+
|
|
1637
|
+
Deux autres défauts, attrapés à la relecture du diff et non par un test :
|
|
1638
|
+
les espaces se règlent AU POINT D'INSERTION, jamais sur le fichier (« site ,
|
|
1639
|
+
c'est » et « page d'admin ) » venaient de là), et la ponctuation ne se
|
|
1640
|
+
double pas, parce que le français ferme souvent une incise par un tiret
|
|
1641
|
+
suivi d'une virgule (un « halo » suivi du tiret puis d'une virgule donnait « halo,, parce que »).
|
|
1642
|
+
|
|
1643
|
+
### Le garde, et sa particularité
|
|
1644
|
+
|
|
1645
|
+
`tests/paquet.test.js` refuse le signe dans tout fichier suivi par git, hors
|
|
1646
|
+
binaires. Sans lui la règle durerait un commit : elle comptait **1 079
|
|
1647
|
+
infractions** le jour où elle a été écrite, ce qui est sa propre
|
|
1648
|
+
démonstration.
|
|
1649
|
+
|
|
1650
|
+
⚠️ Une règle qui bannit un caractère ne peut pas le porter. Le motif du test
|
|
1651
|
+
s'écrit donc en échappement `\u2014`, et AGENTS.md nomme le signe par son
|
|
1652
|
+
point de code : sinon le garde se dénonce lui-même à la première exécution.
|
|
1653
|
+
C'est exactement ce qu'il a fait au premier jet, et il avait raison.
|
|
1654
|
+
|
|
1655
|
+
Il a aussi rendu un service immédiat : un `git checkout` d'essai avait
|
|
1656
|
+
annulé le nettoyage de `tokens.css`, encore non commité. Le garde a signalé
|
|
1657
|
+
la régression dans la minute.
|