@zevra/ui 0.34.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.
Files changed (104) hide show
  1. package/DECISIONS.md +293 -203
  2. package/README.md +21 -21
  3. package/demo/app.html +6 -6
  4. package/demo/index.html +3 -3
  5. package/dist/actions.d.ts +8 -8
  6. package/dist/actions.d.ts.map +1 -1
  7. package/dist/actions.js +1 -1
  8. package/dist/actions.js.map +1 -1
  9. package/dist/catalogue.d.ts +2 -2
  10. package/dist/catalogue.js +67 -67
  11. package/dist/catalogue.js.map +1 -1
  12. package/dist/content.d.ts +23 -23
  13. package/dist/content.d.ts.map +1 -1
  14. package/dist/content.js +16 -16
  15. package/dist/content.js.map +1 -1
  16. package/dist/css-inline.d.ts +1 -1
  17. package/dist/css-inline.d.ts.map +1 -1
  18. package/dist/css-inline.js +4 -4
  19. package/dist/css-inline.js.map +1 -1
  20. package/dist/data-table.d.ts +1 -1
  21. package/dist/data.d.ts +7 -7
  22. package/dist/data.js +5 -5
  23. package/dist/email-tokens.js +1 -1
  24. package/dist/email.d.ts +6 -6
  25. package/dist/email.js +8 -8
  26. package/dist/email.js.map +1 -1
  27. package/dist/feedback.d.ts +10 -10
  28. package/dist/feedback.d.ts.map +1 -1
  29. package/dist/feedback.js +3 -3
  30. package/dist/forms.d.ts +12 -12
  31. package/dist/forms.js +5 -5
  32. package/dist/glyph-data.d.ts +2 -2
  33. package/dist/glyph-data.js +3 -3
  34. package/dist/glyph-urls.js +1 -1
  35. package/dist/glyphes.d.ts +2 -2
  36. package/dist/glyphes.js +4 -4
  37. package/dist/icon-data.d.ts +1 -1
  38. package/dist/icon-data.js +2 -2
  39. package/dist/icon.d.ts +5 -5
  40. package/dist/icon.js +1 -1
  41. package/dist/index.js +4 -4
  42. package/dist/layout.d.ts +21 -21
  43. package/dist/layout.d.ts.map +1 -1
  44. package/dist/layout.js +15 -15
  45. package/dist/layout.js.map +1 -1
  46. package/dist/navigation.d.ts +16 -16
  47. package/dist/navigation.d.ts.map +1 -1
  48. package/dist/navigation.js +9 -9
  49. package/dist/navigation.js.map +1 -1
  50. package/dist/overlays.d.ts +6 -6
  51. package/dist/overlays.d.ts.map +1 -1
  52. package/dist/overlays.js +5 -5
  53. package/dist/select-menu.d.ts +1 -1
  54. package/dist/select-menu.js +2 -2
  55. package/dist/surfaces.d.ts +8 -8
  56. package/dist/surfaces.d.ts.map +1 -1
  57. package/dist/surfaces.js +6 -6
  58. package/dist/surfaces.js.map +1 -1
  59. package/dist/typography.d.ts +4 -4
  60. package/dist/typography.d.ts.map +1 -1
  61. package/dist/typography.js +3 -3
  62. package/dist/typography.js.map +1 -1
  63. package/icons/index.json +1 -1
  64. package/package.json +2 -2
  65. package/react/actions.tsx +9 -9
  66. package/react/catalogue.tsx +68 -68
  67. package/react/content.tsx +28 -28
  68. package/react/css-inline.ts +4 -4
  69. package/react/data-table.tsx +3 -3
  70. package/react/data.tsx +9 -9
  71. package/react/email-tokens.ts +1 -1
  72. package/react/email.ts +10 -10
  73. package/react/feedback.tsx +12 -12
  74. package/react/forms.tsx +15 -15
  75. package/react/glyph-data.ts +3 -3
  76. package/react/glyph-urls.ts +1 -1
  77. package/react/glyphes.ts +4 -4
  78. package/react/icon-data.ts +2 -2
  79. package/react/icon.tsx +6 -6
  80. package/react/index.ts +4 -4
  81. package/react/layout.tsx +22 -22
  82. package/react/navigation.tsx +18 -18
  83. package/react/overlays.tsx +9 -9
  84. package/react/select-menu.tsx +3 -3
  85. package/react/surfaces.tsx +10 -10
  86. package/react/typography.tsx +6 -6
  87. package/src/base.css +10 -10
  88. package/src/components.css +49 -49
  89. package/src/data.css +41 -41
  90. package/src/feedback.css +55 -55
  91. package/src/fonts.css +2 -2
  92. package/src/forms.css +50 -50
  93. package/src/icons.css +10 -10
  94. package/src/index.css +1 -1
  95. package/src/layout.css +27 -27
  96. package/src/motion.css +16 -16
  97. package/src/motion.js +4 -4
  98. package/src/nav.js +5 -5
  99. package/src/navigation.css +93 -62
  100. package/src/overlays.css +14 -14
  101. package/src/rail.js +6 -6
  102. package/src/surfaces.css +11 -11
  103. package/src/tokens.css +14 -14
  104. package/tokens/index.js +8 -8
package/src/forms.css CHANGED
@@ -1,20 +1,20 @@
1
- /* Zevra UI — formulaires : champ, recherche, zone de texte, sélection,
2
- * case/radio, interrupteur, puces de filtre, zone de dépôt — et, depuis le
1
+ /* Zevra UI (formulaires : champ, recherche, zone de texte, sélection,
2
+ * case/radio, interrupteur, puces de filtre, zone de dépôt) et, depuis le
3
3
  * 25/08/2026 (hors relevé, voir DECISIONS.md) : le champ à affixe et le
4
4
  * curseur.
5
5
  *
6
6
  * DÉPEND de tokens.css (toutes les valeurs) et de base.css (reset
7
7
  * box-sizing, anneau :focus-visible). RIEN D'AUTRE : ce module ne lit ni
8
- * layout.css, ni components.css, ni motion.css. C'est volontaire — une app
8
+ * layout.css, ni components.css, ni motion.css. C'est volontaire : une app
9
9
  * purement applicative n'a aucune raison de charger la mise en page de la
10
10
  * vitrine.
11
11
  *
12
12
  * Ce qu'il NE porte PAS :
13
- * · le menu déroulé par .zv-select — il appartient à navigation.css
13
+ * · le menu déroulé par .zv-select (il appartient à navigation.css
14
14
  * (.zv-menu) ; ce module pose l'ancre (.zv-select-anchor) et le
15
15
  * déclencheur, rien de plus ;
16
- * · le bouton d'envoi d'un formulaire — c'est .zv-btn (components.css) ;
17
- * · l'alerte de bloc (role="alert") — module de retours.
16
+ * · le bouton d'envoi d'un formulaire) c'est .zv-btn (components.css) ;
17
+ * · l'alerte de bloc (role="alert")) module de retours.
18
18
  *
19
19
  * PROVENANCE. Relevé dans l'application Mémoire (production, mêmes tokens de
20
20
  * charte) sur six écrans : /connexion, /chat, /repertoire, /bibliotheque,
@@ -89,7 +89,7 @@
89
89
  color: var(--muted);
90
90
  }
91
91
 
92
- /* Le message d'erreur AU NIVEAU DU CHAMP existe — une seule fois dans toute
92
+ /* Le message d'erreur AU NIVEAU DU CHAMP existe : une seule fois dans toute
93
93
  * l'application, hors des six écrans du relevé initial
94
94
  * (add-member-form.tsx:94). Ses valeurs propres (taille, graisse, écart)
95
95
  * n'ont PAS été relevées : celles ci-dessous sont dérivées du reste du
@@ -129,7 +129,7 @@
129
129
 
130
130
  /* Relevé (`focus:border-accent-line`) : c'est :focus et non :focus-visible,
131
131
  * la bordure réagit donc aussi à la souris. L'anneau clavier de base.css
132
- * s'y AJOUTE — on ne reprend PAS le `input { outline: none }` de la prod,
132
+ * s'y AJOUTE : on ne reprend PAS le `input { outline: none }` de la prod,
133
133
  * qui laissait l'application inutilisable au clavier. */
134
134
  .zv-input:focus {
135
135
  border-color: var(--accent-line);
@@ -143,7 +143,7 @@
143
143
 
144
144
  /* <select> NATIF, habillé comme le champ. C'est le motif de sélection
145
145
  * accessible de l'application, relevé deux fois (add-member-form.tsx:82,
146
- * billing-card.tsx:135) avec exactement les valeurs de .zv-input —
146
+ * billing-card.tsx:135) avec exactement les valeurs de .zv-input :
147
147
  * `border-line bg-white px-3 py-[9px] text-[13px] text-ink`. D'où un simple
148
148
  * modificateur : tout est déjà là.
149
149
  *
@@ -151,7 +151,7 @@
151
151
  * la liste native et son annonce viennent du navigateur. La remplacer
152
152
  * imposerait de redessiner tout cela, et le relevé ne le fait pas non plus.
153
153
  * À ne pas confondre avec .zv-select, qui est un déclencheur de menu maison
154
- * — voir plus bas. */
154
+ * - voir plus bas. */
155
155
  .zv-input--select {
156
156
  cursor: pointer;
157
157
  }
@@ -203,15 +203,15 @@
203
203
  * à l'intérieur du cadre, en plus de ce filet. On le garde tel quel plutôt
204
204
  * que de trancher l'un des deux :
205
205
  * · supprimer l'anneau (outline:none) rendrait le champ nu invisible au
206
- * clavier — c'est exactement la faute de la production ;
206
+ * clavier, c'est exactement la faute de la production ;
207
207
  * · supprimer ce filet priverait la souris de tout retour, alors que le
208
208
  * relevé lui en donne un sur les champs bordés.
209
209
  * La redondance coûte moins cher que l'une ou l'autre perte. */
210
- /* ⚠️ REPRIS le 25/08/2026 — la DA jugeait la prise de focus « boff ». Elle
210
+ /* ⚠️ REPRIS le 25/08/2026 : la DA jugeait la prise de focus « boff ». Elle
211
211
  * l'était : le cadre passait à --accent-line, un filet si pâle qu'à côté de
212
212
  * l'anneau du champ intérieur il ne se voyait pas. Trois corrections :
213
213
  * · le filet passe à --accent PLEIN, pas à sa version diluée ;
214
- * · un halo --accent-soft de 3px double le trait — c'est lui qui rend le
214
+ * · un halo --accent-soft de 3px double le trait, c'est lui qui rend le
215
215
  * retour visible du coin de l'œil, sans déplacer un pixel de la mise en
216
216
  * page (box-shadow ne prend pas de place) ;
217
217
  * · la loupe s'allume avec le cadre : elle cesse d'être une invite grise
@@ -220,7 +220,7 @@
220
220
  * L'anneau :focus-visible du champ INTÉRIEUR est neutralisé ici, et
221
221
  * seulement ici : le cadre le remplace, et il le remplace pour la souris
222
222
  * comme pour le clavier. C'est ce qui lève la double marque assumée jusque-là
223
- * — un seul objet à l'écran, un seul retour. Le champ nu reste parfaitement
223
+ * - un seul objet à l'écran, un seul retour. Le champ nu reste parfaitement
224
224
  * repérable au clavier, puisque c'est le cadre entier qui s'allume. */
225
225
  .zv-search:focus-within {
226
226
  border-color: var(--accent);
@@ -240,7 +240,7 @@
240
240
  width: 13px;
241
241
  height: 13px;
242
242
  /* Même gris que le placeholder : la loupe est une invite, pas une donnée.
243
- * Elle s'allume avec le cadre — voir :focus-within plus bas. */
243
+ * Elle s'allume avec le cadre : voir :focus-within plus bas. */
244
244
  stroke: var(--label);
245
245
  transition: stroke 140ms cubic-bezier(0.2, 0.7, 0.2, 1);
246
246
  }
@@ -263,7 +263,7 @@
263
263
  /* ─── Champ à affixe ────────────────────────────────────────────────────
264
264
  * HORS RELEVÉ (25/08/2026, voir DECISIONS.md). « 30 », seul dans un champ,
265
265
  * ne dit pas s'il s'agit de jours ou d'euros. La grammaire est celle de
266
- * .zv-search — le seul cadre-à-champ-nu du relevé : cadre --line, champ nu
266
+ * .zv-search, le seul cadre-à-champ-nu du relevé : cadre --line, champ nu
267
267
  * dedans, allumage :focus-within identique. L'affixe est en mono --label,
268
268
  * comme les libellés de déclencheur : une unité est un libellé, pas une
269
269
  * donnée. */
@@ -286,7 +286,7 @@
286
286
  }
287
287
 
288
288
  /* Même prise de focus que le cadre de recherche : filet --accent plein,
289
- * halo --accent-soft — et l'anneau du champ intérieur est remplacé par le
289
+ * halo --accent-soft, et l'anneau du champ intérieur est remplacé par le
290
290
  * cadre, pour la souris comme pour le clavier. */
291
291
  .zv-affix:focus-within {
292
292
  border-color: var(--accent);
@@ -319,7 +319,7 @@
319
319
  * DÉCISION, PAS UN RELEVÉ : il n'existe AUCUN <textarea> dans l'application,
320
320
  * sur aucun des huit écrans ouverts. Le composeur du chat est un <input> où
321
321
  * Entrée envoie (chat-client.tsx:365). Le bloc ci-dessous est dérivé mot à
322
- * mot de .zv-input ; seules min-height et resize s'y ajoutent — sans elles
322
+ * mot de .zv-input ; seules min-height et resize s'y ajoutent : sans elles
323
323
  * le champ se rend sur une ligne et le composant n'existe pas. min-height
324
324
  * est la SEULE valeur de ce module sans aucune source, dans aucun écran.
325
325
  *
@@ -329,7 +329,7 @@
329
329
  .zv-textarea {
330
330
  width: 100%;
331
331
  min-width: 0;
332
- min-height: 96px; /* sans source — voir ci-dessus */
332
+ min-height: 96px; /* sans source : voir ci-dessus */
333
333
  border: 1px solid var(--line);
334
334
  border-radius: 0;
335
335
  background: var(--white);
@@ -357,7 +357,7 @@
357
357
  * <select> : c'est un bouton qui ouvre .zv-menu (navigation.css). Pour un
358
358
  * vrai choix dans une liste, préférer .zv-input--select, qui est natif.
359
359
  *
360
- * ANCRAGE — arbitrage à consigner dans DECISIONS.md, les deux modules ne
360
+ * ANCRAGE : arbitrage à consigner dans DECISIONS.md, les deux modules ne
361
361
  * disent pas la même chose. Le relevé donne raison à celui-ci : c'est
362
362
  * l'ENVELOPPE qui porte position:relative (`relative inline-block
363
363
  * max-w-full`), pas le déclencheur. Ancrer le menu sur .zv-select
@@ -390,7 +390,7 @@
390
390
  * l'affichage de la liste » (DA, sur pièces).
391
391
  *
392
392
  * Le <select> natif (.zv-input--select) reste dans le paquet et garde son
393
- * usage — mais il ne peut PAS être habillé : la liste déroulée est peinte
393
+ * usage, mais il ne peut PAS être habillé : la liste déroulée est peinte
394
394
  * par le système, pas par la page. Sur un macOS en mode sombre, elle sort
395
395
  * en menu noir au milieu d'une interface claire. Aucun CSS ne corrige cela,
396
396
  * c'est une limite du contrôle.
@@ -398,7 +398,7 @@
398
398
  * D'où ce déclencheur, qui a l'apparence exacte d'un champ et ouvre le
399
399
  * .zv-menu du paquet. Ce qu'il COÛTE, et qu'il faut assumer en le
400
400
  * choisissant : le clavier, l'annonce et la liste native sont à réimplémenter
401
- * — c'est fait dans le composant React (SelectMenu), pas dans ce fichier.
401
+ * - c'est fait dans le composant React (SelectMenu), pas dans ce fichier.
402
402
  * Un gabarit qui pose ces classes à la main sans ce travail livre un select
403
403
  * inutilisable au clavier. Dans ce cas, prendre le natif. */
404
404
  .zv-input--trigger {
@@ -466,7 +466,7 @@
466
466
  /* ─── Case à cocher et bouton radio ─────────────────────────────────────
467
467
  * DÉRIVÉS INTÉGRALEMENT, ET ILS DOIVENT ÊTRE LUS COMME TELS : il n'existe
468
468
  * zéro <input type="checkbox"> et zéro <input type="radio"> dans toute
469
- * l'application — la sélection s'y fait toujours par .zv-seg ou .zv-switch.
469
+ * l'application, la sélection s'y fait toujours par .zv-seg ou .zv-switch.
470
470
  * Le bloc ci-dessous réemploie la grammaire déjà en production (carré au
471
471
  * filet --line sur --white, coché en aplat --accent, rond des pastilles)
472
472
  * sans introduire de valeur de charte nouvelle ; ses DIMENSIONS, elles
@@ -474,7 +474,7 @@
474
474
  * source. Le jour où un vrai écran en pose, c'est lui qui tranche.
475
475
  *
476
476
  * ⚠️ .zv-check est DÉJÀ PRIS par la pastille de validation
477
- * (components.css:482) — d'où .zv-check-box.
477
+ * (components.css:482) : d'où .zv-check-box.
478
478
  *
479
479
  * Contrôles natifs volontairement conservés (appearance:none seulement) : le
480
480
  * clavier, :focus-visible, [disabled] et l'annonce au lecteur d'écran
@@ -516,7 +516,7 @@
516
516
 
517
517
  /* Le point du radio est creusé dans l'aplat par un anneau blanc interne :
518
518
  * un pseudo-élément sur un <input> n'est pas fiable d'un moteur à l'autre.
519
- * Ce box-shadow est une géométrie, pas une ombre de charte — d'où l'absence
519
+ * Ce box-shadow est une géométrie, pas une ombre de charte : d'où l'absence
520
520
  * de token. */
521
521
  .zv-radio:checked {
522
522
  border-color: var(--accent);
@@ -530,11 +530,11 @@
530
530
  *
531
531
  * ⚠️ RABATTEMENT VISIBLE : la piste éteinte était un gris ferme (#C9CEDD),
532
532
  * rabattu sur --accent-line, qui est bleuté. L'état éteint prend donc une
533
- * teinte indigo très pâle. La distinction éteint/allumé tient quand même —
533
+ * teinte indigo très pâle. La distinction éteint/allumé tient quand même :
534
534
  * elle est portée par l'aplat plein et par le libellé accolé, pas par cette
535
535
  * nuance-là. */
536
536
 
537
- /* ⚠️ REDESSINÉ le 25/08/2026 — la DA a tranché « switch horrible » sur
537
+ /* ⚠️ REDESSINÉ le 25/08/2026, la DA a tranché « switch horrible » sur
538
538
  * pièces, et elle avait raison sur trois points :
539
539
  * · 28×16 avec un bouton rond de 12, c'est un jouet posé au milieu de
540
540
  * contrôles carrés de 16px de haut ; la ligne de réglage n'avait aucune
@@ -557,7 +557,7 @@
557
557
  background: var(--white);
558
558
  /* La courbe est celle du paquet (motion.css, `--zv-easing`), recopiée en
559
559
  * clair : forms.css ne dépend pas de motion.css et n'a pas à en dépendre
560
- * pour une transition de couleur. Ce n'est PAS `ease` — le défaut d'un
560
+ * pour une transition de couleur. Ce n'est PAS `ease` : le défaut d'un
561
561
  * framework tiers n'a rien à faire dans le système. */
562
562
  transition:
563
563
  background-color 150ms cubic-bezier(0.2, 0.7, 0.2, 1),
@@ -579,7 +579,7 @@
579
579
  }
580
580
 
581
581
  /* Bouton CARRÉ : le rond ici n'est pas une forme porteuse de sens (ce que
582
- * sont la pastille d'état ou le radio), c'était un style — il tombe avec les
582
+ * sont la pastille d'état ou le radio), c'était un style, il tombe avec les
583
583
  * autres rayons. Éteint il est gris comme un contrôle inactif, allumé il
584
584
  * passe en blanc sur l'aplat indigo. */
585
585
  .zv-switch__knob {
@@ -607,7 +607,7 @@
607
607
  /* La source place la gouttière de 7px sur une enveloppe PARENTE, et
608
608
  * n'entoure que la piste de sa zone tactile (logs-client.tsx:267-273).
609
609
  * Elle est ramenée ici : cette classe enveloppe le contrôle ET son
610
- * libellé, ce qui rend le texte cliquable — un <label> qui n'entoure que
610
+ * libellé, ce qui rend le texte cliquable, un <label> qui n'entoure que
611
611
  * l'interrupteur laisse une cible de 28px là où il en faut 40. Sans la
612
612
  * gouttière, le libellé vient coller à la piste. */
613
613
  align-items: center;
@@ -632,16 +632,16 @@
632
632
  * HORS RELEVÉ (25/08/2026, voir DECISIONS.md). Aucune source ; dérivé de
633
633
  * l'interrupteur redessiné : bouton CARRÉ de 14 px (la taille exacte du
634
634
  * bouton du switch), --accent, --accent-deep au survol. La piste fait 3 px
635
- * — la hauteur de .zv-progress — en --line, remplie en --accent jusqu'au
635
+ * - la hauteur de .zv-progress, en --line, remplie en --accent jusqu'au
636
636
  * curseur. PAS le spectre : la barre de progression est l'un des trois
637
637
  * emplois autorisés, le curseur n'en est pas un.
638
638
  *
639
639
  * Le remplissage est peint par le FOND de l'input (un dégradé à arrêt
640
- * franc), position portée par --zv-range-pos que la façade React calcule —
640
+ * franc), position portée par --zv-range-pos que la façade React calcule :
641
641
  * une géométrie, comme la largeur de Progress, pas une valeur de charte.
642
642
  * Sans elle, la piste s'affiche remplie à moitié : poser la variable, ou
643
643
  * assumer le repli. Le bouton, lui, passe par les pseudo-éléments de
644
- * chaque moteur — c'est le seul contrôle du paquet qui l'exige. */
644
+ * chaque moteur : c'est le seul contrôle du paquet qui l'exige. */
645
645
 
646
646
  .zv-range {
647
647
  --zv-range-pos: 50%;
@@ -706,25 +706,25 @@
706
706
  * 143-180, repertoire-client.tsx:79-94, logs-client.tsx:193-207).
707
707
  *
708
708
  * ⚠️ LA SOURCE DIVERGE, ET C'EST TRANCHÉ ICI :
709
- * · gouttière du groupe — bibliothèque 5px, répertoire et logs 6px. On
709
+ * · gouttière du groupe, bibliothèque 5px, répertoire et logs 6px. On
710
710
  * retient 6px : deux écrans sur trois, et c'est la valeur de .zv-tabs
711
711
  * (navigation.css), qui héberge les mêmes puces. Deux conteneurs des
712
712
  * mêmes puces avec deux écarts différents, c'est un défaut, pas une
713
713
  * nuance.
714
- * · taille et densité — bibliothèque descend à 11px/4-9px au-dessus du
714
+ * · taille et densité : bibliothèque descend à 11px/4-9px au-dessus du
715
715
  * seuil, le répertoire reste à 11px/8-12px partout, en graisse 600. On
716
716
  * retient la puce DENSE de la bibliothèque au-dessus du seuil, et la
717
717
  * graisse 500 (la 600 est réservée à l'état sélectionné, sinon
718
718
  * sélectionné et non sélectionné ne se distinguent plus que par la
719
719
  * couleur).
720
- * · corps — 11 et 12px se rabattent tous les deux sur --app-sm (12px) :
720
+ * · corps, 11 et 12px se rabattent tous les deux sur --app-sm (12px) :
721
721
  * l'écart d'un pixel entre les deux écrans disparaît, et la variante
722
722
  * mobile de la bibliothèque avec lui. C'est le prix de l'échelle
723
723
  * rationalisée, assumé.
724
724
  *
725
725
  * ⚠️ L'état sélectionné n'est porté par AUCUN aria-pressed en production :
726
726
  * il est invisible pour un lecteur d'écran. Le paquet impose <button
727
- * aria-pressed="true|false"> — et le style suit l'attribut autant que la
727
+ * aria-pressed="true|false"> : et le style suit l'attribut autant que la
728
728
  * classe, pour que le balisage correct ne coûte rien. */
729
729
 
730
730
  .zv-seg-group {
@@ -760,7 +760,7 @@
760
760
 
761
761
  /* La rangée de puces vit souvent dans un rail qui défile horizontalement
762
762
  * (.zv-tabs--rail, navigation.css). L'anneau de base.css y serait rogné aux
763
- * deux bords. On ne le REDÉFINIT pas — on déplace seulement son tracé à
763
+ * deux bords. On ne le REDÉFINIT pas : on déplace seulement son tracé à
764
764
  * l'intérieur de la puce, où rien ne le coupe. */
765
765
  .zv-seg:focus-visible {
766
766
  outline-offset: -2px;
@@ -778,7 +778,7 @@
778
778
  }
779
779
 
780
780
  /* Sélection PLEINE (répertoire, logs) : OPT-IN, à poser explicitement, et
781
- * BORNÉE — un seul groupe plein par page, jamais sur une page qui porte
781
+ * BORNÉE, un seul groupe plein par page, jamais sur une page qui porte
782
782
  * déjà un bouton plein. Une page de filtres à plusieurs groupes (la
783
783
  * bibliothèque en a deux) afficherait sinon autant d'aplats indigo que de
784
784
  * groupes, simultanément : c'est le seul mécanisme du paquet capable de
@@ -817,7 +817,7 @@
817
817
  * tabindex="0" (l'anneau de base.css suit alors tout seul).
818
818
  *
819
819
  * L'icône est un SVG du balisage (import-client.tsx:159-166) : viewBox
820
- * 0 0 30 30, fill="none", stroke="var(--accent)", stroke-width="1.5" —
820
+ * 0 0 30 30, fill="none", stroke="var(--accent)", stroke-width="1.5",
821
821
  * relevée en stroke-linecap="round", REPRISE au trait carré le 25/08/2026
822
822
  * comme tout ce qui trace (DECISIONS.md, « Le trait carré ») :
823
823
  * <line x1="15" y1="4" x2="15" y2="18"/>
@@ -842,7 +842,7 @@
842
842
  *
843
843
  * ⚠️ RABATTEMENT VISIBLE : le fond de survol du relevé (#FDFDFF) tombe sur
844
844
  * --panel, à peine distinct du --white de repos. Le fond ne SIGNALE donc
845
- * plus rien — le retour visuel repose entièrement sur le filet qui passe à
845
+ * plus rien : le retour visuel repose entièrement sur le filet qui passe à
846
846
  * --accent. Ne pas le supprimer en croyant que le fond compense. */
847
847
  .zv-drop:hover,
848
848
  .zv-drop.is-dragging {
@@ -850,7 +850,7 @@
850
850
  background: var(--panel);
851
851
  }
852
852
 
853
- /* Stockage indisponible : la zone reste visible mais inerte — la masquer
853
+ /* Stockage indisponible : la zone reste visible mais inerte, la masquer
854
854
  * ferait croire à une page cassée. */
855
855
  .zv-drop--disabled {
856
856
  cursor: not-allowed;
@@ -864,7 +864,7 @@
864
864
  background: var(--panel);
865
865
  }
866
866
 
867
- /* 15px : c'est une phrase, pas un libellé d'interface — d'où le palier de
867
+ /* 15px : c'est une phrase, pas un libellé d'interface, d'où le palier de
868
868
  * corps de texte (--body) plutôt que l'échelle applicative, qui s'arrête à
869
869
  * 14px. */
870
870
  .zv-drop__title {
@@ -908,7 +908,7 @@
908
908
  * paquet a par ailleurs une vignette de format (.zv-filetype, data.css) et
909
909
  * les deux se liraient comme un seul bloc.
910
910
  *
911
- * Conséquence du retrait du flux : l'input n'est PAS focusable — d'où le
911
+ * Conséquence du retrait du flux : l'input n'est PAS focusable, d'où le
912
912
  * role/tabindex exigés sur .zv-drop ci-dessus. Remettre value='' après
913
913
  * chaque sélection, sinon redéposer le même fichier ne déclenche rien. */
914
914
  .zv-drop__input {
@@ -946,7 +946,7 @@
946
946
  }
947
947
 
948
948
  /* Champ en erreur : seul le filet change. Un fond rouge sur un champ à
949
- * remplir rendrait la saisie illisible — l'aplat --err-soft reste réservé au
949
+ * remplir rendrait la saisie illisible : l'aplat --err-soft reste réservé au
950
950
  * bandeau d'alerte. Le sélecteur suit l'attribut autant que la classe :
951
951
  * aria-invalid est ce qui rend l'erreur audible, il ne doit rien coûter. */
952
952
  .zv-field--err .zv-input,
@@ -987,7 +987,7 @@
987
987
  /* 44px, pas --tap (40px) : c'est la valeur des formulaires de connexion et
988
988
  * du pavé d'import, les deux seuls endroits où l'on saisit au doigt.
989
989
  * 16px : en dessous, Safari iOS zoome à la mise au point du champ et
990
- * décale toute la page — ce n'est pas un choix typographique, aucun token
990
+ * décale toute la page, ce n'est pas un choix typographique, aucun token
991
991
  * n'a à porter cette valeur. */
992
992
  .zv-input,
993
993
  .zv-textarea {
@@ -1003,7 +1003,7 @@
1003
1003
 
1004
1004
  /* Le champ nu et celui d'un cadre à affixe. 16px et non --app-lg (14px) :
1005
1005
  * la règle des 16px ci-dessus vaut pour TOUT champ qu'on saisit au doigt,
1006
- * et ces deux-là — le composeur, le sous-domaine d'organisation — sont
1006
+ * et ces deux-là (le composeur, le sous-domaine d'organisation) sont
1007
1007
  * parmi les plus saisis d'une application. Sous 16, Safari iOS zoome à la
1008
1008
  * mise au point et décale la page. */
1009
1009
  .zv-input--bare,
@@ -1087,7 +1087,7 @@
1087
1087
 
1088
1088
  /* ─── Champ mot de passe ────────────────────────────────────────────────
1089
1089
  * HORS RELEVÉ (27/08/2026, 0.18.0). Aucune des planches ne montre d'écran de
1090
- * connexion, et le système n'avait donc rien pour ce champ — alors que tous
1090
+ * connexion, et le système n'avait donc rien pour ce champ : alors que tous
1091
1091
  * les produits en ont un, et que la saisie masquée est le seul endroit de
1092
1092
  * l'interface où l'on tape sans voir ce qu'on écrit.
1093
1093
  *
@@ -1096,8 +1096,8 @@
1096
1096
  *
1097
1097
  * ⚠️ Le bouton est un vrai <button type="button"> : posé sur un <span>, il
1098
1098
  * n'est ni atteignable au clavier ni annoncé, et il envoie le formulaire dès
1099
- * qu'on oublie le type. Son libellé change avec l'état — « Afficher » /
1100
- * « Masquer » — parce qu'une icône seule ne dit pas ce qui va se passer. */
1099
+ * qu'on oublie le type. Son libellé change avec l'état, « Afficher » /
1100
+ * « Masquer », parce qu'une icône seule ne dit pas ce qui va se passer. */
1101
1101
 
1102
1102
  .zv-affix__btn {
1103
1103
  display: inline-flex;
package/src/icons.css CHANGED
@@ -1,20 +1,20 @@
1
- /* Zevra UI — icônes
1
+ /* Zevra UI : icônes
2
2
  * Dépend de tokens.css. Le jeu lui-même vit dans icons/ (index + sprite).
3
3
  *
4
4
  * Les icônes sont TRACÉES, jamais pleines : trait à l'épaisseur 2, sur une
5
- * grille de 24, à BOUTS FRANCS et JONCTIONS VIVES — le trait carré de la
5
+ * grille de 24, à BOUTS FRANCS et JONCTIONS VIVES, le trait carré de la
6
6
  * charte, arbitré le 25/08/2026 (DECISIONS.md, « Le trait carré ») : les
7
7
  * bouts arrondis étaient le dialecte des bibliothèques génériques, pas le
8
8
  * nôtre. Le réglage vit ici, les 55 tracés le suivent d'un coup. Elles
9
- * héritent de la couleur du texte — c'est ce qui leur permet de fonctionner
9
+ * héritent de la couleur du texte : c'est ce qui leur permet de fonctionner
10
10
  * sur papier comme sur la bande manifeste sans qu'on ait à les décliner.
11
11
  *
12
12
  * Deux façons de les poser :
13
13
  *
14
14
  * <svg class="zv-icon"><use href="…/icons/sprite.svg#zv-recherche"/></svg>
15
15
  *
16
- * ou, là où les ressources distantes sont interdites — un canvas Claude
17
- * Design —, en collant le corps de l'icône depuis icons/index.json.
16
+ * ou, là où les ressources distantes sont interdites, un canvas Claude
17
+ * Design, en collant le corps de l'icône depuis icons/index.json.
18
18
  */
19
19
 
20
20
  .zv-icon {
@@ -22,7 +22,7 @@
22
22
  width: 16px;
23
23
  height: 16px;
24
24
  /* `flex: none` évite l'écrasement quand l'icône est posée à côté d'un
25
- * libellé long dans un conteneur flex — le cas le plus fréquent, et la
25
+ * libellé long dans un conteneur flex : le cas le plus fréquent, et la
26
26
  * déformation la plus visible. */
27
27
  flex: none;
28
28
  vertical-align: middle;
@@ -32,7 +32,7 @@
32
32
  /* `square` garde l'emprise optique du rond (le bout dépasse d'une
33
33
  * demi-épaisseur, comme lui) : la silhouette change sans qu'un seul
34
34
  * tracé soit redessiné. Les angles très aigus retombent d'eux-mêmes en
35
- * biseau (miter-limit par défaut) — rien à régler. */
35
+ * biseau (miter-limit par défaut) : rien à régler. */
36
36
  stroke-linecap: square;
37
37
  stroke-linejoin: miter;
38
38
  }
@@ -84,11 +84,11 @@
84
84
  /* Désactivé. C'était la SEULE classe interactive du module sans cet état :
85
85
  * .zv-btn, .zv-chrome-btn, .zv-menu__item, .zv-pager__arrow, .zv-range et
86
86
  * les champs en ont tous un. Sans lui, un bouton fermé se rendait comme un
87
- * bouton actif — curseur main compris — et s'allumait au survol comme s'il
87
+ * bouton actif, curseur main compris, et s'allumait au survol comme s'il
88
88
  * allait agir.
89
89
  * ⚠️ Le survol est neutralisé EXPLICITEMENT : `:hover` s'applique encore à
90
90
  * un bouton désactivé, et l'application ne peut pas le rattraper depuis une
91
- * couche d'utilitaires — ce module n'est pas layered. */
91
+ * couche d'utilitaires, ce module n'est pas layered. */
92
92
  .zv-icon-btn[disabled],
93
93
  .zv-icon-btn[aria-disabled='true'] {
94
94
  opacity: 0.5;
@@ -109,7 +109,7 @@
109
109
 
110
110
  /* ─── Tuile d'icône ─────────────────────────────────────────────────────
111
111
  * HORS RELEVÉ (25/08/2026, voir DECISIONS.md). La pastille carrée qui
112
- * porte une icône devant un argument de la vitrine — liste de garanties,
112
+ * porte une icône devant un argument de la vitrine : liste de garanties,
113
113
  * grille d'atouts. Carrée par NATURE, pas par style : c'est une tuile.
114
114
  * Une par argument, jamais en décor isolé ; c'est le libellé voisin qui
115
115
  * nomme, la tuile est décorative par défaut. */
package/src/index.css CHANGED
@@ -1,4 +1,4 @@
1
- /* Zevra UI — feuille complète.
1
+ /* Zevra UI : feuille complète.
2
2
  * L'ordre compte : les tokens d'abord, le socle ensuite, puis ce qui
3
3
  * s'appuie dessus. Pour n'en charger qu'une partie, importer les modules
4
4
  * un à un dans ce même ordre.
package/src/layout.css CHANGED
@@ -1,10 +1,10 @@
1
- /* Zevra UI — mise en page : conteneurs, grilles, sections, chrome
1
+ /* Zevra UI, mise en page : conteneurs, grilles, sections, chrome
2
2
  * Dépend de tokens.css et base.css. Ne pose ni reset ni fond de page :
3
3
  * c'est le rôle de base.css.
4
4
  *
5
5
  * ⚠️ Les maquettes sont des rendus FIGÉS (1440px pour les planches, 390px
6
6
  * pour Mobile.html). Les reproduire en `width: 1440px` donnerait un
7
- * débordement horizontal garanti sur téléphone — ce que les règles du projet
7
+ * débordement horizontal garanti sur téléphone : ce que les règles du projet
8
8
  * interdisent explicitement. Les conteneurs sont donc fluides et plafonnés,
9
9
  * ce qui rend le rendu identique au-delà de 1440px et utilisable en dessous.
10
10
  */
@@ -23,7 +23,7 @@
23
23
  /* ─── Gouttières ────────────────────────────────────────────────────────
24
24
  * Trois retraits relevés, et un seul mécanisme pour les poser : ces
25
25
  * utilitaires. Les blocs ci-dessous ne portent QUE leur rythme vertical,
26
- * jamais leur retrait horizontal — sans quoi poser un utilitaire par-dessus
26
+ * jamais leur retrait horizontal : sans quoi poser un utilitaire par-dessus
27
27
  * un bloc écraserait son padding vertical (shorthand contre longhand). */
28
28
 
29
29
  .zv-gutter {
@@ -234,7 +234,7 @@
234
234
  * zone apparaît (`.zv-nav__actions` : lanceur, compte), space-between
235
235
  * centrait les liens et ouvrait un trou entre l'appel à l'action et le
236
236
  * compte. Deux apps composant la même barre se rendaient alors
237
- * différemment selon qu'elles avaient ou non la zone de droite — c'est le
237
+ * différemment selon qu'elles avaient ou non la zone de droite : c'est le
238
238
  * défaut rapporté depuis Campus et Mémoire.
239
239
  *
240
240
  * La marge automatique absorbe l'espace libre AVANT que space-between ne
@@ -255,7 +255,7 @@
255
255
  * Le lanceur et le compte, à droite. Elle ne fait PAS partie de
256
256
  * `.zv-nav__links` et c'est tout l'intérêt : cette rangée-là disparaît sous
257
257
  * le point de rupture (et sous 1150px pour `.zv-nav--riche`), remplacée par
258
- * le burger. Le compte, lui, doit rester — sinon on ne peut plus se
258
+ * le burger. Le compte, lui, doit rester : sinon on ne peut plus se
259
259
  * connecter depuis un téléphone, et c'est la première chose qu'on y fait.
260
260
  *
261
261
  * Elle se pose APRÈS `.zv-nav__links` dans le balisage, et avant le burger. */
@@ -310,7 +310,7 @@
310
310
  fill: none;
311
311
  stroke: currentColor;
312
312
  stroke-width: 2;
313
- /* Bouts francs — le trait carré du jeu d'icônes (25/08/2026). Le burger
313
+ /* Bouts francs : le trait carré du jeu d'icônes (25/08/2026). Le burger
314
314
  * applicatif, relevé « extrémités franches », y était déjà. */
315
315
  stroke-linecap: square;
316
316
  }
@@ -354,7 +354,7 @@
354
354
  /* ─── Sélecteur de langue ───────────────────────────────────────────────
355
355
  * Des initiales au registre mono, pas un menu : trois langues se lisent
356
356
  * d'un coup d'œil, et un menu pour trois entrées coûte un clic pour rien.
357
- * Une page qui n'existe que dans une langue ne le pose pas — il vaut mieux
357
+ * Une page qui n'existe que dans une langue ne le pose pas : il vaut mieux
358
358
  * pas de sélecteur qu'un sélecteur qui mène à des 404. */
359
359
 
360
360
  .zv-langues {
@@ -411,14 +411,14 @@
411
411
  * s'y fonde au défilement.
412
412
  *
413
413
  * Deux usages, une seule classe. Il est LA BARRE quand il porte directement
414
- * ses pièces ; il l'ENVELOPPE quand il contient une .zv-nav — c'est la forme
414
+ * ses pièces ; il l'ENVELOPPE quand il contient une .zv-nav : c'est la forme
415
415
  * qu'impose une nav complète, dont les menus déroulants et le tiroir ont
416
416
  * besoin d'un conteneur à eux. Le `:has` bascule tout seul, plutôt que de
417
417
  * demander un modificateur qu'on oublierait.
418
418
  *
419
419
  * ⚠️ backdrop-filter fait de ce bloc le containing block de TOUT descendant
420
420
  * en position fixe. Le tiroir (fixe lui aussi) doit donc vivre EN DEHORS,
421
- * en frère — dedans, il serait rogné par la hauteur de la barre.
421
+ * en frère : dedans, il serait rogné par la hauteur de la barre.
422
422
  *
423
423
  * Le voile venait en rgba littéral, c'est-à-dire hors token : --paper
424
424
  * repeint, la barre serait restée sur l'ancienne couleur. */
@@ -436,7 +436,7 @@
436
436
  /* Le voile est PLEIN derrière la barre, et il se dégrade EN DESSOUS d'elle
437
437
  * (::after). Il était auparavant dégradé sur toute sa hauteur : à sa base
438
438
  * il ne restait donc presque rien, et un titre de 38 ou 56px qui passait
439
- * dessous se retrouvait COUPÉ EN DEUX — moitié voilée, moitié nette, avec
439
+ * dessous se retrouvait COUPÉ EN DEUX, moitié voilée, moitié nette, avec
440
440
  * les entrées de nav posées sur ses lettres. Deux textes superposés, aucun
441
441
  * lisible. Signalé en recette sur mcp-factory.
442
442
  * Le dégradé n'est pas perdu : il vit sous la barre, là où il adoucit le
@@ -445,7 +445,7 @@
445
445
  * L'OPACITÉ, elle, est retombée de 92 à 72 %. À 92 la barre était un
446
446
  * bandeau blanc : ce qui passait dessous n'était plus qu'un fantôme, et
447
447
  * le flou ne servait à rien puisqu'il n'y avait rien à voir au travers.
448
- * C'est du verre qu'on veut, pas un cache — le rendu de
448
+ * C'est du verre qu'on veut, pas un cache : le rendu de
449
449
  * landing.zevra.tech, qui fait toujours référence. À 72 avec un flou de
450
450
  * 14, le contenu transparaît franchement ET les entrées de nav restent
451
451
  * nettes. Comparé à l'écran sur un titre passant sous la barre, à 92, 72
@@ -455,20 +455,20 @@
455
455
  * les deux vont ensemble. C'est le flou qui fait le verre ; l'opacité ne
456
456
  * fait que doser ce qu'on en voit. */
457
457
  background: color-mix(in srgb, var(--paper) 72%, transparent);
458
- /* ⚠️ LE PRÉFIXÉ D'ABORD. Lightning CSS — le compilateur de Tailwind v4,
459
- * donc celui de toutes nos applications Next — SUPPRIME `backdrop-filter`
458
+ /* ⚠️ LE PRÉFIXÉ D'ABORD. Lightning CSS (le compilateur de Tailwind v4,
459
+ * donc celui de toutes nos applications Next) SUPPRIME `backdrop-filter`
460
460
  * non préfixé quand il précède la forme `-webkit-`. Or Firefox ne connaît
461
461
  * QUE la forme non préfixée : la barre y perdait son flou. Reproduit avec
462
462
  * la chaîne exacte des apps, dans les deux ordres. L'ordre est donc une
463
463
  * contrainte, pas un style.
464
464
  *
465
465
  * Le voile, lui, reste en `color-mix` : le compilateur le traite
466
- * CORRECTEMENT — il émet un repli opaque puis la vraie valeur sous
466
+ * CORRECTEMENT, il émet un repli opaque puis la vraie valeur sous
467
467
  * `@supports`, ce qu'on lit dans les bundles livrés. Une note antérieure
468
468
  * affirmait qu'il le « réduisait » ; elle prenait le repli pour le
469
469
  * résultat. Ne pas « corriger » vers `rgb(from …)` : cette syntaxe sort du
470
470
  * compilateur NUE, sans repli, et un navigateur qui l'ignore n'a alors
471
- * plus AUCUN fond sous une barre fixe — 3,5 % d'usage qui voyaient le
471
+ * plus AUCUN fond sous une barre fixe, 3,5 % d'usage qui voyaient le
472
472
  * voile correctement et ne verraient plus rien. */
473
473
  -webkit-backdrop-filter: blur(14px);
474
474
  backdrop-filter: blur(14px);
@@ -477,7 +477,7 @@
477
477
  /* La frange de dégradé, posée SOUS la barre. `pointer-events: none` : elle
478
478
  * couvre le haut du contenu, elle ne doit rien intercepter. */
479
479
  /* Le prolongement du voile SOUS la barre : il éteint le verre au lieu de
480
- * le couper net. Son sommet doit valoir EXACTEMENT l'opacité de la barre —
480
+ * le couper net. Son sommet doit valoir EXACTEMENT l'opacité de la barre :
481
481
  * sinon la jointure fait une marche, d'autant plus visible que la barre est
482
482
  * translucide. Les deux valeurs bougent donc ensemble. */
483
483
  .zv-header::after {
@@ -656,13 +656,13 @@
656
656
  * script et un arbitrage de dessin), pas de points. Le clavier passe par le
657
657
  * focus du conteneur, que la façade rend focalisable.
658
658
  *
659
- * La barre de défilement tombe — le rail visible transformerait la vitrine
659
+ * La barre de défilement tombe : le rail visible transformerait la vitrine
660
660
  * en fenêtre d'application. C'est un MASQUAGE, pas l'habillage que
661
661
  * navigation.css refuse : aucune dimension inventée.
662
662
  *
663
663
  * ⚠️ Un carrousel reste un aveu d'espace : la règle de variété lui préfère
664
664
  * une grille tant que le contenu tient. La largeur des éléments vient du
665
- * consommateur — un carrousel qui la fixerait déciderait de la mise en page
665
+ * consommateur : un carrousel qui la fixerait déciderait de la mise en page
666
666
  * à la place de la grille. */
667
667
 
668
668
  .zv-carousel {
@@ -715,15 +715,15 @@
715
715
  /* ─── Bascule d'affichage ───────────────────────────────────────────────
716
716
  * HORS RELEVÉ : utilitaires mécaniques, pas des décisions de charte. Ils
717
717
  * existent parce que les maquettes desktop et mobile ne montrent PAS les
718
- * mêmes éléments de navigation — les liens de nav desktop deviennent un
719
- * menu burger — et que sans eux chaque app réinvente la même règle. */
718
+ * mêmes éléments de navigation, les liens de nav desktop deviennent un
719
+ * menu burger, et que sans eux chaque app réinvente la même règle. */
720
720
 
721
721
  /* Chaque utilitaire MASQUE dans la plage où l'élément n'a pas sa place, et ne
722
722
  * dit RIEN dans l'autre.
723
723
  *
724
724
  * La version précédente posait `display: none` par défaut puis
725
725
  * `display: revert` au-dessus du seuil. C'était faux : `revert` revient au
726
- * défaut du NAVIGATEUR — `inline` pour un span — et écrasait donc le
726
+ * défaut du NAVIGATEUR, `inline` pour un span, et écrasait donc le
727
727
  * `display: flex` que l'élément tenait de sa propre classe. Une rangée de
728
728
  * liens de navigation perdait sa gouttière et ses libellés se collaient.
729
729
  *
@@ -826,7 +826,7 @@
826
826
 
827
827
  /* Les liens de navigation desktop n'ont pas d'équivalent mobile au
828
828
  * relevé : Mobile.html les remplace par un menu burger. Ils ne sont pas
829
- * masqués d'office — cela casserait les pages sans burger — mais
829
+ * masqués d'office, cela casserait les pages sans burger, mais
830
830
  * .zv-only-desktop est là pour le faire en une classe. */
831
831
 
832
832
  .zv-steps__rail,
@@ -893,11 +893,11 @@
893
893
  * La table des matières d'une page longue, posée sur le côté : un libellé,
894
894
  * un point, et le point courant qui s'allume. Elle NAVIGUE (chaque entrée
895
895
  * est une ancre) et elle SUIT (le module rail.js marque la section en
896
- * cours) — les deux, sinon ce n'est qu'un décor qui occupe la marge.
896
+ * cours) : les deux, sinon ce n'est qu'un décor qui occupe la marge.
897
897
  *
898
898
  * ⚠️ Elle demande de la place à côté du texte. Sous le point de rupture
899
899
  * elle disparaît : un rail fixe sur un téléphone se pose sur la lecture.
900
- * Au-dessus, c'est la mesure de la page qui décide — une page dont le
900
+ * Au-dessus, c'est la mesure de la page qui décide : une page dont le
901
901
  * contenu court d'un bord à l'autre jusqu'à 1100px gagnera à relever le
902
902
  * seuil chez elle.
903
903
  *
@@ -978,7 +978,7 @@
978
978
  }
979
979
 
980
980
  /* L'entrée courante, posée par rail.js. Le halo du point est le seul
981
- * signal dont une navigation discrète a besoin — pas de fond, pas de
981
+ * signal dont une navigation discrète a besoin : pas de fond, pas de
982
982
  * filet. */
983
983
  .zv-rail__item--on {
984
984
  color: var(--accent-deep);
@@ -992,8 +992,8 @@
992
992
  /* ─── Le seuil d'une nav riche ──────────────────────────────────────────
993
993
  *
994
994
  * La bascule vers le tiroir est à 767px, réglée sur la nav de référence :
995
- * quatre liens simples. Une nav qui porte l'architecture d'un site — cinq
996
- * familles à menu, un sélecteur de langue, un appel à l'action — déborde
995
+ * quatre liens simples. Une nav qui porte l'architecture d'un site (cinq
996
+ * familles à menu, un sélecteur de langue, un appel à l'action) déborde
997
997
  * bien avant. Mesuré : entre 768 et 1150px, le logo passe SOUS la première
998
998
  * entrée.
999
999
  *