hadadrjt commited on
Commit
ce1ab17
·
1 Parent(s): 7e6a554

ai: Release demo playground source code.

Browse files
assets/css/animation/style.css ADDED
@@ -0,0 +1,1628 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .loading {
7
+ display: inline-block;
8
+ width: 1.1rem;
9
+ height: 1.1rem;
10
+ border: 2px solid #999;
11
+ border-top-color: transparent;
12
+ border-radius: 50%;
13
+ animation: spin 1s linear infinite;
14
+ }
15
+
16
+ @keyframes spin {
17
+ to {
18
+ transform: rotate(360deg);
19
+ }
20
+ }
21
+
22
+ @keyframes fadeIn {
23
+ to {
24
+ opacity: 1;
25
+ }
26
+ }
27
+
28
+ @keyframes fadeInDown {
29
+ from {
30
+ opacity: 0;
31
+ transform: translateY(-20px);
32
+ }
33
+ to {
34
+ opacity: 1;
35
+ transform: translateY(0);
36
+ }
37
+ }
38
+
39
+ @keyframes slideInUp {
40
+ from {
41
+ opacity: 0;
42
+ transform: translateY(20px);
43
+ }
44
+ to {
45
+ opacity: 1;
46
+ transform: translateY(0);
47
+ }
48
+ }
49
+
50
+ .pulse-animation {
51
+ animation: pulse 2s infinite;
52
+ }
53
+
54
+ @keyframes pulse {
55
+ 0% {
56
+ box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
57
+ }
58
+ 70% {
59
+ box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
60
+ }
61
+ 100% {
62
+ box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
63
+ }
64
+ }
65
+
66
+ .floating-animation {
67
+ animation: floating 3s ease-in-out infinite;
68
+ }
69
+
70
+ @keyframes floating {
71
+ 0% {
72
+ transform: translateY(0px);
73
+ }
74
+ 50% {
75
+ transform: translateY(-10px);
76
+ }
77
+ 100% {
78
+ transform: translateY(0px);
79
+ }
80
+ }
81
+
82
+ .gradient-text {
83
+ background: linear-gradient(90deg, #3b82f6, #8b5cf6, #ec4899);
84
+ -webkit-background-clip: text;
85
+ -webkit-text-fill-color: transparent;
86
+ background-clip: text;
87
+ }
88
+
89
+ .typing-animation::after {
90
+ content: "|";
91
+ animation: blink 1s infinite;
92
+ margin-left: 2px;
93
+ }
94
+
95
+ @keyframes blink {
96
+ 0%, 100% { opacity: 1; }
97
+ 50% { opacity: 0; }
98
+ }
99
+
100
+ .shine-effect {
101
+ position: relative;
102
+ overflow: hidden;
103
+ }
104
+
105
+ .shine-effect::before {
106
+ content: "";
107
+ position: absolute;
108
+ top: 0;
109
+ left: -100%;
110
+ width: 100%;
111
+ height: 100%;
112
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
113
+ transition: 0.5s;
114
+ }
115
+
116
+ .shine-effect:hover::before {
117
+ left: 100%;
118
+ }
119
+
120
+ .bounce-in {
121
+ animation: bounceIn 0.6s ease-out;
122
+ }
123
+
124
+ @keyframes bounceIn {
125
+ 0% {
126
+ transform: scale(0.8);
127
+ opacity: 0;
128
+ }
129
+ 50% {
130
+ transform: scale(1.05);
131
+ }
132
+ 100% {
133
+ transform: scale(1);
134
+ opacity: 1;
135
+ }
136
+ }
137
+
138
+ .slide-in-left {
139
+ animation: slideInLeft 0.5s ease-out;
140
+ }
141
+
142
+ @keyframes slideInLeft {
143
+ from {
144
+ transform: translateX(-100%);
145
+ opacity: 0;
146
+ }
147
+ to {
148
+ transform: translateX(0);
149
+ opacity: 1;
150
+ }
151
+ }
152
+
153
+ .slide-in-right {
154
+ animation: slideInRight 0.5s ease-out;
155
+ }
156
+
157
+ @keyframes slideInRight {
158
+ from {
159
+ transform: translateX(100%);
160
+ opacity: 0;
161
+ }
162
+ to {
163
+ transform: translateX(0);
164
+ opacity: 1;
165
+ }
166
+ }
167
+
168
+ .zoom-in {
169
+ animation: zoomIn 0.4s ease-out;
170
+ }
171
+
172
+ @keyframes zoomIn {
173
+ from {
174
+ transform: scale(0.8);
175
+ opacity: 0;
176
+ }
177
+ to {
178
+ transform: scale(1);
179
+ opacity: 1;
180
+ }
181
+ }
182
+
183
+ .flip-in {
184
+ animation: flipIn 0.6s ease-out;
185
+ }
186
+
187
+ @keyframes flipIn {
188
+ from {
189
+ transform: rotateY(90deg);
190
+ opacity: 0;
191
+ }
192
+ to {
193
+ transform: rotateY(0deg);
194
+ opacity: 1;
195
+ }
196
+ }
197
+
198
+ .fade-in-up {
199
+ animation: fadeInUp 0.5s ease-out;
200
+ }
201
+
202
+ @keyframes fadeInUp {
203
+ from {
204
+ transform: translateY(20px);
205
+ opacity: 0;
206
+ }
207
+ to {
208
+ transform: translateY(0);
209
+ opacity: 1;
210
+ }
211
+ }
212
+
213
+ .fade-in-down {
214
+ animation: fadeInDown 0.5s ease-out;
215
+ }
216
+
217
+ @keyframes fadeInDown {
218
+ from {
219
+ transform: translateY(-20px);
220
+ opacity: 0;
221
+ }
222
+ to {
223
+ transform: translateY(0);
224
+ opacity: 1;
225
+ }
226
+ }
227
+
228
+ .rotate-in {
229
+ animation: rotateIn 0.6s ease-out;
230
+ }
231
+
232
+ @keyframes rotateIn {
233
+ from {
234
+ transform: rotate(15deg);
235
+ opacity: 0;
236
+ }
237
+ to {
238
+ transform: rotate(0deg);
239
+ opacity: 1;
240
+ }
241
+ }
242
+
243
+ .scale-pulse {
244
+ animation: scalePulse 1.5s infinite;
245
+ }
246
+
247
+ @keyframes scalePulse {
248
+ 0%, 100% {
249
+ transform: scale(1);
250
+ }
251
+ 50% {
252
+ transform: scale(1.05);
253
+ }
254
+ }
255
+
256
+ .wave-animation {
257
+ animation: wave 2s infinite linear;
258
+ }
259
+
260
+ @keyframes wave {
261
+ 0% {
262
+ background-position: 0 0;
263
+ }
264
+ 100% {
265
+ background-position: 100% 0;
266
+ }
267
+ }
268
+
269
+ .glow-effect {
270
+ box-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
271
+ transition: box-shadow 0.3s ease;
272
+ }
273
+
274
+ .glow-effect:hover {
275
+ box-shadow: 0 0 20px rgba(59, 130, 246, 0.8);
276
+ }
277
+
278
+ .neon-glow {
279
+ text-shadow: 0 0 5px #3b82f6, 0 0 10px #3b82f6, 0 0 15px #3b82f6, 0 0 20px #3b82f6;
280
+ animation: neonPulse 2s infinite alternate;
281
+ }
282
+
283
+ @keyframes neonPulse {
284
+ from {
285
+ text-shadow: 0 0 5px #3b82f6, 0 0 10px #3b82f6, 0 0 15px #3b82f6, 0 0 20px #3b82f6;
286
+ }
287
+ to {
288
+ text-shadow: 0 0 10px #3b82f6, 0 0 20px #3b82f6, 0 0 30px #3b82f6, 0 0 40px #3b82f6;
289
+ }
290
+ }
291
+
292
+ .rainbow-text {
293
+ background: linear-gradient(90deg, #ff0000, #ff8000, #ffff00, #80ff00, #00ff00, #00ff80, #00ffff, #0080ff, #0000ff, #8000ff, #ff00ff, #ff0080);
294
+ background-size: 200% 200%;
295
+ -webkit-background-clip: text;
296
+ -webkit-text-fill-color: transparent;
297
+ background-clip: text;
298
+ animation: rainbow 3s linear infinite;
299
+ }
300
+
301
+ @keyframes rainbow {
302
+ 0% {
303
+ background-position: 0% 50%;
304
+ }
305
+ 100% {
306
+ background-position: 200% 50%;
307
+ }
308
+ }
309
+
310
+ .hologram-effect {
311
+ position: relative;
312
+ overflow: hidden;
313
+ }
314
+
315
+ .hologram-effect::before {
316
+ content: "";
317
+ position: absolute;
318
+ top: 0;
319
+ left: 0;
320
+ width: 100%;
321
+ height: 100%;
322
+ background: linear-gradient(45deg, rgba(255,255,255,0.1) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.1) 75%, transparent 75%, transparent);
323
+ background-size: 20px 20px;
324
+ animation: hologram 1s linear infinite;
325
+ pointer-events: none;
326
+ }
327
+
328
+ @keyframes hologram {
329
+ 0% {
330
+ background-position: 0 0;
331
+ }
332
+ 100% {
333
+ background-position: 20px 20px;
334
+ }
335
+ }
336
+
337
+ .matrix-effect {
338
+ position: relative;
339
+ overflow: hidden;
340
+ }
341
+
342
+ .matrix-effect::before {
343
+ content: "";
344
+ position: absolute;
345
+ top: 0;
346
+ left: 0;
347
+ width: 100%;
348
+ height: 100%;
349
+ background: linear-gradient(rgba(0, 255, 0, 0.1) 50%, transparent 50%);
350
+ background-size: 100% 4px;
351
+ animation: matrix 0.5s linear infinite;
352
+ pointer-events: none;
353
+ }
354
+
355
+ @keyframes matrix {
356
+ 0% {
357
+ background-position: 0 0;
358
+ }
359
+ 100% {
360
+ background-position: 0 4px;
361
+ }
362
+ }
363
+
364
+ .glass-effect {
365
+ background: rgba(255, 255, 255, 0.05);
366
+ backdrop-filter: blur(10px);
367
+ -webkit-backdrop-filter: blur(10px);
368
+ border: 1px solid rgba(255, 255, 255, 0.1);
369
+ }
370
+
371
+ .card-hover {
372
+ transition: all 0.3s ease;
373
+ transform: translateY(0);
374
+ }
375
+
376
+ .card-hover:hover {
377
+ transform: translateY(-5px);
378
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
379
+ }
380
+
381
+ .text-glow {
382
+ text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
383
+ transition: text-shadow 0.3s ease;
384
+ }
385
+
386
+ .text-glow:hover {
387
+ text-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
388
+ }
389
+
390
+ .border-glow {
391
+ border: 1px solid rgba(255, 255, 255, 0.1);
392
+ transition: border-color 0.3s ease;
393
+ }
394
+
395
+ .border-glow:hover {
396
+ border-color: rgba(59, 130, 246, 0.5);
397
+ }
398
+
399
+ .shadow-glow {
400
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
401
+ transition: box-shadow 0.3s ease;
402
+ }
403
+
404
+ .shadow-glow:hover {
405
+ box-shadow: 0 8px 15px rgba(59, 130, 246, 0.3);
406
+ }
407
+
408
+ .pulse-glow {
409
+ animation: pulseGlow 2s infinite;
410
+ }
411
+
412
+ @keyframes pulseGlow {
413
+ 0% {
414
+ box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
415
+ }
416
+ 70% {
417
+ box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
418
+ }
419
+ 100% {
420
+ box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
421
+ }
422
+ }
423
+
424
+ .floating-glow {
425
+ animation: floatingGlow 3s ease-in-out infinite;
426
+ }
427
+
428
+ @keyframes floatingGlow {
429
+ 0% {
430
+ transform: translateY(0);
431
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
432
+ }
433
+ 50% {
434
+ transform: translateY(-10px);
435
+ box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
436
+ }
437
+ 100% {
438
+ transform: translateY(0);
439
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
440
+ }
441
+ }
442
+
443
+ .rotate-glow {
444
+ animation: rotateGlow 4s linear infinite;
445
+ }
446
+
447
+ @keyframes rotateGlow {
448
+ 0% {
449
+ transform: rotate(0deg);
450
+ box-shadow: 0 0 5px rgba(59, 130, 246, 0.5);
451
+ }
452
+ 25% {
453
+ box-shadow: 5px 0 5px rgba(59, 130, 246, 0.5);
454
+ }
455
+ 50% {
456
+ box-shadow: 0 -5px 5px rgba(59, 130, 246, 0.5);
457
+ }
458
+ 75% {
459
+ box-shadow: -5px 0 5px rgba(59, 130, 246, 0.5);
460
+ }
461
+ 100% {
462
+ transform: rotate(360deg);
463
+ box-shadow: 0 0 5px rgba(59, 130, 246, 0.5);
464
+ }
465
+ }
466
+
467
+ .wave-glow {
468
+ position: relative;
469
+ overflow: hidden;
470
+ }
471
+
472
+ .wave-glow::before {
473
+ content: "";
474
+ position: absolute;
475
+ top: 0;
476
+ left: -100%;
477
+ width: 100%;
478
+ height: 100%;
479
+ background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.2), transparent);
480
+ animation: waveGlow 2s linear infinite;
481
+ }
482
+
483
+ @keyframes waveGlow {
484
+ 0% {
485
+ left: -100%;
486
+ }
487
+ 100% {
488
+ left: 100%;
489
+ }
490
+ }
491
+
492
+ .sparkle {
493
+ position: relative;
494
+ }
495
+
496
+ .sparkle::before {
497
+ content: "";
498
+ position: absolute;
499
+ top: -2px;
500
+ right: -2px;
501
+ width: 6px;
502
+ height: 6px;
503
+ background: #fff;
504
+ border-radius: 50%;
505
+ box-shadow: 0 0 10px #fff, 0 0 20px #fff;
506
+ animation: sparkle 1.5s infinite;
507
+ }
508
+
509
+ @keyframes sparkle {
510
+ 0%, 100% {
511
+ opacity: 0;
512
+ }
513
+ 50% {
514
+ opacity: 1;
515
+ }
516
+ }
517
+
518
+ .shimmer {
519
+ background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0) 100%);
520
+ background-size: 200% 100%;
521
+ animation: shimmer 2s infinite;
522
+ }
523
+
524
+ @keyframes shimmer {
525
+ 0% {
526
+ background-position: -200% 0;
527
+ }
528
+ 100% {
529
+ background-position: 200% 0;
530
+ }
531
+ }
532
+
533
+ .ripple {
534
+ position: relative;
535
+ overflow: hidden;
536
+ }
537
+
538
+ .ripple::after {
539
+ content: "";
540
+ position: absolute;
541
+ top: 50%;
542
+ left: 50%;
543
+ width: 0;
544
+ height: 0;
545
+ border-radius: 50%;
546
+ background: rgba(255, 255, 255, 0.2);
547
+ transform: translate(-50%, -50%);
548
+ opacity: 0;
549
+ }
550
+
551
+ .ripple:active::after {
552
+ width: 200px;
553
+ height: 200px;
554
+ opacity: 1;
555
+ transition: width 0.3s, height 0.3s, opacity 0.3s;
556
+ }
557
+
558
+ .morph {
559
+ transition: all 0.3s ease;
560
+ border-radius: 10px;
561
+ }
562
+
563
+ .morph:hover {
564
+ border-radius: 20px;
565
+ }
566
+
567
+ .tilt {
568
+ transition: transform 0.3s ease;
569
+ transform-style: preserve-3d;
570
+ }
571
+
572
+ .tilt:hover {
573
+ transform: rotateY(10deg) rotateX(10deg);
574
+ }
575
+
576
+ .pop {
577
+ transition: all 0.2s ease;
578
+ }
579
+
580
+ .pop:active {
581
+ transform: scale(0.95);
582
+ }
583
+
584
+ .skew {
585
+ transition: transform 0.3s ease;
586
+ }
587
+
588
+ .skew:hover {
589
+ transform: skew(-5deg);
590
+ }
591
+
592
+ .stretch {
593
+ transition: all 0.3s ease;
594
+ }
595
+
596
+ .stretch:hover {
597
+ transform: scaleX(1.05);
598
+ }
599
+
600
+ .compress {
601
+ transition: all 0.3s ease;
602
+ }
603
+
604
+ .compress:hover {
605
+ transform: scaleY(0.95);
606
+ }
607
+
608
+ .swing {
609
+ transition: transform 0.3s ease;
610
+ transform-origin: top center;
611
+ }
612
+
613
+ .swing:hover {
614
+ transform: rotate(5deg);
615
+ }
616
+
617
+ .wobble {
618
+ animation: wobble 1s ease-in-out;
619
+ }
620
+
621
+ @keyframes wobble {
622
+ 0%, 100% {
623
+ transform: translateX(0);
624
+ }
625
+ 25% {
626
+ transform: translateX(-10px);
627
+ }
628
+ 75% {
629
+ transform: translateX(10px);
630
+ }
631
+ }
632
+
633
+ .jello {
634
+ animation: jello 0.6s ease;
635
+ }
636
+
637
+ @keyframes jello {
638
+ 0%, 100% {
639
+ transform: scale(1, 1);
640
+ }
641
+ 25% {
642
+ transform: scale(1.1, 0.9);
643
+ }
644
+ 50% {
645
+ transform: scale(0.9, 1.1);
646
+ }
647
+ 75% {
648
+ transform: scale(1.05, 0.95);
649
+ }
650
+ }
651
+
652
+ .heartbeat {
653
+ animation: heartbeat 1.5s ease-in-out infinite;
654
+ }
655
+
656
+ @keyframes heartbeat {
657
+ 0%, 100% {
658
+ transform: scale(1);
659
+ }
660
+ 50% {
661
+ transform: scale(1.1);
662
+ }
663
+ }
664
+
665
+ .bounce {
666
+ animation: bounce 1s infinite;
667
+ }
668
+
669
+ @keyframes bounce {
670
+ 0%, 100% {
671
+ transform: translateY(0);
672
+ }
673
+ 50% {
674
+ transform: translateY(-20px);
675
+ }
676
+ }
677
+
678
+ .flip {
679
+ animation: flip 1s ease;
680
+ }
681
+
682
+ @keyframes flip {
683
+ 0% {
684
+ transform: rotateY(0deg);
685
+ }
686
+ 100% {
687
+ transform: rotateY(360deg);
688
+ }
689
+ }
690
+
691
+ .roll {
692
+ animation: roll 1s ease;
693
+ }
694
+
695
+ @keyframes roll {
696
+ 0% {
697
+ transform: rotate(0deg);
698
+ }
699
+ 100% {
700
+ transform: rotate(360deg);
701
+ }
702
+ }
703
+
704
+ .rubberBand {
705
+ animation: rubberBand 1s ease;
706
+ }
707
+
708
+ @keyframes rubberBand {
709
+ 0%, 100% {
710
+ transform: scale(1, 1);
711
+ }
712
+ 30% {
713
+ transform: scaleX(1.25) scaleY(0.75);
714
+ }
715
+ 40% {
716
+ transform: scaleX(0.75) scaleY(1.25);
717
+ }
718
+ 60% {
719
+ transform: scaleX(1.15) scaleY(0.85);
720
+ }
721
+ }
722
+
723
+ .shake {
724
+ animation: shake 0.5s ease;
725
+ }
726
+
727
+ @keyframes shake {
728
+ 0%, 100% {
729
+ transform: translateX(0);
730
+ }
731
+ 25% {
732
+ transform: translateX(-5px);
733
+ }
734
+ 75% {
735
+ transform: translateX(5px);
736
+ }
737
+ }
738
+
739
+ .tada {
740
+ animation: tada 1s ease;
741
+ }
742
+
743
+ @keyframes tada {
744
+ 0%, 100% {
745
+ transform: scale(1);
746
+ }
747
+ 10%, 20% {
748
+ transform: scale(0.9) rotate(-3deg);
749
+ }
750
+ 30%, 50%, 70%, 90% {
751
+ transform: scale(1.1) rotate(3deg);
752
+ }
753
+ 40%, 60%, 80% {
754
+ transform: scale(1.1) rotate(-3deg);
755
+ }
756
+ }
757
+
758
+ .lightSpeedIn {
759
+ animation: lightSpeedIn 0.5s ease-out;
760
+ }
761
+
762
+ @keyframes lightSpeedIn {
763
+ 0% {
764
+ transform: translateX(100%) skewX(-30deg);
765
+ opacity: 0;
766
+ }
767
+ 60% {
768
+ transform: translateX(-20%) skewX(30deg);
769
+ opacity: 1;
770
+ }
771
+ 80% {
772
+ transform: translateX(0%) skewX(-15deg);
773
+ opacity: 1;
774
+ }
775
+ 100% {
776
+ transform: translateX(0%) skewX(0deg);
777
+ opacity: 1;
778
+ }
779
+ }
780
+
781
+ .lightSpeedOut {
782
+ animation: lightSpeedOut 0.5s ease-in;
783
+ }
784
+
785
+ @keyframes lightSpeedOut {
786
+ 0% {
787
+ transform: translateX(0%) skewX(0deg);
788
+ opacity: 1;
789
+ }
790
+ 100% {
791
+ transform: translateX(100%) skewX(-30deg);
792
+ opacity: 0;
793
+ }
794
+ }
795
+
796
+ .rotateInDownLeft {
797
+ animation: rotateInDownLeft 0.6s ease-out;
798
+ }
799
+
800
+ @keyframes rotateInDownLeft {
801
+ 0% {
802
+ transform-origin: left bottom;
803
+ transform: rotate(-90deg);
804
+ opacity: 0;
805
+ }
806
+ 100% {
807
+ transform-origin: left bottom;
808
+ transform: rotate(0deg);
809
+ opacity: 1;
810
+ }
811
+ }
812
+
813
+ .rotateInDownRight {
814
+ animation: rotateInDownRight 0.6s ease-out;
815
+ }
816
+
817
+ @keyframes rotateInDownRight {
818
+ 0% {
819
+ transform-origin: right bottom;
820
+ transform: rotate(90deg);
821
+ opacity: 0;
822
+ }
823
+ 100% {
824
+ transform-origin: right bottom;
825
+ transform: rotate(0deg);
826
+ opacity: 1;
827
+ }
828
+ }
829
+
830
+ .rotateInUpLeft {
831
+ animation: rotateInUpLeft 0.6s ease-out;
832
+ }
833
+
834
+ @keyframes rotateInUpLeft {
835
+ 0% {
836
+ transform-origin: left bottom;
837
+ transform: rotate(90deg);
838
+ opacity: 0;
839
+ }
840
+ 100% {
841
+ transform-origin: left bottom;
842
+ transform: rotate(0deg);
843
+ opacity: 1;
844
+ }
845
+ }
846
+
847
+ .rotateInUpRight {
848
+ animation: rotateInUpRight 0.6s ease-out;
849
+ }
850
+
851
+ @keyframes rotateInUpRight {
852
+ 0% {
853
+ transform-origin: right bottom;
854
+ transform: rotate(-90deg);
855
+ opacity: 0;
856
+ }
857
+ 100% {
858
+ transform-origin: right bottom;
859
+ transform: rotate(0deg);
860
+ opacity: 1;
861
+ }
862
+ }
863
+
864
+ .hinge {
865
+ animation: hinge 2s ease;
866
+ }
867
+
868
+ @keyframes hinge {
869
+ 0% {
870
+ transform-origin: top left;
871
+ animation-timing-function: ease-in-out;
872
+ }
873
+ 20%, 60% {
874
+ transform: rotate(80deg);
875
+ transform-origin: top left;
876
+ animation-timing-function: ease-in-out;
877
+ }
878
+ 40%, 80% {
879
+ transform: rotate(60deg);
880
+ transform-origin: top left;
881
+ animation-timing-function: ease-in-out;
882
+ opacity: 1;
883
+ }
884
+ 100% {
885
+ transform: translateY(700px);
886
+ opacity: 0;
887
+ }
888
+ }
889
+
890
+ .jackInTheBox {
891
+ animation: jackInTheBox 0.7s ease;
892
+ }
893
+
894
+ @keyframes jackInTheBox {
895
+ 0% {
896
+ opacity: 0;
897
+ transform: scale(0.1) rotate(30deg);
898
+ transform-origin: center bottom;
899
+ }
900
+ 50% {
901
+ transform: rotate(-10deg);
902
+ }
903
+ 70% {
904
+ transform: rotate(3deg);
905
+ }
906
+ 100% {
907
+ opacity: 1;
908
+ transform: scale(1);
909
+ }
910
+ }
911
+
912
+ .rollIn {
913
+ animation: rollIn 0.7s ease;
914
+ }
915
+
916
+ @keyframes rollIn {
917
+ 0% {
918
+ opacity: 0;
919
+ transform: translateX(-100%) rotate(-120deg);
920
+ }
921
+ 100% {
922
+ opacity: 1;
923
+ transform: translateX(0) rotate(0deg);
924
+ }
925
+ }
926
+
927
+ .rollOut {
928
+ animation: rollOut 0.7s ease;
929
+ }
930
+
931
+ @keyframes rollOut {
932
+ 0% {
933
+ opacity: 1;
934
+ transform: translateX(0) rotate(0deg);
935
+ }
936
+ 100% {
937
+ opacity: 0;
938
+ transform: translateX(100%) rotate(120deg);
939
+ }
940
+ }
941
+
942
+ .zoomInDown {
943
+ animation: zoomInDown 0.6s ease;
944
+ }
945
+
946
+ @keyframes zoomInDown {
947
+ 0% {
948
+ opacity: 0;
949
+ transform: scale(0.1) translateY(-1000px);
950
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
951
+ }
952
+ 60% {
953
+ opacity: 1;
954
+ transform: scale(0.475) translateY(60px);
955
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
956
+ }
957
+ }
958
+
959
+ .zoomInLeft {
960
+ animation: zoomInLeft 0.6s ease;
961
+ }
962
+
963
+ @keyframes zoomInLeft {
964
+ 0% {
965
+ opacity: 0;
966
+ transform: scale(0.1) translateX(-1000px);
967
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
968
+ }
969
+ 60% {
970
+ opacity: 1;
971
+ transform: scale(0.475) translateX(10px);
972
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
973
+ }
974
+ }
975
+
976
+ .zoomInRight {
977
+ animation: zoomInRight 0.6s ease;
978
+ }
979
+
980
+ @keyframes zoomInRight {
981
+ 0% {
982
+ opacity: 0;
983
+ transform: scale(0.1) translateX(1000px);
984
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
985
+ }
986
+ 60% {
987
+ opacity: 1;
988
+ transform: scale(0.475) translateX(-10px);
989
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
990
+ }
991
+ }
992
+
993
+ .zoomInUp {
994
+ animation: zoomInUp 0.6s ease;
995
+ }
996
+
997
+ @keyframes zoomInUp {
998
+ 0% {
999
+ opacity: 0;
1000
+ transform: scale(0.1) translateY(1000px);
1001
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
1002
+ }
1003
+ 60% {
1004
+ opacity: 1;
1005
+ transform: scale(0.475) translateY(-60px);
1006
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
1007
+ }
1008
+ }
1009
+
1010
+ .zoomOut {
1011
+ animation: zoomOut 0.6s ease;
1012
+ }
1013
+
1014
+ @keyframes zoomOut {
1015
+ 0% {
1016
+ opacity: 1;
1017
+ transform: scale(1);
1018
+ }
1019
+ 50% {
1020
+ opacity: 0;
1021
+ transform: scale(0.3);
1022
+ }
1023
+ 100% {
1024
+ opacity: 0;
1025
+ }
1026
+ }
1027
+
1028
+ .zoomOutDown {
1029
+ animation: zoomOutDown 0.6s ease;
1030
+ }
1031
+
1032
+ @keyframes zoomOutDown {
1033
+ 40% {
1034
+ opacity: 1;
1035
+ transform: scale(0.475) translateY(-60px);
1036
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
1037
+ }
1038
+ 100% {
1039
+ opacity: 0;
1040
+ transform: scale(0.1) translateY(2000px);
1041
+ transform-origin: center bottom;
1042
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
1043
+ }
1044
+ }
1045
+
1046
+ .zoomOutLeft {
1047
+ animation: zoomOutLeft 0.6s ease;
1048
+ }
1049
+
1050
+ @keyframes zoomOutLeft {
1051
+ 40% {
1052
+ opacity: 1;
1053
+ transform: scale(0.475) translateX(42px);
1054
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
1055
+ }
1056
+ 100% {
1057
+ opacity: 0;
1058
+ transform: scale(0.1) translateX(-2000px);
1059
+ transform-origin: left center;
1060
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
1061
+ }
1062
+ }
1063
+
1064
+ .zoomOutRight {
1065
+ animation: zoomOutRight 0.6s ease;
1066
+ }
1067
+
1068
+ @keyframes zoomOutRight {
1069
+ 40% {
1070
+ opacity: 1;
1071
+ transform: scale(0.475) translateX(-42px);
1072
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
1073
+ }
1074
+ 100% {
1075
+ opacity: 0;
1076
+ transform: scale(0.1) translateX(2000px);
1077
+ transform-origin: right center;
1078
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
1079
+ }
1080
+ }
1081
+
1082
+ .zoomOutUp {
1083
+ animation: zoomOutUp 0.6s ease;
1084
+ }
1085
+
1086
+ @keyframes zoomOutUp {
1087
+ 40% {
1088
+ opacity: 1;
1089
+ transform: scale(0.475) translateY(60px);
1090
+ animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
1091
+ }
1092
+ 100% {
1093
+ opacity: 0;
1094
+ transform: scale(0.1) translateY(-2000px);
1095
+ transform-origin: center top;
1096
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
1097
+ }
1098
+ }
1099
+
1100
+ .slideInDown {
1101
+ animation: slideInDown 0.5s ease-out;
1102
+ }
1103
+
1104
+ @keyframes slideInDown {
1105
+ from {
1106
+ transform: translateY(-100%);
1107
+ opacity: 0;
1108
+ }
1109
+ to {
1110
+ transform: translateY(0);
1111
+ opacity: 1;
1112
+ }
1113
+ }
1114
+
1115
+ .slideInLeft {
1116
+ animation: slideInLeft 0.5s ease-out;
1117
+ }
1118
+
1119
+ @keyframes slideInLeft {
1120
+ from {
1121
+ transform: translateX(-100%);
1122
+ opacity: 0;
1123
+ }
1124
+ to {
1125
+ transform: translateX(0);
1126
+ opacity: 1;
1127
+ }
1128
+ }
1129
+
1130
+ .slideInRight {
1131
+ animation: slideInRight 0.5s ease-out;
1132
+ }
1133
+
1134
+ @keyframes slideInRight {
1135
+ from {
1136
+ transform: translateX(100%);
1137
+ opacity: 0;
1138
+ }
1139
+ to {
1140
+ transform: translateX(0);
1141
+ opacity: 1;
1142
+ }
1143
+ }
1144
+
1145
+ .slideInUp {
1146
+ animation: slideInUp 0.5s ease-out;
1147
+ }
1148
+
1149
+ @keyframes slideInUp {
1150
+ from {
1151
+ transform: translateY(100%);
1152
+ opacity: 0;
1153
+ }
1154
+ to {
1155
+ transform: translateY(0);
1156
+ opacity: 1;
1157
+ }
1158
+ }
1159
+
1160
+ .slideOutDown {
1161
+ animation: slideOutDown 0.5s ease-out;
1162
+ }
1163
+
1164
+ @keyframes slideOutDown {
1165
+ from {
1166
+ transform: translateY(0);
1167
+ opacity: 1;
1168
+ }
1169
+ to {
1170
+ transform: translateY(100%);
1171
+ opacity: 0;
1172
+ }
1173
+ }
1174
+
1175
+ .slideOutLeft {
1176
+ animation: slideOutLeft 0.5s ease-out;
1177
+ }
1178
+
1179
+ @keyframes slideOutLeft {
1180
+ from {
1181
+ transform: translateX(0);
1182
+ opacity: 1;
1183
+ }
1184
+ to {
1185
+ transform: translateX(-100%);
1186
+ opacity: 0;
1187
+ }
1188
+ }
1189
+
1190
+ .slideOutRight {
1191
+ animation: slideOutRight 0.5s ease-out;
1192
+ }
1193
+
1194
+ @keyframes slideOutRight {
1195
+ from {
1196
+ transform: translateX(0);
1197
+ opacity: 1;
1198
+ }
1199
+ to {
1200
+ transform: translateX(100%);
1201
+ opacity: 0;
1202
+ }
1203
+ }
1204
+
1205
+ .slideOutUp {
1206
+ animation: slideOutUp 0.5s ease-out;
1207
+ }
1208
+
1209
+ @keyframes slideOutUp {
1210
+ from {
1211
+ transform: translateY(0);
1212
+ opacity: 1;
1213
+ }
1214
+ to {
1215
+ transform: translateY(-100%);
1216
+ opacity: 0;
1217
+ }
1218
+ }
1219
+
1220
+ .fadeIn {
1221
+ animation: fadeIn 0.5s ease-out;
1222
+ }
1223
+
1224
+ .fadeOut {
1225
+ animation: fadeOut 0.5s ease-out;
1226
+ }
1227
+
1228
+ @keyframes fadeOut {
1229
+ from {
1230
+ opacity: 1;
1231
+ }
1232
+ to {
1233
+ opacity: 0;
1234
+ }
1235
+ }
1236
+
1237
+ .fadeInDown {
1238
+ animation: fadeInDown 0.5s ease-out;
1239
+ }
1240
+
1241
+ .fadeOutDown {
1242
+ animation: fadeOutDown 0.5s ease-out;
1243
+ }
1244
+
1245
+ @keyframes fadeOutDown {
1246
+ from {
1247
+ opacity: 1;
1248
+ }
1249
+ to {
1250
+ opacity: 0;
1251
+ transform: translateY(100%);
1252
+ }
1253
+ }
1254
+
1255
+ .fadeInDownBig {
1256
+ animation: fadeInDownBig 0.5s ease-out;
1257
+ }
1258
+
1259
+ @keyframes fadeInDownBig {
1260
+ from {
1261
+ opacity: 0;
1262
+ transform: translateY(-2000px);
1263
+ }
1264
+ to {
1265
+ opacity: 1;
1266
+ transform: translateY(0);
1267
+ }
1268
+ }
1269
+
1270
+ .fadeOutDownBig {
1271
+ animation: fadeOutDownBig 0.5s ease-out;
1272
+ }
1273
+
1274
+ @keyframes fadeOutDownBig {
1275
+ from {
1276
+ opacity: 1;
1277
+ }
1278
+ to {
1279
+ opacity: 0;
1280
+ transform: translateY(2000px);
1281
+ }
1282
+ }
1283
+
1284
+ .fadeInLeft {
1285
+ animation: fadeInLeft 0.5s ease-out;
1286
+ }
1287
+
1288
+ .fadeOutLeft {
1289
+ animation: fadeOutLeft 0.5s ease-out;
1290
+ }
1291
+
1292
+ @keyframes fadeOutLeft {
1293
+ from {
1294
+ opacity: 1;
1295
+ }
1296
+ to {
1297
+ opacity: 0;
1298
+ transform: translateX(-100%);
1299
+ }
1300
+ }
1301
+
1302
+ .fadeInLeftBig {
1303
+ animation: fadeInLeftBig 0.5s ease-out;
1304
+ }
1305
+
1306
+ @keyframes fadeInLeftBig {
1307
+ from {
1308
+ opacity: 0;
1309
+ transform: translateX(-2000px);
1310
+ }
1311
+ to {
1312
+ opacity: 1;
1313
+ transform: translateX(0);
1314
+ }
1315
+ }
1316
+
1317
+ .fadeOutLeftBig {
1318
+ animation: fadeOutLeftBig 0.5s ease-out;
1319
+ }
1320
+
1321
+ @keyframes fadeOutLeftBig {
1322
+ from {
1323
+ opacity: 1;
1324
+ }
1325
+ to {
1326
+ opacity: 0;
1327
+ transform: translateX(-2000px);
1328
+ }
1329
+ }
1330
+
1331
+ .fadeInRight {
1332
+ animation: fadeInRight 0.5s ease-out;
1333
+ }
1334
+
1335
+ .fadeOutRight {
1336
+ animation: fadeOutRight 0.5s ease-out;
1337
+ }
1338
+
1339
+ @keyframes fadeOutRight {
1340
+ from {
1341
+ opacity: 1;
1342
+ }
1343
+ to {
1344
+ opacity: 0;
1345
+ transform: translateX(100%);
1346
+ }
1347
+ }
1348
+
1349
+ .fadeInRightBig {
1350
+ animation: fadeInRightBig 0.5s ease-out;
1351
+ }
1352
+
1353
+ @keyframes fadeInRightBig {
1354
+ from {
1355
+ opacity: 0;
1356
+ transform: translateX(2000px);
1357
+ }
1358
+ to {
1359
+ opacity: 1;
1360
+ transform: translateX(0);
1361
+ }
1362
+ }
1363
+
1364
+ .fadeOutRightBig {
1365
+ animation: fadeOutRightBig 0.5s ease-out;
1366
+ }
1367
+
1368
+ @keyframes fadeOutRightBig {
1369
+ from {
1370
+ opacity: 1;
1371
+ }
1372
+ to {
1373
+ opacity: 0;
1374
+ transform: translateX(2000px);
1375
+ }
1376
+ }
1377
+
1378
+ .fadeInUp {
1379
+ animation: fadeInUp 0.5s ease-out;
1380
+ }
1381
+
1382
+ .fadeOutUp {
1383
+ animation: fadeOutUp 0.5s ease-out;
1384
+ }
1385
+
1386
+ @keyframes fadeOutUp {
1387
+ from {
1388
+ opacity: 1;
1389
+ }
1390
+ to {
1391
+ opacity: 0;
1392
+ transform: translateY(-100%);
1393
+ }
1394
+ }
1395
+
1396
+ .fadeInUpBig {
1397
+ animation: fadeInUpBig 0.5s ease-out;
1398
+ }
1399
+
1400
+ @keyframes fadeInUpBig {
1401
+ from {
1402
+ opacity: 0;
1403
+ transform: translateY(2000px);
1404
+ }
1405
+ to {
1406
+ opacity: 1;
1407
+ transform: translateY(0);
1408
+ }
1409
+ }
1410
+
1411
+ .fadeOutUpBig {
1412
+ animation: fadeOutUpBig 0.5s ease-out;
1413
+ }
1414
+
1415
+ @keyframes fadeOutUpBig {
1416
+ from {
1417
+ opacity: 1;
1418
+ }
1419
+ to {
1420
+ opacity: 0;
1421
+ transform: translateY(-2000px);
1422
+ }
1423
+ }
1424
+
1425
+ .flipInX {
1426
+ animation: flipInX 0.6s ease;
1427
+ }
1428
+
1429
+ @keyframes flipInX {
1430
+ 0% {
1431
+ transform: perspective(400px) rotateX(90deg);
1432
+ opacity: 0;
1433
+ }
1434
+ 40% {
1435
+ transform: perspective(400px) rotateX(-10deg);
1436
+ }
1437
+ 70% {
1438
+ transform: perspective(400px) rotateX(10deg);
1439
+ }
1440
+ 100% {
1441
+ transform: perspective(400px) rotateX(0deg);
1442
+ opacity: 1;
1443
+ }
1444
+ }
1445
+
1446
+ .flipInY {
1447
+ animation: flipInY 0.6s ease;
1448
+ }
1449
+
1450
+ @keyframes flipInY {
1451
+ 0% {
1452
+ transform: perspective(400px) rotateY(90deg);
1453
+ opacity: 0;
1454
+ }
1455
+ 40% {
1456
+ transform: perspective(400px) rotateY(-10deg);
1457
+ }
1458
+ 70% {
1459
+ transform: perspective(400px) rotateY(10deg);
1460
+ }
1461
+ 100% {
1462
+ transform: perspective(400px) rotateY(0deg);
1463
+ opacity: 1;
1464
+ }
1465
+ }
1466
+
1467
+ .flipOutX {
1468
+ animation: flipOutX 0.6s ease;
1469
+ }
1470
+
1471
+ @keyframes flipOutX {
1472
+ 0% {
1473
+ transform: perspective(400px) rotateX(0deg);
1474
+ opacity: 1;
1475
+ }
1476
+ 100% {
1477
+ transform: perspective(400px) rotateX(90deg);
1478
+ opacity: 0;
1479
+ }
1480
+ }
1481
+
1482
+ .flipOutY {
1483
+ animation: flipOutY 0.6s ease;
1484
+ }
1485
+
1486
+ @keyframes flipOutY {
1487
+ 0% {
1488
+ transform: perspective(400px) rotateY(0deg);
1489
+ opacity: 1;
1490
+ }
1491
+ 100% {
1492
+ transform: perspective(400px) rotateY(90deg);
1493
+ opacity: 0;
1494
+ }
1495
+ }
1496
+
1497
+ .lightSpeedInRight {
1498
+ animation: lightSpeedInRight 0.5s ease-out;
1499
+ }
1500
+
1501
+ @keyframes lightSpeedInRight {
1502
+ 0% {
1503
+ transform: translateX(-100%) skewX(30deg);
1504
+ opacity: 0;
1505
+ }
1506
+ 60% {
1507
+ transform: translateX(20%) skewX(-30deg);
1508
+ opacity: 1;
1509
+ }
1510
+ 80% {
1511
+ transform: translateX(0%) skewX(15deg);
1512
+ opacity: 1;
1513
+ }
1514
+ 100% {
1515
+ transform: translateX(0%) skewX(0deg);
1516
+ opacity: 1;
1517
+ }
1518
+ }
1519
+
1520
+ .lightSpeedOutLeft {
1521
+ animation: lightSpeedOutLeft 0.5s ease-in;
1522
+ }
1523
+
1524
+ @keyframes lightSpeedOutLeft {
1525
+ 0% {
1526
+ transform: translateX(0%) skewX(0deg);
1527
+ opacity: 1;
1528
+ }
1529
+ 100% {
1530
+ transform: translateX(-100%) skewX(30deg);
1531
+ opacity: 0;
1532
+ }
1533
+ }
1534
+
1535
+ .lightSpeedOutRight {
1536
+ animation: lightSpeedOutRight 0.5s ease-in;
1537
+ }
1538
+
1539
+ @keyframes lightSpeedOutRight {
1540
+ 0% {
1541
+ transform: translateX(0%) skewX(0deg);
1542
+ opacity: 1;
1543
+ }
1544
+ 100% {
1545
+ transform: translateX(100%) skewX(-30deg);
1546
+ opacity: 0;
1547
+ }
1548
+ }
1549
+
1550
+ .rotateOut {
1551
+ animation: rotateOut 0.6s ease;
1552
+ }
1553
+
1554
+ @keyframes rotateOut {
1555
+ 0% {
1556
+ transform-origin: center;
1557
+ opacity: 1;
1558
+ }
1559
+ 100% {
1560
+ transform-origin: center;
1561
+ transform: rotate(200deg);
1562
+ opacity: 0;
1563
+ }
1564
+ }
1565
+
1566
+ .rotateOutDownLeft {
1567
+ animation: rotateOutDownLeft 0.6s ease;
1568
+ }
1569
+
1570
+ @keyframes rotateOutDownLeft {
1571
+ 0% {
1572
+ transform-origin: left bottom;
1573
+ opacity: 1;
1574
+ }
1575
+ 100% {
1576
+ transform-origin: left bottom;
1577
+ transform: rotate(45deg);
1578
+ opacity: 0;
1579
+ }
1580
+ }
1581
+
1582
+ .rotateOutDownRight {
1583
+ animation: rotateOutDownRight 0.6s ease;
1584
+ }
1585
+
1586
+ @keyframes rotateOutDownRight {
1587
+ 0% {
1588
+ transform-origin: right bottom;
1589
+ opacity: 1;
1590
+ }
1591
+ 100% {
1592
+ transform-origin: right bottom;
1593
+ transform: rotate(-45deg);
1594
+ opacity: 0;
1595
+ }
1596
+ }
1597
+
1598
+ .rotateOutUpLeft {
1599
+ animation: rotateOutUpLeft 0.6s ease;
1600
+ }
1601
+
1602
+ @keyframes rotateOutUpLeft {
1603
+ 0% {
1604
+ transform-origin: left bottom;
1605
+ opacity: 1;
1606
+ }
1607
+ 100% {
1608
+ transform-origin: left bottom;
1609
+ transform: rotate(-45deg);
1610
+ opacity: 0;
1611
+ }
1612
+ }
1613
+
1614
+ .rotateOutUpRight {
1615
+ animation: rotateOutUpRight 0.6s ease;
1616
+ }
1617
+
1618
+ @keyframes rotateOutUpRight {
1619
+ 0% {
1620
+ transform-origin: right bottom;
1621
+ opacity: 1;
1622
+ }
1623
+ 100% {
1624
+ transform-origin: right bottom;
1625
+ transform: rotate(45deg);
1626
+ opacity: 0;
1627
+ }
1628
+ }
assets/css/button.css ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ #sendBtn, #stopBtn {
7
+ width: 2.75rem;
8
+ height: 2.75rem;
9
+ border: none;
10
+ border-radius: 50%;
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ cursor: pointer;
15
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
16
+ flex-shrink: 0;
17
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
18
+ }
19
+
20
+ #sendBtn {
21
+ background: linear-gradient(135deg, var(--color-primary), #2563eb);
22
+ color: white;
23
+ }
24
+
25
+ #sendBtn:hover:not(:disabled) {
26
+ transform: translateY(-2px) scale(1.05);
27
+ box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
28
+ }
29
+
30
+ #sendBtn:active:not(:disabled) {
31
+ transform: translateY(0) scale(0.98);
32
+ }
33
+
34
+ #sendBtn:disabled {
35
+ opacity: 0.6;
36
+ cursor: not-allowed;
37
+ transform: scale(0.96);
38
+ }
39
+
40
+ #stopBtn {
41
+ background: linear-gradient(135deg, #ef4444, #dc2626);
42
+ color: white;
43
+ display: none;
44
+ box-shadow: 0 2px 4px rgba(239, 68, 68, 0.2);
45
+ }
46
+
47
+ #stopBtn:hover {
48
+ transform: translateY(-2px) scale(1.05);
49
+ box-shadow: 0 4px 8px rgba(239, 68, 68, 0.3);
50
+ }
51
+
52
+ #stopBtn:active {
53
+ transform: translateY(0) scale(0.98);
54
+ }
55
+
56
+ #sendIcon {
57
+ width: 1.25rem;
58
+ height: 1.25rem;
59
+ stroke: #fff;
60
+ transition: transform 0.2s ease;
61
+ }
62
+
63
+ #sendBtn:hover:not(:disabled) #sendIcon {
64
+ transform: translateX(2px);
65
+ }
assets/css/chat/bubble.css ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .bubble {
7
+ display: block;
8
+ align-self: flex-start;
9
+ background: #1f1f1f;
10
+ color: #e8e8e8;
11
+ border-radius: var(--bubble-radius);
12
+ line-height: 1.5;
13
+ white-space: normal;
14
+ font-family: 'Inter', sans-serif;
15
+ font-size: 0.95rem;
16
+ position: relative;
17
+ opacity: 0;
18
+ animation: bubbleAppear 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
19
+ margin: 0.75rem 0;
20
+ overflow-wrap: break-word;
21
+ word-break: break-word;
22
+ vertical-align: middle;
23
+ padding: 1rem 1.25rem;
24
+ box-sizing: border-box;
25
+ max-width: 100%;
26
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
27
+ border: 1px solid rgba(255, 255, 255, 0.05);
28
+ transition: all 0.3s ease;
29
+ }
30
+
31
+ .bubble:hover {
32
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
33
+ transform: translateY(-1px);
34
+ }
35
+
36
+ @keyframes bubbleAppear {
37
+ to {
38
+ opacity: 1;
39
+ transform: translateY(0);
40
+ }
41
+ }
42
+
43
+ .bubble-user {
44
+ align-self: flex-end;
45
+ background: linear-gradient(135deg, var(--color-primary), #2563eb);
46
+ color: #fff;
47
+ border-bottom-right-radius: 0.5rem;
48
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.25);
49
+ }
50
+
51
+ .bubble-assist {
52
+ align-self: flex-start;
53
+ background: linear-gradient(135deg, #1f1f1f, #1a1a1a);
54
+ }
assets/css/chat/markdown.css ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .md-content {
7
+ color: inherit;
8
+ font-size: 0.95rem;
9
+ line-height: 1.6;
10
+ overflow-wrap: break-word;
11
+ word-break: break-word;
12
+ }
13
+
14
+ .md-content p {
15
+ margin: 0.5rem 0;
16
+ }
17
+
18
+ .md-content pre {
19
+ overflow: auto;
20
+ padding: 1rem;
21
+ border-radius: 0.75rem;
22
+ margin: 0.75rem 0;
23
+ max-width: 100%;
24
+ box-sizing: border-box;
25
+ background: rgba(0, 0, 0, 0.3);
26
+ border: 1px solid rgba(255, 255, 255, 0.1);
27
+ }
28
+
29
+ .md-content code {
30
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace;
31
+ font-size: 0.85em;
32
+ word-break: break-word;
33
+ background: rgba(0, 0, 0, 0.2);
34
+ padding: 0.2em 0.4em;
35
+ border-radius: 0.3rem;
36
+ }
37
+
38
+ .md-content pre code {
39
+ background: transparent;
40
+ padding: 0;
41
+ }
42
+
43
+ .md-content table {
44
+ width: 100%;
45
+ border-collapse: collapse;
46
+ margin: 0.75rem 0;
47
+ min-width: 100%;
48
+ box-sizing: border-box;
49
+ }
50
+
51
+ .table-wrapper {
52
+ overflow: auto;
53
+ border-radius: 0.6rem;
54
+ border: 1px solid rgba(255, 255, 255, 0.2);
55
+ margin: 0.5rem 0;
56
+ max-width: 100%;
57
+ box-sizing: border-box;
58
+ }
59
+
60
+ .md-content th, .md-content td {
61
+ padding: 0.6rem 0.8rem;
62
+ border: 1px solid rgba(255, 255, 255, 0.2);
63
+ text-align: left;
64
+ vertical-align: top;
65
+ word-break: break-word;
66
+ max-width: 200px;
67
+ }
68
+
69
+ .md-content th {
70
+ background: rgba(255, 255, 255, 0.1);
71
+ font-weight: 600;
72
+ }
73
+
74
+ .md-content tbody tr:nth-child(odd) td {
75
+ background: rgba(255, 255, 255, 0.05);
76
+ }
77
+
78
+ .md-content ul {
79
+ list-style-type: none;
80
+ padding-left: 0;
81
+ }
82
+
83
+ .md-content ul ul {
84
+ list-style-type: none;
85
+ padding-left: 2em;
86
+ }
87
+
88
+ .md-content ul ul ul {
89
+ list-style-type: none;
90
+ padding-left: 2em;
91
+ }
92
+
93
+ .md-content ol {
94
+ list-style-type: none;
95
+ padding-left: 0;
96
+ counter-reset: list-counter;
97
+ }
98
+
99
+ .md-content ol ol {
100
+ list-style-type: none;
101
+ padding-left: 2em;
102
+ }
103
+
104
+ .md-content ol ol ol {
105
+ list-style-type: none;
106
+ padding-left: 2em;
107
+ }
108
+
109
+ .md-content ul > li, .md-content ol > li {
110
+ margin-top: 0.5rem;
111
+ margin-bottom: 0.5rem;
112
+ position: relative;
113
+ padding-left: 2.8em;
114
+ }
115
+
116
+ .md-content ul > li::before {
117
+ content: "•";
118
+ position: absolute;
119
+ left: 1em;
120
+ top: 0;
121
+ font-size: 1.2em;
122
+ color: var(--color-primary);
123
+ }
124
+
125
+ .md-content ol > li {
126
+ counter-increment: list-counter;
127
+ }
128
+
129
+ .md-content ol > li::before {
130
+ content: counter(list-counter) ".";
131
+ position: absolute;
132
+ left: 0;
133
+ top: 0;
134
+ min-width: 2.5em;
135
+ text-align: right;
136
+ padding-right: 0.5em;
137
+ color: var(--color-primary);
138
+ font-weight: 500;
139
+ }
140
+
141
+ .md-content hr {
142
+ border: 0;
143
+ height: 2px;
144
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
145
+ margin: 1.2rem 0;
146
+ border-radius: 2px;
147
+ }
148
+
149
+ .md-content blockquote {
150
+ border-left: 4px solid rgba(59, 130, 246, 0.5);
151
+ padding: 0.75rem 1rem;
152
+ margin: 0.75rem 0;
153
+ color: rgba(255, 255, 255, 0.9);
154
+ background: rgba(59, 130, 246, 0.1);
155
+ border-radius: 0.5rem;
156
+ overflow-wrap: break-word;
157
+ }
158
+
159
+ .md-content img {
160
+ max-width: 100%;
161
+ height: auto;
162
+ display: block;
163
+ margin: 0.75rem auto;
164
+ border-radius: 8px;
165
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
166
+ }
167
+
168
+ .md-content table td pre, .md-content table th pre {
169
+ max-height: 360px;
170
+ overflow: auto;
171
+ }
assets/css/chat/style.css ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .chat-title {
7
+ font-weight: 700;
8
+ font-size: 1rem;
9
+ color: #e6eefc;
10
+ display: flex;
11
+ align-items: center;
12
+ gap: 0.5rem;
13
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
14
+ white-space: nowrap;
15
+ overflow: hidden;
16
+ text-overflow: ellipsis;
17
+ }
18
+
19
+ .chat-controls {
20
+ display: flex;
21
+ align-items: center;
22
+ gap: 0.5rem;
23
+ }
24
+
25
+ .chat-section {
26
+ display: flex;
27
+ flex-direction: column;
28
+ width: 100%;
29
+ height: 100%;
30
+ }
31
+
32
+ #chatArea {
33
+ flex: 1;
34
+ display: flex;
35
+ flex-direction: column;
36
+ overflow-y: auto;
37
+ width: 100%;
38
+ height: 100%;
39
+ box-sizing: border-box;
40
+ overflow-wrap: break-word;
41
+ word-wrap: break-word;
42
+ word-break: break-word;
43
+ max-width: 100%;
44
+ }
45
+
46
+ #chatBox {
47
+ display: none;
48
+ flex-direction: column;
49
+ width: 100%;
50
+ height: 100%;
51
+ overflow-y: auto;
52
+ padding: 0.75rem 1rem calc(var(--footer-height) + 1rem) 1rem;
53
+ box-sizing: border-box;
54
+ max-width: 100%;
55
+ overflow-wrap: break-word;
56
+ word-wrap: break-word;
57
+ word-break: break-word;
58
+ }
assets/css/footer.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ #footerForm {
7
+ display: flex;
8
+ gap: 0.75rem;
9
+ background-color: transparent;
10
+ align-items: center;
11
+ width: 100%;
12
+ max-width: 100%;
13
+ box-sizing: border-box;
14
+ position: fixed;
15
+ bottom: 0;
16
+ left: 0;
17
+ right: 0;
18
+ z-index: 1000;
19
+ animation: slideInUp 0.3s ease-out forwards;
20
+ height: var(--footer-height);
21
+ }
assets/css/header.css ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .main-header, .chat-header {
7
+ position: fixed;
8
+ top: 0;
9
+ left: 0;
10
+ right: 0;
11
+ z-index: 1000;
12
+ display: flex;
13
+ align-items: center;
14
+ width: 100%;
15
+ box-sizing: border-box;
16
+ backdrop-filter: blur(10px);
17
+ -webkit-backdrop-filter: blur(10px);
18
+ transition: all var(--transition-speed) cubic-bezier(0.4, 0, 0.2, 1);
19
+ height: var(--header-height);
20
+ background-color: rgba(15, 15, 15, 0.85);
21
+ }
22
+
23
+ .main-header {
24
+ justify-content: space-between;
25
+ }
26
+
27
+ .chat-header {
28
+ justify-content: space-between;
29
+ display: none;
30
+ }
assets/css/icon.css ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .icon-btn {
7
+ background: transparent;
8
+ border: none;
9
+ cursor: pointer;
10
+ padding: 0.5rem;
11
+ border-radius: 0.5rem;
12
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ gap: 0.5rem;
17
+ color: #dbe3ff;
18
+ backdrop-filter: blur(4px);
19
+ -webkit-backdrop-filter: blur(4px);
20
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
21
+ height: 2.5rem;
22
+ width: 2.5rem;
23
+ }
24
+
25
+ .icon-btn:hover {
26
+ background: rgba(255, 255, 255, 0.1);
27
+ transform: translateY(-2px);
28
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
29
+ }
30
+
31
+ .icon-btn:active {
32
+ transform: translateY(0);
33
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
34
+ }
35
+
36
+ .icon {
37
+ width: 1.2rem;
38
+ height: 1.2rem;
39
+ color: #9ca3af;
40
+ flex-shrink: 0;
41
+ transition: transform 0.2s ease;
42
+ }
43
+
44
+ .prompt-item:hover .icon {
45
+ transform: scale(1.1);
46
+ }
47
+
48
+ #leftIcon {
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ padding: 0 1rem;
53
+ color: #9ca3af;
54
+ cursor: pointer;
55
+ transition: all 0.2s ease;
56
+ }
57
+
58
+ #leftIcon:hover {
59
+ color: var(--color-primary);
60
+ transform: scale(1.1);
61
+ }
62
+
63
+ #rightIconGroup {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ padding: 0 0.5rem;
68
+ gap: 0.5rem;
69
+ }
70
+
71
+ .linkedin {
72
+ display: inline-block;
73
+ width: 1rem;
74
+ height: 1rem;
75
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' fill='%23dbe3ff' class='bi bi-linkedin' viewBox='0 0 16 16'%3E%3Cpath d='M0 1.146C0 .513.526 0 1.175 0h13.65C15.474 0 16 .513 16 1.146v13.708c0 .633-.526 1.146-1.175 1.146H1.175C.526 16 0 15.487 0 14.854zm4.943 12.248V6.169H2.542v7.225zm-1.2-8.212c.837 0 1.358-.554 1.358-1.248-.015-.709-.52-1.248-1.342-1.248S2.4 3.226 2.4 3.934c0 .694.521 1.248 1.327 1.248zm4.908 8.212V9.359c0-.216.016-.432.08-.586.173-.431.568-.878 1.232-.878.869 0 1.216.662 1.216 1.634v3.865h2.401V9.25c0-2.22-1.184-3.252-2.764-3.252-1.274 0-1.845.7-2.165 1.193v.025h-.016l.016-.025V6.169h-2.4c.03.678 0 7.225 0 7.225z'/%3E%3C/svg%3E");
76
+ background-size: contain;
77
+ background-repeat: no-repeat;
78
+ transition: transform 0.2s ease;
79
+ }
80
+
81
+ .icon-btn:hover .linkedin {
82
+ transform: scale(1.1);
83
+ }
assets/css/input.css ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ #inputContainer {
7
+ display: flex;
8
+ align-items: center;
9
+ flex: 1;
10
+ background: linear-gradient(145deg, #1a1a1a, #141414);
11
+ border-radius: 2rem;
12
+ border: 1px solid rgba(255, 255, 255, 0.1);
13
+ padding: 0.25rem;
14
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
15
+ max-width: 100%;
16
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
17
+ }
18
+
19
+ #inputContainer:focus-within {
20
+ border-color: var(--color-primary);
21
+ background: linear-gradient(145deg, #1f1f1f, #1a1a1a);
22
+ box-shadow: 0 4px 8px rgba(59, 130, 246, 0.2);
23
+ transform: translateY(-1px);
24
+ }
25
+
26
+ #userInput {
27
+ flex: 1;
28
+ padding: 0.75rem 1rem;
29
+ border-radius: 2rem;
30
+ border: 1px solid transparent;
31
+ background-color: transparent;
32
+ color: #e0e0e0;
33
+ font-size: 1rem;
34
+ outline: none;
35
+ transition: border-color 0.2s, background-color 0.2s;
36
+ word-break: break-word;
37
+ overflow-wrap: break-word;
38
+ max-width: 100%;
39
+ min-width: 0;
40
+ font-family: 'Inter', sans-serif;
41
+ }
assets/css/logo.css ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .logo {
7
+ font-weight: 800;
8
+ font-size: 1.125rem;
9
+ display: flex;
10
+ align-items: center;
11
+ gap: 0.5rem;
12
+ color: #eaeef8;
13
+ word-break: break-word;
14
+ transition: transform 0.2s ease;
15
+ height: 100%;
16
+ }
17
+
18
+ .logo:hover {
19
+ transform: scale(1.05);
20
+ }
assets/css/prompts.css ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .prompts {
7
+ display: grid;
8
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
9
+ gap: 1rem;
10
+ width: 100%;
11
+ max-width: 100%;
12
+ margin-bottom: 1.5rem;
13
+ }
14
+
15
+ .prompt-item {
16
+ background: linear-gradient(145deg, #1a1a1a, #141414);
17
+ padding: 1rem 1.25rem;
18
+ border-radius: var(--prompt-radius);
19
+ display: flex;
20
+ align-items: center;
21
+ gap: 0.8rem;
22
+ cursor: pointer;
23
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
24
+ word-break: break-word;
25
+ overflow-wrap: break-word;
26
+ border: 1px solid rgba(255, 255, 255, 0.05);
27
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
28
+ animation: fadeIn 0.5s ease-out forwards;
29
+ transform: translateY(20px);
30
+ opacity: 0;
31
+ }
32
+
33
+ .prompt-item:nth-child(1) { animation-delay: 0.1s; }
34
+ .prompt-item:nth-child(2) { animation-delay: 0.2s; }
35
+ .prompt-item:nth-child(3) { animation-delay: 0.3s; }
36
+ .prompt-item:nth-child(4) { animation-delay: 0.4s; }
37
+
38
+ .prompt-item:hover {
39
+ background: linear-gradient(145deg, #1f1f1f, #1a1a1a);
40
+ transform: translateY(-3px) scale(1.02);
41
+ box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
42
+ }
43
+
44
+ .prompt-item:active {
45
+ transform: translateY(0) scale(0.98);
46
+ }
assets/css/screen/1200.css ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (min-width: 1200px) {
7
+ .prompts {
8
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
9
+ max-width: 1200px;
10
+ }
11
+
12
+ .title {
13
+ font-size: clamp(2rem, 3vw, 3rem);
14
+ }
15
+ }
assets/css/screen/2000.css ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (min-width: 2000px) {
7
+ :root {
8
+ --header-height: 4.5rem;
9
+ --footer-height: 6rem;
10
+ --border-radius: 1.25rem;
11
+ --bubble-radius: 1.25rem;
12
+ --prompt-radius: 1.25rem;
13
+ font-size: 1.1rem;
14
+ }
15
+
16
+ .title {
17
+ font-size: clamp(2.5rem, 2.5vw, 3.5rem);
18
+ }
19
+
20
+ .prompts {
21
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
22
+ max-width: 1600px;
23
+ }
24
+
25
+ .prompt-item {
26
+ padding: 1.25rem 1.5rem;
27
+ border-radius: 1.25rem;
28
+ }
29
+
30
+ .bubble {
31
+ padding: 1.25rem 1.5rem;
32
+ font-size: 1.1rem;
33
+ border-radius: 1.25rem;
34
+ }
35
+
36
+ #userInput {
37
+ padding: 1rem 1.25rem;
38
+ font-size: 1.1rem;
39
+ }
40
+
41
+ #sendBtn, #stopBtn {
42
+ width: 3.25rem;
43
+ height: 3.25rem;
44
+ }
45
+
46
+ .icon-btn {
47
+ width: 3rem;
48
+ height: 3rem;
49
+ }
50
+ }
assets/css/screen/320.css ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (max-width: 320px) {
7
+ :root {
8
+ --header-height: 2.25rem;
9
+ --footer-height: 3.5rem;
10
+ --border-radius: 0.5rem;
11
+ --bubble-radius: 0.5rem;
12
+ --prompt-radius: 0.5rem;
13
+ }
14
+
15
+ .main-header, .chat-header {
16
+ padding: 0.3rem 0.4rem;
17
+ }
18
+
19
+ #chatBox {
20
+ padding: 0.3rem 0.4rem calc(var(--footer-height) + 0.4rem) 0.4rem;
21
+ }
22
+
23
+ #footerForm {
24
+ padding: 0.3rem 0.4rem;
25
+ }
26
+
27
+ #userInput {
28
+ padding: 0.4rem 0.5rem;
29
+ font-size: 0.8rem;
30
+ }
31
+
32
+ #sendBtn, #stopBtn {
33
+ width: 1.75rem;
34
+ height: 1.75rem;
35
+ }
36
+
37
+ .title {
38
+ font-size: clamp(1rem, 5vw, 1.4rem);
39
+ margin-bottom: 0.7rem;
40
+ }
41
+
42
+ .prompts {
43
+ gap: 0.4rem;
44
+ margin-bottom: 0.7rem;
45
+ }
46
+
47
+ .prompt-item {
48
+ padding: 0.5rem 0.7rem;
49
+ gap: 0.4rem;
50
+ }
51
+
52
+ .icon {
53
+ width: 0.8rem;
54
+ height: 0.8rem;
55
+ }
56
+
57
+ .system {
58
+ font-size: 0.6rem;
59
+ margin-top: 0.7rem;
60
+ }
61
+
62
+ .bubble {
63
+ padding: 0.5rem 0.7rem;
64
+ font-size: 0.75rem;
65
+ border-radius: 0.5rem;
66
+ margin: 0.3rem 0;
67
+ }
68
+
69
+ .chat-title {
70
+ font-size: 0.8rem;
71
+ }
72
+
73
+ .icon-btn {
74
+ padding: 0.25rem;
75
+ width: 1.5rem;
76
+ height: 1.5rem;
77
+ }
78
+
79
+ .logo {
80
+ font-size: 0.85rem;
81
+ }
82
+ }
assets/css/screen/360.css ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (max-width: 360px) {
7
+ :root {
8
+ --header-height: 2.5rem;
9
+ --footer-height: 3.75rem;
10
+ --border-radius: 0.625rem;
11
+ --bubble-radius: 0.625rem;
12
+ --prompt-radius: 0.625rem;
13
+ }
14
+
15
+ .main-header, .chat-header {
16
+ padding: 0.35rem 0.5rem;
17
+ }
18
+
19
+ #chatBox {
20
+ padding: 0.4rem 0.5rem calc(var(--footer-height) + 0.5rem) 0.5rem;
21
+ }
22
+
23
+ #footerForm {
24
+ padding: 0.4rem 0.5rem;
25
+ }
26
+
27
+ #userInput {
28
+ padding: 0.45rem 0.6rem;
29
+ font-size: 0.85rem;
30
+ }
31
+
32
+ #sendBtn, #stopBtn {
33
+ width: 2rem;
34
+ height: 2rem;
35
+ }
36
+
37
+ .title {
38
+ font-size: clamp(1.1rem, 5vw, 1.6rem);
39
+ margin-bottom: 0.8rem;
40
+ }
41
+
42
+ .prompts {
43
+ gap: 0.5rem;
44
+ margin-bottom: 0.8rem;
45
+ }
46
+
47
+ .prompt-item {
48
+ padding: 0.6rem 0.8rem;
49
+ gap: 0.5rem;
50
+ }
51
+
52
+ .icon {
53
+ width: 0.9rem;
54
+ height: 0.9rem;
55
+ }
56
+
57
+ .system {
58
+ font-size: 0.65rem;
59
+ margin-top: 0.8rem;
60
+ }
61
+
62
+ .bubble {
63
+ padding: 0.6rem 0.8rem;
64
+ font-size: 0.8rem;
65
+ border-radius: 0.625rem;
66
+ margin: 0.4rem 0;
67
+ }
68
+
69
+ .chat-title {
70
+ font-size: 0.85rem;
71
+ }
72
+
73
+ .icon-btn {
74
+ padding: 0.3rem;
75
+ width: 1.75rem;
76
+ height: 1.75rem;
77
+ }
78
+
79
+ .logo {
80
+ font-size: 0.9rem;
81
+ }
82
+ }
assets/css/screen/3840.css ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (min-width: 3840px) {
7
+ :root {
8
+ --header-height: 5.5rem;
9
+ --footer-height: 7rem;
10
+ --border-radius: 1.5rem;
11
+ --bubble-radius: 1.5rem;
12
+ --prompt-radius: 1.5rem;
13
+ font-size: 1.3rem;
14
+ }
15
+
16
+ .title {
17
+ font-size: clamp(3rem, 2vw, 5rem);
18
+ }
19
+
20
+ .prompts {
21
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
22
+ max-width: 2000px;
23
+ gap: 1.5rem;
24
+ }
25
+
26
+ .prompt-item {
27
+ padding: 1.5rem 1.75rem;
28
+ border-radius: 1.5rem;
29
+ }
30
+
31
+ .bubble {
32
+ padding: 1.5rem 1.75rem;
33
+ font-size: 1.2rem;
34
+ border-radius: 1.5rem;
35
+ }
36
+
37
+ #userInput {
38
+ padding: 1.25rem 1.5rem;
39
+ font-size: 1.2rem;
40
+ }
41
+
42
+ #sendBtn, #stopBtn {
43
+ width: 3.75rem;
44
+ height: 3.75rem;
45
+ }
46
+
47
+ .icon-btn {
48
+ width: 3.5rem;
49
+ height: 3.5rem;
50
+ }
51
+ }
assets/css/screen/480.css ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (max-width: 480px) {
7
+ :root {
8
+ --header-height: 2.75rem;
9
+ --footer-height: 4rem;
10
+ --border-radius: 0.75rem;
11
+ --bubble-radius: 0.75rem;
12
+ --prompt-radius: 0.75rem;
13
+ }
14
+
15
+ .main-header, .chat-header {
16
+ padding: 0.4rem 0.6rem;
17
+ }
18
+
19
+ #chatBox {
20
+ padding: 0.5rem 0.6rem calc(var(--footer-height) + 0.6rem) 0.6rem;
21
+ }
22
+
23
+ #footerForm {
24
+ padding: 0.5rem 0.6rem;
25
+ }
26
+
27
+ #userInput {
28
+ padding: 0.5rem 0.7rem;
29
+ font-size: 0.9rem;
30
+ }
31
+
32
+ #sendBtn, #stopBtn {
33
+ width: 2.25rem;
34
+ height: 2.25rem;
35
+ }
36
+
37
+ .title {
38
+ font-size: clamp(1.2rem, 5vw, 1.8rem);
39
+ margin-bottom: 1rem;
40
+ }
41
+
42
+ .prompts {
43
+ gap: 0.6rem;
44
+ margin-bottom: 1rem;
45
+ }
46
+
47
+ .prompt-item {
48
+ padding: 0.7rem 0.9rem;
49
+ gap: 0.6rem;
50
+ }
51
+
52
+ .icon {
53
+ width: 1rem;
54
+ height: 1rem;
55
+ }
56
+
57
+ .system {
58
+ font-size: 0.7rem;
59
+ margin-top: 1rem;
60
+ }
61
+
62
+ .bubble {
63
+ padding: 0.7rem 0.9rem;
64
+ font-size: 0.85rem;
65
+ border-radius: 0.75rem;
66
+ margin: 0.5rem 0;
67
+ }
68
+
69
+ .chat-title {
70
+ font-size: 0.9rem;
71
+ }
72
+
73
+ .icon-btn {
74
+ padding: 0.35rem;
75
+ width: 2rem;
76
+ height: 2rem;
77
+ }
78
+ }
assets/css/screen/720.css ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (max-width: 767px) {
7
+ :root {
8
+ --header-height: 3rem;
9
+ --footer-height: 4.5rem;
10
+ --border-radius: 0.875rem;
11
+ --bubble-radius: 0.875rem;
12
+ --prompt-radius: 0.875rem;
13
+ }
14
+
15
+ .main-header, .chat-header {
16
+ padding: 0.5rem 0.75rem;
17
+ }
18
+
19
+ #chatBox {
20
+ padding: 0.6rem 0.75rem calc(var(--footer-height) + 0.75rem) 0.75rem;
21
+ }
22
+
23
+ #footerForm {
24
+ padding: 0.6rem 0.75rem;
25
+ }
26
+
27
+ #inputContainer {
28
+ padding: 0.2rem;
29
+ }
30
+
31
+ #userInput {
32
+ padding: 0.6rem 0.8rem;
33
+ font-size: 0.95rem;
34
+ }
35
+
36
+ #sendBtn, #stopBtn {
37
+ width: 2.5rem;
38
+ height: 2.5rem;
39
+ }
40
+
41
+ .title {
42
+ font-size: clamp(1.3rem, 5vw, 2rem);
43
+ margin-bottom: 1.2rem;
44
+ }
45
+
46
+ .prompts {
47
+ grid-template-columns: 1fr;
48
+ gap: 0.75rem;
49
+ margin-bottom: 1.2rem;
50
+ }
51
+
52
+ .prompt-item {
53
+ padding: 0.8rem 1rem;
54
+ gap: 0.7rem;
55
+ }
56
+
57
+ .icon {
58
+ width: 1.1rem;
59
+ height: 1.1rem;
60
+ }
61
+
62
+ .system {
63
+ font-size: 0.75rem;
64
+ margin-top: 1.2rem;
65
+ line-height: 1.5;
66
+ }
67
+
68
+ .bubble {
69
+ padding: 0.8rem 1rem;
70
+ font-size: 0.9rem;
71
+ border-radius: 0.875rem;
72
+ margin: 0.6rem 0;
73
+ }
74
+
75
+ .chat-title {
76
+ font-size: 0.95rem;
77
+ }
78
+
79
+ .chat-controls {
80
+ gap: 0.4rem;
81
+ }
82
+
83
+ .icon-btn {
84
+ padding: 0.4rem;
85
+ width: 2.25rem;
86
+ height: 2.25rem;
87
+ }
88
+ }
assets/css/screen/7680.css ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ @media (min-width: 7680px) {
7
+ :root {
8
+ --header-height: 7rem;
9
+ --footer-height: 9rem;
10
+ --border-radius: 2rem;
11
+ --bubble-radius: 2rem;
12
+ --prompt-radius: 2rem;
13
+ font-size: 1.6rem;
14
+ }
15
+
16
+ .title {
17
+ font-size: clamp(4rem, 1.5vw, 7rem);
18
+ }
19
+
20
+ .prompts {
21
+ grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
22
+ max-width: 3000px;
23
+ gap: 2rem;
24
+ }
25
+
26
+ .prompt-item {
27
+ padding: 2rem 2.25rem;
28
+ border-radius: 2rem;
29
+ }
30
+
31
+ .bubble {
32
+ padding: 2rem 2.25rem;
33
+ font-size: 1.4rem;
34
+ border-radius: 2rem;
35
+ }
36
+
37
+ #userInput {
38
+ padding: 1.5rem 2rem;
39
+ font-size: 1.4rem;
40
+ }
41
+
42
+ #sendBtn, #stopBtn {
43
+ width: 4.5rem;
44
+ height: 4.5rem;
45
+ }
46
+
47
+ .icon-btn {
48
+ width: 4rem;
49
+ height: 4rem;
50
+ }
51
+ }
assets/css/screen/common.css ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ .max-w-screen-xl {
7
+ max-width: min(1280px, 100%);
8
+ margin-left: auto;
9
+ margin-right: auto;
10
+ width: 100%;
11
+ padding-left: 1rem;
12
+ padding-right: 1rem;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ @media (min-width: 640px) {
17
+ .max-w-screen-xl {
18
+ padding-left: 1.5rem;
19
+ padding-right: 1.5rem;
20
+ }
21
+ }
22
+
23
+ @media (min-width: 1024px) {
24
+ .max-w-screen-xl {
25
+ padding-left: 2rem;
26
+ padding-right: 2rem;
27
+ }
28
+ }
29
+
30
+ @media (min-width: 1280px) {
31
+ .max-w-screen-xl {
32
+ padding-left: 3rem;
33
+ padding-right: 3rem;
34
+ }
35
+ }
36
+
37
+ @media (min-width: 1536px) {
38
+ .max-w-screen-xl {
39
+ padding-left: 4rem;
40
+ padding-right: 4rem;
41
+ }
42
+ }
43
+
44
+ @media (min-width: 2000px) {
45
+ .max-w-screen-xl {
46
+ max-width: 1600px;
47
+ padding-left: 5rem;
48
+ padding-right: 5rem;
49
+ }
50
+ }
51
+
52
+ @media (min-width: 3840px) {
53
+ .max-w-screen-xl {
54
+ max-width: 2400px;
55
+ padding-left: 6rem;
56
+ padding-right: 6rem;
57
+ }
58
+ }
59
+
60
+ @media (min-width: 7680px) {
61
+ .max-w-screen-xl {
62
+ max-width: 4000px;
63
+ padding-left: 8rem;
64
+ padding-right: 8rem;
65
+ }
66
+ }
assets/css/style.css ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ *, *::before, *::after {
7
+ box-sizing: border-box;
8
+ margin: 0;
9
+ padding: 0;
10
+ }
11
+
12
+ html, body {
13
+ width: 100%;
14
+ height: 100%;
15
+ overflow-x: hidden;
16
+ font-family: 'Inter', sans-serif;
17
+ font-size: 1rem;
18
+ -webkit-font-smoothing: antialiased;
19
+ -moz-osx-font-smoothing: grayscale;
20
+ }
21
+
22
+ body {
23
+ display: flex;
24
+ flex-direction: column;
25
+ background-color: var(--background-dark);
26
+ color: var(--text-dark);
27
+ overflow: hidden;
28
+ word-wrap: break-word;
29
+ }
30
+
31
+ :root {
32
+ --color-primary: #3b82f6;
33
+ --background-dark: #0f0f0f;
34
+ --background-light: #fff;
35
+ --text-dark: #e5e7eb;
36
+ --text-light: #111;
37
+ --white-line-color: #ffffff;
38
+ --header-height: 3.5rem;
39
+ --footer-height: 5rem;
40
+ --transition-speed: 0.3s;
41
+ --border-radius: 1rem;
42
+ --bubble-radius: 1rem;
43
+ --prompt-radius: 1rem;
44
+ }
45
+
46
+ main {
47
+ flex: 1;
48
+ display: flex;
49
+ flex-direction: column;
50
+ margin-top: var(--header-height);
51
+ height: calc(100vh - var(--header-height));
52
+ overflow: hidden;
53
+ }
54
+
55
+ #initialContent {
56
+ display: flex;
57
+ flex-direction: column;
58
+ align-items: center;
59
+ text-align: center;
60
+ max-width: 100%;
61
+ width: 100%;
62
+ height: 100%;
63
+ padding: 1.5rem 1rem;
64
+ box-sizing: border-box;
65
+ overflow-wrap: break-word;
66
+ word-wrap: break-word;
67
+ word-break: break-word;
68
+ animation: fadeIn 0.8s ease-out forwards;
69
+ }
70
+
71
+ .title {
72
+ font-size: clamp(1.5rem, 4vw, 2.5rem);
73
+ font-weight: 800;
74
+ color: #eaeef8;
75
+ margin-bottom: 1.5rem;
76
+ word-break: break-word;
77
+ overflow-wrap: break-word;
78
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
79
+ animation: slideInUp 0.6s ease-out forwards;
80
+ }
81
+
82
+ .system {
83
+ text-align: center;
84
+ margin-top: 1.5rem;
85
+ font-size: 0.8rem;
86
+ color: #9ca3af;
87
+ word-break: break-word;
88
+ overflow-wrap: break-word;
89
+ max-width: 600px;
90
+ line-height: 1.6;
91
+ animation: fadeIn 1s ease-out 0.6s forwards;
92
+ opacity: 0;
93
+ }
assets/css/webkit.css ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ ::-webkit-scrollbar {
7
+ width: 8px;
8
+ height: 8px;
9
+ }
10
+
11
+ ::-webkit-scrollbar-track {
12
+ background: rgba(255, 255, 255, 0.05);
13
+ border-radius: 4px;
14
+ }
15
+
16
+ ::-webkit-scrollbar-thumb {
17
+ background: rgba(59, 130, 246, 0.5);
18
+ border-radius: 4px;
19
+ }
20
+
21
+ ::-webkit-scrollbar-thumb:hover {
22
+ background: rgba(59, 130, 246, 0.7);
23
+ }
24
+
25
+ * {
26
+ -webkit-tap-highlight-color: transparent;
27
+ }
assets/plugins/loader.js ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+
6
+ // Prism.
7
+ Prism.plugins.autoloader.languages_path = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/';
8
+
9
+ // WebSocket.
10
+ const socket = new WebSocket((window.location.protocol==="https:"?"wss":"ws")+"//"+window.location.host);
11
+
12
+ // UI elements.
13
+ const chatArea = document.getElementById('chatArea');
14
+ const chatBox = document.getElementById('chatBox');
15
+ const initialContent = document.getElementById('initialContent');
16
+ const form = document.getElementById('footerForm');
17
+ const input = document.getElementById('userInput');
18
+ const btn = document.getElementById('sendBtn');
19
+ const stopBtn = document.getElementById('stopBtn');
20
+ const promptItems = document.querySelectorAll('.prompt-item');
21
+ const mainHeader = document.getElementById('mainHeader');
22
+ const chatHeader = document.getElementById('chatHeader');
23
+ const homeBtn = document.getElementById('homeBtn');
24
+ const clearBtn = document.getElementById('clearBtn');
25
+
26
+ // Track state.
27
+ let streamMsg = null;
28
+ let conversationHistory = [];
29
+ let currentAssistantText = "";
30
+
31
+ // Render markdown content.
32
+ function renderMarkdown(el) {
33
+ const raw = el.dataset.text || "";
34
+ const html = marked.parse(raw, {
35
+ gfm: true,
36
+ breaks: true,
37
+ smartLists: true,
38
+ smartypants: false,
39
+ headerIds: false
40
+ });
41
+ el.innerHTML = '<div class="md-content">' + html + '</div>';
42
+ const wrapper = el.querySelector('.md-content');
43
+
44
+ // Wrap tables.
45
+ const tables = wrapper.querySelectorAll('table');
46
+ tables.forEach(t => {
47
+ if (t.parentNode && t.parentNode.classList && t.parentNode.classList.contains('table-wrapper')) return;
48
+ const div = document.createElement('div');
49
+ div.className = 'table-wrapper';
50
+ t.parentNode.insertBefore(div, t);
51
+ div.appendChild(t);
52
+ });
53
+
54
+ // Style horizontal rules.
55
+ const hrs = wrapper.querySelectorAll('hr');
56
+ hrs.forEach(h => {
57
+ if (!h.classList.contains('styled-hr')) {
58
+ h.classList.add('styled-hr');
59
+ }
60
+ });
61
+
62
+ // Highlight code.
63
+ Prism.highlightAllUnder(wrapper);
64
+ }
65
+
66
+ // Chat view.
67
+ function enterChatView() {
68
+ mainHeader.style.display = 'none';
69
+ chatHeader.style.display = 'flex';
70
+ chatHeader.setAttribute('aria-hidden', 'false');
71
+ chatBox.style.display = 'flex';
72
+ initialContent.style.display = 'none';
73
+ }
74
+
75
+ // Home view.
76
+ function leaveChatView() {
77
+ mainHeader.style.display = 'flex';
78
+ chatHeader.style.display = 'none';
79
+ chatHeader.setAttribute('aria-hidden', 'true');
80
+ chatBox.style.display = 'none';
81
+ initialContent.style.display = 'flex';
82
+ }
83
+
84
+ // Chat bubble.
85
+ function addMsg(who, text) {
86
+ const div = document.createElement('div');
87
+ div.className = 'bubble ' + (who==='user' ? 'bubble-user' : 'bubble-assist');
88
+ div.dataset.text = text;
89
+ renderMarkdown(div);
90
+ chatBox.appendChild(div);
91
+ chatBox.style.display='flex';
92
+ chatBox.scrollTop = chatBox.scrollHeight;
93
+ return div;
94
+ }
95
+
96
+ // Clear all chat.
97
+ function clearAllMessages() {
98
+ try { socket.send(JSON.stringify({type:'stop'})); } catch {}
99
+ conversationHistory = [];
100
+ currentAssistantText = "";
101
+ if(streamMsg) {
102
+ const loadingEl = streamMsg.querySelector('.loading');
103
+ if(loadingEl) loadingEl.remove();
104
+ streamMsg = null;
105
+ }
106
+ chatBox.innerHTML = "";
107
+ input.value = "";
108
+ btn.disabled = true;
109
+ stopBtn.style.display = 'none';
110
+ btn.style.display = 'inline-flex';
111
+ enterChatView();
112
+ }
113
+
114
+ // Wait for socket ready.
115
+ function sendWhenReady(msgFn) {
116
+ if (socket.readyState === WebSocket.OPEN) {
117
+ msgFn();
118
+ } else {
119
+ socket.addEventListener('open', function handler() {
120
+ msgFn();
121
+ socket.removeEventListener('open', handler);
122
+ });
123
+ }
124
+ }
125
+
126
+ // Prompts.
127
+ promptItems.forEach(p => {
128
+ p.addEventListener('click', () => {
129
+ input.value = p.dataset.prompt;
130
+ sendWhenReady(submitMessage);
131
+ });
132
+ });
133
+
134
+ // Send user message.
135
+ async function submitMessage() {
136
+ const message = input.value.trim();
137
+ if(!message) return;
138
+ enterChatView();
139
+ addMsg('user', message);
140
+ conversationHistory.push({role: 'user', content: message});
141
+ streamMsg = addMsg('assistant', '');
142
+ const loadingEl = document.createElement('span');
143
+ loadingEl.className = 'loading';
144
+ streamMsg.appendChild(loadingEl);
145
+ stopBtn.style.display = 'inline-flex';
146
+ btn.style.display = 'none';
147
+ input.value='';
148
+ btn.disabled = true;
149
+ try {
150
+ socket.send(JSON.stringify({type:'ask', message, history: conversationHistory}));
151
+ } catch (error) {
152
+ if(streamMsg){
153
+ const loadingEl = streamMsg.querySelector('.loading');
154
+ if(loadingEl) loadingEl.remove();
155
+ streamMsg.dataset.text = error.message || 'An error occurred during the request.';
156
+ renderMarkdown(streamMsg);
157
+ streamMsg.dataset.done='1';
158
+ streamMsg=null;
159
+ }
160
+ btn.style.display = 'inline-flex';
161
+ stopBtn.style.display = 'none';
162
+ }
163
+ }
164
+
165
+ // Submit.
166
+ form.addEventListener('submit', e => {
167
+ e.preventDefault();
168
+ submitMessage();
169
+ });
170
+
171
+ // Stop.
172
+ stopBtn.addEventListener('click', () => {
173
+ stopBtn.style.pointerEvents = 'none';
174
+ try { socket.send(JSON.stringify({type:'stop'})); } catch {}
175
+ });
176
+
177
+ // Home.
178
+ homeBtn.addEventListener('click', () => {
179
+ leaveChatView();
180
+ });
181
+
182
+ // Clear messages.
183
+ clearBtn.addEventListener('click', () => {
184
+ clearAllMessages();
185
+ });
186
+
187
+ // Socket messages.
188
+ socket.onmessage = (e) => {
189
+ const data = JSON.parse(e.data);
190
+ if(data.type==='chunk') {
191
+ if(streamMsg) {
192
+ const loadingEl = streamMsg.querySelector('.loading');
193
+ if(loadingEl) loadingEl.remove();
194
+ streamMsg.dataset.text += data.chunk;
195
+ currentAssistantText = streamMsg.dataset.text ||"";
196
+ renderMarkdown(streamMsg);
197
+ chatBox.scrollTop = chatBox.scrollHeight;
198
+ }
199
+ } else if(data.type==='end' || data.type==='error') {
200
+ if(streamMsg){
201
+ const text = streamMsg.dataset.text || "";
202
+ const loadingEl = streamMsg.querySelector('.loading');
203
+ if(loadingEl) loadingEl.remove();
204
+ streamMsg.dataset.done='1';
205
+ if(data.type==='error') {
206
+ streamMsg.dataset.text = data.error || 'An error occurred during the request.';
207
+ renderMarkdown(streamMsg);
208
+ } else {
209
+ conversationHistory.push({role: 'assistant', content: text});
210
+ }
211
+ streamMsg = null;
212
+ }
213
+ btn.style.display = 'inline-flex';
214
+ stopBtn.style.display = 'none';
215
+ stopBtn.style.pointerEvents = 'auto';
216
+ }
217
+ };
218
+
219
+ // Enable send button only if input has text.
220
+ input.addEventListener('input', () => {
221
+ btn.disabled= input.value.trim() === '';
222
+ });
223
+
224
+ // Animations.
225
+ document.addEventListener('DOMContentLoaded', function() {
226
+ AOS.init({
227
+ duration: 800,
228
+ easing: 'ease-out-cubic',
229
+ once: true,
230
+ offset: 50
231
+ });
232
+ });
index.js DELETED
@@ -1,172 +0,0 @@
1
- //
2
- // SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
- // SPDX-License-Identifier: Apache-2.0
4
- //
5
-
6
- import express from "express";
7
- import http from "http";
8
- import { WebSocketServer } from "ws";
9
- import fetch from "node-fetch";
10
- import cookieParser from "cookie-parser";
11
- import path from "path";
12
-
13
- const app = express();
14
- const server = http.createServer(app);
15
- const wss = new WebSocketServer({ server });
16
-
17
- const OPENAI_API_BASE_URL = process.env.OPENAI_API_BASE_URL || "";
18
- const OPENAI_API_KEY = process.env.OPENAI_API_KEY || "";
19
- const UMINT = process.env.UMINT || ``;
20
-
21
- // Use cookies.
22
- app.use(cookieParser());
23
-
24
- // Root.
25
- app.get("/", (_req, res) => res.send(UMINT));
26
-
27
- // SEO.
28
- app.get("/robots.txt", (_req, res) => {
29
- res.sendFile(path.resolve("src/crawlers/robots.txt"));
30
- });
31
- app.get("/sitemap.xml", (_req, res) => {
32
- res.sendFile(path.resolve("src/crawlers/sitemap.xml"));
33
- });
34
- app.get("/google15aba15fe250d693.html", (_req, res) => {
35
- res.sendFile(path.resolve("src/webmasters/google.html"));
36
- });
37
- app.get("/BingSiteAuth.xml", (_req, res) => {
38
- res.sendFile(path.resolve("src/webmasters/bing.xml"));
39
- });
40
-
41
- // Favicon.
42
- app.get("/assets/images/favicon.ico", (_req, res) => {
43
- res.sendFile(path.resolve("assets/images/favicon.ico"));
44
- });
45
-
46
- // Handle WebSocket connections.
47
- wss.on("connection", (ws) => {
48
- let currentAbortController = null;
49
-
50
- // Send messages to client.
51
- const sendToClient = (type, payload) => {
52
- ws.send(JSON.stringify({ type, ...payload }));
53
- };
54
-
55
- // Send logs to client.
56
- const sendError = (message) => {
57
- sendToClient("error", { error: message });
58
- };
59
-
60
- // Make a request.
61
- const streamRequest = async (messages, retries = 3) => {
62
- for (let attempt = 1; attempt <= retries; attempt++) {
63
- currentAbortController = new AbortController();
64
- const signal = currentAbortController.signal;
65
-
66
- try {
67
- const response = await fetch(OPENAI_API_BASE_URL, {
68
- method: "POST",
69
- headers: {
70
- "Content-Type": "application/json",
71
- "Authorization": `Bearer ${OPENAI_API_KEY}`,
72
- },
73
- body: JSON.stringify({
74
- model: "gpt-4.1-nano",
75
- messages,
76
- stream: true,
77
- private: true,
78
- isPrivate: true
79
- }),
80
- signal
81
- });
82
-
83
- if (response.status === 502) {
84
- if (attempt === retries) {
85
- sendError(
86
- "The server is currently busy. Please wait a moment or try again later."
87
- );
88
- return;
89
- }
90
- continue;
91
- }
92
-
93
- if (!response.ok) {
94
- const errText = await response.text();
95
- sendError(`HTTP ${response.status}: ${response.statusText} - ${errText}`);
96
- return;
97
- }
98
-
99
- if (!response.body) {
100
- sendError("Response body is empty.");
101
- return;
102
- }
103
-
104
- let buffer = "";
105
- for await (const chunk of response.body) {
106
- if (signal.aborted) {
107
- sendToClient("end", {});
108
- return;
109
- }
110
- buffer += chunk.toString();
111
- let idx;
112
- while ((idx = buffer.indexOf("\n")) !== -1) {
113
- const line = buffer.slice(0, idx).trim();
114
- buffer = buffer.slice(idx + 1);
115
- if (line.startsWith("data: ")) {
116
- const dataStr = line.substring(6).trim();
117
- if (!dataStr || dataStr === "[DONE]") continue;
118
- try {
119
- const parsed = JSON.parse(dataStr);
120
- const part = parsed?.choices?.[0]?.delta?.content;
121
- if (part) sendToClient("chunk", { chunk: part });
122
- } catch (err) {
123
- sendError(`Parse error: ${err.message}`);
124
- }
125
- }
126
- }
127
- }
128
-
129
- sendToClient("end", {});
130
- return;
131
- } catch (err) {
132
- if (signal.aborted) {
133
- sendToClient("end", {});
134
- return;
135
- }
136
- if (attempt === retries) {
137
- sendError(err.message || "Unknown error.");
138
- }
139
- }
140
- }
141
- };
142
-
143
- // Handle messages from client.
144
- ws.on("message", async (msg) => {
145
- try {
146
- const data = JSON.parse(msg.toString());
147
-
148
- if (data.type === "stop") {
149
- if (currentAbortController) currentAbortController.abort();
150
- sendToClient("end", {});
151
- return;
152
- }
153
-
154
- const message = data.message;
155
- const history = data.history || [];
156
- const setupMessages = [...history, { role: "user", content: message }];
157
- await streamRequest(setupMessages);
158
-
159
- } catch (err) {
160
- sendError(err.message || "An unknown error occurred.");
161
- if (currentAbortController) currentAbortController.abort();
162
- }
163
- });
164
-
165
- // Abort on WebSocket close.
166
- ws.on("close", () => {
167
- if (currentAbortController) currentAbortController.abort();
168
- });
169
- });
170
-
171
- const PORT = process.env.PORT || 7860;
172
- server.listen(PORT);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mapping.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+
6
+ import express from "express";
7
+ import http from "http";
8
+ import cookieParser from "cookie-parser";
9
+ import path from "path";
10
+ import { PORT } from "./src/backend/config.js";
11
+ import attachWss from "./src/backend/request.js";
12
+ import { fileURLToPath } from "url";
13
+
14
+ const app = express();
15
+ const server = http.createServer(app);
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+
19
+ // Cookies.
20
+ app.use(cookieParser());
21
+
22
+ // Root.
23
+ app.get("/", (_req, res) => {
24
+ res.sendFile(path.resolve(__dirname, "src/frontend/loader.html"));
25
+ });
26
+
27
+ // Assets.
28
+ app.use("/assets", express.static(path.resolve("assets")));
29
+
30
+ // SEO.
31
+ app.get("/robots.txt", (_req, res) => {
32
+ res.sendFile(path.resolve("src/crawlers/robots.txt"));
33
+ }); // https://umint-ai.hf.space/robots.txt
34
+
35
+ app.get("/sitemap.xml", (_req, res) => {
36
+ res.sendFile(path.resolve("src/crawlers/sitemap.xml"));
37
+ }); // https://umint-ai.hf.space/sitemap.xml
38
+
39
+ app.get("/google15aba15fe250d693.html", (_req, res) => {
40
+ res.sendFile(path.resolve("src/webmasters/google.html"));
41
+ }); // https://umint-ai.hf.space/google15aba15fe250d693.html
42
+
43
+ app.get("/BingSiteAuth.xml", (_req, res) => {
44
+ res.sendFile(path.resolve("src/webmasters/bing.xml"));
45
+ }); // https://umint-ai.hf.space/BingSiteAuth.xml
46
+
47
+ // Attach WebSocket server.
48
+ attachWss(server);
49
+
50
+ server.listen(PORT);
package.json CHANGED
@@ -1,10 +1,10 @@
1
  {
2
  "name": "UltimaX Intelligence",
3
- "version": "0.0.2",
4
  "type": "module",
5
- "main": "index.js",
6
  "scripts": {
7
- "start": "node index.js"
8
  },
9
  "dependencies": {
10
  "express": "latest",
@@ -12,6 +12,7 @@
12
  "ws": "latest",
13
  "node-fetch": "latest",
14
  "cookie-parser": "latest",
15
- "path": "latest"
 
16
  }
17
  }
 
1
  {
2
  "name": "UltimaX Intelligence",
3
+ "version": "0.0.3",
4
  "type": "module",
5
+ "main": "mapping.js",
6
  "scripts": {
7
+ "start": "node mapping.js"
8
  },
9
  "dependencies": {
10
  "express": "latest",
 
12
  "ws": "latest",
13
  "node-fetch": "latest",
14
  "cookie-parser": "latest",
15
+ "path": "latest",
16
+ "url": "latest"
17
  }
18
  }
src/backend/config.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+
6
+ // Server port.
7
+ export const PORT = process.env.PORT;
8
+ // API endpoint.
9
+ export const OPENAI_API_BASE_URL = process.env.OPENAI_API_BASE_URL;
10
+ // API key.
11
+ export const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
src/backend/request.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ //
5
+
6
+ import { WebSocketServer } from "ws";
7
+ import fetch from "node-fetch";
8
+ import {
9
+ OPENAI_API_BASE_URL,
10
+ OPENAI_API_KEY
11
+ } from "./config.js";
12
+
13
+ export default function attachWss(server) {
14
+ const wss = new WebSocketServer({ server });
15
+
16
+ // Handle WebSocket connections.
17
+ wss.on("connection", (ws) => {
18
+ let currentAbortController = null;
19
+
20
+ // Send messages to client.
21
+ const sendToClient = (type, payload) => {
22
+ ws.send(JSON.stringify({ type, ...payload }));
23
+ };
24
+
25
+ // Send logs to client.
26
+ const sendError = (message) => {
27
+ sendToClient("error", { error: message });
28
+ };
29
+
30
+ // Make a request.
31
+ const streamRequest = async (messages, retries = 3) => {
32
+ for (let attempt = 1; attempt <= retries; attempt++) {
33
+ currentAbortController = new AbortController();
34
+ const signal = currentAbortController.signal;
35
+
36
+ try {
37
+ const response = await fetch(OPENAI_API_BASE_URL, {
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ "Authorization": `Bearer ${OPENAI_API_KEY}`,
42
+ },
43
+ body: JSON.stringify({
44
+ model: "gpt-4.1-nano",
45
+ messages,
46
+ stream: true,
47
+ private: true,
48
+ isPrivate: true
49
+ }),
50
+ signal
51
+ });
52
+
53
+ if (response.status === 502) {
54
+ if (attempt === retries) {
55
+ sendError(
56
+ "The server is currently busy. Please wait a moment or try again later."
57
+ );
58
+ return;
59
+ }
60
+ continue;
61
+ }
62
+
63
+ if (!response.ok) {
64
+ const errText = await response.text();
65
+ sendError(`HTTP ${response.status}: ${response.statusText} - ${errText}`);
66
+ return;
67
+ }
68
+
69
+ if (!response.body) {
70
+ sendError("Response body is empty.");
71
+ return;
72
+ }
73
+
74
+ let buffer = "";
75
+ for await (const chunk of response.body) {
76
+ if (signal.aborted) {
77
+ sendToClient("end", {});
78
+ return;
79
+ }
80
+ buffer += chunk.toString();
81
+ let idx;
82
+ while ((idx = buffer.indexOf("\n")) !== -1) {
83
+ const line = buffer.slice(0, idx).trim();
84
+ buffer = buffer.slice(idx + 1);
85
+ if (line.startsWith("data: ")) {
86
+ const dataStr = line.substring(6).trim();
87
+ if (!dataStr || dataStr === "[DONE]") continue;
88
+ try {
89
+ const parsed = JSON.parse(dataStr);
90
+ const part = parsed?.choices?.[0]?.delta?.content;
91
+ if (part) sendToClient("chunk", { chunk: part });
92
+ } catch (err) {
93
+ sendError(`Parse error: ${err.message}`);
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ sendToClient("end", {});
100
+ return;
101
+ } catch (err) {
102
+ if (signal.aborted) {
103
+ sendToClient("end", {});
104
+ return;
105
+ }
106
+ if (attempt === retries) {
107
+ sendError(err.message || "Unknown error.");
108
+ }
109
+ }
110
+ }
111
+ };
112
+
113
+ // Handle messages from client.
114
+ ws.on("message", async (msg) => {
115
+ try {
116
+ const data = JSON.parse(msg.toString());
117
+
118
+ if (data.type === "stop") {
119
+ if (currentAbortController) currentAbortController.abort();
120
+ sendToClient("end", {});
121
+ return;
122
+ }
123
+
124
+ const message = data.message;
125
+ const history = data.history || [];
126
+ const setupMessages = [...history, { role: "user", content: message }];
127
+ await streamRequest(setupMessages);
128
+
129
+ } catch (err) {
130
+ sendError(err.message || "An unknown error occurred.");
131
+ if (currentAbortController) currentAbortController.abort();
132
+ }
133
+ });
134
+
135
+ // Abort on WebSocket close.
136
+ ws.on("close", () => {
137
+ if (currentAbortController) currentAbortController.abort();
138
+ });
139
+ });
140
+ }
src/crawlers/sitemap.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <!--
3
  SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
4
- SPDX-License-Identifier: MIT
5
  -->
6
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
7
  <url>
 
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <!--
3
  SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
4
+ SPDX-License-Identifier: Apache-2.0
5
  -->
6
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
7
  <url>
src/frontend/loader.html ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--
2
+ SPDX-FileCopyrightText: Hadad <hadad@linuxmail.org>
3
+ SPDX-License-Identifier: Apache-2.0
4
+ -->
5
+
6
+ <!DOCTYPE html>
7
+ <html lang="en" class="dark-theme">
8
+ <head>
9
+ <meta charset="UTF-8" />
10
+ <meta name="viewport"
11
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0,
12
+ user-scalable=no, viewport-fit=cover" />
13
+ <meta name="robots" content="index, follow" />
14
+ <title>UltimaX Intelligence</title>
15
+
16
+ <link rel="sitemap" type="application/xml" title="Sitemap" href="/sitemap.xml" />
17
+
18
+ <meta name="author" content="Hadad Darajat" />
19
+ <meta name="description"
20
+ content="UltimaX Intelligence is a free AI platform unifying multiple
21
+ premium AI models with an intuitive ChatGPT-like interface.
22
+ Powered by Pollinations open-source AI and integrated with
23
+ OpenWebUI, it offers advanced features, no cost, no
24
+ registration, and ensures user privacy with temporary,
25
+ unsaved conversations." />
26
+ <meta name="keywords"
27
+ content="UltimaX Intelligence, free AI platform, premium AI models,
28
+ Pollinations AI, open-source AI, Open-WebUI integration,
29
+ ChatGPT alternative, AI tools free, no registration AI,
30
+ AI privacy, temporary AI conversations, AI platform no login,
31
+ advanced AI features, AI community powered,
32
+ seamless AI experience" />
33
+
34
+ <!-- Open Graph -->
35
+ <meta property="og:domain" content="umint-ai.hf.space" />
36
+ <meta property="og:url" content="https://umint-ai.hf.space" />
37
+ <meta property="og:title" content="UltimaX Intelligence" />
38
+ <meta property="og:description"
39
+ content="UltimaX Intelligence is a free AI platform unifying multiple
40
+ premium AI models with an intuitive ChatGPT-like interface.
41
+ Powered by Pollinations open-source AI and integrated with
42
+ OpenWebUI, it offers advanced features, no cost, no
43
+ registration, and ensures user privacy with temporary,
44
+ unsaved conversations." />
45
+ <meta property="og:image"
46
+ content="https://cdn-uploads.huggingface.co/production/uploads/686e28b405d4ddcdd96adeb2/i9iufR3L-rgj39mk_B9QW.jpeg" />
47
+
48
+ <!-- Twitter -->
49
+ <meta name="twitter:card" content="summary_large_image" />
50
+ <meta name="twitter:domain" content="umint-ai.hf.space" />
51
+ <meta name="twitter:url" content="https://umint-ai.hf.space" />
52
+ <meta name="twitter:title" content="UltimaX Intelligence" />
53
+ <meta name="twitter:description"
54
+ content="UltimaX Intelligence is a free AI platform unifying multiple
55
+ premium AI models with an intuitive ChatGPT-like interface.
56
+ Powered by Pollinations open-source AI and integrated with
57
+ OpenWebUI, it offers advanced features, no cost, no
58
+ registration, and ensures user privacy with temporary,
59
+ unsaved conversations." />
60
+ <meta name="twitter:image"
61
+ content="https://cdn-uploads.huggingface.co/production/uploads/686e28b405d4ddcdd96adeb2/i9iufR3L-rgj39mk_B9QW.jpeg" />
62
+
63
+ <!-- Favicon -->
64
+ <link rel="icon" href="/assets/images/favicon.ico" type="image/x-icon" />
65
+
66
+ <!-- Fonts & Styles -->
67
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
68
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap"
69
+ rel="stylesheet" />
70
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
71
+ rel="stylesheet" />
72
+ <script src="https://cdn.tailwindcss.com"></script>
73
+
74
+ <!-- Markdown & Syntax Highlight -->
75
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
76
+ <link rel="stylesheet"
77
+ href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" />
78
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
79
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
80
+
81
+ <!-- Animations -->
82
+ <script src="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js"></script>
83
+ <link href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css" rel="stylesheet" />
84
+
85
+ <!-- Carousel -->
86
+ <script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js"></script>
87
+ <link rel="stylesheet"
88
+ href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css" />
89
+
90
+ <!-- Smooth Scroll -->
91
+ <script src="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.4/dist/locomotive-scroll.min.js"></script>
92
+ <link rel="stylesheet"
93
+ href="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.4/dist/locomotive-scroll.min.css" />
94
+
95
+ <!-- Styles -->
96
+ <link rel="stylesheet" href="/assets/css/animation/style.css" />
97
+ <link rel="stylesheet" href="/assets/css/button.css" />
98
+ <link rel="stylesheet" href="/assets/css/chat/bubble.css" />
99
+ <link rel="stylesheet" href="/assets/css/chat/markdown.css" />
100
+ <link rel="stylesheet" href="/assets/css/chat/style.css" />
101
+ <link rel="stylesheet" href="/assets/css/footer.css" />
102
+ <link rel="stylesheet" href="/assets/css/header.css" />
103
+ <link rel="stylesheet" href="/assets/css/icon.css" />
104
+ <link rel="stylesheet" href="/assets/css/input.css" />
105
+ <link rel="stylesheet" href="/assets/css/logo.css" />
106
+ <link rel="stylesheet" href="/assets/css/prompts.css" />
107
+ <link rel="stylesheet" href="/assets/css/screen/1200.css" />
108
+ <link rel="stylesheet" href="/assets/css/screen/2000.css" />
109
+ <link rel="stylesheet" href="/assets/css/screen/320.css" />
110
+ <link rel="stylesheet" href="/assets/css/screen/360.css" />
111
+ <link rel="stylesheet" href="/assets/css/screen/3840.css" />
112
+ <link rel="stylesheet" href="/assets/css/screen/480.css" />
113
+ <link rel="stylesheet" href="/assets/css/screen/720.css" />
114
+ <link rel="stylesheet" href="/assets/css/screen/7680.css" />
115
+ <link rel="stylesheet" href="/assets/css/screen/common.css" />
116
+ <link rel="stylesheet" href="/assets/css/style.css" />
117
+ <link rel="stylesheet" href="/assets/css/webkit.css" />
118
+ </head>
119
+ <body>
120
+ <!-- Header -->
121
+ <header class="main-header" id="mainHeader">
122
+ <div class="logo d-flex align-items-center">
123
+ <a id="toggleLink"
124
+ class="icon-btn"
125
+ aria-label="LinkedIn"
126
+ title="Hadad Darajat"
127
+ href="https://linkedin.com/in/hadadrjt"
128
+ target="_blank"
129
+ rel="noopener noreferrer">
130
+ <span class="linkedin"></span>
131
+ </a>
132
+ </div>
133
+ </header>
134
+
135
+ <!-- Chat Header -->
136
+ <header class="chat-header" id="chatHeader" aria-hidden="true">
137
+ <button id="homeBtn"
138
+ class="icon-btn"
139
+ aria-label="Back to Home"
140
+ title="Back to Home">
141
+ <svg width="20" height="20"
142
+ viewBox="0 0 24 24"
143
+ fill="none"
144
+ stroke="currentColor"
145
+ stroke-width="1.8"
146
+ stroke-linecap="round"
147
+ stroke-linejoin="round"
148
+ xmlns="http://www.w3.org/2000/svg">
149
+ <path d="M3 11.5L12 4l9 7.5" />
150
+ <path d="M5 21V11.5h14V21" />
151
+ </svg>
152
+ </button>
153
+
154
+ <div class="chat-title" id="chatTitle">Demo Playground</div>
155
+
156
+ <div class="chat-controls">
157
+ <button id="clearBtn"
158
+ class="icon-btn"
159
+ aria-label="Clear All Messages"
160
+ title="Clear All Messages">
161
+ <svg width="20" height="20"
162
+ viewBox="0 0 24 24"
163
+ fill="none"
164
+ stroke="currentColor"
165
+ stroke-width="1.6"
166
+ stroke-linecap="round"
167
+ stroke-linejoin="round"
168
+ xmlns="http://www.w3.org/2000/svg">
169
+ <path d="M3 6h18" />
170
+ <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
171
+ <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
172
+ <path d="M10 11v6" />
173
+ <path d="M14 11v6" />
174
+ </svg>
175
+ </button>
176
+
177
+ <a href="https://umint-openwebui.hf.space"
178
+ target="_blank"
179
+ rel="noopener noreferrer"
180
+ class="icon-btn"
181
+ aria-label="OpenWebUI"
182
+ title="OpenWebUI">
183
+ <svg width="20" height="20"
184
+ viewBox="0 0 24 24"
185
+ fill="none"
186
+ stroke="currentColor"
187
+ stroke-width="1.8"
188
+ stroke-linecap="round"
189
+ stroke-linejoin="round"
190
+ xmlns="http://www.w3.org/2000/svg">
191
+ <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
192
+ <path d="M15 3h6v6" />
193
+ <path d="M10 14 21 3" />
194
+ </svg>
195
+ </a>
196
+ </div>
197
+ </header>
198
+
199
+ <!-- Main Content -->
200
+ <main>
201
+ <div class="flex-1 flex flex-col h-full max-w-screen-xl w-full mx-auto">
202
+ <div id="chatArea" class="flex-1" aria-live="polite">
203
+ <div id="initialContent"
204
+ class="flex flex-col items-center justify-center text-center"
205
+ style="width:100%; height:100%;">
206
+ <div class="title mb-4 gradient-text">
207
+ How can I help you today?
208
+ </div>
209
+
210
+ <!-- Prompts -->
211
+ <div class="prompts w-full max-w-md mx-auto grid gap-2"
212
+ style="width:100%;">
213
+ <div class="prompt-item"
214
+ data-prompt="How far away is the sun from Earth?"
215
+ style="word-break: break-word;">
216
+ <svg class="icon"
217
+ viewBox="0 0 24 24"
218
+ fill="none"
219
+ stroke="currentColor">
220
+ <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M18.66 18.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M18.66 5.34l1.41-1.41"
221
+ stroke-width="2"
222
+ stroke-linecap="round"
223
+ stroke-linejoin="round" />
224
+ <circle cx="12" cy="12" r="4" stroke-width="2" />
225
+ </svg>
226
+ <span>How far away is the sun from Earth?</span>
227
+ </div>
228
+
229
+ <div class="prompt-item"
230
+ data-prompt="Create complex python code, anything."
231
+ style="word-break: break-word;">
232
+ <svg class="icon"
233
+ viewBox="0 0 24 24"
234
+ fill="none"
235
+ stroke="currentColor">
236
+ <path d="M4 7h16M4 12h16M4 17h16"
237
+ stroke-width="2"
238
+ stroke-linecap="round"
239
+ stroke-linejoin="round" />
240
+ </svg>
241
+ <span>Create complex python code.</span>
242
+ </div>
243
+
244
+ <div class="prompt-item"
245
+ data-prompt="How many R’s are in strawberry?"
246
+ style="word-break: break-word;">
247
+ <svg class="icon"
248
+ viewBox="0 0 24 24"
249
+ fill="none"
250
+ stroke="currentColor">
251
+ <path d="M3 12h18M12 3v18"
252
+ stroke-width="2"
253
+ stroke-linecap="round"
254
+ stroke-linejoin="round" />
255
+ </svg>
256
+ <span>How many R’s are in strawberry?</span>
257
+ </div>
258
+
259
+ <div class="prompt-item"
260
+ data-prompt="Suggest a random prompt."
261
+ style="word-break: break-word;">
262
+ <svg class="icon"
263
+ viewBox="0 0 24 24"
264
+ fill="none"
265
+ stroke="currentColor">
266
+ <path d="M12 3v18M7 12h10"
267
+ stroke-width="2"
268
+ stroke-linecap="round"
269
+ stroke-linejoin="round" />
270
+ </svg>
271
+ <span>Suggest a random prompt.</span>
272
+ </div>
273
+ </div>
274
+
275
+ <p class="system mt-4 text-sm text-gray-400"
276
+ style="word-wrap:break-word;">
277
+ Demo only!
278
+ <a href="https://umint-openwebui.hf.space"
279
+ style="color: #3b82f6;"
280
+ target="_blank">Click here</a>
281
+ to continue.<br>
282
+ Premium AI, all in one tools, and website builder.<br>
283
+ Free, no cost at all.
284
+ </p>
285
+ </div>
286
+ </div>
287
+
288
+ <div id="chatBox"
289
+ class="hidden flex-col"
290
+ aria-live="polite"></div>
291
+
292
+ <!-- Footer Form -->
293
+ <form id="footerForm"
294
+ class="flex p-3 bg-transparent"
295
+ autocomplete="off"
296
+ style="position: relative; margin-top: auto; width: 100%;">
297
+ <div id="inputContainer">
298
+ <input type="text"
299
+ id="userInput"
300
+ placeholder="Ask anything..."
301
+ required
302
+ style="word-break:break-word;" />
303
+ <div id="rightIconGroup">
304
+ <button type="submit"
305
+ id="sendBtn"
306
+ disabled
307
+ aria-label="Send">
308
+ <svg id="sendIcon"
309
+ xmlns="http://www.w3.org/2000/svg"
310
+ fill="none"
311
+ viewBox="0 0 24 24"
312
+ stroke="currentColor">
313
+ <path stroke-linecap="round"
314
+ stroke-linejoin="round"
315
+ stroke-width="2"
316
+ d="M14 5l7 7-7 7M3 12h11" />
317
+ </svg>
318
+ </button>
319
+ <button id="stopBtn"
320
+ class="icon-btn"
321
+ aria-label="Stop"
322
+ title="Stop">
323
+ <svg width="20"
324
+ height="20"
325
+ viewBox="0 0 24 24"
326
+ fill="white"
327
+ xmlns="http://www.w3.org/2000/svg">
328
+ <rect x="6" y="6"
329
+ width="12"
330
+ height="12"
331
+ rx="2"
332
+ fill="white" />
333
+ </svg>
334
+ </button>
335
+ </div>
336
+ </div>
337
+ </form>
338
+ </div>
339
+ </main>
340
+
341
+ <!-- Plugins -->
342
+ <script src="/assets/plugins/loader.js"></script>
343
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
344
+ </body>
345
+ </html>