SolarumAsteridion commited on
Commit
7dfe2c3
·
verified ·
1 Parent(s): 77ed0b7

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +268 -677
index.html CHANGED
@@ -4,73 +4,20 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Neon Exam Countdown</title>
7
- <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Orbitron:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
8
  <style>
9
  * { margin: 0; padding: 0; box-sizing: border-box; }
10
-
11
- :root {
12
- --neon-pink: #FF006E;
13
- --neon-blue: #00D9FF;
14
- --neon-purple: #8B39FF;
15
- --neon-green: #39FF14;
16
- --neon-yellow: #FFFF00;
17
- --dark-bg: #0A0A0F;
18
- }
19
-
20
  body {
21
- font-family: 'Space Grotesk', sans-serif;
22
- background: var(--dark-bg);
23
  min-height: 100vh;
24
  color: #fff;
25
  overflow-x: hidden;
26
- position: relative;
27
- }
28
-
29
- /* Animated gradient background */
30
- body::before {
31
- content: '';
32
- position: fixed;
33
- top: 0;
34
- left: 0;
35
- width: 100%;
36
- height: 100%;
37
- background:
38
- radial-gradient(circle at 20% 80%, rgba(255, 0, 110, 0.1) 0%, transparent 50%),
39
- radial-gradient(circle at 80% 20%, rgba(0, 217, 255, 0.1) 0%, transparent 50%),
40
- radial-gradient(circle at 40% 40%, rgba(139, 57, 255, 0.1) 0%, transparent 50%),
41
- radial-gradient(circle at 90% 70%, rgba(57, 255, 20, 0.05) 0%, transparent 50%);
42
- animation: gradientShift 15s ease infinite;
43
- z-index: 0;
44
- }
45
-
46
- @keyframes gradientShift {
47
- 0%, 100% { transform: rotate(0deg) scale(1); }
48
- 33% { transform: rotate(120deg) scale(1.1); }
49
- 66% { transform: rotate(240deg) scale(1.05); }
50
- }
51
-
52
- /* Grid background */
53
- body::after {
54
- content: '';
55
- position: fixed;
56
- top: 0;
57
- left: 0;
58
- width: 100%;
59
- height: 100%;
60
- background-image:
61
- linear-gradient(rgba(0, 217, 255, 0.03) 1px, transparent 1px),
62
- linear-gradient(90deg, rgba(0, 217, 255, 0.03) 1px, transparent 1px);
63
- background-size: 50px 50px;
64
- animation: gridMove 10s linear infinite;
65
- z-index: 0;
66
- }
67
-
68
- @keyframes gridMove {
69
- 0% { transform: translate(0, 0); }
70
- 100% { transform: translate(50px, 50px); }
71
- }
72
-
73
- /* Enhanced particles */
74
  .particles {
75
  position: fixed;
76
  top: 0;
@@ -79,347 +26,167 @@
79
  height: 100%;
80
  overflow: hidden;
81
  z-index: 1;
 
82
  }
83
-
84
  .particle {
85
  position: absolute;
 
 
 
86
  border-radius: 50%;
87
- pointer-events: none;
88
- }
89
-
90
- .particle.orb {
91
- width: 6px;
92
- height: 6px;
93
- background: radial-gradient(circle, var(--neon-blue) 0%, transparent 70%);
94
- box-shadow: 0 0 10px var(--neon-blue), 0 0 20px var(--neon-blue);
95
- animation: floatOrb 20s infinite linear;
96
- }
97
-
98
- .particle.star {
99
- width: 2px;
100
- height: 2px;
101
- background: white;
102
- box-shadow: 0 0 6px white;
103
- animation: twinkle 3s infinite;
104
- }
105
-
106
- @keyframes floatOrb {
107
- from {
108
- transform: translateY(100vh) translateX(0) scale(0);
109
- opacity: 0;
110
- }
111
- 10% {
112
- opacity: 1;
113
- transform: translateY(90vh) translateX(10px) scale(1);
114
- }
115
- 90% {
116
- opacity: 1;
117
- transform: translateY(10vh) translateX(-10px) scale(1);
118
- }
119
- to {
120
- transform: translateY(-100vh) translateX(100px) scale(0);
121
- opacity: 0;
122
- }
123
- }
124
-
125
- @keyframes twinkle {
126
- 0%, 100% { opacity: 0; transform: scale(0.5); }
127
- 50% { opacity: 1; transform: scale(1); }
128
- }
129
-
130
- .container {
131
- max-width: 1400px;
132
- margin: 0 auto;
133
- padding: 2rem;
134
- position: relative;
135
- z-index: 2;
136
  }
137
 
138
- /* Enhanced header */
 
139
  .header {
140
  display: flex;
141
  justify-content: space-between;
142
  align-items: center;
143
- margin-bottom: 4rem;
144
- padding: 2rem 0;
145
- position: relative;
146
  }
147
-
148
- .header::after {
149
- content: '';
150
- position: absolute;
151
- bottom: 0;
152
- left: 50%;
153
- transform: translateX(-50%);
154
- width: 100%;
155
- height: 1px;
156
- background: linear-gradient(90deg,
157
- transparent,
158
- var(--neon-blue) 20%,
159
- var(--neon-pink) 50%,
160
- var(--neon-purple) 80%,
161
- transparent);
162
- animation: lineGlow 3s ease-in-out infinite;
163
- }
164
-
165
- @keyframes lineGlow {
166
- 0%, 100% { opacity: 0.3; }
167
- 50% { opacity: 1; }
168
- }
169
-
170
  h1 {
171
- font-family: 'Orbitron', monospace;
172
- font-size: 3.5rem;
173
- font-weight: 900;
174
- text-transform: uppercase;
175
  letter-spacing: 3px;
176
- background: linear-gradient(135deg,
177
- var(--neon-blue) 0%,
178
- var(--neon-pink) 25%,
179
- var(--neon-purple) 50%,
180
- var(--neon-green) 75%,
181
- var(--neon-blue) 100%);
182
- background-size: 300% 300%;
183
  -webkit-background-clip: text;
184
  -webkit-text-fill-color: transparent;
185
- background-clip: text;
186
- animation: gradientFlow 4s ease infinite;
187
- filter: drop-shadow(0 0 30px rgba(0, 217, 255, 0.5))
188
- drop-shadow(0 0 60px rgba(255, 0, 110, 0.3));
189
- }
190
-
191
- @keyframes gradientFlow {
192
- 0% { background-position: 0% 50%; }
193
- 50% { background-position: 100% 50%; }
194
- 100% { background-position: 0% 50%; }
195
  }
196
 
197
- /* Enhanced settings button */
198
  .settings-btn {
199
- width: 60px;
200
- height: 60px;
201
- background: linear-gradient(135deg,
202
- rgba(0, 217, 255, 0.1) 0%,
203
- rgba(255, 0, 110, 0.1) 100%);
204
- backdrop-filter: blur(20px);
205
- border: 2px solid transparent;
206
- background-origin: border-box;
207
- background-clip: padding-box, border-box;
208
- border-image: linear-gradient(135deg, var(--neon-blue), var(--neon-pink)) 1;
209
- border-radius: 16px;
210
  display: flex;
211
  align-items: center;
212
  justify-content: center;
213
  cursor: pointer;
214
- transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
215
- position: relative;
216
- overflow: hidden;
217
- }
218
-
219
- .settings-btn::before {
220
- content: '';
221
- position: absolute;
222
- top: 50%;
223
- left: 50%;
224
- width: 100%;
225
- height: 100%;
226
- background: radial-gradient(circle, var(--neon-blue) 0%, transparent 70%);
227
- transform: translate(-50%, -50%) scale(0);
228
- transition: transform 0.5s ease;
229
- z-index: -1;
230
  }
231
-
232
  .settings-btn:hover {
233
- transform: scale(1.1) rotate(90deg);
234
- box-shadow:
235
- 0 0 30px rgba(0, 217, 255, 0.6),
236
- 0 0 60px rgba(255, 0, 110, 0.4),
237
- inset 0 0 20px rgba(0, 217, 255, 0.2);
238
- }
239
-
240
- .settings-btn:hover::before {
241
- transform: translate(-50%, -50%) scale(2);
242
  }
243
-
244
  .settings-btn svg {
245
- width: 28px;
246
- height: 28px;
247
- fill: url(#iconGradient);
248
- filter: drop-shadow(0 0 10px var(--neon-blue));
249
- transition: transform 0.4s ease;
250
  }
251
 
252
- .settings-btn:hover svg {
253
- transform: rotate(-90deg);
254
- }
255
-
256
- /* Enhanced exam grid */
257
  .exams-grid {
258
  display: grid;
259
- grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
260
- gap: 2.5rem;
261
- padding: 2rem 0;
262
  }
263
-
264
- /* Ultra enhanced exam cards */
265
  .exam-card {
266
- background: linear-gradient(135deg,
267
- rgba(0, 217, 255, 0.05) 0%,
268
- rgba(255, 0, 110, 0.05) 100%);
269
- backdrop-filter: blur(40px) saturate(150%);
270
- border: 1px solid transparent;
271
- background-origin: border-box;
272
- background-clip: padding-box, border-box;
273
- border-image: linear-gradient(135deg,
274
- rgba(0, 217, 255, 0.3),
275
- rgba(255, 0, 110, 0.3)) 1;
276
- border-radius: 24px;
277
  padding: 2.5rem;
278
  text-align: center;
279
- transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
280
  position: relative;
281
  overflow: hidden;
282
- transform-style: preserve-3d;
283
- perspective: 1000px;
284
- }
285
-
286
- .exam-card::before {
287
- content: '';
288
- position: absolute;
289
- top: -50%;
290
- left: -50%;
291
- width: 200%;
292
- height: 200%;
293
- background: radial-gradient(circle,
294
- rgba(0, 217, 255, 0.1) 0%,
295
- transparent 40%);
296
- animation: cardPulse 4s ease-in-out infinite;
297
- pointer-events: none;
298
- }
299
-
300
- .exam-card::after {
301
- content: '';
302
- position: absolute;
303
- top: 0;
304
- left: 0;
305
- right: 0;
306
- bottom: 0;
307
- background: linear-gradient(105deg,
308
- transparent 40%,
309
- rgba(255, 255, 255, 0.05) 45%,
310
- rgba(255, 255, 255, 0.1) 50%,
311
- rgba(255, 255, 255, 0.05) 55%,
312
- transparent 60%);
313
- transform: translateX(-100%);
314
- transition: transform 0.6s;
315
- pointer-events: none;
316
- }
317
-
318
- @keyframes cardPulse {
319
- 0%, 100% { transform: scale(1) rotate(0deg); opacity: 0.5; }
320
- 50% { transform: scale(1.2) rotate(180deg); opacity: 0.8; }
321
  }
322
 
 
323
  .exam-card:hover {
324
- transform: translateY(-10px) rotateX(5deg) scale(1.02);
325
  box-shadow:
326
- 0 20px 40px rgba(0, 217, 255, 0.3),
327
- 0 40px 80px rgba(255, 0, 110, 0.2),
328
- inset 0 0 30px rgba(0, 217, 255, 0.1);
329
- border-image: linear-gradient(135deg,
330
- var(--neon-blue),
331
- var(--neon-pink)) 1;
332
- }
333
-
334
- .exam-card:hover::after {
335
- transform: translateX(100%);
336
  }
337
 
338
  .exam-name {
339
- font-size: 1.8rem;
340
- font-weight: 700;
341
  margin-bottom: 1.5rem;
342
- background: linear-gradient(135deg, #fff 0%, #00D9FF 100%);
343
- -webkit-background-clip: text;
344
- -webkit-text-fill-color: transparent;
345
- background-clip: text;
346
  text-transform: uppercase;
347
- letter-spacing: 2px;
348
- filter: drop-shadow(0 2px 10px rgba(0, 217, 255, 0.5));
349
  }
350
 
351
- .countdown-wrapper {
352
- display: flex;
353
- justify-content: center;
354
- gap: 1.5rem;
355
- margin-bottom: 2rem;
356
- }
357
- .countdown-item {
358
- display: flex;
359
- flex-direction: column;
360
- }
361
- .countdown-number {
362
- font-family: 'Orbitron', monospace;
363
- font-size: 3rem;
364
- font-weight: 900;
365
- color: var(--neon-blue);
366
- text-shadow: 0 0 20px var(--neon-blue);
367
  line-height: 1;
 
368
  }
369
  .countdown-label {
370
- font-size: 0.8rem;
371
- color: rgba(255, 255, 255, 0.7);
372
  text-transform: uppercase;
373
- letter-spacing: 2px;
374
- font-weight: 300;
375
  }
376
-
377
  .exam-date {
378
  font-size: 0.95rem;
379
- color: rgba(0, 217, 255, 0.7);
380
  margin-top: 1.5rem;
381
- padding: 0.5rem 1rem;
382
- background: rgba(0, 217, 255, 0.1);
383
- border-radius: 20px;
384
- display: inline-block;
385
- border: 1px solid rgba(0, 217, 255, 0.3);
386
  }
387
 
388
- /* Enhanced delete button */
389
  .delete-btn {
390
  position: absolute;
391
- top: 1.5rem;
392
- right: 1.5rem;
393
- width: 36px;
394
- height: 36px;
395
- background: linear-gradient(135deg,
396
- rgba(255, 0, 110, 0.2) 0%,
397
- rgba(255, 0, 0, 0.2) 100%);
398
- border: 2px solid rgba(255, 0, 110, 0.5);
399
- border-radius: 12px;
400
  display: flex;
401
  align-items: center;
402
  justify-content: center;
403
  cursor: pointer;
404
  transition: all 0.3s ease;
405
- opacity: 0;
406
- transform: scale(0.8);
407
- }
408
-
409
- .exam-card:hover .delete-btn {
410
- opacity: 1;
411
- transform: scale(1);
412
  }
413
-
414
  .delete-btn:hover {
415
- background: linear-gradient(135deg,
416
- rgba(255, 0, 110, 0.4) 0%,
417
- rgba(255, 0, 0, 0.4) 100%);
418
- transform: scale(1.2) rotate(90deg);
419
- box-shadow: 0 0 20px rgba(255, 0, 110, 0.6);
420
  }
 
421
 
422
- /* Enhanced modal */
423
  .modal {
424
  display: none;
425
  position: fixed;
@@ -427,287 +194,164 @@
427
  left: 0;
428
  width: 100%;
429
  height: 100%;
430
- background: rgba(0, 0, 0, 0.9);
431
- backdrop-filter: blur(10px);
432
  z-index: 1000;
433
  align-items: center;
434
  justify-content: center;
435
  padding: 2rem;
436
- animation: modalFadeIn 0.3s ease;
437
- }
438
-
439
- @keyframes modalFadeIn {
440
- from { opacity: 0; }
441
- to { opacity: 1; }
442
  }
 
443
 
444
- .modal.active {
445
- display: flex;
446
  }
447
 
448
  .modal-content {
449
- background: linear-gradient(135deg,
450
- rgba(20, 20, 30, 0.98) 0%,
451
- rgba(30, 20, 40, 0.98) 100%);
452
- backdrop-filter: blur(40px) saturate(150%);
453
- border: 2px solid transparent;
454
- background-origin: border-box;
455
- background-clip: padding-box, border-box;
456
- border-image: linear-gradient(135deg, var(--neon-blue), var(--neon-pink)) 1;
457
  border-radius: 30px;
458
- padding: 3rem;
459
  width: 100%;
460
- max-width: 500px;
461
- box-shadow:
462
- 0 30px 60px rgba(0, 0, 0, 0.5),
463
- 0 0 100px rgba(0, 217, 255, 0.2),
464
- inset 0 0 30px rgba(0, 217, 255, 0.05);
465
- animation: modalSlideIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
466
- position: relative;
467
- overflow: hidden;
468
- }
469
-
470
- .modal-content::before {
471
- content: '';
472
- position: absolute;
473
- top: -50%;
474
- left: -50%;
475
- width: 200%;
476
- height: 200%;
477
- background: radial-gradient(circle,
478
- rgba(0, 217, 255, 0.1) 0%,
479
- transparent 40%);
480
- animation: modalGlow 4s ease-in-out infinite;
481
- }
482
-
483
- @keyframes modalSlideIn {
484
- from { transform: translateY(-50px) scale(0.9); opacity: 0; }
485
- to { transform: translateY(0) scale(1); opacity: 1; }
486
- }
487
-
488
- @keyframes modalGlow {
489
- 0%, 100% { transform: rotate(0deg); }
490
- 50% { transform: rotate(180deg); }
491
  }
 
492
 
493
  .modal-header {
494
  display: flex;
495
  justify-content: space-between;
496
  align-items: center;
497
- margin-bottom: 2.5rem;
498
- position: relative;
499
- z-index: 1;
500
  }
501
-
502
  .modal-title {
503
- font-size: 2rem;
504
- font-weight: 700;
505
- background: linear-gradient(135deg, var(--neon-blue) 0%, var(--neon-pink) 100%);
506
- -webkit-background-clip: text;
507
- -webkit-text-fill-color: transparent;
508
- background-clip: text;
509
- text-transform: uppercase;
510
- letter-spacing: 2px;
511
  }
512
-
513
  .close-btn {
514
- width: 40px;
515
- height: 40px;
516
- background: rgba(255, 0, 110, 0.1);
517
- border: 2px solid rgba(255, 0, 110, 0.3);
518
- border-radius: 12px;
519
  cursor: pointer;
 
520
  display: flex;
521
  align-items: center;
522
  justify-content: center;
523
- transition: all 0.3s ease;
524
  }
525
-
526
  .close-btn:hover {
527
- transform: rotate(90deg) scale(1.1);
528
- background: rgba(255, 0, 110, 0.2);
529
- box-shadow: 0 0 20px rgba(255, 0, 110, 0.5);
530
  }
 
531
 
532
- /* Enhanced form */
533
- .form-group {
 
 
 
 
 
 
 
 
 
534
  margin-bottom: 2rem;
535
- position: relative;
536
- z-index: 1;
537
  }
538
-
539
- .form-group label {
540
- display: block;
541
- margin-bottom: 0.75rem;
542
- font-size: 0.95rem;
543
- color: var(--neon-blue);
544
- text-transform: uppercase;
545
- letter-spacing: 2px;
546
- font-weight: 500;
547
  }
548
 
549
- .form-group input {
550
- width: 100%;
551
- padding: 1.2rem;
552
- background: rgba(0, 217, 255, 0.05);
553
- border: 2px solid rgba(0, 217, 255, 0.2);
554
- border-radius: 12px;
555
- color: #fff;
556
- font-size: 1.1rem;
557
- transition: all 0.3s ease;
558
- font-family: 'Space Grotesk', sans-serif;
 
 
 
 
559
  }
560
-
561
- .form-group input:focus {
562
  outline: none;
563
- border-color: var(--neon-blue);
564
- background: rgba(0, 217, 255, 0.1);
565
- box-shadow:
566
- 0 0 20px rgba(0, 217, 255, 0.3),
567
- inset 0 0 10px rgba(0, 217, 255, 0.1);
568
  }
569
 
570
- .form-group input::placeholder {
571
- color: rgba(255, 255, 255, 0.3);
572
- }
573
-
574
- /* Enhanced add button */
575
  .add-btn {
576
  width: 100%;
577
- padding: 1.5rem;
578
- background: linear-gradient(135deg, var(--neon-blue) 0%, var(--neon-pink) 100%);
579
  border: none;
580
- border-radius: 16px;
581
  color: #fff;
582
- font-size: 1.2rem;
583
  font-weight: 700;
584
  cursor: pointer;
585
- transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
586
- text-transform: uppercase;
587
- letter-spacing: 2px;
588
- position: relative;
589
- overflow: hidden;
590
- z-index: 1;
591
- }
592
-
593
- .add-btn::before {
594
- content: '';
595
- position: absolute;
596
- top: 50%;
597
- left: 50%;
598
- width: 0;
599
- height: 0;
600
- background: radial-gradient(circle,
601
- rgba(255, 255, 255, 0.3) 0%,
602
- transparent 70%);
603
- transform: translate(-50%, -50%);
604
- transition: width 0.6s, height 0.6s;
605
  }
606
-
607
  .add-btn:hover {
608
- transform: translateY(-3px) scale(1.02);
609
- box-shadow:
610
- 0 10px 30px rgba(0, 217, 255, 0.5),
611
- 0 20px 60px rgba(255, 0, 110, 0.3);
612
- }
613
-
614
- .add-btn:hover::before {
615
- width: 300px;
616
- height: 300px;
617
  }
618
 
619
- /* Enhanced empty state */
620
- .empty-state {
621
- text-align: center;
622
- padding: 6rem 2rem;
623
- position: relative;
624
- }
625
-
626
- .empty-state::before {
627
- content: '📚';
628
- font-size: 6rem;
629
- display: block;
630
- margin-bottom: 2rem;
631
- animation: bounce 2s ease-in-out infinite;
632
- }
633
-
634
- @keyframes bounce {
635
- 0%, 100% { transform: translateY(0); }
636
- 50% { transform: translateY(-20px); }
637
- }
638
-
639
- .empty-state p {
640
- font-size: 1.4rem;
641
- background: linear-gradient(135deg,
642
- rgba(255, 255, 255, 0.8) 0%,
643
- rgba(0, 217, 255, 0.8) 100%);
644
- -webkit-background-clip: text;
645
- -webkit-text-fill-color: transparent;
646
- background-clip: text;
647
- margin-bottom: 2rem;
648
- font-weight: 500;
649
- }
650
-
651
- /* Responsive */
652
  @media (max-width: 768px) {
653
- h1 { font-size: 2.5rem; }
654
- .countdown-number { font-size: 2rem; }
655
- .exams-grid { grid-template-columns: 1fr; }
656
- .header { flex-direction: column; gap: 1rem; text-align: center;}
657
- .modal-content { padding: 2rem; }
658
  }
659
  </style>
660
  </head>
661
  <body>
662
- <svg width="0" height="0">
663
- <defs>
664
- <linearGradient id="iconGradient" x1="0%" y1="0%" x2="100%" y2="100%">
665
- <stop offset="0%" style="stop-color:#00D9FF;stop-opacity:1" />
666
- <stop offset="100%" style="stop-color:#FF006E;stop-opacity:1" />
667
- </linearGradient>
668
- </defs>
669
- </svg>
670
-
671
  <div class="particles" id="particles"></div>
672
-
673
  <div class="container">
674
  <div class="header">
675
- <h1>Exam Countdown</h1>
676
  <div class="settings-btn" id="openModalBtn">
677
- <svg viewBox="0 0 24 24">
678
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/>
679
- </svg>
680
  </div>
681
  </div>
682
-
683
  <div class="exams-grid" id="examsGrid"></div>
684
-
685
  <div class="empty-state" id="emptyState" style="display: none;">
686
- <p>No exams scheduled yet. Click the + button to add your first exam!</p>
 
687
  </div>
688
  </div>
689
-
690
  <div class="modal" id="modal">
691
  <div class="modal-content">
692
  <div class="modal-header">
693
- <h2 class="modal-title">Add New Exam</h2>
694
  <button class="close-btn" id="closeModalBtn">
695
- <svg width="24" height="24" viewBox="0 0 24 24" fill="#FF006E">
696
- <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
697
- </svg>
698
  </button>
699
  </div>
700
-
701
  <form id="addExamForm">
702
  <div class="form-group">
703
- <label for="examName">Exam Name</label>
704
- <input type="text" id="examName" required placeholder="e.g., Physics Final">
705
  </div>
706
  <div class="form-group">
707
- <label for="examDate">Exam Date & Time</label>
708
- <input type="datetime-local" id="examDate" required>
709
  </div>
710
- <button type="submit" class="add-btn">Add Exam</button>
711
  </form>
712
  </div>
713
  </div>
@@ -728,16 +372,17 @@
728
  appId: "1:241970333280:web:704e8930bd591c138d6505"
729
  };
730
 
731
- // Initialize Firebase and Database
732
  const app = initializeApp(firebaseConfig);
733
  const database = getDatabase(app);
734
  const examsRef = ref(database, 'exams');
735
 
736
- // DOM Element References
737
  const elements = {
 
738
  openModalBtn: document.getElementById('openModalBtn'),
 
739
  closeModalBtn: document.getElementById('closeModalBtn'),
740
- modal: document.getElementById('modal'),
741
  addExamForm: document.getElementById('addExamForm'),
742
  examNameInput: document.getElementById('examName'),
743
  examDateInput: document.getElementById('examDate'),
@@ -745,175 +390,121 @@
745
  emptyState: document.getElementById('emptyState'),
746
  particlesContainer: document.getElementById('particles')
747
  };
748
-
749
- let exams = []; // This will hold our exams from Firebase
750
-
751
- // --- Enhanced Particle System ---
752
- function createParticles() {
753
- if (elements.particlesContainer.children.length > 0) return;
754
- // Create orbs
755
- for (let i = 0; i < 15; i++) {
756
- const particle = document.createElement('div');
757
- particle.classList.add('particle', 'orb');
758
- particle.style.left = Math.random() * 100 + '%';
759
- particle.style.animationDelay = Math.random() * 20 + 's';
760
- particle.style.animationDuration = (15 + Math.random() * 10) + 's';
761
-
762
- const colors = ['#00D9FF', '#FF006E', '#8B39FF', '#39FF14'];
763
- const color = colors[Math.floor(Math.random() * colors.length)];
764
- particle.style.background = `radial-gradient(circle, ${color} 0%, transparent 70%)`;
765
- particle.style.boxShadow = `0 0 10px ${color}, 0 0 20px ${color}`;
766
-
767
- elements.particlesContainer.appendChild(particle);
768
- }
769
-
770
- // Create stars
771
- for (let i = 0; i < 30; i++) {
772
- const star = document.createElement('div');
773
- star.classList.add('particle', 'star');
774
- star.style.left = Math.random() * 100 + '%';
775
- star.style.top = Math.random() * 100 + '%';
776
- star.style.animationDelay = Math.random() * 3 + 's';
777
- elements.particlesContainer.appendChild(star);
778
- }
779
- }
780
 
781
- // --- Modal & Form Logic ---
782
  const openModal = () => elements.modal.classList.add('active');
783
- const closeModal = () => {
784
- elements.modal.classList.remove('active');
785
- elements.addExamForm.reset();
786
- };
787
 
788
  const addExam = (event) => {
789
  event.preventDefault();
790
- const examIcons = ['📚', '📖', '✏️', '📝', '🎓', '📊', '🧮', '🔬', '💻', '🎨'];
791
  const newExam = {
792
  name: elements.examNameInput.value,
793
- date: new Date(elements.examDateInput.value).getTime(),
794
- icon: examIcons[Math.floor(Math.random() * examIcons.length)]
795
  };
796
- push(examsRef, newExam).catch(err => console.error("Failed to add exam:", err));
797
  closeModal();
798
  };
799
 
800
- const deleteExam = (id) => {
801
- if (!id) return;
802
- remove(ref(database, `exams/${id}`)).catch(err => console.error("Failed to delete exam:", err));
803
- };
804
 
805
  // --- Rendering Logic ---
806
- function getCountdown(targetDate) {
807
- const now = new Date().getTime();
808
- const distance = targetDate - now;
809
-
810
- if (distance < 0) {
811
- return { days: 0, hours: 0, minutes: 0, seconds: 0, isPast: true };
812
- }
813
-
814
- return {
815
- days: Math.floor(distance / (1000 * 60 * 60 * 24)),
816
- hours: Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
817
- minutes: Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)),
818
- seconds: Math.floor((distance % (1000 * 60)) / 1000),
819
- isPast: false
820
- };
821
- }
822
 
823
- function renderExams() {
824
- if (exams.length === 0) {
825
- elements.examsGrid.innerHTML = '';
826
- elements.emptyState.style.display = 'block';
827
- return;
828
- }
 
 
829
 
830
- elements.emptyState.style.display = 'none';
831
- // Sort by date so the soonest is first
832
- const sortedExams = [...exams].sort((a, b) => a.date - b.date);
 
 
 
 
 
 
 
833
 
834
- elements.examsGrid.innerHTML = sortedExams.map(exam => {
835
- const countdown = getCountdown(exam.date);
836
- const examDate = new Date(exam.date);
 
 
837
 
838
- let content;
839
- if(countdown.isPast){
840
- content = `<div style="font-size: 2rem; color: var(--neon-pink); font-family: 'Orbitron', monospace;">EXAM COMPLETE</div>`;
 
 
 
 
 
 
 
841
  } else {
842
- content = `
843
- <div class="countdown-wrapper">
844
- <div class="countdown-item">
845
- <div class="countdown-number">${String(countdown.days).padStart(2, '0')}</div>
846
- <div class="countdown-label">Days</div>
847
- </div>
848
- <div class="countdown-item">
849
- <div class="countdown-number">${String(countdown.hours).padStart(2, '0')}</div>
850
- <div class="countdown-label">Hours</div>
851
- </div>
852
- <div class="countdown-item">
853
- <div class="countdown-number">${String(countdown.minutes).padStart(2, '0')}</div>
854
- <div class="countdown-label">Minutes</div>
855
- </div>
856
- <div class="countdown-item">
857
- <div class="countdown-number">${String(countdown.seconds).padStart(2, '0')}</div>
858
- <div class="countdown-label">Seconds</div>
859
- </div>
860
- </div>`;
861
  }
862
-
863
  return `
864
- <div class="exam-card" data-id="${exam.id}">
865
  <div class="delete-btn" data-delete-id="${exam.id}">
866
- <svg width="20" height="20" viewBox="0 0 24 24" fill="#fff" style="pointer-events: none;">
867
- <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
868
- </svg>
869
  </div>
870
- <div class="exam-name">${exam.icon} ${exam.name}</div>
871
- ${content}
872
- <div class="exam-date">
873
- 📅 ${examDate.toLocaleDateString('en-US', {
874
- weekday: 'long', month: 'long', day: 'numeric',
875
- hour: '2-digit', minute: '2-digit'
876
- })}
877
- </div>
878
- </div>
879
- `;
880
  }).join('');
881
- }
882
 
883
- // --- Event Delegation for Delete Buttons ---
884
- elements.examsGrid.addEventListener('click', (event) => {
885
- if(event.target.matches('.delete-btn')) {
886
- const idToDelete = event.target.dataset.deleteId;
887
- deleteExam(idToDelete);
 
 
 
 
 
888
  }
889
- });
890
-
891
-
892
- // --- App Initialization ---
893
  createParticles();
894
- elements.examDateInput.min = new Date().toISOString().slice(0, 16);
895
 
896
- // Event Listeners for Modal
897
  elements.openModalBtn.addEventListener('click', openModal);
 
898
  elements.closeModalBtn.addEventListener('click', closeModal);
899
  elements.addExamForm.addEventListener('submit', addExam);
900
  window.addEventListener('click', e => { if (e.target === elements.modal) closeModal(); });
 
 
 
 
 
 
 
 
901
 
902
  // Firebase real-time data listener
903
  onValue(examsRef, (snapshot) => {
904
  const data = snapshot.val();
905
- // Convert Firebase object to an array and store it
906
- exams = data ? Object.entries(data).map(([id, value]) => ({ id, ...value })) : [];
907
- // Do an initial render as soon as data is received
908
- renderExams();
909
- }, (error) => {
910
- console.error("Firebase read failed:", error);
911
- alert("Could not connect to the database. Check console for errors and verify database rules.");
912
  });
913
 
914
- // Set an interval to update the countdowns every second
915
- // This makes the timers tick without re-fetching from Firebase
916
- setInterval(renderExams, 1000);
917
  </script>
918
  </body>
919
  </html>
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Neon Exam Countdown</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
8
  <style>
9
  * { margin: 0; padding: 0; box-sizing: border-box; }
 
 
 
 
 
 
 
 
 
 
10
  body {
11
+ font-family: 'Inter', sans-serif;
12
+ background: radial-gradient(circle at 50% 0%, rgba(10, 10, 15, 0.8) 0%, #0A0A0B 40%, #141419 100%);
13
  min-height: 100vh;
14
  color: #fff;
15
  overflow-x: hidden;
16
+ position: relative;
17
+ padding: 20px;
18
+ }
19
+
20
+ /* --- PARTICLE EFFECTS --- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  .particles {
22
  position: fixed;
23
  top: 0;
 
26
  height: 100%;
27
  overflow: hidden;
28
  z-index: 1;
29
+ pointer-events: none; /* Ensures particles don't interfere with clicks */
30
  }
 
31
  .particle {
32
  position: absolute;
33
+ width: 4px;
34
+ height: 4px;
35
+ background: radial-gradient(circle, rgba(0, 212, 255, 0.4) 0%, transparent 70%);
36
  border-radius: 50%;
37
+ animation: float 25s infinite linear;
38
+ box-shadow: 0 0 5px rgba(0, 212, 255, 0.3);
39
+ /* --x is set by JS */
40
+ }
41
+ @keyframes float {
42
+ from { transform: translate(var(--x), 100vh); opacity: 0; }
43
+ 5% { opacity: 0.6; }
44
+ 95% { opacity: 0.6; }
45
+ to { transform: translate(var(--x), -100vh); opacity: 0; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
+ /* --- MAIN LAYOUT --- */
49
+ .container { max-width: 1400px; margin: 0 auto; padding: 1rem 0; position: relative; z-index: 2; }
50
  .header {
51
  display: flex;
52
  justify-content: space-between;
53
  align-items: center;
54
+ margin-bottom: 3rem;
55
+ padding: 0 1rem;
 
56
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  h1 {
58
+ font-size: 3rem;
59
+ font-weight: 700;
 
 
60
  letter-spacing: 3px;
61
+ background: linear-gradient(135deg, #00D4FF 0%, #FF0080 50%, #00FF88 100%);
 
 
 
 
 
 
62
  -webkit-background-clip: text;
63
  -webkit-text-fill-color: transparent;
64
+ background-clip: text;
65
+ text-shadow: 0 0 15px rgba(0, 212, 255, 0.7), 0 0 30px rgba(255, 0, 128, 0.3);
 
 
 
 
 
 
 
 
66
  }
67
 
68
+ /* --- SETTINGS BUTTON (Neon Glow Focus) --- */
69
  .settings-btn {
70
+ width: 50px;
71
+ height: 50px;
72
+ background: rgba(255, 255, 255, 0.08);
73
+ backdrop-filter: blur(15px);
74
+ border: 1px solid rgba(0, 212, 255, 0.3);
75
+ border-radius: 15px;
 
 
 
 
 
76
  display: flex;
77
  align-items: center;
78
  justify-content: center;
79
  cursor: pointer;
80
+ transition: all 0.3s ease;
81
+ box-shadow: 0 0 10px rgba(0, 212, 255, 0.4);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
 
83
  .settings-btn:hover {
84
+ background: rgba(0, 212, 255, 0.15);
85
+ border-color: #00FF88;
86
+ box-shadow: 0 0 30px rgba(0, 255, 136, 0.8), 0 0 10px rgba(0, 212, 255, 0.6);
87
+ transform: scale(1.05);
 
 
 
 
 
88
  }
 
89
  .settings-btn svg {
90
+ width: 26px;
91
+ height: 26px;
92
+ fill: #00D4FF;
93
+ filter: drop-shadow(0 0 5px rgba(0, 212, 255, 0.9));
 
94
  }
95
 
96
+ /* --- EXAM GRID --- */
 
 
 
 
97
  .exams-grid {
98
  display: grid;
99
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
100
+ gap: 2rem;
101
+ padding: 0 1rem;
102
  }
 
 
103
  .exam-card {
104
+ background: rgba(10, 10, 15, 0.7); /* Darker base */
105
+ backdrop-filter: blur(10px);
106
+ border: 1px solid rgba(0, 255, 136, 0.2); /* Subtle green-cyan border */
107
+ border-radius: 25px;
 
 
 
 
 
 
 
108
  padding: 2.5rem;
109
  text-align: center;
110
+ transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
111
  position: relative;
112
  overflow: hidden;
113
+ box-shadow:
114
+ 0 4px 15px rgba(0, 0, 0, 0.5), /* Outer shadow for depth */
115
+ inset 0 0 15px rgba(0, 255, 136, 0.1); /* Subtle inner glow */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
117
 
118
+ /* Card Hover Effect: More dramatic lift and glow */
119
  .exam-card:hover {
120
+ transform: translateY(-8px) scale(1.01);
121
  box-shadow:
122
+ 0 15px 40px rgba(0, 212, 255, 0.5),
123
+ 0 0 50px rgba(0, 255, 136, 0.3),
124
+ inset 0 0 20px rgba(255, 0, 128, 0.2);
125
+ border-color: #00FF88;
 
 
 
 
 
 
126
  }
127
 
128
  .exam-name {
129
+ font-size: 1.6rem;
130
+ font-weight: 600;
131
  margin-bottom: 1.5rem;
132
+ color: #00D4FF;
 
 
 
133
  text-transform: uppercase;
134
+ letter-spacing: 1px;
 
135
  }
136
 
137
+ /* Countdown Numbers: Brightest element */
138
+ .countdown {
139
+ font-size: 4.5rem;
140
+ font-weight: 700;
141
+ text-shadow:
142
+ 0 0 25px rgba(255, 0, 128, 1),
143
+ 0 0 50px rgba(255, 0, 128, 0.7);
144
+ margin-bottom: 0.75rem;
 
 
 
 
 
 
 
 
145
  line-height: 1;
146
+ color: #fff;
147
  }
148
  .countdown-label {
149
+ font-size: 1.1rem;
150
+ color: rgba(255, 255, 255, 0.8);
151
  text-transform: uppercase;
152
+ letter-spacing: 1px;
 
153
  }
 
154
  .exam-date {
155
  font-size: 0.95rem;
156
+ color: rgba(0, 212, 255, 0.6);
157
  margin-top: 1.5rem;
158
+ border-top: 1px dashed rgba(0, 212, 255, 0.1);
159
+ padding-top: 1rem;
 
 
 
160
  }
161
 
162
+ /* Delete Button (Danger Neon) */
163
  .delete-btn {
164
  position: absolute;
165
+ top: 1.2rem;
166
+ right: 1.2rem;
167
+ width: 35px;
168
+ height: 35px;
169
+ background: rgba(255, 0, 128, 0.25);
170
+ border: 1px solid rgba(255, 0, 128, 0.6);
171
+ border-radius: 10px;
 
 
172
  display: flex;
173
  align-items: center;
174
  justify-content: center;
175
  cursor: pointer;
176
  transition: all 0.3s ease;
177
+ opacity: 0;
178
+ z-index: 10;
179
+ box-shadow: 0 0 10px rgba(255, 0, 128, 0.5);
 
 
 
 
180
  }
181
+ .exam-card:hover .delete-btn { opacity: 1; }
182
  .delete-btn:hover {
183
+ background: rgba(255, 0, 128, 0.6);
184
+ box-shadow: 0 0 25px rgba(255, 0, 128, 1);
185
+ transform: scale(1.15);
 
 
186
  }
187
+ .delete-btn svg { width: 18px; height: 18px; fill: #fff; pointer-events: none; }
188
 
189
+ /* --- MODAL STYLES (Holographic Look) --- */
190
  .modal {
191
  display: none;
192
  position: fixed;
 
194
  left: 0;
195
  width: 100%;
196
  height: 100%;
197
+ background: rgba(0, 0, 0, 0.75);
 
198
  z-index: 1000;
199
  align-items: center;
200
  justify-content: center;
201
  padding: 2rem;
202
+ animation: fadeIn 0.3s ease-out;
 
 
 
 
 
203
  }
204
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
205
 
206
+ .modal.active {
207
+ display: flex;
208
  }
209
 
210
  .modal-content {
211
+ background: rgba(15, 15, 20, 0.97);
212
+ backdrop-filter: blur(30px);
213
+ border: 2px solid;
214
+ border-image: linear-gradient(45deg, #00D4FF, #FF0080, #00FF88) 1;
 
 
 
 
215
  border-radius: 30px;
216
+ padding: 2.5rem;
217
  width: 100%;
218
+ max-width: 450px;
219
+ box-shadow: 0 10px 60px rgba(0, 0, 0, 0.8), 0 0 30px rgba(0, 212, 255, 0.2);
220
+ animation: popIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  }
222
+ @keyframes popIn { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
223
 
224
  .modal-header {
225
  display: flex;
226
  justify-content: space-between;
227
  align-items: center;
228
+ margin-bottom: 2rem;
229
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
230
+ padding-bottom: 1rem;
231
  }
 
232
  .modal-title {
233
+ font-size: 1.75rem;
234
+ font-weight: 600;
235
+ color: #00D4FF;
236
+ text-shadow: 0 0 8px rgba(0, 212, 255, 0.5);
 
 
 
 
237
  }
 
238
  .close-btn {
239
+ width: 35px;
240
+ height: 35px;
241
+ background: rgba(255, 255, 255, 0.05);
242
+ border: 1px solid rgba(255, 0, 128, 0.5);
243
+ border-radius: 50%;
244
  cursor: pointer;
245
+ transition: all 0.3s ease;
246
  display: flex;
247
  align-items: center;
248
  justify-content: center;
 
249
  }
 
250
  .close-btn:hover {
251
+ transform: rotate(180deg);
252
+ background: rgba(255, 0, 128, 0.3);
253
+ box-shadow: 0 0 15px rgba(255, 0, 128, 0.8);
254
  }
255
+ .close-btn svg { fill: #FF0080; pointer-events: none;}
256
 
257
+ /* --- EMPTY STATE --- */
258
+ .empty-state {
259
+ text-align: center;
260
+ padding: 6rem 2rem;
261
+ border: 2px dashed rgba(0, 212, 255, 0.2);
262
+ border-radius: 20px;
263
+ margin: 2rem;
264
+ }
265
+ .empty-state p {
266
+ font-size: 1.4rem;
267
+ color: rgba(0, 212, 255, 0.6);
268
  margin-bottom: 2rem;
269
+ text-shadow: 0 0 5px rgba(0, 212, 255, 0.3);
 
270
  }
271
+ #openModalForEmpty {
272
+ padding: 0.9rem 2rem;
273
+ font-size: 1rem;
 
 
 
 
 
 
274
  }
275
 
276
+ /* --- FORM STYLING --- */
277
+ .form-group { margin-bottom: 1.25rem; }
278
+ .form-group label { display: block; margin-bottom: 0.5rem; font-size: 0.9rem; font-weight: 400; color: #ddd; }
279
+
280
+ input[type="text"], input[type="date"] {
281
+ width: 100%;
282
+ padding: 0.85rem;
283
+ border-radius: 8px;
284
+ border: 1px solid rgba(255, 255, 255, 0.15);
285
+ background: rgba(0, 0, 0, 0.6);
286
+ color: #fff;
287
+ font-family: inherit;
288
+ font-size: 1rem;
289
+ transition: border-color 0.3s, box-shadow 0.3s;
290
  }
291
+ input[type="text"]:focus, input[type="date"]:focus {
 
292
  outline: none;
293
+ border-color: #FF0080;
294
+ box-shadow: 0 0 15px rgba(255, 0, 128, 0.6);
 
 
 
295
  }
296
 
 
 
 
 
 
297
  .add-btn {
298
  width: 100%;
299
+ padding: 1rem;
300
+ background: linear-gradient(135deg, #00D4FF 0%, #FF0080 100%);
301
  border: none;
302
+ border-radius: 12px;
303
  color: #fff;
304
+ font-size: 1.1rem;
305
  font-weight: 700;
306
  cursor: pointer;
307
+ transition: all 0.3s ease;
308
+ box-shadow: 0 5px 20px rgba(0, 212, 255, 0.4);
309
+ letter-spacing: 0.5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  }
 
311
  .add-btn:hover {
312
+ transform: translateY(-3px);
313
+ box-shadow: 0 8px 30px rgba(255, 0, 128, 0.8), 0 0 15px #00D4FF;
 
 
 
 
 
 
 
314
  }
315
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  @media (max-width: 768px) {
317
+ h1 { font-size: 2rem; }
318
+ .header { flex-direction: column; gap: 1rem; text-align: center; }
 
 
 
319
  }
320
  </style>
321
  </head>
322
  <body>
 
 
 
 
 
 
 
 
 
323
  <div class="particles" id="particles"></div>
 
324
  <div class="container">
325
  <div class="header">
326
+ <h1>NEON CHRONOS</h1>
327
  <div class="settings-btn" id="openModalBtn">
328
+ <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></svg>
 
 
329
  </div>
330
  </div>
 
331
  <div class="exams-grid" id="examsGrid"></div>
 
332
  <div class="empty-state" id="emptyState" style="display: none;">
333
+ <p>SYSTEM OFFLINE: Input target dates below.</p>
334
+ <button id="openModalForEmpty" class="add-btn" style="max-width: 300px; margin: 1rem auto;">INITIATE NEW TARGET</button>
335
  </div>
336
  </div>
 
337
  <div class="modal" id="modal">
338
  <div class="modal-content">
339
  <div class="modal-header">
340
+ <h2 class="modal-title">Add New Target</h2>
341
  <button class="close-btn" id="closeModalBtn">
342
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
 
 
343
  </button>
344
  </div>
 
345
  <form id="addExamForm">
346
  <div class="form-group">
347
+ <label for="examName">Designation</label>
348
+ <input type="text" id="examName" required placeholder="e.g., Quantum Dynamics Final">
349
  </div>
350
  <div class="form-group">
351
+ <label for="examDate">Execute Date</label>
352
+ <input type="date" id="examDate" required>
353
  </div>
354
+ <button type="submit" class="add-btn">Activate Countdown</button>
355
  </form>
356
  </div>
357
  </div>
 
372
  appId: "1:241970333280:web:704e8930bd591c138d6505"
373
  };
374
 
375
+ // Initialize Firebase
376
  const app = initializeApp(firebaseConfig);
377
  const database = getDatabase(app);
378
  const examsRef = ref(database, 'exams');
379
 
380
+ // DOM Elements
381
  const elements = {
382
+ modal: document.getElementById('modal'),
383
  openModalBtn: document.getElementById('openModalBtn'),
384
+ openModalForEmpty: document.getElementById('openModalForEmpty'),
385
  closeModalBtn: document.getElementById('closeModalBtn'),
 
386
  addExamForm: document.getElementById('addExamForm'),
387
  examNameInput: document.getElementById('examName'),
388
  examDateInput: document.getElementById('examDate'),
 
390
  emptyState: document.getElementById('emptyState'),
391
  particlesContainer: document.getElementById('particles')
392
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
 
394
+ // --- Core Functions ---
395
  const openModal = () => elements.modal.classList.add('active');
396
+ const closeModal = () => elements.modal.classList.remove('active');
 
 
 
397
 
398
  const addExam = (event) => {
399
  event.preventDefault();
400
+ // *** FIX: Save the new date as a number (timestamp) for future consistency ***
401
  const newExam = {
402
  name: elements.examNameInput.value,
403
+ date: new Date(elements.examDateInput.value).getTime()
 
404
  };
405
+ push(examsRef, newExam);
406
  closeModal();
407
  };
408
 
409
+ const deleteExam = (id) => remove(ref(database, `exams/${id}`));
 
 
 
410
 
411
  // --- Rendering Logic ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
+ // *** FIX: This function now handles both old string dates and new number dates ***
414
+ const calculateDaysUntil = (examDate) => {
415
+ const now = new Date();
416
+ now.setHours(0, 0, 0, 0); // Set to midnight for accurate day comparison
417
+
418
+ // The new Date() constructor can handle both numbers (timestamps) and "YYYY-MM-DD" strings.
419
+ const targetDate = new Date(examDate);
420
+ targetDate.setHours(0, 0, 0, 0);
421
 
422
+ const diff = targetDate.getTime() - now.getTime();
423
+ return Math.ceil(diff / (1000 * 60 * 60 * 24));
424
+ };
425
+
426
+ const renderExams = (exams) => {
427
+ const hasExams = exams && exams.length > 0;
428
+ elements.emptyState.style.display = hasExams ? 'none' : 'block';
429
+ elements.examsGrid.style.display = hasExams ? 'grid' : 'none';
430
+
431
+ if (!hasExams) return;
432
 
433
+ exams.sort((a, b) => a.date - b.date);
434
+
435
+ elements.examsGrid.innerHTML = exams.map(exam => {
436
+ const daysUntil = calculateDaysUntil(exam.date);
437
+ const color = daysUntil <= 3 ? '#FF0080' : (daysUntil <= 7 ? '#00FF88' : '#00D4FF');
438
 
439
+ // Create a clean date object that works for both old and new data
440
+ const dateObject = new Date(exam.date);
441
+
442
+ // Handle completed exams
443
+ let countdownContent;
444
+ if (daysUntil < 0) {
445
+ countdownContent = `
446
+ <div class="countdown" style="font-size: 1.8rem; color: #aaa;">COMPLETE</div>
447
+ <div class="countdown-label">on</div>
448
+ `;
449
  } else {
450
+ countdownContent = `
451
+ <div class="countdown" style="color: ${color};">${daysUntil}</div>
452
+ <div class="countdown-label">days remaining</div>
453
+ `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  }
455
+
456
  return `
457
+ <div class="exam-card">
458
  <div class="delete-btn" data-delete-id="${exam.id}">
459
+ <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
 
 
460
  </div>
461
+ <h3 class="exam-name">${exam.name || 'Unnamed Target'}</h3>
462
+ ${countdownContent}
463
+ <div class="exam-date">${dateObject.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}</div>
464
+ </div>`;
 
 
 
 
 
 
465
  }).join('');
466
+ };
467
 
468
+ // --- Particle Effect ---
469
+ const createParticles = () => {
470
+ let particleHtml = '';
471
+ for (let i = 0; i < 50; i++) {
472
+ const style = `
473
+ --x: ${Math.random() * 100}vw;
474
+ animation-delay: ${Math.random() * 20}s;
475
+ animation-duration: ${15 + Math.random() * 10}s;
476
+ `;
477
+ particleHtml += `<div class="particle" style="${style}"></div>`;
478
  }
479
+ elements.particlesContainer.innerHTML = particleHtml;
480
+ };
481
+
482
+ // --- App Initialization & Event Listeners ---
483
  createParticles();
484
+ elements.examDateInput.min = new Date().toISOString().split('T')[0];
485
 
486
+ // Modal Listeners
487
  elements.openModalBtn.addEventListener('click', openModal);
488
+ elements.openModalForEmpty.addEventListener('click', openModal);
489
  elements.closeModalBtn.addEventListener('click', closeModal);
490
  elements.addExamForm.addEventListener('submit', addExam);
491
  window.addEventListener('click', e => { if (e.target === elements.modal) closeModal(); });
492
+
493
+ // Delete button listener (using event delegation)
494
+ elements.examsGrid.addEventListener('click', (event) => {
495
+ const deleteBtn = event.target.closest('.delete-btn');
496
+ if (deleteBtn) {
497
+ deleteExam(deleteBtn.dataset.deleteId);
498
+ }
499
+ });
500
 
501
  // Firebase real-time data listener
502
  onValue(examsRef, (snapshot) => {
503
  const data = snapshot.val();
504
+ const examList = data ? Object.entries(data).map(([id, value]) => ({ id, ...value })) : [];
505
+ renderExams(examList);
 
 
 
 
 
506
  });
507
 
 
 
 
508
  </script>
509
  </body>
510
  </html>