@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.
Files changed (104) hide show
  1. package/DECISIONS.md +264 -208
  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 +62 -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
@@ -1,11 +1,11 @@
1
1
  'use client'
2
2
 
3
- // Catalogue — la planche de tous les composants, avec un exemple rendu et le
3
+ // Catalogue : la planche de tous les composants, avec un exemple rendu et le
4
4
  // code qui le produit.
5
5
  //
6
6
  // Il est PUBLIÉ avec le paquet, pas cantonné aux tests, et c'est délibéré :
7
7
  // · la page « Design system » de l'admin le rend tel quel, donc la
8
- // documentation ne peut pas dériver des composants — c'est le même code ;
8
+ // documentation ne peut pas dériver des composants : c'est le même code ;
9
9
  // · tests/react.test.js le rend en HTML et vérifie que chaque classe émise
10
10
  // existe dans le CSS. Un composant absent du catalogue n'est pas couvert :
11
11
  // c'est le rappel le plus efficace qu'on ait trouvé pour le tenir complet.
@@ -38,7 +38,7 @@ import {
38
38
  } from './forms.js'
39
39
  import { ICONES, Icon, IconButton, IconTile, NOMS_ICONES } from './icon.js'
40
40
  // Les glyphes sont INLINÉS (data-URI) : le catalogue est rendu hors du dépôt
41
- // — planche, kit de canvas, page d'admin — où un chemin d'image ne résout pas.
41
+ // - planche, kit de canvas, page d'admin) où un chemin d'image ne résout pas.
42
42
  import {
43
43
  ACCROCHES_PRODUITS, ADRESSES_PRODUITS, APPS, GLYPHES, MOT_ZEVRA, NOMS_PRODUITS,
44
44
  } from './glyphes.js'
@@ -66,7 +66,7 @@ import {
66
66
  } from './typography.js'
67
67
 
68
68
  export interface Exemple {
69
- /** Identifiant stable — sert d'ancre dans la page de consultation. */
69
+ /** Identifiant stable : sert d'ancre dans la page de consultation. */
70
70
  id: string
71
71
  nom: string
72
72
  /** Ce que le composant fait, et surtout quand NE PAS l'employer. */
@@ -341,7 +341,7 @@ function DemoPopover() {
341
341
  }
342
342
 
343
343
  /** La barre de vitrine dans ses deux états. Rendue au REPOS : survoler le
344
- * lanceur ou la pastille déplie le panneau, comme sur un vrai site — c'est
344
+ * lanceur ou la pastille déplie le panneau, comme sur un vrai site, c'est
345
345
  * du CSS, il n'y a rien à hydrater. La réserve sous chaque barre existe pour
346
346
  * que le panneau ait la place de s'ouvrir sans être coupé. */
347
347
  function DemoNav() {
@@ -447,7 +447,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
447
447
  id: 'headings',
448
448
  nom: 'Titres',
449
449
  resume:
450
- 'Six paliers. Une page n’a qu’un <h1>, mais peut avoir plusieurs blocs à sa taille — passer « as » plutôt que de casser le plan du document.',
450
+ 'Six paliers. Une page n’a qu’un <h1>, mais peut avoir plusieurs blocs à sa taille : passer « as » plutôt que de casser le plan du document.',
451
451
  code: `<H1>La recherche juridique, sourcée</H1>
452
452
  <H2 as="h3">Ce que voit votre équipe</H2>
453
453
  <H3>Indexation continue</H3>
@@ -465,7 +465,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
465
465
  id: 'display',
466
466
  nom: 'Display',
467
467
  resume:
468
- 'Chiffre ou mot posé pour sa présence, HORS de la hiérarchie des titres — annoncé comme titre de section, il pollue le plan du document.',
468
+ 'Chiffre ou mot posé pour sa présence, HORS de la hiérarchie des titres : annoncé comme titre de section, il pollue le plan du document.',
469
469
  code: `<Display>4 812</Display>`,
470
470
  rendu: <Display>4 812</Display>,
471
471
  },
@@ -494,7 +494,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
494
494
  id: 'kicker',
495
495
  nom: 'Kicker et filet',
496
496
  resume:
497
- 'Le filet de spectre 56×2 devant un sur-titre. PREMIER des trois emplois autorisés du spectre — jamais en fond, jamais en texte.',
497
+ 'Le filet de spectre 56×2 devant un sur-titre. PREMIER des trois emplois autorisés du spectre : jamais en fond, jamais en texte.',
498
498
  code: `<Kicker>Méthode</Kicker>
499
499
  <Kicker variante="stack">Sécurité</Kicker>
500
500
  <Spec petit />`,
@@ -552,7 +552,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
552
552
  couche: 'commun',
553
553
  css: 'components.css',
554
554
  resume:
555
- "Quatre variantes, et UNE SEULE pleine par page — « danger » comprise, la règle compte les aplats, pas les couleurs : c'est ce qui fait que l'action principale se voit. Un écran à deux boutons pleins n'en a plus aucun.",
555
+ "Quatre variantes, et UNE SEULE pleine par page, « danger » comprise, la règle compte les aplats, pas les couleurs : c'est ce qui fait que l'action principale se voit. Un écran à deux boutons pleins n'en a plus aucun.",
556
556
  exemples: [
557
557
  {
558
558
  id: 'boutons',
@@ -596,7 +596,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
596
596
  id: 'etats',
597
597
  nom: 'États',
598
598
  resume:
599
- '« danger » COMPTE comme le bouton plein de la page — la règle compte les aplats, pas les couleurs ; à réserver à la confirmation destructive. « occupe » pose aria-busy et aria-disabled et AVALE le clic sans sortir le bouton du parcours clavier : le LIBELLÉ doit changer avec lui, l’estompement seul ne dit pas ce qu’on attend. Survol et appui sont dans le CSS, rien à câbler.',
599
+ '« danger » COMPTE comme le bouton plein de la page : la règle compte les aplats, pas les couleurs ; à réserver à la confirmation destructive. « occupe » pose aria-busy et aria-disabled et AVALE le clic sans sortir le bouton du parcours clavier : le LIBELLÉ doit changer avec lui, l’estompement seul ne dit pas ce qu’on attend. Survol et appui sont dans le CSS, rien à câbler.',
600
600
  code: `<Button variante="danger">Supprimer définitivement</Button>
601
601
  <Button occupe>Connexion…</Button>
602
602
  <Button variante="fantome" disabled>Envoyer</Button>`,
@@ -614,7 +614,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
614
614
  id: 'boutons-icones',
615
615
  nom: 'Boutons à icône',
616
616
  resume:
617
- 'L’icône vient du jeu (16 px) et hérite de la couleur du libellé — en prop, jamais recopiée à la main. « carre » est l’action à icône SEULE : aria-label OBLIGATOIRE, écrit pour l’ACTION. Ne pas confondre avec IconButton (chrome nu, 40 px) ni ChromeButton (croix bordée) : le carré est une action, il en a le poids.',
617
+ 'L’icône vient du jeu (16 px) et hérite de la couleur du libellé : en prop, jamais recopiée à la main. « carre » est l’action à icône SEULE : aria-label OBLIGATOIRE, écrit pour l’ACTION. Ne pas confondre avec IconButton (chrome nu, 40 px) ni ChromeButton (croix bordée) : le carré est une action, il en a le poids.',
618
618
  code: `<Button icone="telecharger">Télécharger le rapport</Button>
619
619
  <Button variante="fantome" iconeApres="chevron-droit">Étape suivante</Button>
620
620
  <Button carre variante="encre" icone="envoyer" aria-label="Envoyer le message" />`,
@@ -696,7 +696,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
696
696
  id: 'select',
697
697
  nom: 'Sélection',
698
698
  resume:
699
- 'Liste DESSINÉE jusqu’au bout — c’est le motif par défaut depuis le 25/08. Le <select> natif ne peut pas être habillé : sa liste est peinte par le système, et sort en menu noir sur un macOS en mode sombre. Clavier, annonce et recherche à la frappe sont réimplémentés ici.',
699
+ 'Liste DESSINÉE jusqu’au bout : c’est le motif par défaut depuis le 25/08. Le <select> natif ne peut pas être habillé : sa liste est peinte par le système, et sort en menu noir sur un macOS en mode sombre. Clavier, annonce et recherche à la frappe sont réimplémentés ici.',
700
700
  code: `<Field label="RÔLE" htmlFor="role">
701
701
  <SelectMenu id="role" valeur={role} onChange={setRole} options={[
702
702
  { valeur: 'admin', label: 'Administrateur' },
@@ -742,7 +742,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
742
742
  id: 'recherche',
743
743
  nom: 'Recherche',
744
744
  resume:
745
- 'Cadre + loupe + champ nu. Deux marquages au clavier (l’anneau du champ ET le filet du cadre) : assumé — supprimer l’un rend le champ invisible, l’autre prive la souris de retour.',
745
+ 'Cadre + loupe + champ nu. Deux marquages au clavier (l’anneau du champ ET le filet du cadre) : assumé, supprimer l’un rend le champ invisible, l’autre prive la souris de retour.',
746
746
  code: `<Search placeholder="Rechercher un document…" />`,
747
747
  rendu: (
748
748
  <div style={{ maxWidth: 380 }}>
@@ -822,7 +822,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
822
822
  id: 'curseur',
823
823
  nom: 'Curseur',
824
824
  resume:
825
- 'Natif habillé : clavier, bornes et annonce viennent du navigateur ; le remplissage suit la valeur en contrôlé. Toujours un intitulé ET la valeur affichée en clair — un curseur seul ne dit ni ce qu’il règle, ni sur combien. Pas de spectre sur la piste : ce n’est pas une barre de progression.',
825
+ 'Natif habillé : clavier, bornes et annonce viennent du navigateur ; le remplissage suit la valeur en contrôlé. Toujours un intitulé ET la valeur affichée en clair : un curseur seul ne dit ni ce qu’il règle, ni sur combien. Pas de spectre sur la piste : ce n’est pas une barre de progression.',
826
826
  code: `<Field label="SOURCES INTERROGÉES" htmlFor="prof" help={\`\${sources} sources sur 17\`}>
827
827
  <Range id="prof" min={1} max={17} value={sources} onChange={…} />
828
828
  </Field>`,
@@ -852,7 +852,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
852
852
  id: 'mot-de-passe',
853
853
  nom: 'Mot de passe',
854
854
  resume:
855
- 'Le seul champ où l’on tape sans voir ce qu’on écrit : sur un mot de passe long saisi au clavier d’un téléphone, la bascule évite l’échec silencieux. L’état est tenu par l’appelant, et le libellé du bouton change — une icône seule ne dit pas ce qui va se passer.',
855
+ 'Le seul champ où l’on tape sans voir ce qu’on écrit : sur un mot de passe long saisi au clavier d’un téléphone, la bascule évite l’échec silencieux. L’état est tenu par l’appelant, et le libellé du bouton change : une icône seule ne dit pas ce qui va se passer.',
856
856
  code: `const [visible, setVisible] = useState(false)
857
857
 
858
858
  <Field label="MOT DE PASSE" htmlFor="mdp">
@@ -871,7 +871,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
871
871
  couche: 'applicatif',
872
872
  css: 'feedback.css',
873
873
  resume:
874
- "Rien n'y crie : le bandeau porte le ton, la pastille l'état, la phrase le travail. La roue, le squelette et l'infobulle — longtemps refusés faute de relevé — sont arbitrés depuis le 25/08/2026 (DECISIONS.md), chacun avec son périmètre écrit ; « Loading », qui nomme ce qu'on attend, reste le motif d'attente par défaut.",
874
+ "Rien n'y crie : le bandeau porte le ton, la pastille l'état, la phrase le travail. La roue, le squelette et l'infobulle, longtemps refusés faute de relevé, sont arbitrés depuis le 25/08/2026 (DECISIONS.md), chacun avec son périmètre écrit ; « Loading », qui nomme ce qu'on attend, reste le motif d'attente par défaut.",
875
875
  exemples: [
876
876
  {
877
877
  id: 'alertes',
@@ -968,7 +968,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
968
968
  id: 'roue',
969
969
  nom: 'Roue',
970
970
  resume:
971
- 'Attente COURTE et LOCALE : un bouton, une cellule, un panneau sans la place d’une phrase. Pour l’attente d’un écran, « Loading » reste le motif — la phrase dit sur quoi et sur combien. Sans label, la roue est décorative et masquée aux lecteurs d’écran.',
971
+ 'Attente COURTE et LOCALE : un bouton, une cellule, un panneau sans la place d’une phrase. Pour l’attente d’un écran, « Loading » reste le motif : la phrase dit sur quoi et sur combien. Sans label, la roue est décorative et masquée aux lecteurs d’écran.',
972
972
  code: `<Spinner label="Vérification du dépôt…" />
973
973
  <Spinner grand />`,
974
974
  rendu: (
@@ -982,7 +982,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
982
982
  id: 'squelette',
983
983
  nom: 'Squelette',
984
984
  resume:
985
- 'Il ANNONCE une structure connue — la carte, la ligne qui va venir ; pour un contenu de forme inconnue, c’est « Loading ». La géométrie vient de l’appelant : un squelette qui invente ses dimensions ne ressemble jamais au contenu. C’est la zone qui charge qui porte aria-busy, pas chaque os.',
985
+ 'Il ANNONCE une structure connue : la carte, la ligne qui va venir ; pour un contenu de forme inconnue, c’est « Loading ». La géométrie vient de l’appelant : un squelette qui invente ses dimensions ne ressemble jamais au contenu. C’est la zone qui charge qui porte aria-busy, pas chaque os.',
986
986
  code: `<div aria-busy="true">
987
987
  <Skeleton texte largeur="60%" />
988
988
  <Skeleton texte />
@@ -1000,7 +1000,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1000
1000
  id: 'infobulle',
1001
1001
  nom: 'Infobulle',
1002
1002
  resume:
1003
- 'Un COMPLÉMENT dispensable — un raccourci, une date exacte, une unité : une commande n’a pas le droit d’y cacher son nom, et le tactile ne survole pas. Liage aria-describedby EXPLICITE (id), comme le htmlFor de Field — pas de useId, le rendu serveur reste possible. Apparition retardée de 300 ms, disparition immédiate, Échap la ferme.',
1003
+ 'Un COMPLÉMENT dispensable, un raccourci, une date exacte, une unité : une commande n’a pas le droit d’y cacher son nom, et le tactile ne survole pas. Liage aria-describedby EXPLICITE (id), comme le htmlFor de Field : pas de useId, le rendu serveur reste possible. Apparition retardée de 300 ms, disparition immédiate, Échap la ferme.',
1004
1004
  code: `<Tooltip id="th-date" contenu="Déposé le 12/08/2026 à 14 h 02">
1005
1005
  <Button variante="fantome" compact aria-describedby="th-date">12 août</Button>
1006
1006
  </Tooltip>`,
@@ -1029,7 +1029,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1029
1029
  id: 'page-erreur',
1030
1030
  nom: 'Page d’erreur',
1031
1031
  resume:
1032
- '404, 403, 410, 500. ⚠️ Le glyphe est DÉCORATIF par défaut (glypheAlt=""), et le mot « Erreur » se passe en prop : la 0.32.0 posait alt="Zevra" et « Erreur » en dur, si bien que la 404 de Mémoire annonçait « Zevra » au lecteur d’écran et affichait « Erreur 404 » sous /en/. Le composant ne porte AUCUN texte : une plaisanterie câblée dans un design system part dans les sept apps, dans une seule langue, et n’en revient jamais. La copie ci-dessous est la RÉFÉRENCE, à copier et à adapter. Elle plaisante en vocabulaire juridique — un mot juste employé de travers, pas une blague sur un ton qu’Encre & Papier n’a pas — et l’ordre est fixe : le titre dit la panne en clair, l’esprit vient ensuite et se dédit lui-même. Une page d’erreur qui fait rire avant d’informer est ratée.',
1032
+ '404, 403, 410, 500. ⚠️ Le glyphe est DÉCORATIF par défaut (glypheAlt=""), et le mot « Erreur » se passe en prop : la 0.32.0 posait alt="Zevra" et « Erreur » en dur, si bien que la 404 de Mémoire annonçait « Zevra » au lecteur d’écran et affichait « Erreur 404 » sous /en/. Le composant ne porte AUCUN texte : une plaisanterie câblée dans un design system part dans les sept apps, dans une seule langue, et n’en revient jamais. La copie ci-dessous est la RÉFÉRENCE, à copier et à adapter. Elle plaisante en vocabulaire juridique (un mot juste employé de travers, pas une blague sur un ton qu’Encre & Papier n’a pas) et l’ordre est fixe : le titre dit la panne en clair, l’esprit vient ensuite et se dédit lui-même. Une page d’erreur qui fait rire avant d’informer est ratée.',
1033
1033
  code: `<PageErreur
1034
1034
  code="404"
1035
1035
  libelle="Erreur" {/* le mot est À VOUS : « Error » sous /en/ */}
@@ -1157,7 +1157,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1157
1157
  id: 'preuve',
1158
1158
  nom: 'Aperçu d’interface',
1159
1159
  resume:
1160
- '⚠️ RÈGLE DE CHARTE : toujours de VRAIES données réalistes, jamais de lorem — c’est ce bloc qui porte la crédibilité de la page.',
1160
+ '⚠️ RÈGLE DE CHARTE : toujours de VRAIES données réalistes, jamais de lorem, c’est ce bloc qui porte la crédibilité de la page.',
1161
1161
  code: `<UiPreview question="Quelle est la durée de préavis ?"
1162
1162
  sources="12 sources" puces={<SrcRow>…</SrcRow>}>
1163
1163
  Trois mois pour les cadres…
@@ -1260,7 +1260,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1260
1260
  id: 'page-legale',
1261
1261
  nom: 'Page légale',
1262
1262
  resume:
1263
- 'La FORME d’un document contractuel ; le TEXTE vit dans @zevra/legal, versionné et archivé — le design system ne dépend pas du contenu, sinon corriger une clause deviendrait une livraison de charte. La version est AFFICHÉE : c’est ce que l’utilisateur cite quand il conteste. ⚠️ Jamais de « voir plus » sur un contrat : ce qu’on accepte se lit en entier là où on l’accepte. Le sommaire se pose à côté, avec « Rail ».',
1263
+ 'La FORME d’un document contractuel ; le TEXTE vit dans @zevra/legal, versionné et archivé : le design system ne dépend pas du contenu, sinon corriger une clause deviendrait une livraison de charte. La version est AFFICHÉE : c’est ce que l’utilisateur cite quand il conteste. ⚠️ Jamais de « voir plus » sur un contrat : ce qu’on accepte se lit en entier là où on l’accepte. Le sommaire se pose à côté, avec « Rail ».',
1264
1264
  code: `import { enVigueur } from '@zevra/legal'
1265
1265
 
1266
1266
  <LegalPage document={enVigueur('mentions-legales')} />`,
@@ -1306,12 +1306,12 @@ export const CATALOGUE: GroupeCatalogue[] = [
1306
1306
  id: 'citation',
1307
1307
  nom: 'Citation client',
1308
1308
  resume:
1309
- '⚠️ RÈGLE DE CHARTE : jamais de fausse citation. Tant qu’un verbatim n’a pas été recueilli, ce bloc reste EN RÉSERVE — un placeholder crédible finit toujours par partir en production.',
1310
- code: `<Band><Quote auteur="— Nom, cabinet">Verbatim réel uniquement.</Quote></Band>`,
1309
+ '⚠️ RÈGLE DE CHARTE : jamais de fausse citation. Tant qu’un verbatim n’a pas été recueilli, ce bloc reste EN RÉSERVE : un placeholder crédible finit toujours par partir en production.',
1310
+ code: `<Band><Quote auteur=": Nom, cabinet">Verbatim réel uniquement.</Quote></Band>`,
1311
1311
  surSombre: true,
1312
1312
  rendu: (
1313
1313
  <Band>
1314
- <Quote auteur="— en attente d’un verbatim recueilli">
1314
+ <Quote auteur=": en attente d’un verbatim recueilli">
1315
1315
  Ce bloc reste en réserve tant qu’aucune citation réelle n’a été
1316
1316
  recueillie.
1317
1317
  </Quote>
@@ -1375,7 +1375,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1375
1375
  id: 'tableau-prose',
1376
1376
  nom: 'Tableau de prose',
1377
1377
  resume:
1378
- 'Les cellules reviennent à la ligne au lieu de tronquer. ⚠️ Dès qu’une cellule porte une PHRASE et non une donnée — une clause, un fondement juridique, une durée et son motif —, tronquer ne raccourcit pas : ça cache, et le lecteur n’a aucun moyen de savoir qu’il manque quelque chose. La troncature reste juste pour une ligne de données, qui se balaye du regard.',
1378
+ 'Les cellules reviennent à la ligne au lieu de tronquer. ⚠️ Dès qu’une cellule porte une PHRASE et non une donnée (une clause, un fondement juridique, une durée et son motif), tronquer ne raccourcit pas : ça cache, et le lecteur n’a aucun moyen de savoir qu’il manque quelque chose. La troncature reste juste pour une ligne de données, qui se balaye du regard.',
1379
1379
  code: `<Table prose gabarit="minmax(0,1fr) minmax(0,2fr)">
1380
1380
  <TableHead><Cell>Donnée</Cell><Cell>Durée et fondement</Cell></TableHead>
1381
1381
  <Row>
@@ -1466,7 +1466,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1466
1466
  id: 'meta',
1467
1467
  nom: 'Métadonnées',
1468
1468
  resume:
1469
- 'Second registre mono, en BAS DE CASSE : taille, date, latence. Ni capitales ni interlettrage — c’est ce qui le distingue de « Mono », et une date en capitales espacées devient illisible.',
1469
+ 'Second registre mono, en BAS DE CASSE : taille, date, latence. Ni capitales ni interlettrage : c’est ce qui le distingue de « Mono », et une date en capitales espacées devient illisible.',
1470
1470
  code: `<MetaRow><Meta>12 mars 2026</Meta><Meta taille="sm">1,2 s</Meta></MetaRow>`,
1471
1471
  rendu: (
1472
1472
  <MetaRow>
@@ -1500,7 +1500,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1500
1500
  id: 'avatar-chip',
1501
1501
  nom: 'Pastilles et catégories',
1502
1502
  resume:
1503
- 'Avatar CARRÉ, jamais rond : le rond est un usage de réseau social. ⚠️ Sa teinte dit la NATURE de l’entité — la changer, c’est changer le sens.',
1503
+ 'Avatar CARRÉ, jamais rond : le rond est un usage de réseau social. ⚠️ Sa teinte dit la NATURE de l’entité : la changer, c’est changer le sens.',
1504
1504
  code: `<Avatar ton="accent">MD</Avatar>
1505
1505
  <ChipRow><Chip>Droit social</Chip><Chip variante="outline">2024</Chip></ChipRow>`,
1506
1506
  rendu: (
@@ -1552,7 +1552,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1552
1552
  id: 'depliant',
1553
1553
  nom: 'Rangée dépliante',
1554
1554
  resume:
1555
- '<details> NATIF : clavier, annonce et état viennent du navigateur, aucun JavaScript. Le pliage APPLICATIF — options avancées, détail d’une ligne de journal ; la FAQ (contenu) reste celui de la vitrine. Plusieurs rangées se posent bord à bord, le filet mitoyen tombe seul.',
1555
+ '<details> NATIF : clavier, annonce et état viennent du navigateur, aucun JavaScript. Le pliage APPLICATIF : options avancées, détail d’une ligne de journal ; la FAQ (contenu) reste celui de la vitrine. Plusieurs rangées se posent bord à bord, le filet mitoyen tombe seul.',
1556
1556
  code: `<Fold titre="Options avancées">…</Fold>
1557
1557
  <Fold titre="Journal d'indexation" ouvert>…</Fold>`,
1558
1558
  rendu: (
@@ -1572,7 +1572,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1572
1572
  id: 'code',
1573
1573
  nom: 'Code et raccourcis',
1574
1574
  resume:
1575
- 'La chasse fixe RÉELLE (--font-code) : --font-mono est proportionnelle et n’aligne pas du code, tabular-nums n’aligne que les chiffres. Aucune coloration syntaxique — elle imposerait une palette que la charte n’a pas. « ⌘K » fait DEUX touches, donc deux Kbd.',
1575
+ 'La chasse fixe RÉELLE (--font-code) : --font-mono est proportionnelle et n’aligne pas du code, tabular-nums n’aligne que les chiffres. Aucune coloration syntaxique : elle imposerait une palette que la charte n’a pas. « ⌘K » fait DEUX touches, donc deux Kbd.',
1576
1576
  code: `<Body>Lancer <Code>pnpm build</Code>, puis <Kbd>⌘</Kbd> <Kbd>K</Kbd>.</Body>
1577
1577
  <CodeBlock>claude mcp add --transport http zevra-design …</CodeBlock>`,
1578
1578
  rendu: (
@@ -1596,13 +1596,13 @@ export const CATALOGUE: GroupeCatalogue[] = [
1596
1596
  couche: 'applicatif',
1597
1597
  css: 'navigation.css',
1598
1598
  resume:
1599
- "Rien n'a d'état propre : l'entrée courante, la page courante et l'item sélectionné viennent de l'appelant — c'est ce qui permet à une colonne de navigation Next de rester rendue au serveur.",
1599
+ "Rien n'a d'état propre : l'entrée courante, la page courante et l'item sélectionné viennent de l'appelant, c'est ce qui permet à une colonne de navigation Next de rester rendue au serveur.",
1600
1600
  exemples: [
1601
1601
  {
1602
1602
  id: 'sidebar',
1603
1603
  nom: 'Colonne latérale',
1604
1604
  resume:
1605
- 'Une colonne, un filet, rien d’autre. « courant » pose aria-current="page" en plus de la classe : sans lui, l’entrée courante est marquée pour l’œil et muette au lecteur d’écran. « num » accepte un rang mono OU un glyphe (le ⚙ du relevé), sur la même colonne de 16 px — jamais les deux.',
1605
+ 'Une colonne, un filet, rien d’autre. « courant » pose aria-current="page" en plus de la classe : sans lui, l’entrée courante est marquée pour l’œil et muette au lecteur d’écran. « num » accepte un rang mono OU un glyphe (le ⚙ du relevé), sur la même colonne de 16 px : jamais les deux.',
1606
1606
  code: `<Sidebar>
1607
1607
  <SidebarHead>…</SidebarHead>
1608
1608
  <SideGroup titre="Espace">
@@ -1644,7 +1644,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1644
1644
  id: 'topbar',
1645
1645
  nom: 'Barre supérieure',
1646
1646
  resume:
1647
- '⚠️ Elle REMPLACE la colonne sous le point de rupture : masquée au-dessus, elle n’apparaît que dans le bloc mobile du CSS. Ne jamais la conditionner en JavaScript — le serveur ne connaît pas la largeur de l’écran.',
1647
+ '⚠️ Elle REMPLACE la colonne sous le point de rupture : masquée au-dessus, elle n’apparaît que dans le bloc mobile du CSS. Ne jamais la conditionner en JavaScript : le serveur ne connaît pas la largeur de l’écran.',
1648
1648
  code: `<Topbar>
1649
1649
  <TopbarBurger aria-label="Ouvrir la navigation">☰</TopbarBurger>
1650
1650
  <TopbarLogo><img src="/logo.svg" alt="" /></TopbarLogo>
@@ -1660,7 +1660,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1660
1660
  id: 'crumbs',
1661
1661
  nom: 'Fil d’Ariane',
1662
1662
  resume:
1663
- '⚠️ Le fil ENTIER est cliquable — c’est un seul nœud, pas une liste de liens. Le DERNIER segment est plus sombre : c’est celui qu’on lit, le reste n’est qu’un chemin.',
1663
+ '⚠️ Le fil ENTIER est cliquable : c’est un seul nœud, pas une liste de liens. Le DERNIER segment est plus sombre : c’est celui qu’on lit, le reste n’est qu’un chemin.',
1664
1664
  code: `<Crumbs href="/dossiers/2024" segments={['Dossiers', '2024', 'Duflot']} />`,
1665
1665
  rendu: <Crumbs href="#" segments={['Dossiers', '2024', 'Duflot & Associés']} />,
1666
1666
  },
@@ -1668,7 +1668,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1668
1668
  id: 'onglets',
1669
1669
  nom: 'Onglets en puces',
1670
1670
  resume:
1671
- 'La rangée de puces, grammaire d’état de Seg — le motif des FILTRES, qui restreignent une collection. Ce composant n’ajoute que l’ARIA. Pour les VUES d’un même objet, prendre la variante soulignée.',
1671
+ 'La rangée de puces, grammaire d’état de Seg : le motif des FILTRES, qui restreignent une collection. Ce composant n’ajoute que l’ARIA. Pour les VUES d’un même objet, prendre la variante soulignée.',
1672
1672
  code: `<Tabs actif={actif} onChange={setActif} onglets={[
1673
1673
  { id: 'apercu', label: 'Aperçu' },
1674
1674
  { id: 'sources', label: 'Sources', compte: 12 },
@@ -1679,7 +1679,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1679
1679
  id: 'onglets-soulignes',
1680
1680
  nom: 'Onglets soulignés',
1681
1681
  resume:
1682
- 'L’arbitrage longtemps en attente, tranché le 25/08/2026 : trait actif de 2 px — l’épaisseur des filets dessinés du système — en accent, PAS en spectre (un quatrième emploi n’existe pas). Pour les VUES d’un même objet (Aperçu / Sources) ; pour filtrer, les puces.',
1682
+ 'L’arbitrage longtemps en attente, tranché le 25/08/2026 : trait actif de 2 px, l’épaisseur des filets dessinés du système, en accent, PAS en spectre (un quatrième emploi n’existe pas). Pour les VUES d’un même objet (Aperçu / Sources) ; pour filtrer, les puces.',
1683
1683
  code: `<Tabs variante="soulignes" actif={actif} onChange={setActif} onglets={[
1684
1684
  { id: 'apercu', label: 'Aperçu' },
1685
1685
  { id: 'sources', label: 'Sources', compte: 12 },
@@ -1690,7 +1690,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1690
1690
  id: 'popover',
1691
1691
  nom: 'Popover',
1692
1692
  resume:
1693
- 'Surface ancrée LIBRE — aide contextuelle, mini-formulaire de filtre — dans la même ancre que le menu (SelectAnchor). Ce n’est PAS une infobulle : le popover s’ouvre au CLIC et peut porter de l’interactif. Fermeture par clic extérieur et Échap : à l’appelant, comme pour le menu.',
1693
+ 'Surface ancrée LIBRE (aide contextuelle, mini-formulaire de filtre) dans la même ancre que le menu (SelectAnchor). Ce n’est PAS une infobulle : le popover s’ouvre au CLIC et peut porter de l’interactif. Fermeture par clic extérieur et Échap : à l’appelant, comme pour le menu.',
1694
1694
  code: `<SelectAnchor>
1695
1695
  <Button variante="fantome" compact aria-expanded={ouvert} onClick={…}>Colonnes affichées</Button>
1696
1696
  {ouvert && <Popover>…</Popover>}
@@ -1776,7 +1776,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1776
1776
  couche: 'commun',
1777
1777
  css: 'overlays.css',
1778
1778
  resume:
1779
- "Le seul module marqué « use client ». Tout ce qui vit ici vole le regard à la page : il faut Échap, un piège de focus et un verrou de défilement — rien de cela ne s'écrit en CSS. Le hook « useOverlay » est exporté pour les enrobages maison.",
1779
+ "Le seul module marqué « use client ». Tout ce qui vit ici vole le regard à la page : il faut Échap, un piège de focus et un verrou de défilement, rien de cela ne s'écrit en CSS. Le hook « useOverlay » est exporté pour les enrobages maison.",
1780
1780
  exemples: [
1781
1781
  {
1782
1782
  id: 'tiroir',
@@ -1793,7 +1793,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1793
1793
  id: 'modale',
1794
1794
  nom: 'Modale',
1795
1795
  resume:
1796
- 'Fermée, elle n’est pas rendue du tout : son contenu — un formulaire, le plus souvent — ne doit pas rester dans le DOM à l’état fantôme. « danger » met l’avertissement dans le filet HAUT, pas dans un fond rouge qui rendrait le texte pénible à lire.',
1796
+ 'Fermée, elle n’est pas rendue du tout : son contenu (un formulaire, le plus souvent) ne doit pas rester dans le DOM à l’état fantôme. « danger » met l’avertissement dans le filet HAUT, pas dans un fond rouge qui rendrait le texte pénible à lire.',
1797
1797
  code: `<Modal ouvert={ouvert} onClose={…} titre="Supprimer" danger
1798
1798
  pied={<ButtonRow>…</ButtonRow>}>
1799
1799
  …
@@ -1804,7 +1804,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1804
1804
  id: 'toast',
1805
1805
  nom: 'Notification',
1806
1806
  resume:
1807
- '⚠️ Ne remplace PAS « Alert » : une erreur de formulaire se dit à côté du champ, jamais dans un coin qui disparaît. Réserver à ce qui est vrai APRÈS COUP — « copié », « enregistré », « envoyé ».',
1807
+ '⚠️ Ne remplace PAS « Alert » : une erreur de formulaire se dit à côté du champ, jamais dans un coin qui disparaît. Réserver à ce qui est vrai APRÈS COUP : « copié », « enregistré », « envoyé ».',
1808
1808
  code: `<Toasts>
1809
1809
  <Toast ton="ok">Lien copié.</Toast>
1810
1810
  </Toasts>`,
@@ -1825,13 +1825,13 @@ export const CATALOGUE: GroupeCatalogue[] = [
1825
1825
  couche: 'commun',
1826
1826
  css: 'icons.css',
1827
1827
  resume:
1828
- "55 icônes TRACÉES, jamais pleines : trait 2, grille de 24, BOUTS FRANCS et jonctions vives — le trait carré de la charte, points d'encre carrés compris. Elles héritent de la couleur du texte — c'est ce qui leur permet de fonctionner sur papier comme sur la bande manifeste sans déclinaison. Le tracé est inliné : rien à résoudre côté bundler, rien à autoriser côté CSP.",
1828
+ "55 icônes TRACÉES, jamais pleines : trait 2, grille de 24, BOUTS FRANCS et jonctions vives, le trait carré de la charte, points d'encre carrés compris. Elles héritent de la couleur du texte : c'est ce qui leur permet de fonctionner sur papier comme sur la bande manifeste sans déclinaison. Le tracé est inliné : rien à résoudre côté bundler, rien à autoriser côté CSP.",
1829
1829
  exemples: [
1830
1830
  {
1831
1831
  id: 'jeu',
1832
1832
  nom: 'Le jeu complet',
1833
1833
  resume:
1834
- 'Sans « titre », l’icône est DÉCORATIVE et masquée aux lecteurs d’écran — le bon défaut : accolée à un libellé qui la répète, elle crée une annonce double.',
1834
+ 'Sans « titre », l’icône est DÉCORATIVE et masquée aux lecteurs d’écran, le bon défaut : accolée à un libellé qui la répète, elle crée une annonce double.',
1835
1835
  code: `<Icon nom="recherche" />
1836
1836
  <Icon nom="document" taille="lg" />
1837
1837
  <Icon nom="alerte" titre="Alerte" />`,
@@ -1873,7 +1873,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1873
1873
  id: 'tuile',
1874
1874
  nom: 'Tuile d’icône',
1875
1875
  resume:
1876
- 'La pastille carrée devant un argument de la vitrine — liste de garanties, grille d’atouts. DÉCORATIVE par défaut : c’est le libellé voisin qui nomme, un titre ne se pose que si elle est seule. UNE par argument, jamais en décor isolé — une tuile sans libellé est un rébus.',
1876
+ 'La pastille carrée devant un argument de la vitrine : liste de garanties, grille d’atouts. DÉCORATIVE par défaut : c’est le libellé voisin qui nomme, un titre ne se pose que si elle est seule. UNE par argument, jamais en décor isolé : une tuile sans libellé est un rébus.',
1877
1877
  code: `<IconTile nom="bouclier-verifie" />
1878
1878
  <IconTile nom="balance" />`,
1879
1879
  rendu: (
@@ -1881,7 +1881,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1881
1881
  {(
1882
1882
  [
1883
1883
  ['bouclier-verifie', 'Hébergement souverain', 'Infrastructure dédiée, en France.'],
1884
- ['balance', 'Sources officielles', 'BOSS, Judilibre, KALI — datées et citées.'],
1884
+ ['balance', 'Sources officielles', 'BOSS, Judilibre, KALI : datées et citées.'],
1885
1885
  ['cadenas', 'Zéro réutilisation', 'Vos pièces n’entraînent aucun modèle.'],
1886
1886
  ] as const
1887
1887
  ).map(([nom, titre, texte]) => (
@@ -1905,13 +1905,13 @@ export const CATALOGUE: GroupeCatalogue[] = [
1905
1905
  couche: 'vitrine',
1906
1906
  css: 'components.css',
1907
1907
  resume:
1908
- "Quatre façons de poser du contenu SANS carte. Ils existent pour une règle de composition de la DA (24/08/2026) : jamais deux blocs de même forme qui se suivent, 80 % de formes différentes par page — les grilles de cartes redeviennent un choix, pas un réflexe.",
1908
+ "Quatre façons de poser du contenu SANS carte. Ils existent pour une règle de composition de la DA (24/08/2026) : jamais deux blocs de même forme qui se suivent, 80 % de formes différentes par page, les grilles de cartes redeviennent un choix, pas un réflexe.",
1909
1909
  exemples: [
1910
1910
  {
1911
1911
  id: 'rows',
1912
1912
  nom: 'Rangées à filets',
1913
1913
  resume:
1914
- 'Libellé fort + contenu, un trait fin entre chaque rangée. Pour les listes où l’ALIGNEMENT fait la lecture (profils rencontrés, prestations, caractéristiques) — là où des cartes casseraient la comparaison.',
1914
+ 'Libellé fort + contenu, un trait fin entre chaque rangée. Pour les listes où l’ALIGNEMENT fait la lecture (profils rencontrés, prestations, caractéristiques) : là où des cartes casseraient la comparaison.',
1915
1915
  code: `<Rows>
1916
1916
  <RowsItem cle="Directions juridiques">Structurer la connaissance interne…</RowsItem>
1917
1917
  <RowsItem cle="Cabinets d’avocats">Retrouver la jurisprudence du cabinet…</RowsItem>
@@ -1953,7 +1953,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1953
1953
  <IndexItem num="02">
1954
1954
  <CardTitle>Indexation</CardTitle>
1955
1955
  <Body taille="dense">
1956
- Le corpus est océrisé, anonymisé et indexé — comptez une semaine pour
1956
+ Le corpus est océrisé, anonymisé et indexé : comptez une semaine pour
1957
1957
  10 000 pièces.
1958
1958
  </Body>
1959
1959
  </IndexItem>
@@ -1964,7 +1964,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1964
1964
  id: 'flow',
1965
1965
  nom: 'Déroulé vertical',
1966
1966
  resume:
1967
- 'La déclinaison verticale de « Steps », pour les méthodes qui se lisent comme un récit. Les points reprennent les couleurs des points de méthode — l’un des trois emplois autorisés du spectre.',
1967
+ 'La déclinaison verticale de « Steps », pour les méthodes qui se lisent comme un récit. Les points reprennent les couleurs des points de méthode : l’un des trois emplois autorisés du spectre.',
1968
1968
  code: `<Flow>
1969
1969
  <FlowStep><CardTitle>Déposer</CardTitle>…</FlowStep>
1970
1970
  <FlowStep teinte="violet"><CardTitle>Interroger</CardTitle>…</FlowStep>
@@ -1991,7 +1991,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
1991
1991
  id: 'callout',
1992
1992
  nom: 'Encart d’appel',
1993
1993
  resume:
1994
- 'Une bande sur accent-soft, un titre, une action : l’offre transverse qui doit se voir sans crier (remise, renvoi vers une autre page). L’action passe en enfant — elle se range à droite et tombe sous le titre sur mobile.',
1994
+ 'Une bande sur accent-soft, un titre, une action : l’offre transverse qui doit se voir sans crier (remise, renvoi vers une autre page). L’action passe en enfant : elle se range à droite et tombe sous le titre sur mobile.',
1995
1995
  code: `<Callout titre="Formation Campus incluse la première année">
1996
1996
  <ButtonLink href="/campus" variante="fantome">Découvrir Campus</ButtonLink>
1997
1997
  </Callout>`,
@@ -2034,7 +2034,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2034
2034
  id: 'grille',
2035
2035
  nom: 'Grilles',
2036
2036
  resume:
2037
- '⚠️ Seules les portées 3, 4, 6, 8 et 9 existent : ce sont les découpes employées par la vitrine. En ajouter une revient à ajouter une mise en page — c’est une décision de DA, pas une utilité.',
2037
+ '⚠️ Seules les portées 3, 4, 6, 8 et 9 existent : ce sont les découpes employées par la vitrine. En ajouter une revient à ajouter une mise en page : c’est une décision de DA, pas une utilité.',
2038
2038
  code: `<Grid12>
2039
2039
  <Col span={8}>…</Col>
2040
2040
  <Col span={4}>…</Col>
@@ -2069,7 +2069,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2069
2069
  id: 'sections',
2070
2070
  nom: 'Sections',
2071
2071
  resume:
2072
- 'Le bloc « aside » tombe SOUS le titre en dessous du point de rupture — c’est le CSS qui le fait, pas une condition de rendu.',
2072
+ 'Le bloc « aside » tombe SOUS le titre en dessous du point de rupture : c’est le CSS qui le fait, pas une condition de rendu.',
2073
2073
  code: `<SectionHead aside={<LinkArrow href="/methode">Tout voir</LinkArrow>}>
2074
2074
  <Kicker>Méthode</Kicker>
2075
2075
  <H2>Trois étapes, rien de plus</H2>
@@ -2088,7 +2088,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2088
2088
  {
2089
2089
  id: 'sheet-section',
2090
2090
  nom: 'Section de document',
2091
- resume: 'Un intitulé mono, un filet, du corps — pour un document long.',
2091
+ resume: 'Un intitulé mono, un filet, du corps : pour un document long.',
2092
2092
  code: `<SheetSection titre="ENGAGEMENTS">…</SheetSection>`,
2093
2093
  rendu: (
2094
2094
  <SheetSection titre="ENGAGEMENTS">
@@ -2103,7 +2103,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2103
2103
  id: 'nav-vitrine',
2104
2104
  nom: 'Navigation',
2105
2105
  resume:
2106
- 'LA barre du site, dans ses deux états — c’est le design de landing.zevra.tech, et il fait référence : une app qui compose sa propre barre finit par ne plus ressembler aux autres. Deux zones, et la distinction n’est pas cosmétique : « NavLinks » porte ce qui TOMBE dans le tiroir sous le point de rupture (familles, langues, appel à l’action) ; « NavActions » porte ce qui RESTE à toutes les largeurs — lanceur, compte, burger. Un compte placé dans NavLinks s’évanouit sur téléphone, et l’on ne peut plus se connecter. ⚠️ Le lanceur ET le compte sont là dans les deux états : les produits sont publics, et une barre où l’on ne peut pas se connecter est une barre où l’on ne revient pas. Seul le contenu du compte change. Survoler une famille, le lanceur ou la pastille pour déplier — c’est du CSS, il n’y a rien à hydrater. « zv-nav--riche » bascule vers le tiroir à 1150px, où une barre de cette densité déborde (mesuré), et non à 768.',
2106
+ 'LA barre du site, dans ses deux états, c’est le design de landing.zevra.tech, et il fait référence : une app qui compose sa propre barre finit par ne plus ressembler aux autres. Deux zones, et la distinction n’est pas cosmétique : « NavLinks » porte ce qui TOMBE dans le tiroir sous le point de rupture (familles, langues, appel à l’action) ; « NavActions » porte ce qui RESTE à toutes les largeurs, lanceur, compte, burger. Un compte placé dans NavLinks s’évanouit sur téléphone, et l’on ne peut plus se connecter. ⚠️ Le lanceur ET le compte sont là dans les deux états : les produits sont publics, et une barre où l’on ne peut pas se connecter est une barre où l’on ne revient pas. Seul le contenu du compte change. Survoler une famille, le lanceur ou la pastille pour déplier : c’est du CSS, il n’y a rien à hydrater. « zv-nav--riche » bascule vers le tiroir à 1150px, où une barre de cette densité déborde (mesuré), et non à 768.',
2107
2107
  code: `<Nav className="zv-nav--riche">
2108
2108
  <NavLogo>
2109
2109
  <Lockup capitale={15}>
@@ -2135,7 +2135,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2135
2135
  {/* APPS = les produits QUI ONT UNE ADRESSE, pas les sept glyphes :
2136
2136
  une tuile qui mène à rien promet un produit et fait tomber le
2137
2137
  visiteur. Plume et Supernovia y entreront le jour où ils ouvrent,
2138
- par une ligne dans logos/index.json — sans toucher aux apps. */}
2138
+ par une ligne dans logos/index.json : sans toucher aux apps. */}
2139
2139
  <Lanceur> {/* titre="Applications" par défaut, filet de spectre */}
2140
2140
  <LanceurGroupe>Suite Zevra</LanceurGroupe>
2141
2141
  <LanceurApps>
@@ -2159,7 +2159,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2159
2159
  id: 'lockup',
2160
2160
  nom: 'Lockup',
2161
2161
  resume:
2162
- 'La marque et le mot. Tout se pilote par « capitale », qui EST la hauteur de capitale : la marque vaut 2,86 fois cette valeur et l’écart 0,64, proportions relevées au pixel sur l’original. Sous 11 px, poser « marqueSeule » — le mot ne se lit plus, quelle que soit sa netteté, et c’est la marque qui identifie.',
2162
+ 'La marque et le mot. Tout se pilote par « capitale », qui EST la hauteur de capitale : la marque vaut 2,86 fois cette valeur et l’écart 0,64, proportions relevées au pixel sur l’original. Sous 11 px, poser « marqueSeule » : le mot ne se lit plus, quelle que soit sa netteté, et c’est la marque qui identifie.',
2163
2163
  code: `<Lockup capitale={15}>
2164
2164
  <LockupMark src={GLYPHES.zevra} />
2165
2165
  <LockupWord src={MOT_ZEVRA} alt="Zevra" />
@@ -2175,7 +2175,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2175
2175
  id: 'tiroir-groupe',
2176
2176
  nom: 'Tiroir groupé',
2177
2177
  resume:
2178
- 'Quand la barre porte des familles, les aplatir en une liste unique rend le tiroir illisible : un label capitale par famille, ses entrées en dessous. Le sélecteur de langue s’y pose en pied, détaché par un filet. L’ouverture et la fermeture viennent de « @zevra/ui/nav.js » — le tiroir doit vivre EN DEHORS du chrome flouté, qui devient sinon son bloc conteneur.',
2178
+ 'Quand la barre porte des familles, les aplatir en une liste unique rend le tiroir illisible : un label capitale par famille, ses entrées en dessous. Le sélecteur de langue s’y pose en pied, détaché par un filet. L’ouverture et la fermeture viennent de « @zevra/ui/nav.js » : le tiroir doit vivre EN DEHORS du chrome flouté, qui devient sinon son bloc conteneur.',
2179
2179
  code: `<NavDrawer>
2180
2180
  <NavDrawerGroup>Services</NavDrawerGroup>
2181
2181
  <NavDrawerLink href="/audit" className="zv-nav-drawer__link--sous">Audit</NavDrawerLink>
@@ -2209,7 +2209,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2209
2209
  id: 'rail',
2210
2210
  nom: 'Rail de lecture',
2211
2211
  resume:
2212
- 'La table des matières d’une page longue, posée sur le côté. Elle NAVIGUE (chaque entrée est une ancre) et elle SUIT — importer « @zevra/ui/rail.js » pour que l’entrée courante s’allume ; sans lui le rail navigue toujours, il ne suit plus. Le module lit la POSITION plutôt que d’observer les intersections : les ancres d’un rail sont souvent des points de 1 px en tête de section, qu’un défilement rapide fait manquer à un IntersectionObserver réduit à sa bande centrale. ⚠️ Il disparaît sous le point de rupture — un rail fixe sur un téléphone se pose sur la lecture.',
2212
+ 'La table des matières d’une page longue, posée sur le côté. Elle NAVIGUE (chaque entrée est une ancre) et elle SUIT : importer « @zevra/ui/rail.js » pour que l’entrée courante s’allume ; sans lui le rail navigue toujours, il ne suit plus. Le module lit la POSITION plutôt que d’observer les intersections : les ancres d’un rail sont souvent des points de 1 px en tête de section, qu’un défilement rapide fait manquer à un IntersectionObserver réduit à sa bande centrale. ⚠️ Il disparaît sous le point de rupture : un rail fixe sur un téléphone se pose sur la lecture.',
2213
2213
  code: `<Rail aria-label="Sections">
2214
2214
  <RailItem href="#intro" courant>Intro</RailItem>
2215
2215
  <RailItem href="#methode">Méthode</RailItem>
@@ -2335,14 +2335,14 @@ export const CATALOGUE: GroupeCatalogue[] = [
2335
2335
  id: 'bandeau',
2336
2336
  nom: 'Bandeau d’annonce',
2337
2337
  resume:
2338
- 'La bande AU-DESSUS de la barre de navigation : annonce de version, information réglementaire. UN SEUL par page, et jamais pour du marketing permanent — un bandeau qui ne part pas devient un bourrelet de chrome. Le lien s’y souligne : sur un fond déjà indigo, la couleur seule ne le distingue plus.',
2338
+ 'La bande AU-DESSUS de la barre de navigation : annonce de version, information réglementaire. UN SEUL par page, et jamais pour du marketing permanent : un bandeau qui ne part pas devient un bourrelet de chrome. Le lien s’y souligne : sur un fond déjà indigo, la couleur seule ne le distingue plus.',
2339
2339
  code: `<Banner>
2340
- La charte évolue — le journal des livraisons est en ligne.{' '}
2340
+ La charte évolue : le journal des livraisons est en ligne.{' '}
2341
2341
  <a href="/journal">Ce qui change</a>
2342
2342
  </Banner>`,
2343
2343
  rendu: (
2344
2344
  <Banner>
2345
- La charte évolue — le journal des livraisons est en ligne.{' '}
2345
+ La charte évolue : le journal des livraisons est en ligne.{' '}
2346
2346
  <a href="#">Ce qui change</a>
2347
2347
  </Banner>
2348
2348
  ),
@@ -2351,7 +2351,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2351
2351
  id: 'carrousel',
2352
2352
  nom: 'Carrousel',
2353
2353
  resume:
2354
- 'Défilement natif scroll-snap, AUCUN JavaScript : pas de flèches, pas de points ; le conteneur prend le focus, et son label est OBLIGATOIRE — une région qui défile sans nom est une énigme au lecteur d’écran. Un carrousel reste un aveu d’espace : la règle de variété lui préfère une grille tant que le contenu tient.',
2354
+ 'Défilement natif scroll-snap, AUCUN JavaScript : pas de flèches, pas de points ; le conteneur prend le focus, et son label est OBLIGATOIRE, une région qui défile sans nom est une énigme au lecteur d’écran. Un carrousel reste un aveu d’espace : la règle de variété lui préfère une grille tant que le contenu tient.',
2355
2355
  code: `<Carousel label="La suite Zevra">
2356
2356
  <CarouselItem style={{ width: 260 }}>
2357
2357
  <Card>…</Card>
@@ -2386,7 +2386,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2386
2386
  id: 'media',
2387
2387
  nom: 'Cadre média',
2388
2388
  resume:
2389
- 'Le rapport vit sur le CADRE, jamais sur l’image : posé sur un enfant de grille aligné au centre, il ne se résout pas et la colonne s’effondre à zéro. Le cadre ne charge ni ne décode rien — pour masquer le temps de décodage, composer Spinner par-dessus.',
2389
+ 'Le rapport vit sur le CADRE, jamais sur l’image : posé sur un enfant de grille aligné au centre, il ne se résout pas et la colonne s’effondre à zéro. Le cadre ne charge ni ne décode rien : pour masquer le temps de décodage, composer Spinner par-dessus.',
2390
2390
  code: `<Media ratio="16-9">
2391
2391
  <MediaImg src={couverture} alt="" />
2392
2392
  <MediaVoile />
@@ -2416,13 +2416,13 @@ export const CATALOGUE: GroupeCatalogue[] = [
2416
2416
  couche: 'vitrine',
2417
2417
  css: 'surfaces.css + motion.css',
2418
2418
  resume:
2419
- "Ce qui distingue une page Zevra d'une page blanche bien composée. ⚠️ Tout y est DÉCORATIF : posé en absolu derrière le contenu, sans capter le pointeur, masqué aux lecteurs d'écran — et suppose un parent « position: relative; overflow: hidden ».",
2419
+ "Ce qui distingue une page Zevra d'une page blanche bien composée. ⚠️ Tout y est DÉCORATIF : posé en absolu derrière le contenu, sans capter le pointeur, masqué aux lecteurs d'écran, et suppose un parent « position: relative; overflow: hidden ».",
2420
2420
  exemples: [
2421
2421
  {
2422
2422
  id: 'bande',
2423
2423
  nom: 'Bande manifeste',
2424
2424
  resume:
2425
- '⚠️ LA surface sombre du système. Les surfaces sombres se font avec elle et --accent-on-dark, JAMAIS en inversant les neutres. La bande ne porte AUCUNE gouttière propre : c’est la page qui la donne — poser un Gutter dedans, sinon le contenu colle au bord.',
2425
+ '⚠️ LA surface sombre du système. Les surfaces sombres se font avec elle et --accent-on-dark, JAMAIS en inversant les neutres. La bande ne porte AUCUNE gouttière propre : c’est la page qui la donne, poser un Gutter dedans, sinon le contenu colle au bord.',
2426
2426
  code: `<Band lueur filigrane={<Glyph variante="watermark">…</Glyph>}>
2427
2427
  <Gutter>
2428
2428
  <Kicker surSombre>Souveraineté</Kicker>
@@ -2451,7 +2451,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2451
2451
  id: 'panneau-navy',
2452
2452
  nom: 'Panneau sombre',
2453
2453
  resume:
2454
- 'Plus petit qu’une bande : une carte, un encart. « TextOnDark » repeint un texte isolé — « Band » le fait déjà pour son contenu courant, l’ajouter dedans ne sert à rien.',
2454
+ 'Plus petit qu’une bande : une carte, un encart. « TextOnDark » repeint un texte isolé : « Band » le fait déjà pour son contenu courant, l’ajouter dedans ne sert à rien.',
2455
2455
  code: `<PanelNavy><TextOnDark>…</TextOnDark></PanelNavy>`,
2456
2456
  surSombre: true,
2457
2457
  rendu: (
@@ -2467,7 +2467,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2467
2467
  id: 'halo',
2468
2468
  nom: 'Halo, sol, voile',
2469
2469
  resume:
2470
- 'Le violet et le cyan du spectre, très dilués. Ce n’est PAS un emploi du spectre en aplat : c’est une lumière — elle ne compte pas dans les trois emplois autorisés.',
2470
+ 'Le violet et le cyan du spectre, très dilués. Ce n’est PAS un emploi du spectre en aplat : c’est une lumière, elle ne compte pas dans les trois emplois autorisés.',
2471
2471
  code: `<section style={{ position: 'relative', overflow: 'hidden' }}>
2472
2472
  <Halo place="hero" />
2473
2473
  <GridFloor />
@@ -2533,7 +2533,7 @@ export const CATALOGUE: GroupeCatalogue[] = [
2533
2533
  id: 'format-social',
2534
2534
  nom: 'Formats sociaux',
2535
2535
  resume:
2536
- 'Planches d’EXPORT — paysage 1200×630 (OpenGraph, lien LinkedIn), carré 1080 (post), story 1080×1920 — FIGÉES en pixels : on les capture, on ne les publie pas en HTML, et elles ignorent le point de rupture. Un visuel social EST une publication : jamais de faux chiffre ni de fausse citation. Rendue ici à l’échelle 0,35.',
2536
+ 'Planches d’EXPORT (paysage 1200×630 (OpenGraph, lien LinkedIn), carré 1080 (post), story 1080×1920) FIGÉES en pixels : on les capture, on ne les publie pas en HTML, et elles ignorent le point de rupture. Un visuel social EST une publication : jamais de faux chiffre ni de fausse citation. Rendue ici à l’échelle 0,35.',
2537
2537
  code: `<SocialFrame manifeste pied={<><Mono ton="on-dark">ZEVRA</Mono><Mono ton="on-dark">zevra.tech</Mono></>}>
2538
2538
  <Kicker surSombre><Mono ton="on-dark">Manifeste · Article 1ᵉʳ</Mono></Kicker>
2539
2539
  <Heading taille="h2" as="p">
@@ -2572,7 +2572,7 @@ function Heading2Cta() {
2572
2572
  return <Heading taille="h2-cta">Voir Zevra sur vos propres pièces.</Heading>
2573
2573
  }
2574
2574
 
2575
- /** Tous les exemples à plat — pratique pour une recherche ou un test. */
2575
+ /** Tous les exemples à plat : pratique pour une recherche ou un test. */
2576
2576
  export const EXEMPLES: (Exemple & { groupe: string })[] = CATALOGUE.flatMap((g) =>
2577
2577
  g.exemples.map((e) => ({ ...e, groupe: g.id })),
2578
2578
  )