@majapisoftwares/ui 6.1.0 → 6.1.2
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/AGENTS.md +27 -27
- package/README.md +79 -79
- package/THIRD_PARTY_NOTICES.md +39 -39
- package/components.json +25 -25
- package/docs/MIGRATION-0.2.md +20 -20
- package/docs/MIGRATION-6.0.md +33 -33
- package/docs/NEXT-STARTER-VALIDATION.md +14 -14
- package/docs/STANDARDS.md +41 -41
- package/docs/VALIDATION.md +11 -11
- package/docs/VERSIONING.md +28 -28
- package/docs/validation/preference-titles.md +22 -0
- package/package.json +88 -84
- package/scripts/check-standards.mjs +41 -41
- package/src/components/ui/accordion.tsx +82 -82
- package/src/components/ui/alert-dialog.tsx +187 -187
- package/src/components/ui/alert.tsx +77 -77
- package/src/components/ui/avatar.tsx +108 -108
- package/src/components/ui/badge.tsx +55 -55
- package/src/components/ui/breadcrumb.tsx +125 -125
- package/src/components/ui/button-group.tsx +89 -89
- package/src/components/ui/button.tsx +59 -59
- package/src/components/ui/card.tsx +101 -101
- package/src/components/ui/checkbox.tsx +27 -27
- package/src/components/ui/collapsible.tsx +21 -21
- package/src/components/ui/context-menu.tsx +271 -271
- package/src/components/ui/dialog.tsx +161 -161
- package/src/components/ui/dropdown-menu.tsx +271 -271
- package/src/components/ui/empty.tsx +105 -105
- package/src/components/ui/field.tsx +238 -238
- package/src/components/ui/hover-card.tsx +50 -50
- package/src/components/ui/input-group.tsx +155 -155
- package/src/components/ui/input.tsx +21 -21
- package/src/components/ui/kbd.tsx +28 -28
- package/src/components/ui/label.tsx +19 -19
- package/src/components/ui/orb.css +1002 -1002
- package/src/components/ui/orb.tsx +752 -752
- package/src/components/ui/popover.tsx +89 -89
- package/src/components/ui/progress.tsx +82 -82
- package/src/components/ui/radio-group.tsx +37 -37
- package/src/components/ui/scroll-area.tsx +54 -54
- package/src/components/ui/select.tsx +204 -204
- package/src/components/ui/separator.tsx +24 -24
- package/src/components/ui/sheet.tsx +139 -139
- package/src/components/ui/sidebar.tsx +1039 -1035
- package/src/components/ui/skeleton.tsx +15 -15
- package/src/components/ui/slider.tsx +53 -53
- package/src/components/ui/sonner.tsx +44 -44
- package/src/components/ui/spinner.tsx +32 -32
- package/src/components/ui/switch.tsx +31 -31
- package/src/components/ui/table.tsx +121 -121
- package/src/components/ui/tabs.tsx +81 -81
- package/src/components/ui/textarea.tsx +19 -19
- package/src/components/ui/toggle-group.tsx +89 -89
- package/src/components/ui/toggle.tsx +44 -44
- package/src/components/ui/tooltip.tsx +65 -65
- package/src/hooks/use-mobile.ts +20 -20
- package/src/lib/i18n.tsx +109 -109
- package/src/lib/utils.ts +1 -1
- package/src/patterns/app-shell.tsx +177 -179
- package/src/patterns/data-table.tsx +2486 -2486
- package/src/patterns/details-sheet.tsx +54 -54
- package/src/patterns/filter-tabs.tsx +53 -53
- package/src/patterns/majapi-logo.tsx +32 -32
- package/src/patterns/page-header.tsx +62 -62
- package/src/patterns/preferences.tsx +15 -7
- package/src/patterns/status-badge.tsx +24 -24
- package/src/patterns/user-menu.tsx +218 -218
- package/src/patterns/workspace-switcher.tsx +176 -173
- package/src/styles.css +165 -165
- package/src/templates/admin-dashboard.tsx +44 -44
- package/src/templates/auth-layout.tsx +30 -30
- package/src/templates/login-form.tsx +129 -129
- package/src/templates/signup-form.tsx +177 -177
|
@@ -1,1002 +1,1002 @@
|
|
|
1
|
-
/* Adapted from AICSS Orbs (MIT, https://github.com/kvnkld/aicss). */
|
|
2
|
-
/* Orbs - two families of agent activity indicator.
|
|
3
|
-
*
|
|
4
|
-
* The geometry is authored at a 28px stage and scaled with --orb-k, so
|
|
5
|
-
* the hand-tuned dot sizes, pitch and blur radii hold at any size.
|
|
6
|
-
*
|
|
7
|
-
* Per-segment easings inside @keyframes are written as literals: an
|
|
8
|
-
* `animation-timing-function` declaration inside a keyframe block is
|
|
9
|
-
* read by the animation engine, not resolved against the element, so a
|
|
10
|
-
* var() there would not resolve. The numbers mirror the three custom
|
|
11
|
-
* properties below exactly. */
|
|
12
|
-
|
|
13
|
-
/* Majapi UI: colors follow the theme tokens instead of upstream hex values.
|
|
14
|
-
The dots inherit the surrounding text color (e.g. inside a Button). */
|
|
15
|
-
.orb-root {
|
|
16
|
-
--orb-fg: currentColor;
|
|
17
|
-
--orb-pill-bg: var(--popover);
|
|
18
|
-
--orb-pill-shadow:
|
|
19
|
-
0 0 0 0.5px color-mix(in oklch, var(--foreground) 8%, transparent),
|
|
20
|
-
0 1px 2px color-mix(in oklch, var(--foreground) 5%, transparent),
|
|
21
|
-
0 2px 4px color-mix(in oklch, var(--foreground) 2%, transparent);
|
|
22
|
-
--orb-label: var(--foreground);
|
|
23
|
-
--orb-rest-ink: 0.14;
|
|
24
|
-
--orb-dim-ink: 0.07;
|
|
25
|
-
--orb-ring-rest-ink: 0.22;
|
|
26
|
-
}
|
|
27
|
-
.dark .orb-root {
|
|
28
|
-
--orb-rest-ink: 0.2;
|
|
29
|
-
--orb-dim-ink: 0.1;
|
|
30
|
-
--orb-ring-rest-ink: 0.3;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.orb-root {
|
|
34
|
-
--orb-ease-smooth: cubic-bezier(0.22, 1, 0.36, 1);
|
|
35
|
-
--orb-ease-out: cubic-bezier(0.17, 1, 0.32, 1);
|
|
36
|
-
--orb-ease-in-out: cubic-bezier(0.66, 0, 0.34, 1);
|
|
37
|
-
|
|
38
|
-
display: inline-flex;
|
|
39
|
-
align-items: center;
|
|
40
|
-
vertical-align: middle;
|
|
41
|
-
color: var(--orb-fg);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/* The inline pill form - same component, wrapped. */
|
|
45
|
-
.orb-root[data-pill] {
|
|
46
|
-
gap: 6px;
|
|
47
|
-
height: 32px;
|
|
48
|
-
padding: 0 12px 0 6px;
|
|
49
|
-
border-radius: 999px;
|
|
50
|
-
background: var(--orb-pill-bg);
|
|
51
|
-
/* A hairline ring rather than a border, so it can't affect layout, plus
|
|
52
|
-
a tight contact shadow and a wider ambient one. */
|
|
53
|
-
box-shadow: var(--orb-pill-shadow);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.orb-pill-label {
|
|
57
|
-
/* Majapi UI: same type as buttons/badges instead of upstream Inter 11.5px. */
|
|
58
|
-
font-family: inherit;
|
|
59
|
-
font-size: 0.875rem;
|
|
60
|
-
font-weight: 500;
|
|
61
|
-
line-height: 1;
|
|
62
|
-
color: var(--orb-label);
|
|
63
|
-
white-space: nowrap;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.orb-glyph {
|
|
67
|
-
position: relative;
|
|
68
|
-
display: block;
|
|
69
|
-
flex: none;
|
|
70
|
-
width: 20px;
|
|
71
|
-
height: 20px;
|
|
72
|
-
overflow: hidden;
|
|
73
|
-
contain: strict;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* --- Lattice: discrete dots on a fixed 3×3 grid ------------------- */
|
|
77
|
-
|
|
78
|
-
.orb-lattice {
|
|
79
|
-
position: absolute;
|
|
80
|
-
left: 0;
|
|
81
|
-
top: 0;
|
|
82
|
-
width: 28px;
|
|
83
|
-
height: 28px;
|
|
84
|
-
transform-origin: 0 0;
|
|
85
|
-
/* Three 3px dots on a 6px pitch measure 15px, so the grid is offset to sit
|
|
86
|
-
centred on the 28px stage. It deliberately does not fill the stage: that
|
|
87
|
-
is what keeps its visual weight level with the Lens circles. */
|
|
88
|
-
transform: scale(var(--orb-k, 1)) translate(6.5px, 6.5px);
|
|
89
|
-
/* Resting ink of an unlit cell - the grid stays legible between beats.
|
|
90
|
-
--orb-dim is for cells sitting a choreography out entirely. */
|
|
91
|
-
--orb-rest: var(--orb-rest-ink, 0.14);
|
|
92
|
-
--orb-dim: var(--orb-dim-ink, 0.07);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.orb-cell {
|
|
96
|
-
position: absolute;
|
|
97
|
-
width: 3px;
|
|
98
|
-
height: 3px;
|
|
99
|
-
border-radius: 50%;
|
|
100
|
-
background: currentColor;
|
|
101
|
-
opacity: var(--orb-rest);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/* One wave shape drives all three sweeps. What separates them is the pair of
|
|
105
|
-
duration and per-cell stagger: the stagger sets how fast the wavefront
|
|
106
|
-
travels, the duration how many cells it holds lit at once - which is to
|
|
107
|
-
say, how wide the band reads. */
|
|
108
|
-
.orb-lattice[data-variant="S1"] .orb-cell {
|
|
109
|
-
animation: orb-wave 1.7s var(--orb-ease-in-out) infinite both;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.orb-lattice[data-variant="S2"] .orb-cell {
|
|
113
|
-
animation: orb-wave 1.7s var(--orb-ease-in-out) infinite both;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.orb-lattice[data-variant="S4"] .orb-cell {
|
|
117
|
-
animation: orb-wave 1.6s var(--orb-ease-in-out) infinite both;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.orb-lattice[data-variant="S3"] .orb-cell {
|
|
121
|
-
animation: orb-comet 1.7s var(--orb-ease-smooth) infinite both;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/* Interior cells sit out `orbit` and drop back, so the ring reads as a
|
|
125
|
-
ring and the travelling head has something to stand out against. */
|
|
126
|
-
.orb-lattice[data-variant="S3"] .orb-cell[data-still] {
|
|
127
|
-
animation: none;
|
|
128
|
-
opacity: var(--orb-dim);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.orb-lattice[data-variant="S5"] .orb-cell {
|
|
132
|
-
animation: orb-comet 1.7s var(--orb-ease-smooth) infinite both;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.orb-lattice[data-variant="S5"] .orb-cell[data-still] {
|
|
136
|
-
animation: none;
|
|
137
|
-
opacity: var(--orb-dim);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/* Swells and subsides on the same symmetric curve, so there is no flash and
|
|
141
|
-
no hard edge - the cell rises out of its resting ink and sinks back into
|
|
142
|
-
it. The long tail after 56% is the gap between beats. */
|
|
143
|
-
@keyframes orb-wave {
|
|
144
|
-
0% {
|
|
145
|
-
opacity: var(--orb-rest);
|
|
146
|
-
transform: scale(1);
|
|
147
|
-
animation-timing-function: cubic-bezier(0.66, 0, 0.34, 1);
|
|
148
|
-
}
|
|
149
|
-
28% {
|
|
150
|
-
opacity: 1;
|
|
151
|
-
transform: scale(1.18);
|
|
152
|
-
animation-timing-function: cubic-bezier(0.66, 0, 0.34, 1);
|
|
153
|
-
}
|
|
154
|
-
56% {
|
|
155
|
-
opacity: var(--orb-rest);
|
|
156
|
-
transform: scale(1);
|
|
157
|
-
}
|
|
158
|
-
100% {
|
|
159
|
-
opacity: var(--orb-rest);
|
|
160
|
-
transform: scale(1);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/* Starts lit and decays, so staggered ring cells form a head and tail.
|
|
165
|
-
The decay spans ~3.5 of the 8 ring positions - enough to read as a comet. */
|
|
166
|
-
@keyframes orb-comet {
|
|
167
|
-
0% {
|
|
168
|
-
opacity: 1;
|
|
169
|
-
transform: scale(1.2);
|
|
170
|
-
/* Linear, so the cells behind the head form an even gradient instead
|
|
171
|
-
of collapsing to rest within the first two. */
|
|
172
|
-
animation-timing-function: linear;
|
|
173
|
-
}
|
|
174
|
-
45% {
|
|
175
|
-
opacity: var(--orb-rest);
|
|
176
|
-
transform: scale(1);
|
|
177
|
-
}
|
|
178
|
-
100% {
|
|
179
|
-
opacity: var(--orb-rest);
|
|
180
|
-
transform: scale(1);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/* --- Lens: three circles at depth, blur reads as distance --------- */
|
|
185
|
-
|
|
186
|
-
.orb-lens {
|
|
187
|
-
position: absolute;
|
|
188
|
-
left: 0;
|
|
189
|
-
top: 0;
|
|
190
|
-
width: 28px;
|
|
191
|
-
height: 28px;
|
|
192
|
-
transform-origin: 0 0;
|
|
193
|
-
transform: scale(var(--orb-k, 1));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.orb-shape {
|
|
197
|
-
position: absolute;
|
|
198
|
-
left: 50%;
|
|
199
|
-
top: 50%;
|
|
200
|
-
width: var(--orb-d, 7px);
|
|
201
|
-
height: var(--orb-d, 7px);
|
|
202
|
-
/* Pulled back by its own half-size, so --orb-d is the only knob a variant
|
|
203
|
-
has to touch to resize the cast and it stays centred on the stage. */
|
|
204
|
-
margin: calc(var(--orb-d, 7px) / -2) 0 0 calc(var(--orb-d, 7px) / -2);
|
|
205
|
-
border-radius: 50%;
|
|
206
|
-
background: currentColor;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* focus - attention travels the cast: each circle pulls into focus in turn.
|
|
210
|
-
Four circles on the corners of a square, one size for all of them, so the
|
|
211
|
-
only thing separating them is which one is sharp.
|
|
212
|
-
|
|
213
|
-
A second longer than the three-circle version it grew out of: the square
|
|
214
|
-
has four stations to visit and each one keeps the same unhurried second.
|
|
215
|
-
|
|
216
|
-
The delays count down rather than up because a more negative delay seeds a
|
|
217
|
-
circle further into its cycle: -3s of a 4s cycle runs three quarters ahead,
|
|
218
|
-
which is what sends focus round the square clockwise. */
|
|
219
|
-
.orb-lens[data-variant="B1"] .orb-shape {
|
|
220
|
-
--orb-d: 6px;
|
|
221
|
-
animation: orb-focus 4s var(--orb-ease-smooth) infinite both;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.orb-lens[data-variant="B1"] .orb-shape-a {
|
|
225
|
-
--orb-ox: -4.5px;
|
|
226
|
-
--orb-oy: -4.5px;
|
|
227
|
-
animation-delay: 0s;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.orb-lens[data-variant="B1"] .orb-shape-b {
|
|
231
|
-
--orb-ox: 4.5px;
|
|
232
|
-
--orb-oy: -4.5px;
|
|
233
|
-
animation-delay: -3s;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
.orb-lens[data-variant="B1"] .orb-shape-c {
|
|
237
|
-
--orb-ox: 4.5px;
|
|
238
|
-
--orb-oy: 4.5px;
|
|
239
|
-
animation-delay: -2s;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.orb-lens[data-variant="B1"] .orb-shape-d {
|
|
243
|
-
--orb-ox: -4.5px;
|
|
244
|
-
--orb-oy: 4.5px;
|
|
245
|
-
animation-delay: -1s;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/* Opacity gradient around the square: active = 1.0, next neighbour = 0.30,
|
|
249
|
-
diagonal = 0.10, far = 0.05. Two circles are always clearly visible, the
|
|
250
|
-
rest are ghost hints. */
|
|
251
|
-
@keyframes orb-focus {
|
|
252
|
-
0%,
|
|
253
|
-
100% {
|
|
254
|
-
opacity: 0.05;
|
|
255
|
-
filter: blur(2px);
|
|
256
|
-
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.12);
|
|
257
|
-
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
258
|
-
}
|
|
259
|
-
12% {
|
|
260
|
-
opacity: 1;
|
|
261
|
-
filter: blur(0);
|
|
262
|
-
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1);
|
|
263
|
-
animation-timing-function: linear;
|
|
264
|
-
}
|
|
265
|
-
22% {
|
|
266
|
-
opacity: 1;
|
|
267
|
-
filter: blur(0);
|
|
268
|
-
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1);
|
|
269
|
-
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
270
|
-
}
|
|
271
|
-
/* Next neighbour - one quarter away: clearly visible */
|
|
272
|
-
38% {
|
|
273
|
-
opacity: 0.3;
|
|
274
|
-
filter: blur(1.2px);
|
|
275
|
-
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.06);
|
|
276
|
-
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
277
|
-
}
|
|
278
|
-
/* Diagonal - half a cycle away: ghost */
|
|
279
|
-
58% {
|
|
280
|
-
opacity: 0.1;
|
|
281
|
-
filter: blur(1.8px);
|
|
282
|
-
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.1);
|
|
283
|
-
animation-timing-function: linear;
|
|
284
|
-
}
|
|
285
|
-
/* Far neighbour - three quarters away: barely there */
|
|
286
|
-
82% {
|
|
287
|
-
opacity: 0.05;
|
|
288
|
-
filter: blur(2px);
|
|
289
|
-
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.12);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/* drift - the cast circles the stage on one track, sharp at the front and
|
|
294
|
-
blurred away at the back, so the orb reads as looking around. Uniform
|
|
295
|
-
size: the depth cue is doing the work, a size ladder would fight it. */
|
|
296
|
-
.orb-lens[data-variant="B2"] .orb-shape {
|
|
297
|
-
animation: orb-revolve 3.3s linear infinite both;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/* Evenly spaced around the track, so one is always at the front. */
|
|
301
|
-
.orb-lens[data-variant="B2"] .orb-shape-a {
|
|
302
|
-
animation-delay: 0s;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
.orb-lens[data-variant="B2"] .orb-shape-b {
|
|
306
|
-
animation-delay: -1.1s;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.orb-lens[data-variant="B2"] .orb-shape-c {
|
|
310
|
-
animation-delay: -2.2s;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/* rotate() then translateY() walks a circle. Linear all the way: an eased
|
|
314
|
-
rotation on a circular path reads as a wobble, not as travel. */
|
|
315
|
-
@keyframes orb-revolve {
|
|
316
|
-
0% {
|
|
317
|
-
opacity: 1;
|
|
318
|
-
filter: blur(0);
|
|
319
|
-
transform: rotate(0deg) translateY(6.5px) scale(1);
|
|
320
|
-
}
|
|
321
|
-
25% {
|
|
322
|
-
opacity: 0.55;
|
|
323
|
-
filter: blur(1.3px);
|
|
324
|
-
transform: rotate(90deg) translateY(6.5px) scale(0.82);
|
|
325
|
-
}
|
|
326
|
-
50% {
|
|
327
|
-
opacity: 0.28;
|
|
328
|
-
filter: blur(2.4px);
|
|
329
|
-
transform: rotate(180deg) translateY(6.5px) scale(0.66);
|
|
330
|
-
}
|
|
331
|
-
75% {
|
|
332
|
-
opacity: 0.55;
|
|
333
|
-
filter: blur(1.3px);
|
|
334
|
-
transform: rotate(270deg) translateY(6.5px) scale(0.82);
|
|
335
|
-
}
|
|
336
|
-
100% {
|
|
337
|
-
opacity: 1;
|
|
338
|
-
filter: blur(0);
|
|
339
|
-
transform: rotate(360deg) translateY(6.5px) scale(1);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/* bloom - shapes emanate from the centre, blurring out as they grow.
|
|
344
|
-
Linear keeps the total ink even; on a front-loaded curve the shapes
|
|
345
|
-
jump to their large, blurred end state and the orb alternates between
|
|
346
|
-
a heavy blot and an empty haze. */
|
|
347
|
-
.orb-lens[data-variant="B3"] .orb-shape {
|
|
348
|
-
animation: orb-bloom 4.2s linear infinite both;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
.orb-lens[data-variant="B3"] .orb-shape-a {
|
|
352
|
-
animation-delay: 0s;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
.orb-lens[data-variant="B3"] .orb-shape-b {
|
|
356
|
-
animation-delay: -1.4s;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
.orb-lens[data-variant="B3"] .orb-shape-c {
|
|
360
|
-
animation-delay: -2.8s;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/* Each ripple dies at 62% and waits out the rest, so the three overlapping
|
|
364
|
-
blooms leave gaps. Without the gap the aggregate is a constant haze and
|
|
365
|
-
the outward motion stops reading at all. Sharp circle appears, holds
|
|
366
|
-
briefly, then dissolves outward - blur only kicks in once opacity starts
|
|
367
|
-
dropping, so the circle stays crisp while it's visible and the blur reads
|
|
368
|
-
as the ripple dissipating. */
|
|
369
|
-
@keyframes orb-bloom {
|
|
370
|
-
0% {
|
|
371
|
-
opacity: 0;
|
|
372
|
-
filter: blur(0);
|
|
373
|
-
transform: scale(0.35);
|
|
374
|
-
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
375
|
-
}
|
|
376
|
-
8% {
|
|
377
|
-
opacity: 1;
|
|
378
|
-
filter: blur(0);
|
|
379
|
-
transform: scale(0.55);
|
|
380
|
-
animation-timing-function: linear;
|
|
381
|
-
}
|
|
382
|
-
24% {
|
|
383
|
-
opacity: 1;
|
|
384
|
-
filter: blur(0);
|
|
385
|
-
transform: scale(0.72);
|
|
386
|
-
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
387
|
-
}
|
|
388
|
-
42% {
|
|
389
|
-
opacity: 0.1;
|
|
390
|
-
filter: blur(1.8px);
|
|
391
|
-
transform: scale(1.5);
|
|
392
|
-
}
|
|
393
|
-
62% {
|
|
394
|
-
opacity: 0;
|
|
395
|
-
filter: blur(2.8px);
|
|
396
|
-
transform: scale(2.4);
|
|
397
|
-
}
|
|
398
|
-
100% {
|
|
399
|
-
opacity: 0;
|
|
400
|
-
filter: blur(2.8px);
|
|
401
|
-
transform: scale(2.4);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/* converge - a single circle traces an equilateral triangle (top → bottom-right
|
|
406
|
-
→ bottom-left → top) with handoff-style easing: full size and sharp at each
|
|
407
|
-
vertex, smaller and slightly blurred in transit. orbB breathes at the
|
|
408
|
-
centroid as a subtle depth cue; orbC is hidden. */
|
|
409
|
-
.orb-lens[data-variant="B4"] .orb-shape-a {
|
|
410
|
-
animation: orb-converge 3.6s linear infinite both;
|
|
411
|
-
}
|
|
412
|
-
.orb-lens[data-variant="B4"] .orb-shape-b {
|
|
413
|
-
animation: orb-breathe 3.6s ease-in-out infinite both;
|
|
414
|
-
}
|
|
415
|
-
.orb-lens[data-variant="B4"] .orb-shape-c {
|
|
416
|
-
display: none;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
@keyframes orb-converge {
|
|
420
|
-
0% {
|
|
421
|
-
transform: translate(0px, -5px) scale(1);
|
|
422
|
-
filter: blur(0);
|
|
423
|
-
animation-timing-function: linear;
|
|
424
|
-
}
|
|
425
|
-
10% {
|
|
426
|
-
transform: translate(0px, -5px) scale(1);
|
|
427
|
-
filter: blur(0);
|
|
428
|
-
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
429
|
-
}
|
|
430
|
-
22% {
|
|
431
|
-
transform: translate(2.15px, -1.25px) scale(0.72);
|
|
432
|
-
filter: blur(0.8px);
|
|
433
|
-
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
434
|
-
}
|
|
435
|
-
33% {
|
|
436
|
-
transform: translate(4.3px, 2.5px) scale(1);
|
|
437
|
-
filter: blur(0);
|
|
438
|
-
animation-timing-function: linear;
|
|
439
|
-
}
|
|
440
|
-
43% {
|
|
441
|
-
transform: translate(4.3px, 2.5px) scale(1);
|
|
442
|
-
filter: blur(0);
|
|
443
|
-
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
444
|
-
}
|
|
445
|
-
55% {
|
|
446
|
-
transform: translate(0px, 2.5px) scale(0.72);
|
|
447
|
-
filter: blur(0.8px);
|
|
448
|
-
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
449
|
-
}
|
|
450
|
-
66% {
|
|
451
|
-
transform: translate(-4.3px, 2.5px) scale(1);
|
|
452
|
-
filter: blur(0);
|
|
453
|
-
animation-timing-function: linear;
|
|
454
|
-
}
|
|
455
|
-
77% {
|
|
456
|
-
transform: translate(-4.3px, 2.5px) scale(1);
|
|
457
|
-
filter: blur(0);
|
|
458
|
-
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
459
|
-
}
|
|
460
|
-
88% {
|
|
461
|
-
transform: translate(-2.15px, -1.25px) scale(0.72);
|
|
462
|
-
filter: blur(0.8px);
|
|
463
|
-
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
464
|
-
}
|
|
465
|
-
100% {
|
|
466
|
-
transform: translate(0px, -5px) scale(1);
|
|
467
|
-
filter: blur(0);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/* handoff - the cast crosses the focal plane one after another, always left
|
|
472
|
-
to right, like work being passed on. The shorthand curve is only a
|
|
473
|
-
fallback; every segment below sets its own. */
|
|
474
|
-
.orb-lens[data-variant="B5"] .orb-shape {
|
|
475
|
-
animation: orb-handoff 2.8s linear infinite both;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
/* Half a cycle apart, so one is always at the focal plane while the other is
|
|
479
|
-
invisible at an end and the loop point cannot be seen. */
|
|
480
|
-
.orb-lens[data-variant="B5"] .orb-shape-a {
|
|
481
|
-
animation-delay: 0s;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
.orb-lens[data-variant="B5"] .orb-shape-c {
|
|
485
|
-
animation-delay: -1.4s;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/* The third holds the centre and breathes - a soft depth cue behind the
|
|
489
|
-
traffic rather than another traveller. */
|
|
490
|
-
.orb-lens[data-variant="B5"] .orb-shape-b {
|
|
491
|
-
animation-name: orb-breathe;
|
|
492
|
-
animation-duration: 3.6s;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/* Enters small from the left, reaches standard size at the focal plane, then
|
|
496
|
-
shrinks and fades out to the right. At the dwell (centre) the circle is
|
|
497
|
-
exactly 1× - no pulsing, no bounce, just a clean handoff. */
|
|
498
|
-
@keyframes orb-handoff {
|
|
499
|
-
0% {
|
|
500
|
-
opacity: 0;
|
|
501
|
-
filter: blur(2.4px);
|
|
502
|
-
transform: translateX(-11px) scale(0.55);
|
|
503
|
-
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
504
|
-
}
|
|
505
|
-
22% {
|
|
506
|
-
opacity: 1;
|
|
507
|
-
filter: blur(0);
|
|
508
|
-
transform: translateX(-1px) scale(1);
|
|
509
|
-
animation-timing-function: linear;
|
|
510
|
-
}
|
|
511
|
-
37% {
|
|
512
|
-
opacity: 1;
|
|
513
|
-
filter: blur(0);
|
|
514
|
-
transform: translateX(0) scale(1);
|
|
515
|
-
animation-timing-function: linear;
|
|
516
|
-
}
|
|
517
|
-
52% {
|
|
518
|
-
opacity: 1;
|
|
519
|
-
filter: blur(0);
|
|
520
|
-
transform: translateX(1px) scale(1);
|
|
521
|
-
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
522
|
-
}
|
|
523
|
-
70% {
|
|
524
|
-
opacity: 0;
|
|
525
|
-
filter: blur(2.4px);
|
|
526
|
-
transform: translateX(11px) scale(0.55);
|
|
527
|
-
}
|
|
528
|
-
100% {
|
|
529
|
-
opacity: 0;
|
|
530
|
-
filter: blur(2.4px);
|
|
531
|
-
transform: translateX(11px) scale(0.55);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
@keyframes orb-breathe {
|
|
536
|
-
0%,
|
|
537
|
-
100% {
|
|
538
|
-
opacity: 0.16;
|
|
539
|
-
filter: blur(2.4px);
|
|
540
|
-
transform: scale(1.2);
|
|
541
|
-
}
|
|
542
|
-
50% {
|
|
543
|
-
opacity: 0.32;
|
|
544
|
-
filter: blur(1.6px);
|
|
545
|
-
transform: scale(0.98);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/* --- Ring: eight circles on a fixed ring ----------------------------- */
|
|
550
|
-
|
|
551
|
-
.orb-ring {
|
|
552
|
-
position: absolute;
|
|
553
|
-
inset: 0;
|
|
554
|
-
transform: scale(var(--orb-k, 1));
|
|
555
|
-
--orb-ring-rest: var(--orb-ring-rest-ink, 0.22);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
.orb-ring-dot {
|
|
559
|
-
position: absolute;
|
|
560
|
-
left: 50%;
|
|
561
|
-
top: 50%;
|
|
562
|
-
width: 3px;
|
|
563
|
-
height: 3px;
|
|
564
|
-
margin: -1.5px 0 0 -1.5px;
|
|
565
|
-
border-radius: 50%;
|
|
566
|
-
background: currentColor;
|
|
567
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
.orb-ring[data-variant="C1"] .orb-ring-dot {
|
|
571
|
-
opacity: var(--orb-ring-rest);
|
|
572
|
-
animation: orb-ring-chase 1.6s linear infinite both;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
@keyframes orb-ring-chase {
|
|
576
|
-
0%,
|
|
577
|
-
11% {
|
|
578
|
-
opacity: 1;
|
|
579
|
-
}
|
|
580
|
-
12.5%,
|
|
581
|
-
100% {
|
|
582
|
-
opacity: var(--orb-ring-rest);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
.orb-ring[data-variant="C2"] .orb-ring-dot {
|
|
587
|
-
animation: orb-ring-pulse 2s ease-in-out infinite both;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
@keyframes orb-ring-pulse {
|
|
591
|
-
0%,
|
|
592
|
-
100% {
|
|
593
|
-
opacity: 0.18;
|
|
594
|
-
transform: translate(var(--orb-rx), var(--orb-ry)) scale(0.7);
|
|
595
|
-
}
|
|
596
|
-
50% {
|
|
597
|
-
opacity: 1;
|
|
598
|
-
transform: translate(var(--orb-rx), var(--orb-ry)) scale(1.15);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
.orb-ring[data-variant="C3"] .orb-ring-dot {
|
|
603
|
-
animation: orb-ring-comet 1.8s ease-in-out infinite both;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
@keyframes orb-ring-comet {
|
|
607
|
-
0%,
|
|
608
|
-
100% {
|
|
609
|
-
opacity: 0.08;
|
|
610
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
611
|
-
}
|
|
612
|
-
12% {
|
|
613
|
-
opacity: 1;
|
|
614
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
615
|
-
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
616
|
-
}
|
|
617
|
-
35% {
|
|
618
|
-
opacity: 0.5;
|
|
619
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
620
|
-
}
|
|
621
|
-
60% {
|
|
622
|
-
opacity: 0.12;
|
|
623
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
.orb-ring[data-variant="C4"] .orb-ring-dot {
|
|
628
|
-
animation: orb-ring-stagger 1.6s ease-in-out infinite both;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
@keyframes orb-ring-stagger {
|
|
632
|
-
0%,
|
|
633
|
-
100% {
|
|
634
|
-
opacity: 1;
|
|
635
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
636
|
-
}
|
|
637
|
-
50% {
|
|
638
|
-
opacity: 0.15;
|
|
639
|
-
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
.orb-ring[data-variant="C5"] .orb-ring-dot {
|
|
644
|
-
animation: orb-ring-comet 1.8s ease-in-out infinite both;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
/* ---- Globe (Helix family) ---- */
|
|
648
|
-
.orb-helix {
|
|
649
|
-
position: absolute;
|
|
650
|
-
inset: 0;
|
|
651
|
-
transform: scale(var(--orb-k, 1));
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
.orb-helix-dot {
|
|
655
|
-
position: absolute;
|
|
656
|
-
left: 50%;
|
|
657
|
-
top: 50%;
|
|
658
|
-
width: 2px;
|
|
659
|
-
height: 2px;
|
|
660
|
-
margin: -1px 0 0 -1px;
|
|
661
|
-
border-radius: 50%;
|
|
662
|
-
background: currentColor;
|
|
663
|
-
will-change: transform, opacity;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
.orb-helix[data-variant="G1"] .orb-helix-dot {
|
|
667
|
-
animation: orb-globe-spin 4.5s linear infinite both;
|
|
668
|
-
}
|
|
669
|
-
.orb-helix[data-variant="G2"] .orb-helix-dot {
|
|
670
|
-
animation: orb-globe-spin 3.6s linear infinite both;
|
|
671
|
-
}
|
|
672
|
-
.orb-helix[data-variant="G3"] .orb-helix-dot {
|
|
673
|
-
animation: orb-globe-ringturn 2.8s linear infinite both;
|
|
674
|
-
}
|
|
675
|
-
.orb-helix[data-variant="G4"] .orb-helix-dot {
|
|
676
|
-
animation: orb-globe-ringturn 2.8s linear infinite both;
|
|
677
|
-
}
|
|
678
|
-
.orb-helix[data-variant="G5"] .orb-helix-dot {
|
|
679
|
-
animation: orb-globe-breathe 3.6s linear infinite both;
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
@keyframes orb-globe-spin {
|
|
683
|
-
0%,
|
|
684
|
-
100% {
|
|
685
|
-
transform: translate(var(--g0x), var(--g0y));
|
|
686
|
-
opacity: var(--g0o);
|
|
687
|
-
}
|
|
688
|
-
12.5% {
|
|
689
|
-
transform: translate(var(--g1x), var(--g1y));
|
|
690
|
-
opacity: var(--g1o);
|
|
691
|
-
}
|
|
692
|
-
25% {
|
|
693
|
-
transform: translate(var(--g2x), var(--g2y));
|
|
694
|
-
opacity: var(--g2o);
|
|
695
|
-
}
|
|
696
|
-
37.5% {
|
|
697
|
-
transform: translate(var(--g3x), var(--g3y));
|
|
698
|
-
opacity: var(--g3o);
|
|
699
|
-
}
|
|
700
|
-
50% {
|
|
701
|
-
transform: translate(var(--g4x), var(--g4y));
|
|
702
|
-
opacity: var(--g4o);
|
|
703
|
-
}
|
|
704
|
-
62.5% {
|
|
705
|
-
transform: translate(var(--g5x), var(--g5y));
|
|
706
|
-
opacity: var(--g5o);
|
|
707
|
-
}
|
|
708
|
-
75% {
|
|
709
|
-
transform: translate(var(--g6x), var(--g6y));
|
|
710
|
-
opacity: var(--g6o);
|
|
711
|
-
}
|
|
712
|
-
87.5% {
|
|
713
|
-
transform: translate(var(--g7x), var(--g7y));
|
|
714
|
-
opacity: var(--g7o);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
@keyframes orb-globe-ringturn {
|
|
719
|
-
0% {
|
|
720
|
-
transform: translate(var(--g0x), var(--g0y));
|
|
721
|
-
opacity: var(--g0o);
|
|
722
|
-
}
|
|
723
|
-
2.5% {
|
|
724
|
-
transform: translate(var(--g1x), var(--g1y));
|
|
725
|
-
opacity: var(--g1o);
|
|
726
|
-
}
|
|
727
|
-
5% {
|
|
728
|
-
transform: translate(var(--g2x), var(--g2y));
|
|
729
|
-
opacity: var(--g2o);
|
|
730
|
-
}
|
|
731
|
-
7.5%,
|
|
732
|
-
10% {
|
|
733
|
-
transform: translate(var(--g3x), var(--g3y));
|
|
734
|
-
opacity: var(--g3o);
|
|
735
|
-
}
|
|
736
|
-
12.5% {
|
|
737
|
-
transform: translate(var(--g4x), var(--g4y));
|
|
738
|
-
opacity: var(--g4o);
|
|
739
|
-
}
|
|
740
|
-
15% {
|
|
741
|
-
transform: translate(var(--g5x), var(--g5y));
|
|
742
|
-
opacity: var(--g5o);
|
|
743
|
-
}
|
|
744
|
-
17.5%,
|
|
745
|
-
20% {
|
|
746
|
-
transform: translate(var(--g6x), var(--g6y));
|
|
747
|
-
opacity: var(--g6o);
|
|
748
|
-
}
|
|
749
|
-
22.5% {
|
|
750
|
-
transform: translate(var(--g7x), var(--g7y));
|
|
751
|
-
opacity: var(--g7o);
|
|
752
|
-
}
|
|
753
|
-
25% {
|
|
754
|
-
transform: translate(var(--g8x), var(--g8y));
|
|
755
|
-
opacity: var(--g8o);
|
|
756
|
-
}
|
|
757
|
-
27.5%,
|
|
758
|
-
30% {
|
|
759
|
-
transform: translate(var(--g9x), var(--g9y));
|
|
760
|
-
opacity: var(--g9o);
|
|
761
|
-
}
|
|
762
|
-
32.5% {
|
|
763
|
-
transform: translate(var(--g10x), var(--g10y));
|
|
764
|
-
opacity: var(--g10o);
|
|
765
|
-
}
|
|
766
|
-
35% {
|
|
767
|
-
transform: translate(var(--g11x), var(--g11y));
|
|
768
|
-
opacity: var(--g11o);
|
|
769
|
-
}
|
|
770
|
-
37.5%,
|
|
771
|
-
40% {
|
|
772
|
-
transform: translate(var(--g12x), var(--g12y));
|
|
773
|
-
opacity: var(--g12o);
|
|
774
|
-
}
|
|
775
|
-
42.5% {
|
|
776
|
-
transform: translate(var(--g13x), var(--g13y));
|
|
777
|
-
opacity: var(--g13o);
|
|
778
|
-
}
|
|
779
|
-
45% {
|
|
780
|
-
transform: translate(var(--g14x), var(--g14y));
|
|
781
|
-
opacity: var(--g14o);
|
|
782
|
-
}
|
|
783
|
-
47.5%,
|
|
784
|
-
50% {
|
|
785
|
-
transform: translate(var(--g15x), var(--g15y));
|
|
786
|
-
opacity: var(--g15o);
|
|
787
|
-
}
|
|
788
|
-
52.5% {
|
|
789
|
-
transform: translate(var(--g16x), var(--g16y));
|
|
790
|
-
opacity: var(--g16o);
|
|
791
|
-
}
|
|
792
|
-
55% {
|
|
793
|
-
transform: translate(var(--g17x), var(--g17y));
|
|
794
|
-
opacity: var(--g17o);
|
|
795
|
-
}
|
|
796
|
-
57.5%,
|
|
797
|
-
60% {
|
|
798
|
-
transform: translate(var(--g18x), var(--g18y));
|
|
799
|
-
opacity: var(--g18o);
|
|
800
|
-
}
|
|
801
|
-
62.5% {
|
|
802
|
-
transform: translate(var(--g19x), var(--g19y));
|
|
803
|
-
opacity: var(--g19o);
|
|
804
|
-
}
|
|
805
|
-
65% {
|
|
806
|
-
transform: translate(var(--g20x), var(--g20y));
|
|
807
|
-
opacity: var(--g20o);
|
|
808
|
-
}
|
|
809
|
-
67.5%,
|
|
810
|
-
70% {
|
|
811
|
-
transform: translate(var(--g21x), var(--g21y));
|
|
812
|
-
opacity: var(--g21o);
|
|
813
|
-
}
|
|
814
|
-
72.5% {
|
|
815
|
-
transform: translate(var(--g22x), var(--g22y));
|
|
816
|
-
opacity: var(--g22o);
|
|
817
|
-
}
|
|
818
|
-
75% {
|
|
819
|
-
transform: translate(var(--g23x), var(--g23y));
|
|
820
|
-
opacity: var(--g23o);
|
|
821
|
-
}
|
|
822
|
-
77.5%,
|
|
823
|
-
80% {
|
|
824
|
-
transform: translate(var(--g24x), var(--g24y));
|
|
825
|
-
opacity: var(--g24o);
|
|
826
|
-
}
|
|
827
|
-
82.5% {
|
|
828
|
-
transform: translate(var(--g25x), var(--g25y));
|
|
829
|
-
opacity: var(--g25o);
|
|
830
|
-
}
|
|
831
|
-
85% {
|
|
832
|
-
transform: translate(var(--g26x), var(--g26y));
|
|
833
|
-
opacity: var(--g26o);
|
|
834
|
-
}
|
|
835
|
-
87.5%,
|
|
836
|
-
90% {
|
|
837
|
-
transform: translate(var(--g27x), var(--g27y));
|
|
838
|
-
opacity: var(--g27o);
|
|
839
|
-
}
|
|
840
|
-
92.5% {
|
|
841
|
-
transform: translate(var(--g28x), var(--g28y));
|
|
842
|
-
opacity: var(--g28o);
|
|
843
|
-
}
|
|
844
|
-
95% {
|
|
845
|
-
transform: translate(var(--g29x), var(--g29y));
|
|
846
|
-
opacity: var(--g29o);
|
|
847
|
-
}
|
|
848
|
-
97.5%,
|
|
849
|
-
100% {
|
|
850
|
-
transform: translate(var(--g30x), var(--g30y));
|
|
851
|
-
opacity: var(--g30o);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
@keyframes orb-globe-breathe {
|
|
856
|
-
0% {
|
|
857
|
-
transform: translate(var(--g0x), var(--g0y));
|
|
858
|
-
opacity: var(--g0o);
|
|
859
|
-
}
|
|
860
|
-
19% {
|
|
861
|
-
transform: translate(var(--g1x), var(--g1y));
|
|
862
|
-
opacity: var(--g1o);
|
|
863
|
-
}
|
|
864
|
-
25% {
|
|
865
|
-
transform: translate(var(--g2x), var(--g2y));
|
|
866
|
-
opacity: var(--g2o);
|
|
867
|
-
}
|
|
868
|
-
44% {
|
|
869
|
-
transform: translate(var(--g3x), var(--g3y));
|
|
870
|
-
opacity: var(--g3o);
|
|
871
|
-
}
|
|
872
|
-
50% {
|
|
873
|
-
transform: translate(var(--g4x), var(--g4y));
|
|
874
|
-
opacity: var(--g4o);
|
|
875
|
-
}
|
|
876
|
-
69% {
|
|
877
|
-
transform: translate(var(--g5x), var(--g5y));
|
|
878
|
-
opacity: var(--g5o);
|
|
879
|
-
}
|
|
880
|
-
75% {
|
|
881
|
-
transform: translate(var(--g6x), var(--g6y));
|
|
882
|
-
opacity: var(--g6o);
|
|
883
|
-
}
|
|
884
|
-
94% {
|
|
885
|
-
transform: translate(var(--g7x), var(--g7y));
|
|
886
|
-
opacity: var(--g7o);
|
|
887
|
-
}
|
|
888
|
-
100% {
|
|
889
|
-
transform: translate(var(--g8x), var(--g8y));
|
|
890
|
-
opacity: var(--g8o);
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
/* ---- Morph ---- */
|
|
895
|
-
.orb-morph {
|
|
896
|
-
position: absolute;
|
|
897
|
-
inset: 0;
|
|
898
|
-
transform: scale(var(--orb-k, 1));
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
.orb-morph-dot {
|
|
902
|
-
position: absolute;
|
|
903
|
-
left: 50%;
|
|
904
|
-
top: 50%;
|
|
905
|
-
width: 3px;
|
|
906
|
-
height: 3px;
|
|
907
|
-
margin: -1.5px 0 0 -1.5px;
|
|
908
|
-
border-radius: 50%;
|
|
909
|
-
background: currentColor;
|
|
910
|
-
animation: orb-morph 4.8s cubic-bezier(0.4, 0, 0.2, 1) infinite both;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
@keyframes orb-morph {
|
|
914
|
-
0%,
|
|
915
|
-
5% {
|
|
916
|
-
transform: translate(var(--m-1));
|
|
917
|
-
}
|
|
918
|
-
25%,
|
|
919
|
-
30% {
|
|
920
|
-
transform: translate(var(--m-2));
|
|
921
|
-
}
|
|
922
|
-
50%,
|
|
923
|
-
55% {
|
|
924
|
-
transform: translate(var(--m-3));
|
|
925
|
-
}
|
|
926
|
-
75%,
|
|
927
|
-
80% {
|
|
928
|
-
transform: translate(var(--m-4));
|
|
929
|
-
}
|
|
930
|
-
100% {
|
|
931
|
-
transform: translate(var(--m-1));
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
.orb-morph[data-variant="M2"] {
|
|
936
|
-
animation: orb-morph-twist 9.6s linear infinite;
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
.orb-morph[data-variant="M4"] {
|
|
940
|
-
animation: orb-morph-twist 9.6s linear infinite;
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
.orb-morph[data-variant="M5"] .orb-morph-dot {
|
|
944
|
-
animation: orb-morph-scatter 2.8s cubic-bezier(0.4, 0, 0.2, 1) infinite both;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
@keyframes orb-morph-scatter {
|
|
948
|
-
0%,
|
|
949
|
-
12% {
|
|
950
|
-
transform: translate(var(--m-1));
|
|
951
|
-
opacity: 1;
|
|
952
|
-
}
|
|
953
|
-
38%,
|
|
954
|
-
62% {
|
|
955
|
-
transform: translate(var(--m-2));
|
|
956
|
-
opacity: calc(1 - 0.6 * var(--m-depth, 0));
|
|
957
|
-
}
|
|
958
|
-
88%,
|
|
959
|
-
100% {
|
|
960
|
-
transform: translate(var(--m-1));
|
|
961
|
-
opacity: 1;
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
@keyframes orb-morph-twist {
|
|
966
|
-
from {
|
|
967
|
-
transform: scale(var(--orb-k, 1)) rotate(0deg);
|
|
968
|
-
}
|
|
969
|
-
to {
|
|
970
|
-
transform: scale(var(--orb-k, 1)) rotate(360deg);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
@media (prefers-reduced-motion: reduce) {
|
|
975
|
-
.orb-cell,
|
|
976
|
-
.orb-shape,
|
|
977
|
-
.orb-ring-dot,
|
|
978
|
-
.orb-helix-dot,
|
|
979
|
-
.orb-morph-dot {
|
|
980
|
-
animation: none !important;
|
|
981
|
-
}
|
|
982
|
-
.orb-cell[data-mid] {
|
|
983
|
-
opacity: 1 !important;
|
|
984
|
-
}
|
|
985
|
-
.orb-shape {
|
|
986
|
-
opacity: 0.3 !important;
|
|
987
|
-
filter: blur(1.4px) !important;
|
|
988
|
-
transform: none !important;
|
|
989
|
-
}
|
|
990
|
-
.orb-shape-a {
|
|
991
|
-
opacity: 1 !important;
|
|
992
|
-
filter: blur(0) !important;
|
|
993
|
-
}
|
|
994
|
-
.orb-ring-dot {
|
|
995
|
-
opacity: 0.7 !important;
|
|
996
|
-
}
|
|
997
|
-
.orb-ring,
|
|
998
|
-
.orb-helix,
|
|
999
|
-
.orb-morph {
|
|
1000
|
-
animation: none !important;
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1
|
+
/* Adapted from AICSS Orbs (MIT, https://github.com/kvnkld/aicss). */
|
|
2
|
+
/* Orbs - two families of agent activity indicator.
|
|
3
|
+
*
|
|
4
|
+
* The geometry is authored at a 28px stage and scaled with --orb-k, so
|
|
5
|
+
* the hand-tuned dot sizes, pitch and blur radii hold at any size.
|
|
6
|
+
*
|
|
7
|
+
* Per-segment easings inside @keyframes are written as literals: an
|
|
8
|
+
* `animation-timing-function` declaration inside a keyframe block is
|
|
9
|
+
* read by the animation engine, not resolved against the element, so a
|
|
10
|
+
* var() there would not resolve. The numbers mirror the three custom
|
|
11
|
+
* properties below exactly. */
|
|
12
|
+
|
|
13
|
+
/* Majapi UI: colors follow the theme tokens instead of upstream hex values.
|
|
14
|
+
The dots inherit the surrounding text color (e.g. inside a Button). */
|
|
15
|
+
.orb-root {
|
|
16
|
+
--orb-fg: currentColor;
|
|
17
|
+
--orb-pill-bg: var(--popover);
|
|
18
|
+
--orb-pill-shadow:
|
|
19
|
+
0 0 0 0.5px color-mix(in oklch, var(--foreground) 8%, transparent),
|
|
20
|
+
0 1px 2px color-mix(in oklch, var(--foreground) 5%, transparent),
|
|
21
|
+
0 2px 4px color-mix(in oklch, var(--foreground) 2%, transparent);
|
|
22
|
+
--orb-label: var(--foreground);
|
|
23
|
+
--orb-rest-ink: 0.14;
|
|
24
|
+
--orb-dim-ink: 0.07;
|
|
25
|
+
--orb-ring-rest-ink: 0.22;
|
|
26
|
+
}
|
|
27
|
+
.dark .orb-root {
|
|
28
|
+
--orb-rest-ink: 0.2;
|
|
29
|
+
--orb-dim-ink: 0.1;
|
|
30
|
+
--orb-ring-rest-ink: 0.3;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.orb-root {
|
|
34
|
+
--orb-ease-smooth: cubic-bezier(0.22, 1, 0.36, 1);
|
|
35
|
+
--orb-ease-out: cubic-bezier(0.17, 1, 0.32, 1);
|
|
36
|
+
--orb-ease-in-out: cubic-bezier(0.66, 0, 0.34, 1);
|
|
37
|
+
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
vertical-align: middle;
|
|
41
|
+
color: var(--orb-fg);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* The inline pill form - same component, wrapped. */
|
|
45
|
+
.orb-root[data-pill] {
|
|
46
|
+
gap: 6px;
|
|
47
|
+
height: 32px;
|
|
48
|
+
padding: 0 12px 0 6px;
|
|
49
|
+
border-radius: 999px;
|
|
50
|
+
background: var(--orb-pill-bg);
|
|
51
|
+
/* A hairline ring rather than a border, so it can't affect layout, plus
|
|
52
|
+
a tight contact shadow and a wider ambient one. */
|
|
53
|
+
box-shadow: var(--orb-pill-shadow);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.orb-pill-label {
|
|
57
|
+
/* Majapi UI: same type as buttons/badges instead of upstream Inter 11.5px. */
|
|
58
|
+
font-family: inherit;
|
|
59
|
+
font-size: 0.875rem;
|
|
60
|
+
font-weight: 500;
|
|
61
|
+
line-height: 1;
|
|
62
|
+
color: var(--orb-label);
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.orb-glyph {
|
|
67
|
+
position: relative;
|
|
68
|
+
display: block;
|
|
69
|
+
flex: none;
|
|
70
|
+
width: 20px;
|
|
71
|
+
height: 20px;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
contain: strict;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* --- Lattice: discrete dots on a fixed 3×3 grid ------------------- */
|
|
77
|
+
|
|
78
|
+
.orb-lattice {
|
|
79
|
+
position: absolute;
|
|
80
|
+
left: 0;
|
|
81
|
+
top: 0;
|
|
82
|
+
width: 28px;
|
|
83
|
+
height: 28px;
|
|
84
|
+
transform-origin: 0 0;
|
|
85
|
+
/* Three 3px dots on a 6px pitch measure 15px, so the grid is offset to sit
|
|
86
|
+
centred on the 28px stage. It deliberately does not fill the stage: that
|
|
87
|
+
is what keeps its visual weight level with the Lens circles. */
|
|
88
|
+
transform: scale(var(--orb-k, 1)) translate(6.5px, 6.5px);
|
|
89
|
+
/* Resting ink of an unlit cell - the grid stays legible between beats.
|
|
90
|
+
--orb-dim is for cells sitting a choreography out entirely. */
|
|
91
|
+
--orb-rest: var(--orb-rest-ink, 0.14);
|
|
92
|
+
--orb-dim: var(--orb-dim-ink, 0.07);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.orb-cell {
|
|
96
|
+
position: absolute;
|
|
97
|
+
width: 3px;
|
|
98
|
+
height: 3px;
|
|
99
|
+
border-radius: 50%;
|
|
100
|
+
background: currentColor;
|
|
101
|
+
opacity: var(--orb-rest);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* One wave shape drives all three sweeps. What separates them is the pair of
|
|
105
|
+
duration and per-cell stagger: the stagger sets how fast the wavefront
|
|
106
|
+
travels, the duration how many cells it holds lit at once - which is to
|
|
107
|
+
say, how wide the band reads. */
|
|
108
|
+
.orb-lattice[data-variant="S1"] .orb-cell {
|
|
109
|
+
animation: orb-wave 1.7s var(--orb-ease-in-out) infinite both;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.orb-lattice[data-variant="S2"] .orb-cell {
|
|
113
|
+
animation: orb-wave 1.7s var(--orb-ease-in-out) infinite both;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.orb-lattice[data-variant="S4"] .orb-cell {
|
|
117
|
+
animation: orb-wave 1.6s var(--orb-ease-in-out) infinite both;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.orb-lattice[data-variant="S3"] .orb-cell {
|
|
121
|
+
animation: orb-comet 1.7s var(--orb-ease-smooth) infinite both;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Interior cells sit out `orbit` and drop back, so the ring reads as a
|
|
125
|
+
ring and the travelling head has something to stand out against. */
|
|
126
|
+
.orb-lattice[data-variant="S3"] .orb-cell[data-still] {
|
|
127
|
+
animation: none;
|
|
128
|
+
opacity: var(--orb-dim);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.orb-lattice[data-variant="S5"] .orb-cell {
|
|
132
|
+
animation: orb-comet 1.7s var(--orb-ease-smooth) infinite both;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.orb-lattice[data-variant="S5"] .orb-cell[data-still] {
|
|
136
|
+
animation: none;
|
|
137
|
+
opacity: var(--orb-dim);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Swells and subsides on the same symmetric curve, so there is no flash and
|
|
141
|
+
no hard edge - the cell rises out of its resting ink and sinks back into
|
|
142
|
+
it. The long tail after 56% is the gap between beats. */
|
|
143
|
+
@keyframes orb-wave {
|
|
144
|
+
0% {
|
|
145
|
+
opacity: var(--orb-rest);
|
|
146
|
+
transform: scale(1);
|
|
147
|
+
animation-timing-function: cubic-bezier(0.66, 0, 0.34, 1);
|
|
148
|
+
}
|
|
149
|
+
28% {
|
|
150
|
+
opacity: 1;
|
|
151
|
+
transform: scale(1.18);
|
|
152
|
+
animation-timing-function: cubic-bezier(0.66, 0, 0.34, 1);
|
|
153
|
+
}
|
|
154
|
+
56% {
|
|
155
|
+
opacity: var(--orb-rest);
|
|
156
|
+
transform: scale(1);
|
|
157
|
+
}
|
|
158
|
+
100% {
|
|
159
|
+
opacity: var(--orb-rest);
|
|
160
|
+
transform: scale(1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Starts lit and decays, so staggered ring cells form a head and tail.
|
|
165
|
+
The decay spans ~3.5 of the 8 ring positions - enough to read as a comet. */
|
|
166
|
+
@keyframes orb-comet {
|
|
167
|
+
0% {
|
|
168
|
+
opacity: 1;
|
|
169
|
+
transform: scale(1.2);
|
|
170
|
+
/* Linear, so the cells behind the head form an even gradient instead
|
|
171
|
+
of collapsing to rest within the first two. */
|
|
172
|
+
animation-timing-function: linear;
|
|
173
|
+
}
|
|
174
|
+
45% {
|
|
175
|
+
opacity: var(--orb-rest);
|
|
176
|
+
transform: scale(1);
|
|
177
|
+
}
|
|
178
|
+
100% {
|
|
179
|
+
opacity: var(--orb-rest);
|
|
180
|
+
transform: scale(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* --- Lens: three circles at depth, blur reads as distance --------- */
|
|
185
|
+
|
|
186
|
+
.orb-lens {
|
|
187
|
+
position: absolute;
|
|
188
|
+
left: 0;
|
|
189
|
+
top: 0;
|
|
190
|
+
width: 28px;
|
|
191
|
+
height: 28px;
|
|
192
|
+
transform-origin: 0 0;
|
|
193
|
+
transform: scale(var(--orb-k, 1));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.orb-shape {
|
|
197
|
+
position: absolute;
|
|
198
|
+
left: 50%;
|
|
199
|
+
top: 50%;
|
|
200
|
+
width: var(--orb-d, 7px);
|
|
201
|
+
height: var(--orb-d, 7px);
|
|
202
|
+
/* Pulled back by its own half-size, so --orb-d is the only knob a variant
|
|
203
|
+
has to touch to resize the cast and it stays centred on the stage. */
|
|
204
|
+
margin: calc(var(--orb-d, 7px) / -2) 0 0 calc(var(--orb-d, 7px) / -2);
|
|
205
|
+
border-radius: 50%;
|
|
206
|
+
background: currentColor;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* focus - attention travels the cast: each circle pulls into focus in turn.
|
|
210
|
+
Four circles on the corners of a square, one size for all of them, so the
|
|
211
|
+
only thing separating them is which one is sharp.
|
|
212
|
+
|
|
213
|
+
A second longer than the three-circle version it grew out of: the square
|
|
214
|
+
has four stations to visit and each one keeps the same unhurried second.
|
|
215
|
+
|
|
216
|
+
The delays count down rather than up because a more negative delay seeds a
|
|
217
|
+
circle further into its cycle: -3s of a 4s cycle runs three quarters ahead,
|
|
218
|
+
which is what sends focus round the square clockwise. */
|
|
219
|
+
.orb-lens[data-variant="B1"] .orb-shape {
|
|
220
|
+
--orb-d: 6px;
|
|
221
|
+
animation: orb-focus 4s var(--orb-ease-smooth) infinite both;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.orb-lens[data-variant="B1"] .orb-shape-a {
|
|
225
|
+
--orb-ox: -4.5px;
|
|
226
|
+
--orb-oy: -4.5px;
|
|
227
|
+
animation-delay: 0s;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.orb-lens[data-variant="B1"] .orb-shape-b {
|
|
231
|
+
--orb-ox: 4.5px;
|
|
232
|
+
--orb-oy: -4.5px;
|
|
233
|
+
animation-delay: -3s;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.orb-lens[data-variant="B1"] .orb-shape-c {
|
|
237
|
+
--orb-ox: 4.5px;
|
|
238
|
+
--orb-oy: 4.5px;
|
|
239
|
+
animation-delay: -2s;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.orb-lens[data-variant="B1"] .orb-shape-d {
|
|
243
|
+
--orb-ox: -4.5px;
|
|
244
|
+
--orb-oy: 4.5px;
|
|
245
|
+
animation-delay: -1s;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Opacity gradient around the square: active = 1.0, next neighbour = 0.30,
|
|
249
|
+
diagonal = 0.10, far = 0.05. Two circles are always clearly visible, the
|
|
250
|
+
rest are ghost hints. */
|
|
251
|
+
@keyframes orb-focus {
|
|
252
|
+
0%,
|
|
253
|
+
100% {
|
|
254
|
+
opacity: 0.05;
|
|
255
|
+
filter: blur(2px);
|
|
256
|
+
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.12);
|
|
257
|
+
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
258
|
+
}
|
|
259
|
+
12% {
|
|
260
|
+
opacity: 1;
|
|
261
|
+
filter: blur(0);
|
|
262
|
+
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1);
|
|
263
|
+
animation-timing-function: linear;
|
|
264
|
+
}
|
|
265
|
+
22% {
|
|
266
|
+
opacity: 1;
|
|
267
|
+
filter: blur(0);
|
|
268
|
+
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1);
|
|
269
|
+
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
270
|
+
}
|
|
271
|
+
/* Next neighbour - one quarter away: clearly visible */
|
|
272
|
+
38% {
|
|
273
|
+
opacity: 0.3;
|
|
274
|
+
filter: blur(1.2px);
|
|
275
|
+
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.06);
|
|
276
|
+
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
277
|
+
}
|
|
278
|
+
/* Diagonal - half a cycle away: ghost */
|
|
279
|
+
58% {
|
|
280
|
+
opacity: 0.1;
|
|
281
|
+
filter: blur(1.8px);
|
|
282
|
+
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.1);
|
|
283
|
+
animation-timing-function: linear;
|
|
284
|
+
}
|
|
285
|
+
/* Far neighbour - three quarters away: barely there */
|
|
286
|
+
82% {
|
|
287
|
+
opacity: 0.05;
|
|
288
|
+
filter: blur(2px);
|
|
289
|
+
transform: translate(var(--orb-ox), var(--orb-oy)) scale(1.12);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/* drift - the cast circles the stage on one track, sharp at the front and
|
|
294
|
+
blurred away at the back, so the orb reads as looking around. Uniform
|
|
295
|
+
size: the depth cue is doing the work, a size ladder would fight it. */
|
|
296
|
+
.orb-lens[data-variant="B2"] .orb-shape {
|
|
297
|
+
animation: orb-revolve 3.3s linear infinite both;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* Evenly spaced around the track, so one is always at the front. */
|
|
301
|
+
.orb-lens[data-variant="B2"] .orb-shape-a {
|
|
302
|
+
animation-delay: 0s;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.orb-lens[data-variant="B2"] .orb-shape-b {
|
|
306
|
+
animation-delay: -1.1s;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.orb-lens[data-variant="B2"] .orb-shape-c {
|
|
310
|
+
animation-delay: -2.2s;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* rotate() then translateY() walks a circle. Linear all the way: an eased
|
|
314
|
+
rotation on a circular path reads as a wobble, not as travel. */
|
|
315
|
+
@keyframes orb-revolve {
|
|
316
|
+
0% {
|
|
317
|
+
opacity: 1;
|
|
318
|
+
filter: blur(0);
|
|
319
|
+
transform: rotate(0deg) translateY(6.5px) scale(1);
|
|
320
|
+
}
|
|
321
|
+
25% {
|
|
322
|
+
opacity: 0.55;
|
|
323
|
+
filter: blur(1.3px);
|
|
324
|
+
transform: rotate(90deg) translateY(6.5px) scale(0.82);
|
|
325
|
+
}
|
|
326
|
+
50% {
|
|
327
|
+
opacity: 0.28;
|
|
328
|
+
filter: blur(2.4px);
|
|
329
|
+
transform: rotate(180deg) translateY(6.5px) scale(0.66);
|
|
330
|
+
}
|
|
331
|
+
75% {
|
|
332
|
+
opacity: 0.55;
|
|
333
|
+
filter: blur(1.3px);
|
|
334
|
+
transform: rotate(270deg) translateY(6.5px) scale(0.82);
|
|
335
|
+
}
|
|
336
|
+
100% {
|
|
337
|
+
opacity: 1;
|
|
338
|
+
filter: blur(0);
|
|
339
|
+
transform: rotate(360deg) translateY(6.5px) scale(1);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/* bloom - shapes emanate from the centre, blurring out as they grow.
|
|
344
|
+
Linear keeps the total ink even; on a front-loaded curve the shapes
|
|
345
|
+
jump to their large, blurred end state and the orb alternates between
|
|
346
|
+
a heavy blot and an empty haze. */
|
|
347
|
+
.orb-lens[data-variant="B3"] .orb-shape {
|
|
348
|
+
animation: orb-bloom 4.2s linear infinite both;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.orb-lens[data-variant="B3"] .orb-shape-a {
|
|
352
|
+
animation-delay: 0s;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.orb-lens[data-variant="B3"] .orb-shape-b {
|
|
356
|
+
animation-delay: -1.4s;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.orb-lens[data-variant="B3"] .orb-shape-c {
|
|
360
|
+
animation-delay: -2.8s;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Each ripple dies at 62% and waits out the rest, so the three overlapping
|
|
364
|
+
blooms leave gaps. Without the gap the aggregate is a constant haze and
|
|
365
|
+
the outward motion stops reading at all. Sharp circle appears, holds
|
|
366
|
+
briefly, then dissolves outward - blur only kicks in once opacity starts
|
|
367
|
+
dropping, so the circle stays crisp while it's visible and the blur reads
|
|
368
|
+
as the ripple dissipating. */
|
|
369
|
+
@keyframes orb-bloom {
|
|
370
|
+
0% {
|
|
371
|
+
opacity: 0;
|
|
372
|
+
filter: blur(0);
|
|
373
|
+
transform: scale(0.35);
|
|
374
|
+
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
375
|
+
}
|
|
376
|
+
8% {
|
|
377
|
+
opacity: 1;
|
|
378
|
+
filter: blur(0);
|
|
379
|
+
transform: scale(0.55);
|
|
380
|
+
animation-timing-function: linear;
|
|
381
|
+
}
|
|
382
|
+
24% {
|
|
383
|
+
opacity: 1;
|
|
384
|
+
filter: blur(0);
|
|
385
|
+
transform: scale(0.72);
|
|
386
|
+
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
387
|
+
}
|
|
388
|
+
42% {
|
|
389
|
+
opacity: 0.1;
|
|
390
|
+
filter: blur(1.8px);
|
|
391
|
+
transform: scale(1.5);
|
|
392
|
+
}
|
|
393
|
+
62% {
|
|
394
|
+
opacity: 0;
|
|
395
|
+
filter: blur(2.8px);
|
|
396
|
+
transform: scale(2.4);
|
|
397
|
+
}
|
|
398
|
+
100% {
|
|
399
|
+
opacity: 0;
|
|
400
|
+
filter: blur(2.8px);
|
|
401
|
+
transform: scale(2.4);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/* converge - a single circle traces an equilateral triangle (top → bottom-right
|
|
406
|
+
→ bottom-left → top) with handoff-style easing: full size and sharp at each
|
|
407
|
+
vertex, smaller and slightly blurred in transit. orbB breathes at the
|
|
408
|
+
centroid as a subtle depth cue; orbC is hidden. */
|
|
409
|
+
.orb-lens[data-variant="B4"] .orb-shape-a {
|
|
410
|
+
animation: orb-converge 3.6s linear infinite both;
|
|
411
|
+
}
|
|
412
|
+
.orb-lens[data-variant="B4"] .orb-shape-b {
|
|
413
|
+
animation: orb-breathe 3.6s ease-in-out infinite both;
|
|
414
|
+
}
|
|
415
|
+
.orb-lens[data-variant="B4"] .orb-shape-c {
|
|
416
|
+
display: none;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
@keyframes orb-converge {
|
|
420
|
+
0% {
|
|
421
|
+
transform: translate(0px, -5px) scale(1);
|
|
422
|
+
filter: blur(0);
|
|
423
|
+
animation-timing-function: linear;
|
|
424
|
+
}
|
|
425
|
+
10% {
|
|
426
|
+
transform: translate(0px, -5px) scale(1);
|
|
427
|
+
filter: blur(0);
|
|
428
|
+
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
429
|
+
}
|
|
430
|
+
22% {
|
|
431
|
+
transform: translate(2.15px, -1.25px) scale(0.72);
|
|
432
|
+
filter: blur(0.8px);
|
|
433
|
+
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
434
|
+
}
|
|
435
|
+
33% {
|
|
436
|
+
transform: translate(4.3px, 2.5px) scale(1);
|
|
437
|
+
filter: blur(0);
|
|
438
|
+
animation-timing-function: linear;
|
|
439
|
+
}
|
|
440
|
+
43% {
|
|
441
|
+
transform: translate(4.3px, 2.5px) scale(1);
|
|
442
|
+
filter: blur(0);
|
|
443
|
+
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
444
|
+
}
|
|
445
|
+
55% {
|
|
446
|
+
transform: translate(0px, 2.5px) scale(0.72);
|
|
447
|
+
filter: blur(0.8px);
|
|
448
|
+
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
449
|
+
}
|
|
450
|
+
66% {
|
|
451
|
+
transform: translate(-4.3px, 2.5px) scale(1);
|
|
452
|
+
filter: blur(0);
|
|
453
|
+
animation-timing-function: linear;
|
|
454
|
+
}
|
|
455
|
+
77% {
|
|
456
|
+
transform: translate(-4.3px, 2.5px) scale(1);
|
|
457
|
+
filter: blur(0);
|
|
458
|
+
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
459
|
+
}
|
|
460
|
+
88% {
|
|
461
|
+
transform: translate(-2.15px, -1.25px) scale(0.72);
|
|
462
|
+
filter: blur(0.8px);
|
|
463
|
+
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
464
|
+
}
|
|
465
|
+
100% {
|
|
466
|
+
transform: translate(0px, -5px) scale(1);
|
|
467
|
+
filter: blur(0);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* handoff - the cast crosses the focal plane one after another, always left
|
|
472
|
+
to right, like work being passed on. The shorthand curve is only a
|
|
473
|
+
fallback; every segment below sets its own. */
|
|
474
|
+
.orb-lens[data-variant="B5"] .orb-shape {
|
|
475
|
+
animation: orb-handoff 2.8s linear infinite both;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/* Half a cycle apart, so one is always at the focal plane while the other is
|
|
479
|
+
invisible at an end and the loop point cannot be seen. */
|
|
480
|
+
.orb-lens[data-variant="B5"] .orb-shape-a {
|
|
481
|
+
animation-delay: 0s;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.orb-lens[data-variant="B5"] .orb-shape-c {
|
|
485
|
+
animation-delay: -1.4s;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* The third holds the centre and breathes - a soft depth cue behind the
|
|
489
|
+
traffic rather than another traveller. */
|
|
490
|
+
.orb-lens[data-variant="B5"] .orb-shape-b {
|
|
491
|
+
animation-name: orb-breathe;
|
|
492
|
+
animation-duration: 3.6s;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* Enters small from the left, reaches standard size at the focal plane, then
|
|
496
|
+
shrinks and fades out to the right. At the dwell (centre) the circle is
|
|
497
|
+
exactly 1× - no pulsing, no bounce, just a clean handoff. */
|
|
498
|
+
@keyframes orb-handoff {
|
|
499
|
+
0% {
|
|
500
|
+
opacity: 0;
|
|
501
|
+
filter: blur(2.4px);
|
|
502
|
+
transform: translateX(-11px) scale(0.55);
|
|
503
|
+
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
504
|
+
}
|
|
505
|
+
22% {
|
|
506
|
+
opacity: 1;
|
|
507
|
+
filter: blur(0);
|
|
508
|
+
transform: translateX(-1px) scale(1);
|
|
509
|
+
animation-timing-function: linear;
|
|
510
|
+
}
|
|
511
|
+
37% {
|
|
512
|
+
opacity: 1;
|
|
513
|
+
filter: blur(0);
|
|
514
|
+
transform: translateX(0) scale(1);
|
|
515
|
+
animation-timing-function: linear;
|
|
516
|
+
}
|
|
517
|
+
52% {
|
|
518
|
+
opacity: 1;
|
|
519
|
+
filter: blur(0);
|
|
520
|
+
transform: translateX(1px) scale(1);
|
|
521
|
+
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
522
|
+
}
|
|
523
|
+
70% {
|
|
524
|
+
opacity: 0;
|
|
525
|
+
filter: blur(2.4px);
|
|
526
|
+
transform: translateX(11px) scale(0.55);
|
|
527
|
+
}
|
|
528
|
+
100% {
|
|
529
|
+
opacity: 0;
|
|
530
|
+
filter: blur(2.4px);
|
|
531
|
+
transform: translateX(11px) scale(0.55);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
@keyframes orb-breathe {
|
|
536
|
+
0%,
|
|
537
|
+
100% {
|
|
538
|
+
opacity: 0.16;
|
|
539
|
+
filter: blur(2.4px);
|
|
540
|
+
transform: scale(1.2);
|
|
541
|
+
}
|
|
542
|
+
50% {
|
|
543
|
+
opacity: 0.32;
|
|
544
|
+
filter: blur(1.6px);
|
|
545
|
+
transform: scale(0.98);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/* --- Ring: eight circles on a fixed ring ----------------------------- */
|
|
550
|
+
|
|
551
|
+
.orb-ring {
|
|
552
|
+
position: absolute;
|
|
553
|
+
inset: 0;
|
|
554
|
+
transform: scale(var(--orb-k, 1));
|
|
555
|
+
--orb-ring-rest: var(--orb-ring-rest-ink, 0.22);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.orb-ring-dot {
|
|
559
|
+
position: absolute;
|
|
560
|
+
left: 50%;
|
|
561
|
+
top: 50%;
|
|
562
|
+
width: 3px;
|
|
563
|
+
height: 3px;
|
|
564
|
+
margin: -1.5px 0 0 -1.5px;
|
|
565
|
+
border-radius: 50%;
|
|
566
|
+
background: currentColor;
|
|
567
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.orb-ring[data-variant="C1"] .orb-ring-dot {
|
|
571
|
+
opacity: var(--orb-ring-rest);
|
|
572
|
+
animation: orb-ring-chase 1.6s linear infinite both;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
@keyframes orb-ring-chase {
|
|
576
|
+
0%,
|
|
577
|
+
11% {
|
|
578
|
+
opacity: 1;
|
|
579
|
+
}
|
|
580
|
+
12.5%,
|
|
581
|
+
100% {
|
|
582
|
+
opacity: var(--orb-ring-rest);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.orb-ring[data-variant="C2"] .orb-ring-dot {
|
|
587
|
+
animation: orb-ring-pulse 2s ease-in-out infinite both;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
@keyframes orb-ring-pulse {
|
|
591
|
+
0%,
|
|
592
|
+
100% {
|
|
593
|
+
opacity: 0.18;
|
|
594
|
+
transform: translate(var(--orb-rx), var(--orb-ry)) scale(0.7);
|
|
595
|
+
}
|
|
596
|
+
50% {
|
|
597
|
+
opacity: 1;
|
|
598
|
+
transform: translate(var(--orb-rx), var(--orb-ry)) scale(1.15);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.orb-ring[data-variant="C3"] .orb-ring-dot {
|
|
603
|
+
animation: orb-ring-comet 1.8s ease-in-out infinite both;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
@keyframes orb-ring-comet {
|
|
607
|
+
0%,
|
|
608
|
+
100% {
|
|
609
|
+
opacity: 0.08;
|
|
610
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
611
|
+
}
|
|
612
|
+
12% {
|
|
613
|
+
opacity: 1;
|
|
614
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
615
|
+
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
|
|
616
|
+
}
|
|
617
|
+
35% {
|
|
618
|
+
opacity: 0.5;
|
|
619
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
620
|
+
}
|
|
621
|
+
60% {
|
|
622
|
+
opacity: 0.12;
|
|
623
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.orb-ring[data-variant="C4"] .orb-ring-dot {
|
|
628
|
+
animation: orb-ring-stagger 1.6s ease-in-out infinite both;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
@keyframes orb-ring-stagger {
|
|
632
|
+
0%,
|
|
633
|
+
100% {
|
|
634
|
+
opacity: 1;
|
|
635
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
636
|
+
}
|
|
637
|
+
50% {
|
|
638
|
+
opacity: 0.15;
|
|
639
|
+
transform: translate(var(--orb-rx), var(--orb-ry));
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.orb-ring[data-variant="C5"] .orb-ring-dot {
|
|
644
|
+
animation: orb-ring-comet 1.8s ease-in-out infinite both;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/* ---- Globe (Helix family) ---- */
|
|
648
|
+
.orb-helix {
|
|
649
|
+
position: absolute;
|
|
650
|
+
inset: 0;
|
|
651
|
+
transform: scale(var(--orb-k, 1));
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.orb-helix-dot {
|
|
655
|
+
position: absolute;
|
|
656
|
+
left: 50%;
|
|
657
|
+
top: 50%;
|
|
658
|
+
width: 2px;
|
|
659
|
+
height: 2px;
|
|
660
|
+
margin: -1px 0 0 -1px;
|
|
661
|
+
border-radius: 50%;
|
|
662
|
+
background: currentColor;
|
|
663
|
+
will-change: transform, opacity;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.orb-helix[data-variant="G1"] .orb-helix-dot {
|
|
667
|
+
animation: orb-globe-spin 4.5s linear infinite both;
|
|
668
|
+
}
|
|
669
|
+
.orb-helix[data-variant="G2"] .orb-helix-dot {
|
|
670
|
+
animation: orb-globe-spin 3.6s linear infinite both;
|
|
671
|
+
}
|
|
672
|
+
.orb-helix[data-variant="G3"] .orb-helix-dot {
|
|
673
|
+
animation: orb-globe-ringturn 2.8s linear infinite both;
|
|
674
|
+
}
|
|
675
|
+
.orb-helix[data-variant="G4"] .orb-helix-dot {
|
|
676
|
+
animation: orb-globe-ringturn 2.8s linear infinite both;
|
|
677
|
+
}
|
|
678
|
+
.orb-helix[data-variant="G5"] .orb-helix-dot {
|
|
679
|
+
animation: orb-globe-breathe 3.6s linear infinite both;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
@keyframes orb-globe-spin {
|
|
683
|
+
0%,
|
|
684
|
+
100% {
|
|
685
|
+
transform: translate(var(--g0x), var(--g0y));
|
|
686
|
+
opacity: var(--g0o);
|
|
687
|
+
}
|
|
688
|
+
12.5% {
|
|
689
|
+
transform: translate(var(--g1x), var(--g1y));
|
|
690
|
+
opacity: var(--g1o);
|
|
691
|
+
}
|
|
692
|
+
25% {
|
|
693
|
+
transform: translate(var(--g2x), var(--g2y));
|
|
694
|
+
opacity: var(--g2o);
|
|
695
|
+
}
|
|
696
|
+
37.5% {
|
|
697
|
+
transform: translate(var(--g3x), var(--g3y));
|
|
698
|
+
opacity: var(--g3o);
|
|
699
|
+
}
|
|
700
|
+
50% {
|
|
701
|
+
transform: translate(var(--g4x), var(--g4y));
|
|
702
|
+
opacity: var(--g4o);
|
|
703
|
+
}
|
|
704
|
+
62.5% {
|
|
705
|
+
transform: translate(var(--g5x), var(--g5y));
|
|
706
|
+
opacity: var(--g5o);
|
|
707
|
+
}
|
|
708
|
+
75% {
|
|
709
|
+
transform: translate(var(--g6x), var(--g6y));
|
|
710
|
+
opacity: var(--g6o);
|
|
711
|
+
}
|
|
712
|
+
87.5% {
|
|
713
|
+
transform: translate(var(--g7x), var(--g7y));
|
|
714
|
+
opacity: var(--g7o);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
@keyframes orb-globe-ringturn {
|
|
719
|
+
0% {
|
|
720
|
+
transform: translate(var(--g0x), var(--g0y));
|
|
721
|
+
opacity: var(--g0o);
|
|
722
|
+
}
|
|
723
|
+
2.5% {
|
|
724
|
+
transform: translate(var(--g1x), var(--g1y));
|
|
725
|
+
opacity: var(--g1o);
|
|
726
|
+
}
|
|
727
|
+
5% {
|
|
728
|
+
transform: translate(var(--g2x), var(--g2y));
|
|
729
|
+
opacity: var(--g2o);
|
|
730
|
+
}
|
|
731
|
+
7.5%,
|
|
732
|
+
10% {
|
|
733
|
+
transform: translate(var(--g3x), var(--g3y));
|
|
734
|
+
opacity: var(--g3o);
|
|
735
|
+
}
|
|
736
|
+
12.5% {
|
|
737
|
+
transform: translate(var(--g4x), var(--g4y));
|
|
738
|
+
opacity: var(--g4o);
|
|
739
|
+
}
|
|
740
|
+
15% {
|
|
741
|
+
transform: translate(var(--g5x), var(--g5y));
|
|
742
|
+
opacity: var(--g5o);
|
|
743
|
+
}
|
|
744
|
+
17.5%,
|
|
745
|
+
20% {
|
|
746
|
+
transform: translate(var(--g6x), var(--g6y));
|
|
747
|
+
opacity: var(--g6o);
|
|
748
|
+
}
|
|
749
|
+
22.5% {
|
|
750
|
+
transform: translate(var(--g7x), var(--g7y));
|
|
751
|
+
opacity: var(--g7o);
|
|
752
|
+
}
|
|
753
|
+
25% {
|
|
754
|
+
transform: translate(var(--g8x), var(--g8y));
|
|
755
|
+
opacity: var(--g8o);
|
|
756
|
+
}
|
|
757
|
+
27.5%,
|
|
758
|
+
30% {
|
|
759
|
+
transform: translate(var(--g9x), var(--g9y));
|
|
760
|
+
opacity: var(--g9o);
|
|
761
|
+
}
|
|
762
|
+
32.5% {
|
|
763
|
+
transform: translate(var(--g10x), var(--g10y));
|
|
764
|
+
opacity: var(--g10o);
|
|
765
|
+
}
|
|
766
|
+
35% {
|
|
767
|
+
transform: translate(var(--g11x), var(--g11y));
|
|
768
|
+
opacity: var(--g11o);
|
|
769
|
+
}
|
|
770
|
+
37.5%,
|
|
771
|
+
40% {
|
|
772
|
+
transform: translate(var(--g12x), var(--g12y));
|
|
773
|
+
opacity: var(--g12o);
|
|
774
|
+
}
|
|
775
|
+
42.5% {
|
|
776
|
+
transform: translate(var(--g13x), var(--g13y));
|
|
777
|
+
opacity: var(--g13o);
|
|
778
|
+
}
|
|
779
|
+
45% {
|
|
780
|
+
transform: translate(var(--g14x), var(--g14y));
|
|
781
|
+
opacity: var(--g14o);
|
|
782
|
+
}
|
|
783
|
+
47.5%,
|
|
784
|
+
50% {
|
|
785
|
+
transform: translate(var(--g15x), var(--g15y));
|
|
786
|
+
opacity: var(--g15o);
|
|
787
|
+
}
|
|
788
|
+
52.5% {
|
|
789
|
+
transform: translate(var(--g16x), var(--g16y));
|
|
790
|
+
opacity: var(--g16o);
|
|
791
|
+
}
|
|
792
|
+
55% {
|
|
793
|
+
transform: translate(var(--g17x), var(--g17y));
|
|
794
|
+
opacity: var(--g17o);
|
|
795
|
+
}
|
|
796
|
+
57.5%,
|
|
797
|
+
60% {
|
|
798
|
+
transform: translate(var(--g18x), var(--g18y));
|
|
799
|
+
opacity: var(--g18o);
|
|
800
|
+
}
|
|
801
|
+
62.5% {
|
|
802
|
+
transform: translate(var(--g19x), var(--g19y));
|
|
803
|
+
opacity: var(--g19o);
|
|
804
|
+
}
|
|
805
|
+
65% {
|
|
806
|
+
transform: translate(var(--g20x), var(--g20y));
|
|
807
|
+
opacity: var(--g20o);
|
|
808
|
+
}
|
|
809
|
+
67.5%,
|
|
810
|
+
70% {
|
|
811
|
+
transform: translate(var(--g21x), var(--g21y));
|
|
812
|
+
opacity: var(--g21o);
|
|
813
|
+
}
|
|
814
|
+
72.5% {
|
|
815
|
+
transform: translate(var(--g22x), var(--g22y));
|
|
816
|
+
opacity: var(--g22o);
|
|
817
|
+
}
|
|
818
|
+
75% {
|
|
819
|
+
transform: translate(var(--g23x), var(--g23y));
|
|
820
|
+
opacity: var(--g23o);
|
|
821
|
+
}
|
|
822
|
+
77.5%,
|
|
823
|
+
80% {
|
|
824
|
+
transform: translate(var(--g24x), var(--g24y));
|
|
825
|
+
opacity: var(--g24o);
|
|
826
|
+
}
|
|
827
|
+
82.5% {
|
|
828
|
+
transform: translate(var(--g25x), var(--g25y));
|
|
829
|
+
opacity: var(--g25o);
|
|
830
|
+
}
|
|
831
|
+
85% {
|
|
832
|
+
transform: translate(var(--g26x), var(--g26y));
|
|
833
|
+
opacity: var(--g26o);
|
|
834
|
+
}
|
|
835
|
+
87.5%,
|
|
836
|
+
90% {
|
|
837
|
+
transform: translate(var(--g27x), var(--g27y));
|
|
838
|
+
opacity: var(--g27o);
|
|
839
|
+
}
|
|
840
|
+
92.5% {
|
|
841
|
+
transform: translate(var(--g28x), var(--g28y));
|
|
842
|
+
opacity: var(--g28o);
|
|
843
|
+
}
|
|
844
|
+
95% {
|
|
845
|
+
transform: translate(var(--g29x), var(--g29y));
|
|
846
|
+
opacity: var(--g29o);
|
|
847
|
+
}
|
|
848
|
+
97.5%,
|
|
849
|
+
100% {
|
|
850
|
+
transform: translate(var(--g30x), var(--g30y));
|
|
851
|
+
opacity: var(--g30o);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
@keyframes orb-globe-breathe {
|
|
856
|
+
0% {
|
|
857
|
+
transform: translate(var(--g0x), var(--g0y));
|
|
858
|
+
opacity: var(--g0o);
|
|
859
|
+
}
|
|
860
|
+
19% {
|
|
861
|
+
transform: translate(var(--g1x), var(--g1y));
|
|
862
|
+
opacity: var(--g1o);
|
|
863
|
+
}
|
|
864
|
+
25% {
|
|
865
|
+
transform: translate(var(--g2x), var(--g2y));
|
|
866
|
+
opacity: var(--g2o);
|
|
867
|
+
}
|
|
868
|
+
44% {
|
|
869
|
+
transform: translate(var(--g3x), var(--g3y));
|
|
870
|
+
opacity: var(--g3o);
|
|
871
|
+
}
|
|
872
|
+
50% {
|
|
873
|
+
transform: translate(var(--g4x), var(--g4y));
|
|
874
|
+
opacity: var(--g4o);
|
|
875
|
+
}
|
|
876
|
+
69% {
|
|
877
|
+
transform: translate(var(--g5x), var(--g5y));
|
|
878
|
+
opacity: var(--g5o);
|
|
879
|
+
}
|
|
880
|
+
75% {
|
|
881
|
+
transform: translate(var(--g6x), var(--g6y));
|
|
882
|
+
opacity: var(--g6o);
|
|
883
|
+
}
|
|
884
|
+
94% {
|
|
885
|
+
transform: translate(var(--g7x), var(--g7y));
|
|
886
|
+
opacity: var(--g7o);
|
|
887
|
+
}
|
|
888
|
+
100% {
|
|
889
|
+
transform: translate(var(--g8x), var(--g8y));
|
|
890
|
+
opacity: var(--g8o);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/* ---- Morph ---- */
|
|
895
|
+
.orb-morph {
|
|
896
|
+
position: absolute;
|
|
897
|
+
inset: 0;
|
|
898
|
+
transform: scale(var(--orb-k, 1));
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.orb-morph-dot {
|
|
902
|
+
position: absolute;
|
|
903
|
+
left: 50%;
|
|
904
|
+
top: 50%;
|
|
905
|
+
width: 3px;
|
|
906
|
+
height: 3px;
|
|
907
|
+
margin: -1.5px 0 0 -1.5px;
|
|
908
|
+
border-radius: 50%;
|
|
909
|
+
background: currentColor;
|
|
910
|
+
animation: orb-morph 4.8s cubic-bezier(0.4, 0, 0.2, 1) infinite both;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
@keyframes orb-morph {
|
|
914
|
+
0%,
|
|
915
|
+
5% {
|
|
916
|
+
transform: translate(var(--m-1));
|
|
917
|
+
}
|
|
918
|
+
25%,
|
|
919
|
+
30% {
|
|
920
|
+
transform: translate(var(--m-2));
|
|
921
|
+
}
|
|
922
|
+
50%,
|
|
923
|
+
55% {
|
|
924
|
+
transform: translate(var(--m-3));
|
|
925
|
+
}
|
|
926
|
+
75%,
|
|
927
|
+
80% {
|
|
928
|
+
transform: translate(var(--m-4));
|
|
929
|
+
}
|
|
930
|
+
100% {
|
|
931
|
+
transform: translate(var(--m-1));
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
.orb-morph[data-variant="M2"] {
|
|
936
|
+
animation: orb-morph-twist 9.6s linear infinite;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.orb-morph[data-variant="M4"] {
|
|
940
|
+
animation: orb-morph-twist 9.6s linear infinite;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
.orb-morph[data-variant="M5"] .orb-morph-dot {
|
|
944
|
+
animation: orb-morph-scatter 2.8s cubic-bezier(0.4, 0, 0.2, 1) infinite both;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
@keyframes orb-morph-scatter {
|
|
948
|
+
0%,
|
|
949
|
+
12% {
|
|
950
|
+
transform: translate(var(--m-1));
|
|
951
|
+
opacity: 1;
|
|
952
|
+
}
|
|
953
|
+
38%,
|
|
954
|
+
62% {
|
|
955
|
+
transform: translate(var(--m-2));
|
|
956
|
+
opacity: calc(1 - 0.6 * var(--m-depth, 0));
|
|
957
|
+
}
|
|
958
|
+
88%,
|
|
959
|
+
100% {
|
|
960
|
+
transform: translate(var(--m-1));
|
|
961
|
+
opacity: 1;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
@keyframes orb-morph-twist {
|
|
966
|
+
from {
|
|
967
|
+
transform: scale(var(--orb-k, 1)) rotate(0deg);
|
|
968
|
+
}
|
|
969
|
+
to {
|
|
970
|
+
transform: scale(var(--orb-k, 1)) rotate(360deg);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
@media (prefers-reduced-motion: reduce) {
|
|
975
|
+
.orb-cell,
|
|
976
|
+
.orb-shape,
|
|
977
|
+
.orb-ring-dot,
|
|
978
|
+
.orb-helix-dot,
|
|
979
|
+
.orb-morph-dot {
|
|
980
|
+
animation: none !important;
|
|
981
|
+
}
|
|
982
|
+
.orb-cell[data-mid] {
|
|
983
|
+
opacity: 1 !important;
|
|
984
|
+
}
|
|
985
|
+
.orb-shape {
|
|
986
|
+
opacity: 0.3 !important;
|
|
987
|
+
filter: blur(1.4px) !important;
|
|
988
|
+
transform: none !important;
|
|
989
|
+
}
|
|
990
|
+
.orb-shape-a {
|
|
991
|
+
opacity: 1 !important;
|
|
992
|
+
filter: blur(0) !important;
|
|
993
|
+
}
|
|
994
|
+
.orb-ring-dot {
|
|
995
|
+
opacity: 0.7 !important;
|
|
996
|
+
}
|
|
997
|
+
.orb-ring,
|
|
998
|
+
.orb-helix,
|
|
999
|
+
.orb-morph {
|
|
1000
|
+
animation: none !important;
|
|
1001
|
+
}
|
|
1002
|
+
}
|