@zevra/ui 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DECISIONS.md +99 -0
- package/README.md +10 -3
- package/demo/index.html +1 -0
- package/dist/actions.d.ts +18 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +6 -5
- package/dist/actions.js.map +1 -1
- package/dist/catalogue.d.ts.map +1 -1
- package/dist/catalogue.js +34 -8
- package/dist/catalogue.js.map +1 -1
- package/dist/content.js +1 -1
- package/dist/content.js.map +1 -1
- package/dist/css-inline.d.ts.map +1 -1
- package/dist/css-inline.js +1 -1
- package/dist/css-inline.js.map +1 -1
- package/dist/data.js +1 -1
- package/dist/data.js.map +1 -1
- package/dist/forms.js +1 -1
- package/dist/forms.js.map +1 -1
- package/dist/icon-data.js +11 -11
- package/dist/icon-data.js.map +1 -1
- package/dist/icon.d.ts +12 -1
- package/dist/icon.d.ts.map +1 -1
- package/dist/icon.js +6 -0
- package/dist/icon.js.map +1 -1
- package/icons/index.json +12 -12
- package/icons/sprite.svg +11 -11
- package/package.json +2 -1
- package/react/actions.tsx +36 -2
- package/react/catalogue.tsx +74 -17
- package/react/content.tsx +1 -1
- package/react/css-inline.ts +1 -1
- package/react/data.tsx +2 -2
- package/react/forms.tsx +1 -1
- package/react/icon-data.ts +11 -11
- package/react/icon.tsx +23 -1
- package/src/components.css +34 -1
- package/src/forms.css +6 -5
- package/src/icons.css +31 -6
- package/src/layout.css +3 -1
- package/src/motion.css +184 -105
- package/src/motion.js +53 -0
- package/src/surfaces.css +9 -0
package/react/data.tsx
CHANGED
|
@@ -334,8 +334,8 @@ export function Fold({ titre, ouvert, className, children, ...reste }: FoldProps
|
|
|
334
334
|
fill="none"
|
|
335
335
|
stroke="currentColor"
|
|
336
336
|
strokeWidth="2"
|
|
337
|
-
strokeLinecap="
|
|
338
|
-
strokeLinejoin="
|
|
337
|
+
strokeLinecap="square"
|
|
338
|
+
strokeLinejoin="miter"
|
|
339
339
|
aria-hidden="true"
|
|
340
340
|
>
|
|
341
341
|
<path d="M6.67 9.33 L12 14.67 L17.33 9.33" />
|
package/react/forms.tsx
CHANGED
package/react/icon-data.ts
CHANGED
|
@@ -61,24 +61,24 @@ export type IconId =
|
|
|
61
61
|
export const CORPS: Record<IconId, string> = {
|
|
62
62
|
'accueil': "<path d=\"M4 10.67 L12 4 L20 10.67 V20 H4 Z\" /><path d=\"M9.33 20 V13.33 H14.67 V20\" />",
|
|
63
63
|
'activite': "<path d=\"M3.33 12 H8 L10.67 5.33 L14 18.67 L16 12 H20.67\" />",
|
|
64
|
-
'aide': "<circle cx=\"12\" cy=\"12\" r=\"8.67\" /><path d=\"M9.33 9.33 A2.67 2.67 0 0 1 14.53 10.13 C14.53 11.87 12 12.27 12 14\" /><
|
|
64
|
+
'aide': "<circle cx=\"12\" cy=\"12\" r=\"8.67\" /><path d=\"M9.33 9.33 A2.67 2.67 0 0 1 14.53 10.13 C14.53 11.87 12 12.27 12 14\" /><rect x=\"11.2\" y=\"16.27\" width=\"1.6\" height=\"1.6\" fill=\"currentColor\" stroke=\"none\" />",
|
|
65
65
|
'app-couches': "<path d=\"M12 2.67 L20 6.67 L12 10.67 L4 6.67 Z\" /><path d=\"M4 12 L12 16 L20 12\" /><path d=\"M4 17.33 L12 21.33 L20 17.33\" />",
|
|
66
|
-
'archiver': "<rect x=\"3.33\" y=\"4\" width=\"17.33\" height=\"4.67\"
|
|
67
|
-
'attention': "<path d=\"M10.67 3.87 L2.53 17.87 A1.55 1.55 0 0 0 3.87 20.19 H20.13 A1.55 1.55 0 0 0 21.47 17.87 L13.33 3.87 A1.54 1.54 0 0 0 10.67 3.87 Z\" /><path d=\"M12 9.33 V13.33\" /><
|
|
66
|
+
'archiver': "<rect x=\"3.33\" y=\"4\" width=\"17.33\" height=\"4.67\" /><path d=\"M5.33 8.67 V18.93 A1.07 1.07 0 0 0 6.4 20 H17.6 A1.07 1.07 0 0 0 18.67 18.93 V8.67\" /><path d=\"M9.33 12.67 H14.67\" />",
|
|
67
|
+
'attention': "<path d=\"M10.67 3.87 L2.53 17.87 A1.55 1.55 0 0 0 3.87 20.19 H20.13 A1.55 1.55 0 0 0 21.47 17.87 L13.33 3.87 A1.54 1.54 0 0 0 10.67 3.87 Z\" /><path d=\"M12 9.33 V13.33\" /><rect x=\"11.2\" y=\"15.73\" width=\"1.6\" height=\"1.6\" fill=\"currentColor\" stroke=\"none\" />",
|
|
68
68
|
'balance': "<path d=\"M12 3.33 V20.67\" /><path d=\"M8.67 20.67 H15.33\" /><path d=\"M5.33 6 H18.67\" /><path d=\"M6.67 6 L3.33 13.33\" /><path d=\"M6.67 6 L10 13.33\" /><path d=\"M3.33 13.33 A3.33 3.33 0 0 0 10 13.33\" /><path d=\"M17.33 6 L14 13.33\" /><path d=\"M17.33 6 L20.67 13.33\" /><path d=\"M14 13.33 A3.33 3.33 0 0 0 20.67 13.33\" />",
|
|
69
69
|
'base-de-donnees': "<ellipse cx=\"12\" cy=\"6\" rx=\"7.33\" ry=\"2.67\" /><path d=\"M4.67 6 V12 C4.67 13.47 7.87 14.67 12 14.67 C16.13 14.67 19.33 13.47 19.33 12 V6\" /><path d=\"M4.67 12 V18 C4.67 19.47 7.87 20.67 12 20.67 C16.13 20.67 19.33 19.47 19.33 18 V12\" />",
|
|
70
70
|
'bouclier-verifie': "<path d=\"M12 2.67 L20 6 V12 C20 16.67 16.67 19.73 12 21.33 C7.33 19.73 4 16.67 4 12 V6 Z\" /><path d=\"M8.67 12 L11.07 14.4 L15.33 10\" />",
|
|
71
|
-
'cadenas': "<rect x=\"4.67\" y=\"10.67\" width=\"14.67\" height=\"9.33\"
|
|
71
|
+
'cadenas': "<rect x=\"4.67\" y=\"10.67\" width=\"14.67\" height=\"9.33\" /><path d=\"M8 10.67 V7.33 A4 4 0 0 1 16 7.33 V10.67\" /><circle cx=\"12\" cy=\"15.33\" r=\"1.33\" />",
|
|
72
72
|
'cadrer': "<path d=\"M4 8 V4 H8\" /><path d=\"M20 8 V4 H16\" /><path d=\"M4 16 V20 H8\" /><path d=\"M20 16 V20 H16\" />",
|
|
73
|
-
'calendrier': "<rect x=\"3.33\" y=\"4.67\" width=\"17.33\" height=\"16\"
|
|
73
|
+
'calendrier': "<rect x=\"3.33\" y=\"4.67\" width=\"17.33\" height=\"16\" /><path d=\"M3.33 9.33 H20.67\" /><path d=\"M8 2.67 V6.67\" /><path d=\"M16 2.67 V6.67\" />",
|
|
74
74
|
'chevron-bas': "<path d=\"M6.67 9.33 L12 14.67 L17.33 9.33\" />",
|
|
75
75
|
'chevron-droit': "<path d=\"M9.33 4 L17.33 12 L9.33 20\" />",
|
|
76
76
|
'chevron-gauche': "<path d=\"M14.67 4 L6.67 12 L14.67 20\" />",
|
|
77
77
|
'chevron-haut': "<path d=\"M6.67 14.67 L12 9.33 L17.33 14.67\" />",
|
|
78
78
|
'coche': "<path d=\"M5 12.4 L9.4 16.8 L19 6.8\" />",
|
|
79
|
-
'copier': "<rect x=\"4\" y=\"4\" width=\"12\" height=\"12\"
|
|
79
|
+
'copier': "<rect x=\"4\" y=\"4\" width=\"12\" height=\"12\" /><path d=\"M8 16 V18.93 A1.07 1.07 0 0 0 9.07 20 H18.93 A1.07 1.07 0 0 0 20 18.93 V9.07 A1.07 1.07 0 0 0 18.93 8 H16\" />",
|
|
80
80
|
'corbeille': "<path d=\"M4 6.67 H20\" /><path d=\"M9.33 6.67 V4.67 A1.33 1.33 0 0 1 10.67 3.33 H13.33 A1.33 1.33 0 0 1 14.67 4.67 V6.67\" /><path d=\"M6 6.67 L6.93 18.93 A1.33 1.33 0 0 0 8.27 20 H15.73 A1.33 1.33 0 0 0 17.07 18.93 L18 6.67\" /><path d=\"M10 10.67 V16.67\" /><path d=\"M14 10.67 V16.67\" />",
|
|
81
|
-
'courriel': "<rect x=\"2.67\" y=\"5.33\" width=\"18.67\" height=\"13.33\"
|
|
81
|
+
'courriel': "<rect x=\"2.67\" y=\"5.33\" width=\"18.67\" height=\"13.33\" /><path d=\"M2.67 7.33 L12 13.33 L21.33 7.33\" />",
|
|
82
82
|
'cube': "<path d=\"M3.33 8 L12 4 L20.67 8 V16 L12 20 L3.33 16 Z\" /><path d=\"M3.33 8 L12 12 L20.67 8\" /><path d=\"M12 12 V20\" />",
|
|
83
83
|
'deconnexion': "<path d=\"M14.67 4 H5.33 V20 H14.67\" /><path d=\"M10.67 12 H20\" /><path d=\"M16.67 8 L20.67 12 L16.67 16\" />",
|
|
84
84
|
'depot-fichier': "<path d=\"M12 3.2 V14.4\" /><polyline points=\"7.6,10 12,14.4 16.4,10\" /><path d=\"M4 16.8 v2.4 a1.6 1.6 0 0 0 1.6 1.6 h12.8 a1.6 1.6 0 0 0 1.6-1.6 v-2.4\" />",
|
|
@@ -96,8 +96,8 @@ export const CORPS: Record<IconId, string> = {
|
|
|
96
96
|
'globe': "<circle cx=\"12\" cy=\"12\" r=\"8.67\" /><path d=\"M3.33 12 H20.67\" /><path d=\"M12 3.33 C14.22 5.64 15.47 8.71 15.47 12 C15.47 15.29 14.22 18.36 12 20.67 C9.78 18.36 8.53 15.29 8.53 12 C8.53 8.71 9.78 5.64 12 3.33 Z\" />",
|
|
97
97
|
'graphique': "<path d=\"M4 4 V20 H20\" /><path d=\"M8.67 20 V12.67\" /><path d=\"M12.67 20 V8\" /><path d=\"M16.67 20 V15.33\" />",
|
|
98
98
|
'horloge': "<circle cx=\"12\" cy=\"12\" r=\"8\" /><path d=\"M12 6.67 V12 L15.33 14\" />",
|
|
99
|
-
'imprimante': "<path d=\"M6.67 8 V3.33 H17.33 V8\" /><path d=\"M6.67 17.33 H4.67 A1.33 1.33 0 0 1 3.33 16 V10.67 A1.33 1.33 0 0 1 4.67 9.33 H19.33 A1.33 1.33 0 0 1 20.67 10.67 V16 A1.33 1.33 0 0 1 19.33 17.33 H17.33\" /><rect x=\"6.67\" y=\"13.33\" width=\"10.67\" height=\"7.33\"
|
|
100
|
-
'info': "<circle cx=\"12\" cy=\"12\" r=\"8.67\" /><path d=\"M12 11.33 V16\" /><
|
|
99
|
+
'imprimante': "<path d=\"M6.67 8 V3.33 H17.33 V8\" /><path d=\"M6.67 17.33 H4.67 A1.33 1.33 0 0 1 3.33 16 V10.67 A1.33 1.33 0 0 1 4.67 9.33 H19.33 A1.33 1.33 0 0 1 20.67 10.67 V16 A1.33 1.33 0 0 1 19.33 17.33 H17.33\" /><rect x=\"6.67\" y=\"13.33\" width=\"10.67\" height=\"7.33\" />",
|
|
100
|
+
'info': "<circle cx=\"12\" cy=\"12\" r=\"8.67\" /><path d=\"M12 11.33 V16\" /><rect x=\"11.2\" y=\"7.2\" width=\"1.6\" height=\"1.6\" fill=\"currentColor\" stroke=\"none\" />",
|
|
101
101
|
'lien-externe': "<path d=\"M10.67 4 H4 V20 H20 V13.33\" /><path d=\"M14.67 4 H20 V9.33\" /><path d=\"M20 4 L12 12\" />",
|
|
102
102
|
'livre-ouvert': "<path d=\"M2.67 5.33 C5.33 4.67 7.78 4.89 12 6.67 C16.22 4.89 18.67 4.67 21.33 5.33 V18 C18.67 17.33 16.22 17.56 12 19.33 C7.78 17.56 5.33 17.33 2.67 18 Z\" /><path d=\"M12 6.67 V19.33\" />",
|
|
103
103
|
'menu': "<path d=\"M0 5.33 H24\" /><path d=\"M0 12 H24\" /><path d=\"M0 18.67 H24\" />",
|
|
@@ -105,14 +105,14 @@ export const CORPS: Record<IconId, string> = {
|
|
|
105
105
|
'oeil': "<path d=\"M2 12 C5.33 6.67 8.67 4.67 12 4.67 C15.33 4.67 18.67 6.67 22 12 C18.67 17.33 15.33 19.33 12 19.33 C8.67 19.33 5.33 17.33 2 12 Z\" /><circle cx=\"12\" cy=\"12\" r=\"2.67\" />",
|
|
106
106
|
'plus': "<path d=\"M12 4 V20\" /><path d=\"M4 12 H20\" />",
|
|
107
107
|
'recherche': "<circle cx=\"10.67\" cy=\"10.67\" r=\"6\" /><path d=\"M15.33 15.33 L20 20\" />",
|
|
108
|
-
'registre': "<rect x=\"3.33\" y=\"5.33\" width=\"17.33\" height=\"5.33\"
|
|
108
|
+
'registre': "<rect x=\"3.33\" y=\"5.33\" width=\"17.33\" height=\"5.33\" /><rect x=\"3.33\" y=\"13.33\" width=\"17.33\" height=\"5.33\" /><rect x=\"5.87\" y=\"7.2\" width=\"1.6\" height=\"1.6\" fill=\"currentColor\" stroke=\"none\" /><rect x=\"5.87\" y=\"15.2\" width=\"1.6\" height=\"1.6\" fill=\"currentColor\" stroke=\"none\" />",
|
|
109
109
|
'reglages': "<circle cx=\"12\" cy=\"12\" r=\"2.93\" /><path d=\"M12 2 V4.67 M12 19.33 V22 M2 12 H4.67 M19.33 12 H22 M4.8 4.8 L6.67 6.67 M17.33 17.33 L19.2 19.2 M19.2 4.8 L17.33 6.67 M6.67 17.33 L4.8 19.2\" />",
|
|
110
110
|
'reseau': "<circle cx=\"12\" cy=\"12\" r=\"8\" /><path d=\"M4 12 H20\" /><path d=\"M12 4 C14.67 8 14.67 16 12 20\" /><path d=\"M12 4 C9.33 8 9.33 16 12 20\" />",
|
|
111
111
|
'taches': "<path d=\"M4.67 6.67 L6.67 8.67 L10 5.33\" /><path d=\"M4.67 16 L6.67 18 L10 14.67\" /><path d=\"M13.33 7.33 H20\" /><path d=\"M13.33 16.67 H20\" />",
|
|
112
112
|
'telecharger': "<path d=\"M12 3.33 V15.33\" /><polyline points=\"6.67,10 12,15.33 17.33,10\" /><path d=\"M4.67 20.67 H19.33\" />",
|
|
113
113
|
'telephone': "<path d=\"M20.67 16.93 V19.33 A1.6 1.6 0 0 1 18.93 20.93 C16.13 20.67 13.47 19.67 11.2 18.13 C9.09 16.71 7.29 14.91 5.87 12.8 C4.33 10.52 3.33 7.85 3.07 5.05 A1.6 1.6 0 0 1 4.67 3.33 H7.07 A1.6 1.6 0 0 1 8.67 4.71 C8.79 5.83 9.04 6.93 9.4 7.97 A1.6 1.6 0 0 1 9.04 9.65 L8 10.69 C9.32 13.01 11.03 14.71 13.33 16 L14.37 14.96 A1.6 1.6 0 0 1 16.05 14.6 C17.09 14.96 18.19 15.21 19.31 15.33 A1.6 1.6 0 0 1 20.67 16.93 Z\" />",
|
|
114
114
|
'tri': "<path d=\"M8 4 V20\" /><path d=\"M4.67 7.33 L8 4 L11.33 7.33\" /><path d=\"M16 20 V4\" /><path d=\"M12.67 16.67 L16 20 L19.33 16.67\" />",
|
|
115
|
-
'trois-points': "<
|
|
115
|
+
'trois-points': "<rect x=\"4\" y=\"10.67\" width=\"2.66\" height=\"2.66\" fill=\"currentColor\" stroke=\"none\" /><rect x=\"10.67\" y=\"10.67\" width=\"2.66\" height=\"2.66\" fill=\"currentColor\" stroke=\"none\" /><rect x=\"17.34\" y=\"10.67\" width=\"2.66\" height=\"2.66\" fill=\"currentColor\" stroke=\"none\" />",
|
|
116
116
|
'utilisateur': "<circle cx=\"12\" cy=\"8\" r=\"3.33\" /><path d=\"M5.33 20 C5.33 15.33 8.33 13.33 12 13.33 C15.67 13.33 18.67 15.33 18.67 20\" />",
|
|
117
117
|
}
|
|
118
118
|
|
package/react/icon.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// autoriser côté CSP. L'icône hérite de la couleur du texte : elle fonctionne
|
|
6
6
|
// sur papier comme sur la bande manifeste sans déclinaison.
|
|
7
7
|
|
|
8
|
-
import type { ButtonHTMLAttributes, ReactNode, SVGAttributes } from 'react'
|
|
8
|
+
import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode, SVGAttributes } from 'react'
|
|
9
9
|
import { cx } from './cx.js'
|
|
10
10
|
import { CORPS, NOMS, type IconId } from './icon-data.js'
|
|
11
11
|
|
|
@@ -82,3 +82,25 @@ export function IconButton({
|
|
|
82
82
|
</button>
|
|
83
83
|
)
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
/* ─── Tuile d'icône ────────────────────────────────────────────────── */
|
|
87
|
+
|
|
88
|
+
export interface IconTileProps
|
|
89
|
+
extends Omit<HTMLAttributes<HTMLSpanElement>, 'className'> {
|
|
90
|
+
nom: IconId
|
|
91
|
+
/** Titre accessible. Sans lui la tuile est DÉCORATIVE — le bon défaut :
|
|
92
|
+
* elle accompagne un libellé qui la nomme déjà. */
|
|
93
|
+
titre?: string
|
|
94
|
+
className?: string
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** La pastille carrée qui porte une icône devant un argument de la vitrine
|
|
98
|
+
* (liste de garanties, grille d'atouts). UNE par argument, jamais en décor
|
|
99
|
+
* isolé : une tuile sans libellé voisin est un rébus. */
|
|
100
|
+
export function IconTile({ nom, titre, className, ...reste }: IconTileProps) {
|
|
101
|
+
return (
|
|
102
|
+
<span className={cx('zv-icon-tile', className)} {...reste}>
|
|
103
|
+
<Icon nom={nom} titre={titre} />
|
|
104
|
+
</span>
|
|
105
|
+
)
|
|
106
|
+
}
|
package/src/components.css
CHANGED
|
@@ -146,6 +146,22 @@
|
|
|
146
146
|
width: 100%;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
/* Bouton d'action à icône SEULE : l'envoi d'un composeur, l'action unique
|
|
150
|
+
* d'une barre. HORS RELEVÉ (25/08/2026, voir DECISIONS.md). Le libellé
|
|
151
|
+
* accessible est OBLIGATOIRE (aria-label), et s'écrit pour l'ACTION.
|
|
152
|
+
* Ne pas confondre : .zv-icon-btn est le chrome nu (40 px, sans cadre),
|
|
153
|
+
* .zv-chrome-btn la croix bordée (26 px) — le carré est une action, il en
|
|
154
|
+
* a le poids et l'aplat. */
|
|
155
|
+
.zv-btn--carre {
|
|
156
|
+
width: 48px;
|
|
157
|
+
padding: 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.zv-btn--sm.zv-btn--carre {
|
|
161
|
+
width: 40px;
|
|
162
|
+
padding: 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
149
165
|
.zv-btn[disabled],
|
|
150
166
|
.zv-btn--ghost[disabled],
|
|
151
167
|
.zv-btn--ink[disabled],
|
|
@@ -224,7 +240,8 @@
|
|
|
224
240
|
/* ─── Lien fléché ───────────────────────────────────────────────────────
|
|
225
241
|
* Le SVG fait 15×15 : quatre occurrences dans Main.html contre une seule
|
|
226
242
|
* à 16px dans DesignSystem.html. Tracés : M5 12h14 et M13 6l6 6-6 6, sur
|
|
227
|
-
* un viewBox 0 0 24 24
|
|
243
|
+
* un viewBox 0 0 24 24 — au trait carré depuis le 25/08/2026, comme tout
|
|
244
|
+
* le jeu d'icônes (DECISIONS.md, « Le trait carré »). */
|
|
228
245
|
|
|
229
246
|
/* ⚠️ REPRIS le 25/08/2026 — la DA le jugeait « pas ouf ». Le diagnostic :
|
|
230
247
|
* c'était un lien bleu avec un chevron collé, sans rien qui le distingue
|
|
@@ -281,6 +298,16 @@
|
|
|
281
298
|
width: 15px;
|
|
282
299
|
height: 15px;
|
|
283
300
|
flex: none;
|
|
301
|
+
/* ⚠️ CORRIGÉ le 25/08/2026 : le trait n'avait JAMAIS été déclaré — ni
|
|
302
|
+
* fill:none ni stroke —, la flèche se rendait en triangle PLEIN noir (le
|
|
303
|
+
* fût, d'aire nulle, disparaissait) au lieu du tracé que le commentaire
|
|
304
|
+
* d'en-tête promettait depuis le premier jour. Posé au trait carré, avec
|
|
305
|
+
* le reste du jeu. */
|
|
306
|
+
fill: none;
|
|
307
|
+
stroke: currentColor;
|
|
308
|
+
stroke-width: 2;
|
|
309
|
+
stroke-linecap: square;
|
|
310
|
+
stroke-linejoin: miter;
|
|
284
311
|
transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
285
312
|
}
|
|
286
313
|
|
|
@@ -890,6 +917,12 @@
|
|
|
890
917
|
font-size: 13px;
|
|
891
918
|
}
|
|
892
919
|
|
|
920
|
+
/* Le carré compact suit la hauteur compacte mobile. */
|
|
921
|
+
.zv-btn--sm.zv-btn--carre {
|
|
922
|
+
width: 36px;
|
|
923
|
+
padding: 0;
|
|
924
|
+
}
|
|
925
|
+
|
|
893
926
|
.zv-pill {
|
|
894
927
|
height: 26px;
|
|
895
928
|
padding: 0 12px;
|
package/src/forms.css
CHANGED
|
@@ -503,11 +503,12 @@
|
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
/* Le blanc du glyphe est écrit en clair (%23fff) : une data-URI ne lit pas
|
|
506
|
-
* les variables CSS. Valeur strictement égale à --white.
|
|
506
|
+
* les variables CSS. Valeur strictement égale à --white. La coche est au
|
|
507
|
+
* trait carré depuis le 25/08/2026, comme tout ce qui trace. */
|
|
507
508
|
.zv-check-box:checked {
|
|
508
509
|
border-color: var(--accent);
|
|
509
510
|
background-color: var(--accent);
|
|
510
|
-
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23fff' stroke-width='1.5' stroke-linecap='
|
|
511
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23fff' stroke-width='1.5' stroke-linecap='square' stroke-linejoin='miter'%3E%3Cpolyline points='2.5,6.5 5,9 9.5,3.5'/%3E%3C/svg%3E");
|
|
511
512
|
background-position: center;
|
|
512
513
|
background-repeat: no-repeat;
|
|
513
514
|
background-size: 12px 12px;
|
|
@@ -816,9 +817,9 @@
|
|
|
816
817
|
* tabindex="0" (l'anneau de base.css suit alors tout seul).
|
|
817
818
|
*
|
|
818
819
|
* L'icône est un SVG du balisage (import-client.tsx:159-166) : viewBox
|
|
819
|
-
* 0 0 30 30, fill="none", stroke="var(--accent)", stroke-width="1.5"
|
|
820
|
-
* stroke-linecap="round"
|
|
821
|
-
*
|
|
820
|
+
* 0 0 30 30, fill="none", stroke="var(--accent)", stroke-width="1.5" —
|
|
821
|
+
* relevée en stroke-linecap="round", REPRISE au trait carré le 25/08/2026
|
|
822
|
+
* comme tout ce qui trace (DECISIONS.md, « Le trait carré ») :
|
|
822
823
|
* <line x1="15" y1="4" x2="15" y2="18"/>
|
|
823
824
|
* <polyline points="9.5,12.5 15,18 20.5,12.5"/>
|
|
824
825
|
* <path d="M5 21 v3 a2 2 0 0 0 2 2 h16 a2 2 0 0 0 2-2 v-3"/> */
|
package/src/icons.css
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
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
|
-
* Les icônes sont TRACÉES, jamais pleines : trait à l'épaisseur 2,
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
|
6
|
+
* charte, arbitré le 25/08/2026 (DECISIONS.md, « Le trait carré ») : les
|
|
7
|
+
* bouts arrondis étaient le dialecte des bibliothèques génériques, pas le
|
|
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
|
|
10
|
+
* sur papier comme sur la bande manifeste sans qu'on ait à les décliner.
|
|
8
11
|
*
|
|
9
12
|
* Deux façons de les poser :
|
|
10
13
|
*
|
|
@@ -26,8 +29,12 @@
|
|
|
26
29
|
fill: none;
|
|
27
30
|
stroke: currentColor;
|
|
28
31
|
stroke-width: 2;
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
/* `square` garde l'emprise optique du rond (le bout dépasse d'une
|
|
33
|
+
* demi-épaisseur, comme lui) : la silhouette change sans qu'un seul
|
|
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. */
|
|
36
|
+
stroke-linecap: square;
|
|
37
|
+
stroke-linejoin: miter;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
/* Accolée à du texte dense : métadonnée, puce de source, cellule. */
|
|
@@ -79,3 +86,21 @@
|
|
|
79
86
|
.zv-icon--quiet {
|
|
80
87
|
color: var(--label);
|
|
81
88
|
}
|
|
89
|
+
|
|
90
|
+
/* ─── Tuile d'icône ─────────────────────────────────────────────────────
|
|
91
|
+
* HORS RELEVÉ (25/08/2026, voir DECISIONS.md). La pastille carrée qui
|
|
92
|
+
* porte une icône devant un argument de la vitrine — liste de garanties,
|
|
93
|
+
* grille d'atouts. Carrée par NATURE, pas par style : c'est une tuile.
|
|
94
|
+
* Une par argument, jamais en décor isolé ; c'est le libellé voisin qui
|
|
95
|
+
* nomme, la tuile est décorative par défaut. */
|
|
96
|
+
.zv-icon-tile {
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
width: 40px;
|
|
101
|
+
height: 40px;
|
|
102
|
+
flex: none;
|
|
103
|
+
border: 1px solid var(--accent-line);
|
|
104
|
+
background: var(--accent-soft);
|
|
105
|
+
color: var(--accent);
|
|
106
|
+
}
|
package/src/layout.css
CHANGED
|
@@ -263,7 +263,9 @@
|
|
|
263
263
|
fill: none;
|
|
264
264
|
stroke: currentColor;
|
|
265
265
|
stroke-width: 2;
|
|
266
|
-
|
|
266
|
+
/* Bouts francs — le trait carré du jeu d'icônes (25/08/2026). Le burger
|
|
267
|
+
* applicatif, relevé « extrémités franches », y était déjà. */
|
|
268
|
+
stroke-linecap: square;
|
|
267
269
|
}
|
|
268
270
|
|
|
269
271
|
/* Le tiroir de la vitrine : liens empilés, respiration généreuse. Le panneau
|
package/src/motion.css
CHANGED
|
@@ -14,9 +14,24 @@
|
|
|
14
14
|
*
|
|
15
15
|
* ─── Comment c'est construit ────────────────────────────────────────────
|
|
16
16
|
* L'état AU REPOS de chaque élément est son état FINAL : sans animation, la
|
|
17
|
-
* page est complète et lisible.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* page est complète et lisible.
|
|
18
|
+
*
|
|
19
|
+
* Les ENTRÉES se jouent UNE FOIS (arbitrage du 26/08/2026, DECISIONS.md) :
|
|
20
|
+
* l'ancien pilotage par `animation-timeline: view()` rejouait chaque entrée
|
|
21
|
+
* à l'envers dès qu'on remontait — le contenu disparaissait sous le lecteur,
|
|
22
|
+
* et une grille haute n'était jamais « contenue », donc jamais posée. Le
|
|
23
|
+
* paquet arme désormais les entrées par `html.zv-motion` (posé par
|
|
24
|
+
* motion.js, importable en `@zevra/ui/motion.js`), et chaque élément se
|
|
25
|
+
* révèle quand il entre au viewport, puis N'EN BOUGE PLUS. Sans JavaScript,
|
|
26
|
+
* rien n'est armé : la page s'affiche complète — même dégradation douce
|
|
27
|
+
* qu'avant.
|
|
28
|
+
*
|
|
29
|
+
* Un échafaudage de scènes (l'expérience épinglée d'une home) peut vouloir
|
|
30
|
+
* garder le pilotage au défilement : poser `data-zv-motion-skip` sur la
|
|
31
|
+
* scène — motion.js n'y touche pas — et re-brancher les @keyframes du
|
|
32
|
+
* paquet sur ses timelines nommées. Seuls la barre de progression
|
|
33
|
+
* (zv-anim-progress) et le point d'étape (zv-anim-dot-active) restent
|
|
34
|
+
* scroll-pilotés ici : suivre la lecture est leur raison d'être.
|
|
20
35
|
*
|
|
21
36
|
* Les deux boucles (drift, breathe) animent les propriétés `translate` et
|
|
22
37
|
* `scale` INDÉPENDANTES, jamais `transform` : les éléments concernés — halo
|
|
@@ -69,146 +84,210 @@
|
|
|
69
84
|
animation: zv-breathe 9s ease-in-out infinite;
|
|
70
85
|
}
|
|
71
86
|
|
|
72
|
-
/* ─── Entrées
|
|
73
|
-
*
|
|
74
|
-
*
|
|
87
|
+
/* ─── Entrées : une révélation par visite ───────────────────────────────
|
|
88
|
+
* Les @keyframes vivent au niveau racine : un échafaudage de scènes peut
|
|
89
|
+
* les re-brancher sur ses propres timelines nommées (voir l'en-tête). */
|
|
75
90
|
|
|
76
|
-
@
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
from {
|
|
81
|
-
opacity: 0;
|
|
82
|
-
transform: translateY(32px);
|
|
83
|
-
}
|
|
91
|
+
@keyframes zv-rise {
|
|
92
|
+
from {
|
|
93
|
+
opacity: 0;
|
|
94
|
+
transform: translateY(32px);
|
|
84
95
|
}
|
|
96
|
+
}
|
|
85
97
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
/* Le même mouvement, DOSÉ pour les blocs des pages intérieures : douze
|
|
99
|
+
* pixels au lieu de trente-deux — le bloc est posé avant que l'œil ait fini
|
|
100
|
+
* d'arriver, et une visite répétée ne le remarque plus. */
|
|
101
|
+
@keyframes zv-rise-doux {
|
|
102
|
+
from {
|
|
103
|
+
opacity: 0;
|
|
104
|
+
transform: translateY(12px);
|
|
90
105
|
}
|
|
106
|
+
}
|
|
91
107
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
* change que l'amplitude et la plage. La home garde l'entrée
|
|
97
|
-
* pleine : c'est elle la signature, le doux est le quotidien. */
|
|
98
|
-
@keyframes zv-rise-doux {
|
|
99
|
-
from {
|
|
100
|
-
opacity: 0;
|
|
101
|
-
transform: translateY(12px);
|
|
102
|
-
}
|
|
108
|
+
@keyframes zv-glyph-in {
|
|
109
|
+
from {
|
|
110
|
+
opacity: 0;
|
|
111
|
+
transform: translateY(40px) scale(0.7);
|
|
103
112
|
}
|
|
113
|
+
}
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
115
|
+
/* La signature de la page d'accueil : les glyphes convergent vers le Z
|
|
116
|
+
* depuis les quatre coins — la seule entrée latérale du système, latérale
|
|
117
|
+
* parce qu'elle converge, pas parce qu'elle glisse. */
|
|
118
|
+
@keyframes zv-converge-tl {
|
|
119
|
+
from {
|
|
120
|
+
opacity: 0;
|
|
121
|
+
transform: translate(-420px, -420px) scale(1.5);
|
|
108
122
|
}
|
|
123
|
+
}
|
|
109
124
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
transform: translateY(40px) scale(0.7);
|
|
115
|
-
}
|
|
125
|
+
@keyframes zv-converge-tr {
|
|
126
|
+
from {
|
|
127
|
+
opacity: 0;
|
|
128
|
+
transform: translate(420px, -420px) scale(1.5);
|
|
116
129
|
}
|
|
130
|
+
}
|
|
117
131
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
132
|
+
@keyframes zv-converge-bl {
|
|
133
|
+
from {
|
|
134
|
+
opacity: 0;
|
|
135
|
+
transform: translate(-420px, 420px) scale(1.5);
|
|
122
136
|
}
|
|
137
|
+
}
|
|
123
138
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
@keyframes zv-converge-tl {
|
|
129
|
-
from {
|
|
130
|
-
opacity: 0;
|
|
131
|
-
transform: translate(-420px, -420px) scale(1.5);
|
|
132
|
-
}
|
|
139
|
+
@keyframes zv-converge-br {
|
|
140
|
+
from {
|
|
141
|
+
opacity: 0;
|
|
142
|
+
transform: translate(420px, 420px) scale(1.5);
|
|
133
143
|
}
|
|
144
|
+
}
|
|
134
145
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
146
|
+
@keyframes zv-pop {
|
|
147
|
+
from {
|
|
148
|
+
opacity: 0;
|
|
149
|
+
transform: scale(0.6);
|
|
140
150
|
}
|
|
151
|
+
}
|
|
141
152
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
/* Le filet de spectre se dessine : on anime bien la largeur, et non une
|
|
154
|
+
* mise à l'échelle — le dégradé doit se révéler, pas s'étirer. */
|
|
155
|
+
@keyframes zv-filet {
|
|
156
|
+
from {
|
|
157
|
+
width: 0;
|
|
147
158
|
}
|
|
159
|
+
}
|
|
148
160
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
161
|
+
/* ─── Le contrat au repos : des définitions inertes ─────────────────────
|
|
162
|
+
* Chaque classe d'entrée possède ici sa définition PROPRE, volontairement
|
|
163
|
+
* inerte tant que rien n'est armé : sans motion.js, aucune animation n'est
|
|
164
|
+
* attachée et ces propriétés n'ont pas d'effet — la page s'affiche
|
|
165
|
+
* complète. C'est aussi le point d'ancrage du dosage : le décalage d'un
|
|
166
|
+
* groupe se règle en posant --zv-delay par élément (120 ms). */
|
|
167
|
+
|
|
168
|
+
.zv-anim-rise {
|
|
169
|
+
animation-delay: var(--zv-delay);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.zv-anim-rise--doux {
|
|
173
|
+
animation-duration: 0.45s;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.zv-anim-glyph-in {
|
|
177
|
+
animation-delay: var(--zv-delay);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.zv-anim-converge {
|
|
181
|
+
animation-delay: var(--zv-delay);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.zv-anim-converge--tr {
|
|
185
|
+
animation-name: zv-converge-tr;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.zv-anim-converge--bl {
|
|
189
|
+
animation-name: zv-converge-bl;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.zv-anim-converge--br {
|
|
193
|
+
animation-name: zv-converge-br;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.zv-anim-pop {
|
|
197
|
+
animation-delay: var(--zv-delay);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Les six vagues : 70 ms d'écart — un délai en secondes retrouve son sens
|
|
201
|
+
* maintenant que l'entrée est temporelle. */
|
|
202
|
+
.zv-anim-pop--2 { animation-delay: calc(var(--zv-delay) + 0.07s); }
|
|
203
|
+
.zv-anim-pop--3 { animation-delay: calc(var(--zv-delay) + 0.14s); }
|
|
204
|
+
.zv-anim-pop--4 { animation-delay: calc(var(--zv-delay) + 0.21s); }
|
|
205
|
+
.zv-anim-pop--5 { animation-delay: calc(var(--zv-delay) + 0.28s); }
|
|
206
|
+
.zv-anim-pop--6 { animation-delay: calc(var(--zv-delay) + 0.35s); }
|
|
207
|
+
|
|
208
|
+
.zv-anim-filet {
|
|
209
|
+
animation-delay: var(--zv-delay);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* ─── L'armement, puis la libération ────────────────────────────────────
|
|
213
|
+
* `:where(html.zv-motion)` garde la spécificité d'une classe simple : les
|
|
214
|
+
* définitions inertes ci-dessus (délais, noms, durées) restent lisibles à
|
|
215
|
+
* travers l'armement, et `.zv-in` — plus bas dans le fichier — gagne à la
|
|
216
|
+
* cascade sans surenchère. Armé, l'élément attend en PAUSE sur la première
|
|
217
|
+
* image de son animation (fill both) ; libéré, elle se joue une fois et
|
|
218
|
+
* s'arrête sur l'état final. Le défilement n'y reviendra jamais. */
|
|
219
|
+
|
|
220
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
221
|
+
/* 3 · Entrée standard de tout contenu texte et panneau. */
|
|
222
|
+
:where(html.zv-motion) .zv-anim-rise {
|
|
223
|
+
animation: zv-rise 0.6s var(--zv-easing) both paused;
|
|
224
|
+
animation-delay: var(--zv-delay);
|
|
154
225
|
}
|
|
155
226
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
227
|
+
/* 3 bis · Le dosage des pages intérieures : se pose AVEC zv-anim-rise,
|
|
228
|
+
* dont il ne change que l'amplitude et la durée. La home garde
|
|
229
|
+
* l'entrée pleine : c'est elle la signature, le doux est le
|
|
230
|
+
* quotidien. */
|
|
231
|
+
:where(html.zv-motion) .zv-anim-rise--doux {
|
|
232
|
+
animation-name: zv-rise-doux;
|
|
233
|
+
animation-duration: 0.45s;
|
|
160
234
|
}
|
|
161
235
|
|
|
162
|
-
.
|
|
236
|
+
/* 4 · Entrée des glyphes produit : montée et grossissement. */
|
|
237
|
+
:where(html.zv-motion) .zv-anim-glyph-in {
|
|
238
|
+
animation: zv-glyph-in 0.6s var(--zv-easing) both paused;
|
|
239
|
+
animation-delay: var(--zv-delay);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* 5 · La convergence. Direction par modificateur. */
|
|
243
|
+
:where(html.zv-motion) .zv-anim-converge {
|
|
244
|
+
animation: zv-converge-tl 0.7s var(--zv-easing) both paused;
|
|
245
|
+
animation-delay: var(--zv-delay);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
:where(html.zv-motion) .zv-anim-converge--tr {
|
|
163
249
|
animation-name: zv-converge-tr;
|
|
164
250
|
}
|
|
165
251
|
|
|
166
|
-
.zv-anim-converge--bl {
|
|
252
|
+
:where(html.zv-motion) .zv-anim-converge--bl {
|
|
167
253
|
animation-name: zv-converge-bl;
|
|
168
254
|
}
|
|
169
255
|
|
|
170
|
-
.zv-anim-converge--br {
|
|
256
|
+
:where(html.zv-motion) .zv-anim-converge--br {
|
|
171
257
|
animation-name: zv-converge-br;
|
|
172
258
|
}
|
|
173
259
|
|
|
174
|
-
/* 6 · Badges, jetons d'entités, éléments de preuve.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
opacity: 0;
|
|
179
|
-
transform: scale(0.6);
|
|
180
|
-
}
|
|
260
|
+
/* 6 · Badges, jetons d'entités, éléments de preuve — en cascade. */
|
|
261
|
+
:where(html.zv-motion) .zv-anim-pop {
|
|
262
|
+
animation: zv-pop 0.4s var(--zv-easing) both paused;
|
|
263
|
+
animation-delay: var(--zv-delay);
|
|
181
264
|
}
|
|
182
265
|
|
|
183
|
-
.zv-anim-pop {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
266
|
+
:where(html.zv-motion) .zv-anim-pop--2 { animation-delay: calc(var(--zv-delay) + 0.07s); }
|
|
267
|
+
:where(html.zv-motion) .zv-anim-pop--3 { animation-delay: calc(var(--zv-delay) + 0.14s); }
|
|
268
|
+
:where(html.zv-motion) .zv-anim-pop--4 { animation-delay: calc(var(--zv-delay) + 0.21s); }
|
|
269
|
+
:where(html.zv-motion) .zv-anim-pop--5 { animation-delay: calc(var(--zv-delay) + 0.28s); }
|
|
270
|
+
:where(html.zv-motion) .zv-anim-pop--6 { animation-delay: calc(var(--zv-delay) + 0.35s); }
|
|
188
271
|
|
|
189
|
-
/*
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
.zv-anim-pop--4 { animation-range: contain 48% contain 88%; }
|
|
194
|
-
.zv-anim-pop--5 { animation-range: contain 54% contain 94%; }
|
|
195
|
-
.zv-anim-pop--6 { animation-range: contain 60% contain 100%; }
|
|
196
|
-
|
|
197
|
-
/* 7 · Le filet de spectre se dessine à l'entrée de chaque en-tête de
|
|
198
|
-
* section. On anime bien la largeur, et non une mise à l'échelle :
|
|
199
|
-
* le dégradé doit se révéler, pas s'étirer. */
|
|
200
|
-
@keyframes zv-filet {
|
|
201
|
-
from {
|
|
202
|
-
width: 0;
|
|
203
|
-
}
|
|
272
|
+
/* 7 · Le filet de spectre, à l'entrée de chaque en-tête de section. */
|
|
273
|
+
:where(html.zv-motion) .zv-anim-filet {
|
|
274
|
+
animation: zv-filet 0.5s var(--zv-easing) both paused;
|
|
275
|
+
animation-delay: var(--zv-delay);
|
|
204
276
|
}
|
|
277
|
+
}
|
|
205
278
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
279
|
+
/* La libération, commune : posée par motion.js à l'entrée au viewport, une
|
|
280
|
+
* seule fois. Sa place APRÈS l'armement fait tout : à spécificité égale,
|
|
281
|
+
* c'est elle qui a le dernier mot. */
|
|
282
|
+
.zv-in {
|
|
283
|
+
animation-play-state: running;
|
|
284
|
+
}
|
|
211
285
|
|
|
286
|
+
/* ─── Les deux lectures du défilement, conservées ───────────────────────
|
|
287
|
+
* Suivre la position de lecture est leur raison d'être : elles doivent
|
|
288
|
+
* avancer ET reculer avec le lecteur. */
|
|
289
|
+
|
|
290
|
+
@supports (animation-timeline: view()) {
|
|
212
291
|
/* 8 · Le point d'étape s'allume à l'entrée de sa scène et s'éteint à la
|
|
213
292
|
* sortie. Un seul actif à la fois. */
|
|
214
293
|
@keyframes zv-dot-active {
|