weltenschmid commited on
Commit
bc0e72b
·
verified ·
1 Parent(s): ee56293

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +556 -759
index.html CHANGED
@@ -3,933 +3,730 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Royal Fortune | Modern Casino</title>
7
-
8
- <!-- Google Fonts: Inter for clean, modern UI -->
9
- <link rel="preconnect" href="https://fonts.googleapis.com">
10
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
12
-
13
- <!-- FontAwesome for Icons -->
14
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
15
-
16
  <style>
17
- /* --- CSS VARIABLES & RESET --- */
18
  :root {
19
- --bg-body: #0f172a;
20
- --bg-surface: #1e293b;
21
- --bg-surface-hover: #334155;
22
- --primary: #6366f1; /* Indigo */
23
- --primary-hover: #4f46e5;
24
- --accent-gold: #fbbf24;
25
- --accent-red: #ef4444;
26
  --accent-green: #10b981;
27
- --text-main: #f8fafc;
28
- --text-muted: #94a3b8;
29
- --border: #334155;
30
- --radius-sm: 8px;
31
- --radius-md: 12px;
32
- --radius-lg: 20px;
33
- --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
34
- --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
35
  }
36
 
37
  * {
38
  box-sizing: border-box;
39
  margin: 0;
40
  padding: 0;
41
- -webkit-tap-highlight-color: transparent;
42
  }
43
 
44
  body {
45
- font-family: 'Inter', sans-serif;
46
- background-color: var(--bg-body);
47
- color: var(--text-main);
48
- line-height: 1.5;
 
 
49
  min-height: 100vh;
50
  display: flex;
51
  flex-direction: column;
 
52
  }
53
 
54
- /* --- UTILITIES --- */
55
- .container {
56
- width: 100%;
57
- max-width: 1200px;
58
- margin: 0 auto;
59
- padding: 0 20px;
 
 
 
 
 
 
60
  }
61
 
62
- .flex-center { display: flex; align-items: center; justify-content: center; }
63
- .flex-between { display: flex; align-items: center; justify-content: space-between; }
64
- .text-center { text-align: center; }
65
- .hidden { display: none !important; }
66
-
67
- /* --- BUTTONS --- */
68
- .btn {
69
- display: inline-flex;
70
  align-items: center;
71
- justify-content: center;
72
- gap: 8px;
73
- padding: 10px 20px;
74
- border-radius: var(--radius-md);
75
- border: none;
76
- font-weight: 600;
77
- cursor: pointer;
78
- transition: all 0.2s ease;
79
- font-size: 0.95rem;
80
  }
81
 
82
- .btn:active { transform: scale(0.98); }
83
-
84
- .btn-primary {
85
- background-color: var(--primary);
86
- color: white;
87
  }
88
- .btn-primary:hover { background-color: var(--primary-hover); }
89
 
90
- .btn-outline {
91
- background: transparent;
92
- border: 1px solid var(--border);
93
- color: var(--text-main);
 
 
 
 
94
  }
95
- .btn-outline:hover { background-color: var(--bg-surface-hover); border-color: var(--text-muted); }
96
 
97
- .btn-gold {
98
- background: linear-gradient(135deg, var(--accent-gold), #d97706);
99
- color: #000;
 
100
  }
101
- .btn-gold:hover { filter: brightness(1.1); }
102
 
103
- .btn-danger { background-color: var(--accent-red); color: white; }
104
- .btn-success { background-color: var(--accent-green); color: white; }
105
-
106
- /* --- HEADER --- */
107
- header {
108
- background: rgba(15, 23, 42, 0.9);
109
- backdrop-filter: blur(10px);
110
- position: sticky;
111
- top: 0;
112
- z-index: 50;
113
- padding: 16px 0;
114
- border-bottom: 1px solid var(--border);
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
 
117
- .logo {
118
- font-size: 1.25rem;
119
- font-weight: 700;
120
- color: var(--text-main);
121
- display: flex;
122
- align-items: center;
123
- gap: 8px;
124
  }
125
- .logo i { color: var(--accent-gold); }
126
 
127
- .header-controls {
128
  display: flex;
 
129
  align-items: center;
130
- gap: 12px;
131
  }
132
 
133
- .balance-pill {
134
- background: var(--bg-surface);
135
- padding: 6px 12px;
136
- border-radius: 20px;
137
  font-weight: 600;
138
- color: var(--accent-gold);
139
- font-size: 0.9rem;
140
  display: flex;
141
  align-items: center;
142
- gap: 6px;
143
- border: 1px solid rgba(251, 191, 36, 0.2);
144
  }
145
 
146
- .lang-select {
147
- background: transparent;
148
- color: var(--text-muted);
149
- border: none;
150
- font-family: inherit;
151
- cursor: pointer;
152
- font-size: 0.9rem;
153
  }
154
 
155
- /* --- HERO & PROMO --- */
156
- .hero {
157
- padding: 40px 0;
158
  }
159
 
160
- .promo-card {
161
- background: linear-gradient(135deg, #1e293b, #0f172a);
162
- border: 1px solid var(--border);
163
- border-radius: var(--radius-lg);
164
- padding: 30px;
165
- display: grid;
166
- grid-template-columns: 1fr 1fr;
167
- gap: 30px;
168
- align-items: center;
169
- margin-bottom: 40px;
170
- position: relative;
171
  overflow: hidden;
172
  }
173
-
174
- /* Decorative background blob */
175
- .promo-card::before {
176
- content: '';
177
- position: absolute;
178
- top: -50%;
179
- right: -20%;
180
- width: 400px;
181
- height: 400px;
182
- background: var(--primary);
183
- filter: blur(120px);
184
- opacity: 0.15;
185
- border-radius: 50%;
186
- }
187
-
188
- .promo-content {
189
- position: relative;
190
- z-index: 1;
191
- }
192
 
193
- .promo-title {
194
- font-size: 2rem;
195
- margin-bottom: 10px;
196
- background: linear-gradient(to right, #fff, #94a3b8);
197
- -webkit-background-clip: text;
198
- -webkit-text-fill-color: transparent;
199
  }
200
 
201
- .promo-desc {
202
- color: var(--text-muted);
203
- margin-bottom: 20px;
 
 
204
  }
205
 
206
- .promo-image {
207
- height: 200px;
208
- background: url('https://picsum.photos/seed/casino/600/400') center/cover no-repeat;
209
- border-radius: var(--radius-md);
210
- opacity: 0.8;
211
- box-shadow: var(--shadow-lg);
212
  }
213
 
214
- /* --- GAMES GRID --- */
215
- .section-header {
216
- margin-bottom: 20px;
217
- display: flex;
218
- justify-content: space-between;
219
- align-items: flex-end;
 
220
  }
221
- .section-title { font-size: 1.5rem; font-weight: 700; }
222
 
223
- .games-grid {
224
- display: grid;
225
- grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
226
- gap: 20px;
227
- margin-bottom: 60px;
228
- }
229
 
230
- .game-card {
231
- background: var(--bg-surface);
232
- border-radius: var(--radius-md);
 
 
 
233
  overflow: hidden;
234
- transition: transform 0.2s, box-shadow 0.2s;
235
- cursor: pointer;
236
- border: 1px solid transparent;
237
- display: flex;
238
- flex-direction: column;
239
  }
240
 
241
- .game-card:hover {
242
- transform: translateY(-4px);
243
- box-shadow: var(--shadow-lg);
244
- border-color: var(--primary);
245
- }
246
-
247
- .card-thumb {
248
- height: 160px;
249
- background-color: #000;
250
  position: relative;
251
- background-size: cover;
252
- background-position: center;
253
  }
254
 
255
- .card-thumb::after {
256
  content: '';
257
  position: absolute;
258
- inset: 0;
259
- background: linear-gradient(to top, var(--bg-surface), transparent);
 
 
260
  }
261
 
262
- .card-body {
263
- padding: 16px;
264
- flex: 1;
265
- display: flex;
266
- flex-direction: column;
267
- justify-content: space-between;
268
  }
269
 
270
- .game-name { font-weight: 600; font-size: 1.1rem; margin-bottom: 4px; }
271
- .game-meta { font-size: 0.85rem; color: var(--text-muted); display: flex; justify-content: space-between; }
272
- .game-tag { background: rgba(99, 102, 241, 0.2); color: var(--primary); padding: 2px 6px; border-radius: 4px; font-size: 0.7rem; font-weight: 600; }
273
-
274
- /* --- MODALS --- */
275
- .modal-overlay {
276
- position: fixed;
277
- inset: 0;
278
- background: rgba(0, 0, 0, 0.8);
279
- backdrop-filter: blur(4px);
280
- z-index: 100;
281
- display: flex;
282
- align-items: center;
283
- justify-content: center;
284
- opacity: 0;
285
- visibility: hidden;
286
- transition: all 0.2s;
287
- padding: 20px;
288
  }
289
 
290
- .modal-overlay.active { opacity: 1; visibility: visible; }
291
-
292
- .modal {
293
- background: var(--bg-surface);
294
- width: 100%;
295
- max-width: 500px;
296
- border-radius: var(--radius-lg);
297
- border: 1px solid var(--border);
298
- box-shadow: var(--shadow-lg);
299
- transform: scale(0.95);
300
- transition: transform 0.2s;
301
- overflow: hidden;
302
  display: flex;
303
  flex-direction: column;
304
- max-height: 90vh;
305
  }
306
 
307
- .modal-overlay.active .modal { transform: scale(1); }
308
-
309
- .modal-header {
310
- padding: 20px;
311
- border-bottom: 1px solid var(--border);
312
  display: flex;
313
- justify-content: space-between;
314
- align-items: center;
315
  }
316
 
317
- .modal-title { font-size: 1.25rem; font-weight: 700; }
 
 
 
318
 
319
- .close-btn {
320
- background: none;
 
 
321
  border: none;
322
- color: var(--text-muted);
323
- font-size: 1.25rem;
324
  cursor: pointer;
325
- }
326
-
327
- .modal-body {
328
- padding: 20px;
329
- overflow-y: auto;
330
- }
331
-
332
- .modal-footer {
333
- padding: 16px 20px;
334
- border-top: 1px solid var(--border);
335
- background: rgba(0,0,0,0.2);
336
- display: flex;
337
- justify-content: space-between;
338
- align-items: center;
339
- }
340
-
341
- /* --- GAME UI COMPONENTS --- */
342
- .game-arena {
343
- background: #000;
344
- border-radius: var(--radius-md);
345
- min-height: 250px;
346
  display: flex;
347
- flex-direction: column;
348
- justify-content: center;
349
  align-items: center;
350
- margin-bottom: 20px;
351
- position: relative;
352
- padding: 20px;
353
- border: 1px solid var(--border);
354
- }
355
-
356
- .game-message {
357
- font-size: 1.5rem;
358
- font-weight: 700;
359
- margin-bottom: 10px;
360
- text-align: center;
361
- }
362
-
363
- /* Playing Cards */
364
- .cards-row {
365
- display: flex;
366
- justify-content: center;
367
- gap: 10px;
368
- margin: 10px 0;
369
- flex-wrap: wrap;
370
- }
371
-
372
- .playing-card {
373
- width: 60px;
374
- height: 84px;
375
- background: white;
376
- border-radius: 6px;
377
- color: #333;
378
- font-weight: bold;
379
- display: flex;
380
- flex-direction: column;
381
- justify-content: space-between;
382
- padding: 6px;
383
- font-size: 1.2rem;
384
- box-shadow: 0 2px 5px rgba(0,0,0,0.3);
385
- animation: dealCard 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
386
- }
387
-
388
- @keyframes dealCard {
389
- from { opacity: 0; transform: translateY(-20px) scale(0.8); }
390
- to { opacity: 1; transform: translateY(0) scale(1); }
391
  }
392
 
393
- .playing-card.red { color: #dc2626; }
394
- .playing-card.black { color: #1e293b; }
395
-
396
- .card-center { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 1.5rem; }
397
- .card-corner-bottom { transform: rotate(180deg); }
398
-
399
- .hidden-card {
400
- background: repeating-linear-gradient(45deg, #1e293b, #1e293b 10px, #334155 10px, #334155 20px);
401
- border: 2px solid #fff;
402
  }
403
- .hidden-card * { display: none; }
404
 
405
- /* Slot Machine */
406
- .slot-machine {
407
- display: flex;
408
- gap: 10px;
409
- background: #222;
410
- padding: 15px;
411
- border-radius: 10px;
412
- border: 4px solid var(--accent-gold);
413
- }
414
- .slot-reel {
415
- width: 60px;
416
- height: 80px;
417
- background: #fff;
418
- border-radius: 4px;
419
- display: flex;
420
- align-items: center;
421
- justify-content: center;
422
- font-size: 2.5rem;
423
- color: #333;
424
  }
425
 
426
- /* Controls */
427
- .bet-controls {
428
- display: flex;
429
- align-items: center;
430
- gap: 10px;
431
- background: var(--bg-surface-hover);
432
- padding: 5px;
433
- border-radius: var(--radius-sm);
434
- }
435
- .bet-btn {
436
- width: 32px;
437
- height: 32px;
438
- border-radius: 6px;
439
- border: none;
440
- background: var(--bg-surface);
441
- color: var(--text-main);
442
- cursor: pointer;
443
- font-weight: bold;
444
  }
445
- .bet-btn:hover { background: var(--primary); color: white; }
446
- .bet-display { min-width: 60px; text-align: center; font-weight: 600; }
447
 
448
- .game-actions {
449
- display: grid;
450
- grid-template-columns: repeat(3, 1fr);
451
- gap: 10px;
452
  }
453
- .game-actions.full { grid-template-columns: 1fr; }
454
 
455
- /* --- TOAST NOTIFICATIONS --- */
456
- .toast-container {
457
  position: fixed;
458
- bottom: 20px;
459
- right: 20px;
460
- z-index: 200;
461
  display: flex;
462
  flex-direction: column;
463
- gap: 10px;
 
464
  }
465
 
466
  .toast {
467
- background: var(--bg-surface);
468
- border-left: 4px solid var(--primary);
469
- padding: 12px 20px;
470
  border-radius: 4px;
471
- box-shadow: var(--shadow-lg);
472
- color: var(--text-main);
473
- font-size: 0.9rem;
474
- animation: slideIn 0.3s ease;
475
  display: flex;
476
  align-items: center;
477
- gap: 10px;
 
478
  }
479
- .toast.success { border-color: var(--accent-green); }
480
- .toast.error { border-color: var(--accent-red); }
481
 
482
- @keyframes slideIn {
483
- from { transform: translateX(100%); opacity: 0; }
484
- to { transform: translateX(0); opacity: 1; }
485
  }
486
 
487
- /* --- FOOTER --- */
488
- footer {
489
- margin-top: auto;
490
- padding: 30px 0;
491
- background: var(--bg-surface);
492
- border-top: 1px solid var(--border);
493
- text-align: center;
494
  }
495
- .footer-link {
496
- color: var(--text-muted);
497
- text-decoration: none;
498
- font-size: 0.85rem;
499
- transition: color 0.2s;
500
- }
501
- .footer-link:hover { color: var(--primary); }
502
 
503
- /* --- RESPONSIVE --- */
504
- @media (max-width: 768px) {
505
- .promo-card { grid-template-columns: 1fr; text-align: center; }
506
- .promo-image { height: 150px; order: -1; }
507
- .header-controls span { display: none; } /* Hide label text on mobile */
508
- .modal { height: 100vh; max-height: 100vh; border-radius: 0; }
509
  }
510
  </style>
511
  </head>
512
  <body>
513
 
514
- <!-- NAV -->
515
  <header>
516
- <div class="container flex-between">
517
- <div class="logo">
518
- <i class="fas fa-crown"></i>
519
- <span>ROYAL FORTUNE</span>
520
- </div>
521
- <div class="header-controls">
522
- <select id="langSelect" class="lang-select">
523
- <option value="en">EN</option>
524
- <option value="es">ES</option>
525
- <option value="fr">FR</option>
526
- <option value="de">DE</option>
527
- </select>
528
- <div class="balance-pill">
529
- <i class="fas fa-coins"></i>
530
- <span id="balanceDisplay">1000</span>
531
- </div>
532
- <button class="btn btn-primary" id="topUpBtn">
533
- <i class="fas fa-plus"></i>
534
- <span class="desktop-only" data-i18n="topUp">Top Up</span>
535
- </button>
536
- </div>
537
  </div>
 
 
 
538
  </header>
539
 
540
- <!-- MAIN CONTENT -->
541
- <main class="container">
542
-
543
- <!-- HERO -->
544
- <section class="hero">
545
- <div class="promo-card">
546
- <div class="promo-content">
547
- <h1 class="promo-title" data-i18n="heroTitle">Welcome to Fortune</h1>
548
- <p class="promo-desc" data-i18n="heroDesc">Experience the thrill of modern gaming. Play smarter, win bigger.</p>
549
- <div style="margin-bottom: 15px;">
550
- <span style="background: rgba(16, 185, 129, 0.2); color: var(--accent-green); padding: 4px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600;">
551
- <i class="fas fa-gift"></i> <span data-i18n="dailyBonus">Daily Bonus Active</span>
552
- </span>
553
  </div>
554
- <button class="btn btn-gold" onclick="openGame('blackjack')">
555
- <span data-i18n="playNow">Play Now</span> <i class="fas fa-arrow-right"></i>
556
- </button>
 
 
 
 
 
557
  </div>
558
- <div class="promo-image"></div>
559
  </div>
560
- </section>
561
 
562
- <!-- GAMES -->
563
- <section>
564
- <div class="section-header">
565
- <h2 class="section-title" data-i18n="ourGames">Our Games</h2>
 
 
 
 
 
 
 
 
 
566
  </div>
567
-
568
- <div class="games-grid" id="gamesGrid">
569
- <!-- Injected via JS -->
 
 
 
 
 
 
 
 
 
 
 
 
 
570
  </div>
571
- </section>
572
 
573
- </main>
574
 
575
- <!-- FOOTER -->
576
- <footer>
577
- <div class="container">
578
- <p style="color: var(--text-muted); font-size: 0.85rem; margin-bottom: 10px;">
579
- &copy; 2023 Royal Fortune. <span data-i18n="responsibleGamble">Please gamble responsibly.</span>
580
- </p>
581
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="footer-link" style="font-weight: 600; color: var(--primary);">
582
- Built with anycoder
583
- </a>
584
- </div>
585
- </footer>
586
-
587
- <!-- TOP UP MODAL -->
588
- <div class="modal-overlay" id="topUpModal">
589
- <div class="modal">
590
- <div class="modal-header">
591
- <h3 class="modal-title" data-i18n="addFunds">Add Funds</h3>
592
- <button class="close-btn" onclick="closeModal('topUpModal')">&times;</button>
593
- </div>
594
- <div class="modal-body">
595
- <div class="form-group">
596
- <label style="display:block; margin-bottom: 8px; color: var(--text-muted);" data-i18n="amount">Amount</label>
597
- <input type="number" id="topUpInput" class="form-input" value="500" min="10" style="width: 100%; padding: 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg-body); color: white;">
598
  </div>
599
  </div>
600
- <div class="modal-footer">
601
- <button class="btn btn-outline" onclick="closeModal('topUpModal')" data-i18n="cancel">Cancel</button>
602
- <button class="btn btn-primary" onclick="processTopUp()" data-i18n="confirm">Confirm</button>
603
- </div>
604
- </div>
605
- </div>
606
-
607
- <!-- GAME MODAL -->
608
- <div class="modal-overlay" id="gameModal">
609
- <div class="modal" style="max-width: 600px;">
610
- <div class="modal-header">
611
- <h3 class="modal-title" id="gameModalTitle">Game</h3>
612
- <button class="close-btn" onclick="closeGame()">&times;</button>
613
  </div>
614
- <div class="modal-body">
615
- <div class="game-arena" id="gameArena">
616
- <!-- Dynamic Game Content -->
 
 
 
 
617
  </div>
 
 
 
618
  </div>
619
- <div class="modal-footer">
620
- <div class="bet-controls">
621
- <button class="bet-btn" onclick="adjustBet(-10)">-</button>
622
- <span class="bet-display"><i class="fas fa-coins" style="color: var(--accent-gold)"></i> <span id="currentBet">10</span></span>
623
- <button class="bet-btn" onclick="adjustBet(10)">+</button>
624
- </div>
625
- <div class="game-actions" id="gameControls">
626
- <!-- Dynamic Buttons -->
627
- </div>
628
  </div>
629
- </div>
630
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
631
 
632
- <!-- TOAST CONTAINER -->
633
- <div class="toast-container" id="toastContainer"></div>
634
 
635
  <script>
636
- // --- TRANSLATIONS ---
637
- const i18n = {
638
- en: {
639
- topUp: "Top Up", heroTitle: "Welcome to Fortune", heroDesc: "Experience the thrill of modern gaming.",
640
- dailyBonus: "Daily Bonus Active", playNow: "Play Now", ourGames: "Our Games",
641
- addFunds: "Add Funds", amount: "Amount", confirm: "Confirm", cancel: "Cancel",
642
- spin: "Spin", hit: "Hit", stand: "Stand", double: "Double",
643
- red: "Red", black: "Black", green: "Green", higher: "Higher", lower: "Lower",
644
- msgWin: "You Won!", msgLose: "House Wins", msgBust: "Bust!", msgTie: "Push",
645
- msgInsufficient: "Insufficient Funds!", responsibleGamble: "Please gamble responsibly.",
646
- games: {
647
- slots: { name: "Neon Slots", desc: "Match symbols to win" },
648
- blackjack: { name: "Blackjack", desc: "Beat the dealer to 21" },
649
- roulette: { name: "Roulette", desc: "Pick your lucky color" },
650
- highlow: { name: "High Low", desc: "Guess the next card" }
651
- }
652
- },
653
- es: {
654
- topUp: "Recargar", heroTitle: "Bienvenido", heroDesc: "Vive la emoción del juego moderno.",
655
- dailyBonus: "Bono Diario Activo", playNow: "Jugar", ourGames: "Nuestros Juegos",
656
- addFunds: "Añadir Fondos", amount: "Cantidad", confirm: "Confirmar", cancel: "Cancelar",
657
- spin: "Girar", hit: "Pedir", stand: "Plantarse", double: "Doblar",
658
- red: "Rojo", black: "Negro", green: "Verde", higher: "Más Alto", lower: "Más Bajo",
659
- msgWin: "¡Ganaste!", msgLose: "Gana la Casa", msgBust: "¡Te pasaste!", msgTie: "Empate",
660
- msgInsufficient: "¡Fondos insuficientes!", responsibleGamble: "Juega con responsabilidad.",
661
- games: {
662
- slots: { name: "Tragamonedas", desc: "Combina símbolos" },
663
- blackjack: { name: "Blackjack", desc: "Supera al croupier" },
664
- roulette: { name: "Ruleta", desc: "Elige tu color" },
665
- highlow: { name: "Alto Bajo", desc: "Adivina la carta" }
666
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
667
  }
668
- // Simplified for brevity, defaulting to EN/ES logic
669
- };
670
-
671
- // --- STATE ---
672
- const state = {
673
- balance: 1000,
674
- bet: 10,
675
- lang: 'en',
676
- activeGame: null,
677
- // Game States
678
- bj: { deck: [], player: [], dealer: [], active: false },
679
- slots: { symbols: ['🍒', '🍋', '🍉', '⭐', '💎', '7️⃣'] }
680
- };
681
-
682
- // --- CORE FUNCTIONS ---
683
- function init() {
684
- renderGames();
685
- updateBalanceUI();
686
- setupEventListeners();
687
- }
688
-
689
- function updateText() {
690
- document.querySelectorAll('[data-i18n]').forEach(el => {
691
- const key = el.getAttribute('data-i18n');
692
- if (i18n[state.lang][key]) {
693
- el.textContent = i18n[state.lang][key];
694
- }
695
- });
696
- renderGames(); // Re-render grid for game titles
697
  }
698
 
699
- function updateBalanceUI() {
700
- document.getElementById('balanceDisplay').textContent = state.balance;
701
- document.getElementById('currentBet').textContent = state.bet;
702
- }
703
-
704
- function showToast(msg, type = 'info') {
705
- const container = document.getElementById('toastContainer');
706
- const toast = document.createElement('div');
707
- toast.className = `toast ${type}`;
708
- toast.innerHTML = `<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i> ${msg}`;
709
- container.appendChild(toast);
710
- setTimeout(() => toast.remove(), 3000);
711
- }
712
 
713
- // --- MODAL & NAVIGATION ---
714
- function openModal(id) { document.getElementById(id).classList.add('active'); }
715
- function closeModal(id) { document.getElementById(id).classList.remove('active'); }
716
 
717
- function openTopUp() { openModal('topUpModal'); }
718
-
719
- function processTopUp() {
720
- const amount = parseInt(document.getElementById('topUpInput').value);
721
- if (amount > 0) {
722
- state.balance += amount;
723
- updateBalanceUI();
724
- closeModal('topUpModal');
725
- showToast(i18n[state.lang].msgTopUpSuccess || "Funds added!", 'success');
 
 
 
 
 
726
  }
727
- }
728
 
729
- function openGame(gameId) {
730
- if (state.balance < state.bet) {
731
- showToast(i18n[state.lang].msgInsufficient, 'error');
732
- openTopUp();
733
- return;
734
- }
735
- state.activeGame = gameId;
736
- const gameNames = i18n[state.lang].games;
737
- document.getElementById('gameModalTitle').textContent = gameNames[gameId].name;
738
- openModal('gameModal');
 
 
 
 
 
 
 
739
 
740
- // Init Game
741
- if (gameId === 'blackjack') initBlackjack();
742
- else if (gameId === 'slots') initSlots();
743
- else if (gameId === 'roulette') initRoulette();
744
- else if (gameId === 'highlow') initHighLow();
 
 
 
 
 
 
 
 
 
 
745
  }
746
 
747
- function closeGame() {
748
- closeModal('gameModal');
749
- state.activeGame = null;
 
 
 
 
 
 
 
 
 
 
 
750
  }
751
 
752
- function adjustBet(amount) {
753
- const newBet = state.bet + amount;
754
- if (newBet >= 10 && newBet <= state.balance) {
755
- state.bet = newBet;
756
- updateBalanceUI();
 
 
 
 
 
 
 
 
 
 
757
  }
 
 
 
 
 
 
 
758
  }
759
 
760
- // --- GAME GRID RENDERING ---
761
- function renderGames() {
762
- const grid = document.getElementById('gamesGrid');
763
- const games = ['slots', 'blackjack', 'roulette', 'highlow'];
764
- const meta = i18n[state.lang].games;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
765
 
766
- grid.innerHTML = games.map(g => {
767
- const info = meta[g];
768
- // Generate a consistent gradient based on game name
769
- return `
770
- <div class="game-card" onclick="openGame('${g}')">
771
- <div class="card-thumb" style="background: linear-gradient(135deg, hsl(${Math.random()*360}, 60%, 20%), hsl(${Math.random()*360}, 60%, 10%))">
772
- <div style="position: absolute; bottom: 10px; left: 10px; font-size: 2rem;">
773
- ${g === 'slots' ? '🎰' : g === 'blackjack' ? '🃏' : g === 'roulette' ? '🎡' : '📈'}
774
- </div>
775
- </div>
776
- <div class="card-body">
777
- <div>
778
- <div class="game-name">${info.name}</div>
779
- <div class="game-meta">
780
- <span>${info.desc}</span>
781
- </div>
782
- </div>
783
- <div style="margin-top: 10px; display:flex; justify-content:space-between; align-items:center;">
784
- <span class="game-tag">CASINO</span>
785
- <i class="fas fa-play-circle" style="color: var(--primary);"></i>
786
- </div>
787
- </div>
788
- </div>
789
- `;
790
- }).join('');
791
  }
792
 
793
- // --- GAME LOGIC: BLACKJACK ---
794
- function initBlackjack() {
795
- state.bj = { deck: [], player: [], dealer: [], active: true };
796
- createDeck();
797
- shuffleDeck();
798
- dealBJ();
799
- renderBJ();
800
-
801
- const controls = document.getElementById('gameControls');
802
- controls.innerHTML = `
803
- <button class="btn btn-primary" onclick="bjHit()">${i18n[state.lang].hit}</button>
804
- <button class="btn btn-danger" onclick="bjStand()">${i18n[state.lang].stand}</button>
805
- <button class="btn btn-outline" onclick="bjDouble()" id="bjDoubleBtn">${i18n[state.lang].double}</button>
806
- `;
807
-
808
- if (state.bet * 2 > state.balance) document.getElementById('bjDoubleBtn').disabled = true;
809
  }
810
 
811
- function createDeck() {
812
- const suits = ['♠', '♥', '♦', '♣'];
813
- const values = ['2','3','4','5','6','7','8','9','10','J','Q','K','A'];
814
- state.bj.deck = [];
815
- for(let s of suits) {
816
- for(let v of values) {
817
- state.bj.deck.push({ suit: s, value: v });
818
- }
819
  }
820
- }
 
 
 
 
 
 
 
 
821
 
822
- function shuffleDeck() {
823
- for (let i = state.bj.deck.length - 1; i > 0; i--) {
824
- const j = Math.floor(Math.random() * (i + 1));
825
- [state.bj.deck[i], state.bj.deck[j]] = [state.bj.deck[j], state.bj.deck[i]];
826
  }
827
  }
828
 
829
- function getHandValue(hand) {
830
- let val = 0;
831
- let aces = 0;
832
- for(let card of hand) {
833
- if (['J','Q','K'].includes(card.value)) val += 10;
834
- else if (card.value === 'A') { val += 11; aces++; }
835
- else val += parseInt(card.value);
836
- }
837
- while (val > 21 && aces > 0) { val -= 10; aces--; }
838
- return val;
839
- }
840
-
841
- function dealBJ() {
842
- state.bj.player.push(state.bj.deck.pop());
843
- state.bj.dealer.push(state.bj.deck.pop());
844
- state.bj.player.push(state.bj.deck.pop());
845
- state.bj.dealer.push(state.bj.deck.pop());
846
- }
847
-
848
- function renderBJ(showDealer = false) {
849
- const arena = document.getElementById('gameArena');
850
- const pScore = getHandValue(state.bj.player);
851
- const dScore = getHandValue(state.bj.dealer);
852
-
853
- let dealerHTML = state.bj.dealer.map((c, i) => {
854
- if (i === 1 && !showDealer) return `<div class="playing-card hidden-card"></div>`;
855
- return `<div class="playing-card ${['♥','♦'].includes(c.suit)?'red':'black'}">
856
- <div>${c.value} ${c.suit}</div>
857
- <div class="card-center">${c.suit}</div>
858
- <div class="card-corner-bottom">${c.value} ${c.suit}</div>
859
- </div>`;
860
- }).join('');
861
-
862
- let playerHTML = state.bj.player.map(c =>
863
- `<div class="playing-card ${['♥','♦'].includes(c.suit)?'red':'black'}">
864
- <div>${c.value} ${c.suit}</div>
865
- <div class="card-center">${c.suit}</div>
866
- <div class="card-corner-bottom">${c.value} ${c.suit}</div>
867
- </div>`
868
- ).join('');
869
-
870
- let msg = "";
871
- let color = "white";
872
 
873
- if (pScore > 21) { msg = i18n[state.lang].msgBust; color = "var(--accent-red)"; endBJ('lose'); }
874
- else if (pScore === 21) { msg = "BLACKJACK!"; color = "var(--accent-gold)"; endBJ('blackjack'); }
875
-
876
- arena.innerHTML = `
877
- <div style="width:100%">
878
- <div style="text-align:center; color:var(--text-muted); font-size:0.8rem; margin-bottom:5px;">DEALER (${showDealer ? dScore : '?'})</div>
879
- <div class="cards-row">${dealerHTML}</div>
880
- <div style="height: 20px;"></div>
881
- <div style="text-align:center; color:var(--text-muted); font-size:0.8rem; margin-bottom:5px;">YOU (${pScore})</div>
882
- <div class="cards-row">${playerHTML}</div>
883
- <div class="game-message" style="color:${color}; margin-top: 20px;">${msg}</div>
884
- </div>
885
- `;
886
- }
887
 
888
- function bjHit() {
889
- state.bj.player.push(state.bj.deck.pop());
890
- renderBJ();
 
891
  }
892
 
893
- function bjStand() {
894
- // Dealer Logic
895
- while(getHandValue(state.bj.dealer) < 17) {
896
- state.bj.dealer.push(state.bj.deck.pop());
897
- }
898
- renderBJ(true);
899
- determineWinner();
900
  }
901
 
902
- function bjDouble() {
903
- state.balance -= state.bet; // Deduct extra bet
904
- updateBalanceUI();
905
- state.bj.player.push(state.bj.deck.pop());
906
- bjStand();
907
- }
 
 
 
 
 
 
 
 
 
 
 
 
908
 
909
- function determineWinner() {
910
- const p = getHandValue(state.bj.player);
911
- const d = getHandValue(state.bj.dealer);
912
- let msg = "";
913
 
914
- if (p > 21) msg = i18n[state.lang].msgBust;
915
- else if (d > 21) msg = i18n[state.lang].msgWin;
916
- else if (p > d) msg = i18n[state.lang].msgWin;
917
- else if (p < d) msg = i18n[state.lang].msgLose;
918
- else msg = i18n[state.lang].msgTie;
919
 
920
- const arena = document.getElementById('gameArena');
921
- const msgEl = arena.querySelector('.game-message');
922
- msgEl.textContent = msg;
923
- msgEl.style.color = msg === i18n[state.lang].msgWin ? "var(--accent-green)" : (msg === i18n[state.lang].msgTie ? "white" : "var(--accent-red)");
 
 
 
 
 
 
 
 
924
  }
925
 
926
- function endBJ(result) {
927
- state.bj.active = false;
928
- document.getElementById('gameControls').innerHTML = `<button class="btn btn-primary full" onclick="openGame('blackjack')">Play Again</button>`;
929
-
930
- if (result === 'blackjack') {
931
- state.balance += state.bet * 2.5;
932
- showToast(`Blackjack! +${state.bet * 1.5}`, 'success');
933
- } else if (result === 'lose') {
934
- state.balance -= state.bet;
935
- showToast(`Lost
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>NetDiag: Host & Connection Monitor</title>
7
+ <!-- Importing FontAwesome for Icons -->
 
 
 
 
 
 
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+
10
  <style>
 
11
  :root {
12
+ --bg-color: #0f172a;
13
+ --card-bg: rgba(30, 41, 59, 0.7);
14
+ --card-border: rgba(148, 163, 184, 0.1);
15
+ --text-primary: #f1f5f9;
16
+ --text-secondary: #94a3b8;
17
+ --accent-cyan: #06b6d4;
 
18
  --accent-green: #10b981;
19
+ --accent-red: #ef4444;
20
+ --accent-orange: #f59e0b;
21
+ --glow: 0 0 15px rgba(6, 182, 212, 0.3);
22
+ --font-main: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
 
 
 
 
23
  }
24
 
25
  * {
26
  box-sizing: border-box;
27
  margin: 0;
28
  padding: 0;
 
29
  }
30
 
31
  body {
32
+ font-family: var(--font-main);
33
+ background-color: var(--bg-color);
34
+ background-image:
35
+ radial-gradient(at 0% 0%, rgba(6, 182, 212, 0.15) 0px, transparent 50%),
36
+ radial-gradient(at 100% 100%, rgba(16, 185, 129, 0.15) 0px, transparent 50%);
37
+ color: var(--text-primary);
38
  min-height: 100vh;
39
  display: flex;
40
  flex-direction: column;
41
+ overflow-x: hidden;
42
  }
43
 
44
+ /* --- Header --- */
45
+ header {
46
+ display: flex;
47
+ justify-content: space-between;
48
+ align-items: center;
49
+ padding: 1.5rem 2rem;
50
+ border-bottom: 1px solid var(--card-border);
51
+ backdrop-filter: blur(10px);
52
+ position: sticky;
53
+ top: 0;
54
+ z-index: 100;
55
+ background: rgba(15, 23, 42, 0.8);
56
  }
57
 
58
+ .brand {
59
+ display: flex;
 
 
 
 
 
 
60
  align-items: center;
61
+ gap: 0.75rem;
62
+ font-size: 1.5rem;
63
+ font-weight: 700;
64
+ color: var(--accent-cyan);
65
+ text-shadow: 0 0 10px rgba(6, 182, 212, 0.4);
 
 
 
 
66
  }
67
 
68
+ .brand i {
69
+ font-size: 1.8rem;
 
 
 
70
  }
 
71
 
72
+ .anycoder-link {
73
+ font-size: 0.9rem;
74
+ color: var(--text-secondary);
75
+ text-decoration: none;
76
+ padding: 0.5rem 1rem;
77
+ border: 1px solid var(--card-border);
78
+ border-radius: 20px;
79
+ transition: all 0.3s ease;
80
  }
 
81
 
82
+ .anycoder-link:hover {
83
+ color: var(--text-primary);
84
+ border-color: var(--accent-cyan);
85
+ box-shadow: var(--glow);
86
  }
 
87
 
88
+ /* --- Main Layout --- */
89
+ main {
90
+ flex: 1;
91
+ padding: 2rem;
92
+ max-width: 1400px;
93
+ margin: 0 auto;
94
+ width: 100%;
95
+ display: grid;
96
+ grid-template-columns: repeat(12, 1fr);
97
+ gap: 1.5rem;
98
+ }
99
+
100
+ /* --- Cards Generic --- */
101
+ .card {
102
+ background: var(--card-bg);
103
+ border: 1px solid var(--card-border);
104
+ border-radius: 16px;
105
+ padding: 1.5rem;
106
+ backdrop-filter: blur(12px);
107
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
108
+ display: flex;
109
+ flex-direction: column;
110
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
111
  }
112
 
113
+ .card:hover {
114
+ transform: translateY(-2px);
115
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
 
 
 
 
116
  }
 
117
 
118
+ .card-header {
119
  display: flex;
120
+ justify-content: space-between;
121
  align-items: center;
122
+ margin-bottom: 1rem;
123
  }
124
 
125
+ .card-title {
126
+ font-size: 1rem;
 
 
127
  font-weight: 600;
128
+ color: var(--text-secondary);
 
129
  display: flex;
130
  align-items: center;
131
+ gap: 0.5rem;
 
132
  }
133
 
134
+ /* --- Specific Grid Areas --- */
135
+ .status-panel {
136
+ grid-column: span 12;
137
+ display: grid;
138
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
139
+ gap: 1.5rem;
 
140
  }
141
 
142
+ .chart-panel {
143
+ grid-column: span 8;
144
+ min-height: 400px;
145
  }
146
 
147
+ .log-panel {
148
+ grid-column: span 4;
149
+ min-height: 400px;
 
 
 
 
 
 
 
 
150
  overflow: hidden;
151
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
+ .controls-panel {
154
+ grid-column: span 12;
155
+ display: flex;
156
+ justify-content: flex-end;
157
+ gap: 1rem;
158
+ align-items: center;
159
  }
160
 
161
+ /* --- Metrics & Visuals --- */
162
+ .metric-value {
163
+ font-size: 2.5rem;
164
+ font-weight: 700;
165
+ margin: 0.5rem 0;
166
  }
167
 
168
+ .metric-unit {
169
+ font-size: 1rem;
170
+ color: var(--text-secondary);
171
+ font-weight: 400;
 
 
172
  }
173
 
174
+ .status-indicator {
175
+ width: 12px;
176
+ height: 12px;
177
+ border-radius: 50%;
178
+ background-color: var(--text-secondary);
179
+ box-shadow: 0 0 10px currentColor;
180
+ transition: background-color 0.3s ease, box-shadow 0.3s ease;
181
  }
 
182
 
183
+ .status-indicator.active { background-color: var(--accent-green); color: var(--accent-green); }
184
+ .status-indicator.warning { background-color: var(--accent-orange); color: var(--accent-orange); }
185
+ .status-indicator.critical { background-color: var(--accent-red); color: var(--accent-red); }
 
 
 
186
 
187
+ /* Progress Bars */
188
+ .progress-container {
189
+ width: 100%;
190
+ height: 8px;
191
+ background: rgba(255, 255, 255, 0.1);
192
+ border-radius: 4px;
193
  overflow: hidden;
194
+ margin-top: 0.5rem;
 
 
 
 
195
  }
196
 
197
+ .progress-bar {
198
+ height: 100%;
199
+ width: 0%;
200
+ background: var(--accent-cyan);
201
+ border-radius: 4px;
202
+ transition: width 0.5s ease, background-color 0.3s ease;
 
 
 
203
  position: relative;
 
 
204
  }
205
 
206
+ .progress-bar::after {
207
  content: '';
208
  position: absolute;
209
+ top: 0; left: 0; right: 0; bottom: 0;
210
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
211
+ transform: translateX(-100%);
212
+ animation: shimmer 2s infinite;
213
  }
214
 
215
+ @keyframes shimmer {
216
+ 100% { transform: translateX(100%); }
 
 
 
 
217
  }
218
 
219
+ /* Canvas */
220
+ canvas {
221
+ width: 100%;
222
+ height: 100%;
223
+ display: block;
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
225
 
226
+ /* Logs */
227
+ .log-container {
228
+ font-family: 'Courier New', monospace;
229
+ font-size: 0.85rem;
230
+ color: var(--text-secondary);
231
+ overflow-y: auto;
232
+ flex: 1;
233
+ padding-right: 0.5rem;
 
 
 
 
234
  display: flex;
235
  flex-direction: column;
236
+ gap: 0.25rem;
237
  }
238
 
239
+ .log-entry {
 
 
 
 
240
  display: flex;
241
+ gap: 0.5rem;
 
242
  }
243
 
244
+ .log-time { color: var(--accent-cyan); }
245
+ .log-msg-info { color: var(--text-primary); }
246
+ .log-msg-warn { color: var(--accent-orange); }
247
+ .log-msg-err { color: var(--accent-red); }
248
 
249
+ /* Buttons */
250
+ .btn {
251
+ padding: 0.75rem 1.5rem;
252
+ border-radius: 8px;
253
  border: none;
254
+ font-weight: 600;
 
255
  cursor: pointer;
256
+ transition: all 0.2s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  display: flex;
 
 
258
  align-items: center;
259
+ gap: 0.5rem;
260
+ font-size: 0.95rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  }
262
 
263
+ .btn-primary {
264
+ background: var(--accent-cyan);
265
+ color: #0f172a;
 
 
 
 
 
 
266
  }
 
267
 
268
+ .btn-primary:hover {
269
+ background: #22d3ee;
270
+ box-shadow: 0 0 15px rgba(6, 182, 212, 0.5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
272
 
273
+ .btn-danger {
274
+ background: transparent;
275
+ border: 1px solid var(--accent-red);
276
+ color: var(--accent-red);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  }
 
 
278
 
279
+ .btn-danger:hover {
280
+ background: rgba(239, 68, 68, 0.1);
 
 
281
  }
 
282
 
283
+ /* Toast Notification */
284
+ #toast-container {
285
  position: fixed;
286
+ bottom: 2rem;
287
+ right: 2rem;
 
288
  display: flex;
289
  flex-direction: column;
290
+ gap: 1rem;
291
+ z-index: 1000;
292
  }
293
 
294
  .toast {
295
+ background: rgba(15, 23, 42, 0.95);
296
+ border-left: 4px solid var(--accent-cyan);
297
+ padding: 1rem 1.5rem;
298
  border-radius: 4px;
299
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
300
+ color: var(--text-primary);
301
+ transform: translateX(120%);
302
+ transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
303
  display: flex;
304
  align-items: center;
305
+ gap: 0.75rem;
306
+ backdrop-filter: blur(5px);
307
  }
 
 
308
 
309
+ .toast.show {
310
+ transform: translateX(0);
 
311
  }
312
 
313
+ /* Responsive Design */
314
+ @media (max-width: 1024px) {
315
+ .chart-panel { grid-column: span 12; }
316
+ .log-panel { grid-column: span 12; min-height: 250px; }
 
 
 
317
  }
 
 
 
 
 
 
 
318
 
319
+ @media (max-width: 600px) {
320
+ header { flex-direction: column; gap: 1rem; }
321
+ .metric-value { font-size: 2rem; }
322
+ .controls-panel { flex-direction: column; align-items: stretch; }
 
 
323
  }
324
  </style>
325
  </head>
326
  <body>
327
 
 
328
  <header>
329
+ <div class="brand">
330
+ <i class="fa-solid fa-network-wired"></i>
331
+ <span>NetDiag</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  </div>
333
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">
334
+ Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square" style="font-size: 0.7em; margin-left:4px;"></i>
335
+ </a>
336
  </header>
337
 
338
+ <main>
339
+ <!-- Status Panel: Host vs Connection -->
340
+ <section class="status-panel">
341
+
342
+ <!-- Host Limits (CPU/RAM) -->
343
+ <div class="card">
344
+ <div class="card-header">
345
+ <div class="card-title">
346
+ <i class="fa-solid fa-server"></i> Host CPU Load
 
 
 
 
347
  </div>
348
+ <div id="host-status-light" class="status-indicator active"></div>
349
+ </div>
350
+ <div class="metric-value" id="cpu-val">0%</div>
351
+ <div class="progress-container">
352
+ <div id="cpu-bar" class="progress-bar"></div>
353
+ </div>
354
+ <div style="margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-secondary);">
355
+ Limit: 90% (Throttling Threshold)
356
  </div>
 
357
  </div>
 
358
 
359
+ <div class="card">
360
+ <div class="card-header">
361
+ <div class="card-title">
362
+ <i class="fa-solid fa-memory"></i> Memory Usage
363
+ </div>
364
+ </div>
365
+ <div class="metric-value" id="ram-val">0<span class="metric-unit">GB</span></div>
366
+ <div class="progress-container">
367
+ <div id="ram-bar" class="progress-bar" style="background-color: var(--accent-green);"></div>
368
+ </div>
369
+ <div style="margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-secondary);">
370
+ Total: 16 GB
371
+ </div>
372
  </div>
373
+
374
+ <!-- Connection Quality -->
375
+ <div class="card">
376
+ <div class="card-header">
377
+ <div class="card-title">
378
+ <i class="fa-solid fa-wifi"></i> Connection Latency
379
+ </div>
380
+ <div id="conn-status-light" class="status-indicator active"></div>
381
+ </div>
382
+ <div class="metric-value" id="ping-val">0<span class="metric-unit">ms</span></div>
383
+ <div class="progress-container">
384
+ <div id="ping-bar" class="progress-bar" style="background-color: var(--accent-orange);"></div>
385
+ </div>
386
+ <div style="margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-secondary);">
387
+ Jitter: <span id="jitter-val">0</span>ms
388
+ </div>
389
  </div>
 
390
 
391
+ </section>
392
 
393
+ <!-- Main Chart Panel -->
394
+ <section class="card chart-panel">
395
+ <div class="card-header">
396
+ <div class="card-title">
397
+ <i class="fa-solid fa-chart-line"></i> Real-Time Traffic Analysis
398
+ </div>
399
+ <div style="font-size: 0.8rem; color: var(--text-secondary);">
400
+ <span style="color: var(--accent-cyan)">●</span> Requests &nbsp;
401
+ <span style="color: var(--accent-red)">●</span> Errors
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  </div>
403
  </div>
404
+ <div style="flex: 1; position: relative;">
405
+ <canvas id="trafficChart"></canvas>
 
 
 
 
 
 
 
 
 
 
 
406
  </div>
407
+ </section>
408
+
409
+ <!-- Log Panel -->
410
+ <section class="card log-panel">
411
+ <div class="card-header">
412
+ <div class="card-title">
413
+ <i class="fa-solid fa-terminal"></i> System Logs
414
  </div>
415
+ <button onclick="clearLogs()" style="background:none; border:none; color:var(--text-secondary); cursor:pointer;">
416
+ <i class="fa-solid fa-trash"></i>
417
+ </button>
418
  </div>
419
+ <div class="log-container" id="log-container">
420
+ <!-- Logs will appear here -->
 
 
 
 
 
 
 
421
  </div>
422
+ </section>
423
+
424
+ <!-- Controls -->
425
+ <section class="controls-panel">
426
+ <button class="btn btn-danger" id="stop-btn" onclick="toggleMonitoring(false)" disabled>
427
+ <i class="fa-solid fa-stop"></i> Stop Monitor
428
+ </button>
429
+ <button class="btn btn-primary" id="start-btn" onclick="toggleMonitoring(true)">
430
+ <i class="fa-solid fa-play"></i> Start Diagnostics
431
+ </button>
432
+ <button class="btn btn-primary" style="background: var(--accent-orange);" onclick="simulateSpike()">
433
+ <i class="fa-solid fa-bolt"></i> Test Host Limit
434
+ </button>
435
+ </section>
436
+
437
+ </main>
438
 
439
+ <!-- Toast Container -->
440
+ <div id="toast-container"></div>
441
 
442
  <script>
443
+ // --- State Management ---
444
+ let isRunning = false;
445
+ let intervalId = null;
446
+ let chartIntervalId = null;
447
+
448
+ // Data arrays for the chart
449
+ const maxDataPoints = 60;
450
+ let trafficData = new Array(maxDataPoints).fill(0);
451
+ let errorData = new Array(maxDataPoints).fill(0);
452
+
453
+ // --- DOM Elements ---
454
+ const cpuVal = document.getElementById('cpu-val');
455
+ const cpuBar = document.getElementById('cpu-bar');
456
+ const ramVal = document.getElementById('ram-val');
457
+ const ramBar = document.getElementById('ram-bar');
458
+ const pingVal = document.getElementById('ping-val');
459
+ const pingBar = document.getElementById('ping-bar');
460
+ const jitterVal = document.getElementById('jitter-val');
461
+
462
+ const hostLight = document.getElementById('host-status-light');
463
+ const connLight = document.getElementById('conn-status-light');
464
+
465
+ const logContainer = document.getElementById('log-container');
466
+ const canvas = document.getElementById('trafficChart');
467
+ const ctx = canvas.getContext('2d');
468
+
469
+ // --- Initialization ---
470
+ resizeCanvas();
471
+ window.addEventListener('resize', resizeCanvas);
472
+ addLog("System initialized. Ready to diagnose.", "info");
473
+
474
+ // --- Core Logic ---
475
+
476
+ function toggleMonitoring(start) {
477
+ if (start) {
478
+ if (isRunning) return;
479
+ isRunning = true;
480
+ document.getElementById('start-btn').disabled = true;
481
+ document.getElementById('stop-btn').disabled = false;
482
+ addLog("Diagnostics started...", "info");
483
+ showToast("Monitoring Active", "success");
484
+
485
+ // Start Data Loop (Every 1s)
486
+ intervalId = setInterval(updateMetrics, 1000);
487
+
488
+ // Start Chart Loop (Every 100ms for smoothness)
489
+ chartIntervalId = setInterval(updateChartData, 100);
490
+ } else {
491
+ isRunning = false;
492
+ document.getElementById('start-btn').disabled = false;
493
+ document.getElementById('stop-btn').disabled = true;
494
+ clearInterval(intervalId);
495
+ clearInterval(chartIntervalId);
496
+ addLog("Diagnostics paused by user.", "warn");
497
+ showToast("Monitoring Paused", "default");
498
+
499
+ // Reset lights
500
+ hostLight.className = "status-indicator";
501
+ connLight.className = "status-indicator";
502
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  }
504
 
505
+ function updateMetrics() {
506
+ // Simulate Host Stats (CPU/RAM)
507
+ // Random fluctuation + potential spike
508
+ let cpu = Math.floor(Math.random() * 30) + 20; // Base 20-50%
509
+ let ram = (Math.random() * 2 + 4).toFixed(1); // Base 4-6 GB
 
 
 
 
 
 
 
 
510
 
511
+ // Randomly spike CPU to simulate host limit issues
512
+ if (Math.random() > 0.8) cpu += 30;
 
513
 
514
+ // Update DOM - CPU
515
+ cpuVal.innerText = cpu + "%";
516
+ cpuBar.style.width = cpu + "%";
517
+
518
+ if (cpu > 90) {
519
+ cpuBar.style.backgroundColor = "var(--accent-red)";
520
+ hostLight.className = "status-indicator critical";
521
+ if(Math.random() > 0.7) addLog("Host CPU Limit Critical! Throttling detected.", "err");
522
+ } else if (cpu > 70) {
523
+ cpuBar.style.backgroundColor = "var(--accent-orange)";
524
+ hostLight.className = "status-indicator warning";
525
+ } else {
526
+ cpuBar.style.backgroundColor = "var(--accent-cyan)";
527
+ hostLight.className = "status-indicator active";
528
  }
 
529
 
530
+ // Update DOM - RAM
531
+ ramVal.innerHTML = ram + '<span class="metric-unit">GB</span>';
532
+ const ramPercent = (ram / 16) * 100;
533
+ ramBar.style.width = ramPercent + "%";
534
+ if(ramPercent > 80) ramBar.style.backgroundColor = "var(--accent-red)";
535
+ else ramBar.style.backgroundColor = "var(--accent-green)";
536
+
537
+ // Simulate Connection Stats (Ping/Jitter)
538
+ let ping = Math.floor(Math.random() * 40) + 10; // Base 10-50ms
539
+ let jitter = Math.floor(Math.random() * 10);
540
+
541
+ // Randomly spike Ping to simulate connection issues
542
+ if (Math.random() > 0.85) ping += 150;
543
+
544
+ // Update DOM - Ping
545
+ pingVal.innerHTML = ping + '<span class="metric-unit">ms</span>';
546
+ jitterVal.innerText = jitter;
547
 
548
+ // Ping bar scale: 0ms = 0%, 200ms = 100%
549
+ const pingPercent = Math.min((ping / 200) * 100, 100);
550
+ pingBar.style.width = pingPercent + "%";
551
+
552
+ if (ping > 150) {
553
+ pingBar.style.backgroundColor = "var(--accent-red)";
554
+ connLight.className = "status-indicator critical";
555
+ if(Math.random() > 0.7) addLog(`Connection timeout: ${ping}ms latency.`, "err");
556
+ } else if (ping > 80) {
557
+ pingBar.style.backgroundColor = "var(--accent-orange)";
558
+ connLight.className = "status-indicator warning";
559
+ } else {
560
+ pingBar.style.backgroundColor = "var(--accent-green)";
561
+ connLight.className = "status-indicator active";
562
+ }
563
  }
564
 
565
+ function updateChartData() {
566
+ // Shift data
567
+ trafficData.shift();
568
+ errorData.shift();
569
+
570
+ // Add new random data points
571
+ // Traffic usually flows
572
+ let newTraffic = Math.floor(Math.random() * 50) + 20;
573
+ let newError = Math.random() > 0.95 ? Math.floor(Math.random() * 40) : 0;
574
+
575
+ trafficData.push(newTraffic);
576
+ errorData.push(newError);
577
+
578
+ drawChart();
579
  }
580
 
581
+ // --- Canvas Drawing (2D Tool) ---
582
+ function drawChart() {
583
+ const w = canvas.width;
584
+ const h = canvas.height;
585
+
586
+ // Clear
587
+ ctx.clearRect(0, 0, w, h);
588
+
589
+ // Grid lines
590
+ ctx.strokeStyle = "rgba(148, 163, 184, 0.1)";
591
+ ctx.lineWidth = 1;
592
+ ctx.beginPath();
593
+ for(let i=0; i<h; i+=40) {
594
+ ctx.moveTo(0, i);
595
+ ctx.lineTo(w, i);
596
  }
597
+ ctx.stroke();
598
+
599
+ // Draw Traffic Line (Cyan)
600
+ drawLine(trafficData, "#06b6d4", 2);
601
+
602
+ // Draw Error Line (Red)
603
+ drawLine(errorData, "#ef4444", 2);
604
  }
605
 
606
+ function drawLine(data, color, width) {
607
+ const w = canvas.width;
608
+ const h = canvas.height;
609
+ const step = w / (maxDataPoints - 1);
610
+
611
+ ctx.beginPath();
612
+ ctx.strokeStyle = color;
613
+ ctx.lineWidth = width;
614
+ ctx.lineJoin = 'round';
615
+
616
+ for (let i = 0; i < data.length; i++) {
617
+ // Map value (0-100) to height
618
+ // y = h - (value/100 * h)
619
+ const y = h - ((data[i] / 100) * h);
620
+ const x = i * step;
621
+
622
+ if (i === 0) ctx.moveTo(x, y);
623
+ else ctx.lineTo(x, y);
624
+ }
625
+ ctx.stroke();
626
+
627
+ // Add fill gradient under the line
628
+ ctx.lineTo(w, h);
629
+ ctx.lineTo(0, h);
630
+ ctx.closePath();
631
 
632
+ const gradient = ctx.createLinearGradient(0, 0, 0, h);
633
+ gradient.addColorStop(0, color + "44"); // Hex + alpha
634
+ gradient.addColorStop(1, color + "00");
635
+ ctx.fillStyle = gradient;
636
+ ctx.fill();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
637
  }
638
 
639
+ function resizeCanvas() {
640
+ // Handle high DPI displays
641
+ const container = canvas.parentElement;
642
+ canvas.width = container.clientWidth;
643
+ canvas.height = container.clientHeight;
644
+ drawChart();
 
 
 
 
 
 
 
 
 
 
645
  }
646
 
647
+ // --- Interaction: Simulate Host Limit ---
648
+ function simulateSpike() {
649
+ if(!isRunning) {
650
+ showToast("Start monitoring first!", "warn");
651
+ return;
 
 
 
652
  }
653
+
654
+ // Force visual spike
655
+ cpuVal.innerText = "98%";
656
+ cpuBar.style.width = "98%";
657
+ cpuBar.style.backgroundColor = "var(--accent-red)";
658
+ hostLight.className = "status-indicator critical";
659
+
660
+ addLog("MANUAL TEST: Simulating Host Limit Breach...", "err");
661
+ showToast("Host Limit Test Triggered", "error");
662
 
663
+ // Inject data into chart
664
+ for(let i=0; i<20; i++) {
665
+ trafficData.push(Math.random() * 20 + 80);
666
+ trafficData.shift();
667
  }
668
  }
669
 
670
+ // --- Utilities ---
671
+
672
+ function addLog(msg, type) {
673
+ const time = new Date().toLocaleTimeString('en-US', { hour12: false });
674
+ const div = document.createElement('div');
675
+ div.className = 'log-entry';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676
 
677
+ let colorClass = "log-msg-info";
678
+ if (type === "warn") colorClass = "log-msg-warn";
679
+ if (type === "err") colorClass = "log-msg-err";
 
 
 
 
 
 
 
 
 
 
 
680
 
681
+ div.innerHTML = `<span class="log-time">[${time}]</span> <span class="${colorClass}">${msg}</span>`;
682
+
683
+ logContainer.appendChild(div);
684
+ logContainer.scrollTop = logContainer.scrollHeight; // Auto scroll
685
  }
686
 
687
+ function clearLogs() {
688
+ logContainer.innerHTML = '';
689
+ addLog("Logs cleared.", "info");
 
 
 
 
690
  }
691
 
692
+ function showToast(message, type = "default") {
693
+ const container = document.getElementById('toast-container');
694
+ const toast = document.createElement('div');
695
+ toast.className = 'toast';
696
+
697
+ let icon = '<i class="fa-solid fa-info-circle"></i>';
698
+ let color = 'var(--accent-cyan)';
699
+
700
+ if (type === 'success') {
701
+ icon = '<i class="fa-solid fa-check-circle"></i>';
702
+ color = 'var(--accent-green)';
703
+ } else if (type === 'error') {
704
+ icon = '<i class="fa-solid fa-triangle-exclamation"></i>';
705
+ color = 'var(--accent-red)';
706
+ } else if (type === 'warn') {
707
+ icon = '<i class="fa-solid fa-exclamation-circle"></i>';
708
+ color = 'var(--accent-orange)';
709
+ }
710
 
711
+ toast.style.borderLeftColor = color;
712
+ toast.innerHTML = `<span style="color:${color}; font-size: 1.2rem;">${icon}</span> ${message}`;
 
 
713
 
714
+ container.appendChild(toast);
 
 
 
 
715
 
716
+ // Trigger animation
717
+ requestAnimationFrame(() => {
718
+ toast.classList.add('show');
719
+ });
720
+
721
+ // Remove after 3 seconds
722
+ setTimeout(() => {
723
+ toast.classList.remove('show');
724
+ setTimeout(() => {
725
+ toast.remove();
726
+ }, 300);
727
+ }, 3000);
728
  }
729
 
730
+ </script>
731
+ </body>
732
+ </html>