Dhurgh commited on
Commit
e807d13
Β·
1 Parent(s): 4624e03

Fix video call: ICE state crash, dead TURN servers, video not playing after recovery (v2.6.3)

Browse files
Files changed (3) hide show
  1. client.js +0 -0
  2. index.html +641 -46
  3. package.json +1 -1
client.js CHANGED
The diff for this file is too large to render. See raw diff
 
index.html CHANGED
@@ -4,6 +4,7 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Discord-Like Chat App</title>
 
7
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
  <style>
9
  * {
@@ -187,6 +188,15 @@
187
  cursor: pointer;
188
  }
189
 
 
 
 
 
 
 
 
 
 
190
 
191
  .main-container {
192
  display: grid;
@@ -247,6 +257,7 @@
247
  border-right: 1px solid var(--border-color);
248
  display: flex;
249
  flex-direction: column;
 
250
  }
251
 
252
  .sidebar-header {
@@ -272,9 +283,49 @@
272
 
273
  .channels-list {
274
  flex: 1;
275
- overflow-y: scroll;
276
  padding: 8px 0;
277
  scrollbar-gutter: stable;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
279
 
280
  .channel-item {
@@ -285,6 +336,17 @@
285
  align-items: center;
286
  gap: 10px;
287
  transition: all 0.2s ease;
 
 
 
 
 
 
 
 
 
 
 
288
  }
289
 
290
  .channel-item:hover {
@@ -346,6 +408,10 @@
346
  color: var(--text-secondary);
347
  font-size: 12px;
348
  font-weight: bold;
 
 
 
 
349
  }
350
 
351
 
@@ -401,6 +467,20 @@
401
  transition: all 0.2s ease;
402
  }
403
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  .header-btn:hover {
405
  color: var(--text-primary);
406
  }
@@ -421,6 +501,7 @@
421
  flex: 1;
422
  min-height: 0;
423
  overflow-y: auto;
 
424
  padding: 16px 24px;
425
  padding-right: 44px;
426
  padding-bottom: 24px;
@@ -479,6 +560,8 @@
479
  animation: fadeIn 0.2s ease;
480
  scroll-snap-align: end;
481
  scroll-snap-stop: always;
 
 
482
  }
483
 
484
  @keyframes fadeIn {
@@ -501,6 +584,8 @@
501
 
502
  .message-content {
503
  flex: 1;
 
 
504
  }
505
 
506
  .message-header {
@@ -598,12 +683,16 @@
598
  .message-text {
599
  color: var(--text-primary);
600
  line-height: 1.5;
 
 
 
601
  }
602
 
603
  .message-media {
604
  margin-top: 8px;
605
  border-radius: 8px;
606
  max-width: 400px;
 
607
  overflow: hidden;
608
  }
609
 
@@ -799,21 +888,290 @@
799
  overflow-y: auto;
800
  display: flex;
801
  flex-direction: column;
 
 
 
 
 
802
  }
803
 
804
  .profile-panel.show {
805
  transform: translateX(0);
 
 
806
  }
807
 
808
- .profile-close {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
809
  position: absolute;
810
- top: 12px;
811
- right: 12px;
812
- background: none;
813
  border: none;
814
- color: var(--text-secondary);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
  font-size: 24px;
816
  cursor: pointer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817
  }
818
 
819
  .profile-header {
@@ -849,6 +1207,9 @@
849
  .profile-content {
850
  padding: 24px;
851
  flex: 1;
 
 
 
852
  }
853
 
854
  .tab-buttons {
@@ -954,6 +1315,36 @@
954
  align-items: center;
955
  }
956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
957
  .shop-item-name {
958
  font-weight: 600;
959
  font-size: 14px;
@@ -975,6 +1366,67 @@
975
  font-size: 12px;
976
  }
977
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
978
  .friend-item {
979
  padding: 12px;
980
  background: var(--bg-color);
@@ -1087,14 +1539,24 @@
1087
  border-radius: 8px 8px 0 0;
1088
  box-shadow: 0 -4px 24px rgba(0,0,0,0.3);
1089
  display: none;
1090
- flex-direction: column;
1091
- z-index: 100;
1092
- border: 1px solid var(--border-color);
1093
- border-bottom: none;
1094
  }
1095
 
1096
  .picker-panel.show {
1097
  display: flex;
 
 
 
 
 
 
 
 
 
 
 
 
1098
  }
1099
 
1100
  .picker-tabs {
@@ -1621,6 +2083,11 @@
1621
  display: none;
1622
  }
1623
 
 
 
 
 
 
1624
  .header-btn {
1625
  font-size: 16px;
1626
  padding: 8px;
@@ -1629,16 +2096,15 @@
1629
  .chat-header-actions {
1630
  gap: 4px;
1631
  flex-wrap: nowrap;
 
 
 
1632
  }
1633
 
1634
  .chat-header-actions .header-btn {
1635
  padding: 6px;
1636
- }
1637
-
1638
- .chat-header-actions button:nth-of-type(1),
1639
- .chat-header-actions button:nth-of-type(3),
1640
- .chat-header-actions button:nth-of-type(7) {
1641
- display: none;
1642
  }
1643
 
1644
 
@@ -1676,21 +2142,25 @@
1676
 
1677
 
1678
  .input-area {
1679
- padding: 12px 16px;
1680
- gap: 8px;
1681
  flex-shrink: 0;
1682
  border-top: 2px solid var(--border-color);
 
 
 
1683
  }
1684
 
1685
  .input-area input {
1686
  font-size: 16px;
1687
- padding: 10px 14px;
 
1688
  }
1689
 
1690
  .input-btn {
1691
- width: 40px;
1692
- height: 40px;
1693
- font-size: 16px;
1694
  flex-shrink: 0;
1695
  }
1696
 
@@ -2191,6 +2661,16 @@
2191
 
2192
 
2193
  @media (max-width: 768px) {
 
 
 
 
 
 
 
 
 
 
2194
  .custom-dialog-content {
2195
  min-width: 90%;
2196
  padding: 24px;
@@ -2235,6 +2715,9 @@
2235
  .profile-panel {
2236
  width: 100vw;
2237
  right: -100vw;
 
 
 
2238
  }
2239
 
2240
  .profile-panel.show {
@@ -2262,12 +2745,19 @@
2262
  }
2263
 
2264
  .channel-sidebar .sidebar-header > div button {
2265
- display: none;
 
 
2266
  }
2267
 
2268
- .channel-sidebar .sidebar-header > div button:nth-child(3),
2269
- .channel-sidebar .sidebar-header > div button:nth-child(5) {
2270
- display: inline-block;
 
 
 
 
 
2271
  }
2272
 
2273
 
@@ -2313,16 +2803,27 @@
2313
  .chat-header-actions {
2314
  gap: 4px;
2315
  flex-shrink: 0;
 
 
 
2316
  }
2317
 
2318
  .chat-header-actions button {
2319
- display: none;
 
 
 
2320
  }
2321
 
2322
  .chat-header-actions .mobile-essential {
2323
  display: inline-flex;
2324
  }
2325
 
 
 
 
 
 
2326
  .build-badge {
2327
  display: none;
2328
  }
@@ -2395,14 +2896,18 @@
2395
  left: 0;
2396
  top: 0;
2397
  width: 100vw;
2398
- height: 100vh;
2399
- z-index: 1000;
 
 
 
2400
  }
2401
 
2402
  .profile-content {
2403
  width: 100%;
2404
  max-width: none;
2405
  border-radius: 0;
 
2406
  }
2407
 
2408
  .friends-modal {
@@ -2476,6 +2981,7 @@
2476
  </div>
2477
  <button type="button" class="auth-mini-button" onclick="resetForgottenPassword()">Reset Password</button>
2478
  </div>
 
2479
  <div class="auth-toggle">
2480
  <span>Don't have an account? <button type="button" onclick="toggleAuthMode()">Register</button></span>
2481
  </div>
@@ -2542,8 +3048,8 @@
2542
  <div class="chat-header-title" id="chatTitle">πŸ’¬ Select a friend to chat</div>
2543
  </div>
2544
  <div class="chat-header-actions">
2545
- <span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.3.3</span>
2546
- <button class="header-btn" onclick="toggleArchiveChat()" title="Archive chat">
2547
  <i class="fas fa-archive"></i>
2548
  </button>
2549
  <button class="header-btn mobile-essential" onclick="startVideoCall()" title="Video call">
@@ -2552,10 +3058,10 @@
2552
  <button class="header-btn mobile-essential" onclick="togglePinCurrentChat()" title="Pin/Unpin chat" id="pinChatBtn">
2553
  <i class="fas fa-thumbtack"></i>
2554
  </button>
2555
- <button class="header-btn success" onclick="addCurrentChatToList()" title="Add chat to list">
2556
  <i class="fas fa-bookmark"></i>
2557
  </button>
2558
- <button class="header-btn danger-hover mobile-essential" onclick="closeCurrentChat()" title="Close Chat" id="closeChatBtn" style="display: none;">
2559
  <i class="fas fa-times-circle"></i>
2560
  </button>
2561
  <button class="header-btn mobile-essential" onclick="toggleMobileMembers()" title="View members">
@@ -2567,6 +3073,10 @@
2567
  <button class="header-btn mobile-essential" onclick="openSettings()" title="Settings">
2568
  <i class="fas fa-cog"></i>
2569
  </button>
 
 
 
 
2570
  <button class="header-btn mobile-essential" onclick="openProfile()" title="Profile">
2571
  <i class="fas fa-user-circle"></i>
2572
  </button>
@@ -2596,8 +3106,8 @@
2596
  <button class="input-btn" onclick="document.getElementById('fileInput').click()" title="Upload Image">
2597
  <i class="fas fa-image"></i>
2598
  </button>
2599
- <button class="input-btn" onclick="document.getElementById('videoInput').click()" title="Upload Video">
2600
- <i class="fas fa-video"></i>
2601
  </button>
2602
  <button class="input-btn" onclick="togglePicker()" title="Stickers & GIFs">
2603
  <i class="fas fa-smile"></i>
@@ -2610,7 +3120,7 @@
2610
  <i class="fas fa-paper-plane"></i>
2611
  </button>
2612
  <input type="file" id="fileInput" class="input-file" onchange="handleFileUpload(event)" accept="image/*" multiple>
2613
- <input type="file" id="videoInput" class="input-file" onchange="handleFileUpload(event)" accept="video/*" multiple>
2614
  </div>
2615
  </div>
2616
 
@@ -2622,8 +3132,15 @@
2622
  </div>
2623
 
2624
 
 
 
 
2625
  <div class="profile-panel" id="profilePanel">
2626
  <button class="profile-close" onclick="closeProfile()"><i class="fas fa-times"></i></button>
 
 
 
 
2627
  <div class="profile-header">
2628
  <div class="profile-avatar" id="profileAvatar">U</div>
2629
  <div class="profile-name" id="profileName">Username</div>
@@ -2633,6 +3150,8 @@
2633
  <div class="tab-buttons">
2634
  <button class="tab-btn active" onclick="switchProfileTab('profile', this)">Profile</button>
2635
  <button class="tab-btn" onclick="switchProfileTab('inventory', this)">Inventory</button>
 
 
2636
  </div>
2637
 
2638
 
@@ -2667,6 +3186,30 @@
2667
  <div class="tab-content" id="inventoryTab">
2668
  <div id="inventoryList"></div>
2669
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2670
  </div>
2671
  </div>
2672
 
@@ -2674,9 +3217,9 @@
2674
  <div class="modal-content">
2675
  <h2><i class="fas fa-users"></i> Friends & Friend Requests</h2>
2676
  <h3 style="margin-top: 20px; margin-bottom: 10px;">Pending Requests</h3>
2677
- <div id="friendRequests"></div>
2678
  <h3 style="margin-top: 20px; margin-bottom: 10px;">Your Friends</h3>
2679
- <div id="friendsList"></div>
2680
  <button class="save-btn" onclick="closeFriendsModal()" style="margin-top: 20px;">Close</button>
2681
  </div>
2682
  </div>
@@ -2691,14 +3234,26 @@
2691
  </div>
2692
  </div>
2693
 
 
 
 
 
 
 
 
 
 
 
 
 
2694
 
2695
  <div class="toast-container" id="toastContainer"></div>
2696
 
2697
 
2698
  <div class="picker-panel" id="pickerPanel">
2699
  <div class="picker-tabs">
2700
- <button class="picker-tab active" onclick="switchPickerTab('stickers')">πŸ˜€ Stickers</button>
2701
- <button class="picker-tab" onclick="switchPickerTab('gifs')">🎬 GIFs</button>
2702
  </div>
2703
  <div class="picker-content" id="pickerContent">
2704
 
@@ -2971,23 +3526,25 @@
2971
 
2972
 
2973
  <div class="modal hidden" id="communitiesModal">
2974
- <div class="modal-content">
2975
  <h2><i class="fas fa-globe"></i> Communities</h2>
2976
  <p style="margin-top: 10px; color: var(--text-secondary);">Join public communities to discover people with shared interests.</p>
2977
- <div id="communitiesList" style="margin-top: 16px;"></div>
 
2978
  <button class="save-btn" onclick="closeCommunitiesModal()" style="margin-top: 20px;">Close</button>
2979
  </div>
2980
  </div>
2981
 
2982
 
2983
  <div class="modal hidden" id="groupsModal">
2984
- <div class="modal-content">
2985
  <h2><i class="fas fa-user-group"></i> Groups</h2>
2986
  <p style="margin-top: 10px; color: var(--text-secondary);">Create and manage your own small group chats.</p>
2987
- <div id="groupsList" style="margin-top: 16px;"></div>
 
 
2988
  <button class="save-btn" onclick="closeGroupsModal()" style="margin-top: 20px;">Close</button>
2989
  </div>
2990
-
2991
  </div>
2992
 
2993
 
@@ -3070,9 +3627,47 @@
3070
 
3071
  <div id="customDialog" style="display: none;"></div>
3072
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3073
  <script src="/socket.io/socket.io.js"></script>
3074
  <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
3075
- <script src="client.js?v=2.2.9"></script>
3076
  </body>
3077
  </html>
3078
 
 
 
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Discord-Like Chat App</title>
7
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ctext y='50' font-size='48'%3EπŸ’¬%3C/text%3E%3C/svg%3E">
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
  * {
 
188
  cursor: pointer;
189
  }
190
 
191
+ .auth-status {
192
+ margin-top: 12px;
193
+ font-size: 13px;
194
+ min-height: 18px;
195
+ color: var(--text-secondary);
196
+ text-align: center;
197
+ line-height: 1.35;
198
+ }
199
+
200
 
201
  .main-container {
202
  display: grid;
 
257
  border-right: 1px solid var(--border-color);
258
  display: flex;
259
  flex-direction: column;
260
+ min-height: 0;
261
  }
262
 
263
  .sidebar-header {
 
283
 
284
  .channels-list {
285
  flex: 1;
286
+ overflow-y: auto;
287
  padding: 8px 0;
288
  scrollbar-gutter: stable;
289
+ min-height: 0;
290
+ padding-bottom: 24px;
291
+ }
292
+
293
+ .archived-modal-content {
294
+ background: var(--chat-bg);
295
+ padding: 20px;
296
+ border-radius: 10px;
297
+ width: min(95vw, 900px);
298
+ max-height: 88vh;
299
+ display: flex;
300
+ flex-direction: column;
301
+ box-shadow: 0 16px 44px rgba(0,0,0,0.55);
302
+ border: 1px solid var(--border-color);
303
+ }
304
+
305
+ .archived-modal-list {
306
+ flex: 1;
307
+ overflow-y: auto;
308
+ margin-top: 10px;
309
+ padding-right: 4px;
310
+ min-height: 260px;
311
+ scrollbar-gutter: stable;
312
+ overscroll-behavior: contain;
313
+ }
314
+
315
+ .archived-modal-list::-webkit-scrollbar {
316
+ width: 10px;
317
+ }
318
+
319
+ .archived-modal-list::-webkit-scrollbar-thumb {
320
+ background: rgba(255, 255, 255, 0.22);
321
+ border-radius: 8px;
322
+ border: 2px solid transparent;
323
+ background-clip: content-box;
324
+ }
325
+
326
+ .archived-modal-list::-webkit-scrollbar-track {
327
+ background: rgba(255, 255, 255, 0.06);
328
+ border-radius: 8px;
329
  }
330
 
331
  .channel-item {
 
336
  align-items: center;
337
  gap: 10px;
338
  transition: all 0.2s ease;
339
+ min-width: 0;
340
+ position: relative;
341
+ z-index: 1;
342
+ }
343
+
344
+ .channel-label {
345
+ min-width: 0;
346
+ flex: 1;
347
+ overflow: hidden;
348
+ text-overflow: ellipsis;
349
+ white-space: nowrap;
350
  }
351
 
352
  .channel-item:hover {
 
408
  color: var(--text-secondary);
409
  font-size: 12px;
410
  font-weight: bold;
411
+ position: relative;
412
+ background: var(--sidebar-bg);
413
+ border-top: 1px solid var(--border-color);
414
+ border-bottom: 1px solid var(--border-color);
415
  }
416
 
417
 
 
467
  transition: all 0.2s ease;
468
  }
469
 
470
+ @keyframes headerFloat {
471
+ 0%, 100% { transform: translateY(0); }
472
+ 50% { transform: translateY(-2px); }
473
+ }
474
+
475
+ .chat-header-actions .header-btn {
476
+ animation: headerFloat 3.6s ease-in-out infinite;
477
+ }
478
+
479
+ .chat-header-actions .header-btn:nth-child(2) { animation-delay: 0.25s; }
480
+ .chat-header-actions .header-btn:nth-child(3) { animation-delay: 0.5s; }
481
+ .chat-header-actions .header-btn:nth-child(4) { animation-delay: 0.75s; }
482
+ .chat-header-actions .header-btn:nth-child(5) { animation-delay: 1s; }
483
+
484
  .header-btn:hover {
485
  color: var(--text-primary);
486
  }
 
501
  flex: 1;
502
  min-height: 0;
503
  overflow-y: auto;
504
+ overflow-x: hidden;
505
  padding: 16px 24px;
506
  padding-right: 44px;
507
  padding-bottom: 24px;
 
560
  animation: fadeIn 0.2s ease;
561
  scroll-snap-align: end;
562
  scroll-snap-stop: always;
563
+ min-width: 0;
564
+ max-width: 100%;
565
  }
566
 
567
  @keyframes fadeIn {
 
584
 
585
  .message-content {
586
  flex: 1;
587
+ min-width: 0;
588
+ max-width: 100%;
589
  }
590
 
591
  .message-header {
 
683
  .message-text {
684
  color: var(--text-primary);
685
  line-height: 1.5;
686
+ overflow-wrap: anywhere;
687
+ word-break: break-word;
688
+ max-width: 100%;
689
  }
690
 
691
  .message-media {
692
  margin-top: 8px;
693
  border-radius: 8px;
694
  max-width: 400px;
695
+ width: min(100%, 400px);
696
  overflow: hidden;
697
  }
698
 
 
888
  overflow-y: auto;
889
  display: flex;
890
  flex-direction: column;
891
+ visibility: hidden;
892
+ -webkit-overflow-scrolling: touch;
893
+ overscroll-behavior: contain;
894
+ touch-action: pan-y;
895
+ pointer-events: none;
896
  }
897
 
898
  .profile-panel.show {
899
  transform: translateX(0);
900
+ visibility: visible;
901
+ pointer-events: auto;
902
  }
903
 
904
+ /* ==================== PROFILE BANNER ==================== */
905
+ .profile-banner-wrap {
906
+ position: relative;
907
+ width: 100%;
908
+ height: 160px;
909
+ background: linear-gradient(135deg, var(--primary-color), #4752c4);
910
+ overflow: hidden;
911
+ flex-shrink: 0;
912
+ }
913
+ .profile-banner-img {
914
+ width: 100%;
915
+ height: 100%;
916
+ object-fit: cover;
917
+ display: block;
918
+ }
919
+ .profile-banner-edit-btn {
920
  position: absolute;
921
+ bottom: 8px;
922
+ right: 8px;
923
+ background: rgba(0,0,0,0.55);
924
  border: none;
925
+ color: white;
926
+ border-radius: 6px;
927
+ padding: 4px 10px;
928
+ font-size: 12px;
929
+ cursor: pointer;
930
+ transition: background 0.2s;
931
+ }
932
+ .profile-banner-edit-btn:hover { background: rgba(0,0,0,0.85); }
933
+
934
+ /* ==================== CALL OVERLAY ==================== */
935
+ #callOverlay {
936
+ position: fixed;
937
+ inset: 0;
938
+ background: #0a0a0a;
939
+ z-index: 10000;
940
+ display: none;
941
+ flex-direction: column;
942
+ }
943
+ #callOverlay.active { display: flex; }
944
+ #remoteCallVideo, #localCallVideo, #localCallVideoOld {
945
+ display: block;
946
+ }
947
+ .call-overlay-header {
948
+ position: absolute;
949
+ top: 0; left: 0; right: 0;
950
+ padding: 16px 20px;
951
+ background: linear-gradient(180deg, rgba(0,0,0,0.75), transparent);
952
+ z-index: 2;
953
+ display: flex;
954
+ align-items: center;
955
+ justify-content: space-between;
956
+ }
957
+ .call-overlay-controls {
958
+ position: absolute;
959
+ bottom: 0; left: 0; right: 0;
960
+ padding: 24px 20px 32px;
961
+ background: linear-gradient(0deg, rgba(0,0,0,0.75), transparent);
962
+ display: flex;
963
+ justify-content: center;
964
+ gap: 20px;
965
+ z-index: 2;
966
+ }
967
+ .call-ctrl-btn {
968
+ width: 64px; height: 64px;
969
+ border-radius: 50%;
970
+ background: rgba(255,255,255,0.18);
971
+ border: 2px solid rgba(255,255,255,0.3);
972
+ color: white;
973
  font-size: 24px;
974
  cursor: pointer;
975
+ display: flex; align-items: center; justify-content: center;
976
+ transition: all 0.2s;
977
+ }
978
+ .call-ctrl-btn:hover { background: rgba(255,255,255,0.35); transform: scale(1.08); }
979
+ .call-ctrl-btn.muted { background: rgba(240,71,71,0.5); border-color: #f04747; }
980
+ .call-ctrl-btn.cam-off { background: rgba(240,71,71,0.5); border-color: #f04747; }
981
+ .call-end-btn {
982
+ width: 72px; height: 72px;
983
+ background: #f04747;
984
+ border: none;
985
+ border-radius: 50%;
986
+ color: white;
987
+ font-size: 26px;
988
+ cursor: pointer;
989
+ display: flex; align-items: center; justify-content: center;
990
+ transition: all 0.2s;
991
+ }
992
+ .call-end-btn:hover { background: #c0392b; transform: scale(1.1); }
993
+ #callDebugPanel {
994
+ position: absolute;
995
+ top: 80px; right: 10px;
996
+ background: rgba(0,0,0,0.88);
997
+ color: #00ff88;
998
+ font-size: 11px;
999
+ padding: 12px;
1000
+ border-radius: 8px;
1001
+ z-index: 3;
1002
+ min-width: 230px;
1003
+ font-family: monospace;
1004
+ border: 1px solid #00ff88;
1005
+ display: none;
1006
+ }
1007
+ #callDebugPanel .dbg-row { margin-bottom: 4px; }
1008
+
1009
+ /* ==================== NOTIFICATION PANEL ==================== */
1010
+ .notif-bell-btn {
1011
+ position: relative;
1012
+ }
1013
+ .notif-badge {
1014
+ position: absolute;
1015
+ top: -3px; right: -3px;
1016
+ background: #f04747;
1017
+ color: white;
1018
+ border-radius: 50%;
1019
+ width: 16px; height: 16px;
1020
+ font-size: 9px;
1021
+ font-weight: 700;
1022
+ display: none;
1023
+ align-items: center;
1024
+ justify-content: center;
1025
+ line-height: 1;
1026
+ }
1027
+ .notif-badge.visible { display: flex; }
1028
+ #notifPanel {
1029
+ position: fixed;
1030
+ top: 0; right: -360px;
1031
+ width: 340px;
1032
+ max-height: 100vh;
1033
+ background: var(--chat-bg);
1034
+ border-left: 1px solid var(--border-color);
1035
+ z-index: 1050;
1036
+ transition: right 0.3s ease;
1037
+ overflow-y: auto;
1038
+ box-shadow: -4px 0 24px rgba(0,0,0,0.4);
1039
+ display: flex; flex-direction: column;
1040
+ }
1041
+ #notifPanel.show { right: 0; }
1042
+ .notif-panel-header {
1043
+ padding: 16px 18px;
1044
+ border-bottom: 1px solid var(--border-color);
1045
+ display: flex; align-items: center; justify-content: space-between;
1046
+ position: sticky; top: 0;
1047
+ background: var(--chat-bg);
1048
+ z-index: 2;
1049
+ }
1050
+ .notif-item {
1051
+ padding: 12px 16px;
1052
+ border-bottom: 1px solid var(--border-color);
1053
+ cursor: pointer;
1054
+ transition: background 0.15s;
1055
+ }
1056
+ .notif-item:hover { background: var(--bg-color); }
1057
+ .notif-item.notif-unread { background: rgba(88,101,242,0.1); border-left: 3px solid var(--primary-color); }
1058
+ .notif-item-title { font-size: 13px; font-weight: 600; margin-bottom: 3px; }
1059
+ .notif-item-body { font-size: 12px; color: var(--text-secondary); }
1060
+ .notif-item-time { font-size: 10px; color: var(--text-secondary); margin-top: 4px; }
1061
+
1062
+ /* ==================== UPLOAD SPINNER ==================== */
1063
+ .upload-progress-bar {
1064
+ height: 3px;
1065
+ background: linear-gradient(90deg, var(--primary-color), #4752c4);
1066
+ border-radius: 2px;
1067
+ width: 0%;
1068
+ transition: width 0.3s ease;
1069
+ position: absolute;
1070
+ top: 0; left: 0; right: 0;
1071
+ }
1072
+ .upload-overlay {
1073
+ position: absolute;
1074
+ inset: 0;
1075
+ background: rgba(0,0,0,0.4);
1076
+ display: flex;
1077
+ align-items: center;
1078
+ justify-content: center;
1079
+ border-radius: 8px;
1080
+ z-index: 5;
1081
+ }
1082
+ @keyframes spin { to { transform: rotate(360deg); } }
1083
+ .spinner-ring {
1084
+ width: 40px; height: 40px;
1085
+ border: 3px solid rgba(255,255,255,0.2);
1086
+ border-top-color: white;
1087
+ border-radius: 50%;
1088
+ animation: spin 0.7s linear infinite;
1089
+ }
1090
+ .input-area { position: relative; }
1091
+ .input-upload-spinner {
1092
+ position: absolute;
1093
+ top: -2px; left: 0; right: 0;
1094
+ height: 3px;
1095
+ background: var(--bg-color);
1096
+ border-radius: 2px;
1097
+ overflow: hidden;
1098
+ }
1099
+ .input-upload-spinner-bar {
1100
+ height: 100%;
1101
+ background: linear-gradient(90deg, var(--primary-color), var(--success), var(--primary-color));
1102
+ background-size: 200% 100%;
1103
+ animation: shimmerSlide 1s linear infinite;
1104
+ width: 100%;
1105
+ }
1106
+ @keyframes shimmerSlide {
1107
+ 0% { background-position: 200% 0; }
1108
+ 100% { background-position: -200% 0; }
1109
+ }
1110
+
1111
+ /* ==================== HOVER EFFECTS ==================== */
1112
+ .message { transition: background 0.15s; border-radius: 8px; padding: 4px 6px; }
1113
+ .message:hover { background: rgba(255,255,255,0.04); }
1114
+ .friend-item { transition: all 0.18s ease; }
1115
+ .friend-item:hover { transform: translateX(3px); box-shadow: -3px 0 0 var(--primary-color); }
1116
+ .guild-item { transition: all 0.2s; }
1117
+ .guild-item:hover:not(.active) { border-radius: 16px; background: var(--primary-color); transform: scale(1.05); }
1118
+ .header-btn { transition: all 0.18s; }
1119
+ .header-btn:hover { background: rgba(255,255,255,0.12); transform: scale(1.1); border-radius: 6px; }
1120
+ .input-btn { transition: all 0.18s; }
1121
+ .input-btn:hover { background: rgba(88,101,242,0.18); color: var(--primary-color); transform: scale(1.1); }
1122
+ .tab-btn { transition: all 0.18s; }
1123
+ .tab-btn:hover:not(.active) { background: rgba(255,255,255,0.07); }
1124
+ .secondary-btn { transition: all 0.18s; }
1125
+ .secondary-btn:hover { background: rgba(88,101,242,0.2); transform: translateY(-1px); box-shadow: 0 3px 10px rgba(88,101,242,0.25); }
1126
+ .save-btn { transition: all 0.18s; }
1127
+ .save-btn:hover { filter: brightness(1.12); transform: translateY(-1px); box-shadow: 0 3px 12px rgba(88,101,242,0.3); }
1128
+ .message-action-btn { transition: all 0.18s; }
1129
+ .message-action-btn:hover { background: var(--primary-color) !important; color: white; transform: scale(1.15); }
1130
+ .mobile-nav-item { transition: all 0.2s; }
1131
+ .mobile-nav-item:hover, .mobile-nav-item.active { color: var(--primary-color); }
1132
+ .settings-nav-item { transition: all 0.15s; }
1133
+ .settings-nav-item:hover { background: rgba(88,101,242,0.15); color: var(--primary-color); }
1134
+
1135
+ /* ==================== GROUPS MODAL ENHANCEMENTS ==================== */
1136
+ .groups-search { width: 100%; padding: 10px 14px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 8px; color: var(--text-primary); font-size: 14px; margin-bottom: 12px; }
1137
+ .groups-search:focus { outline: none; border-color: var(--primary-color); }
1138
+ .group-card {
1139
+ display: flex; align-items: center; gap: 14px;
1140
+ padding: 14px 16px;
1141
+ background: var(--bg-color);
1142
+ border-radius: 10px;
1143
+ margin-bottom: 10px;
1144
+ border: 1px solid var(--border-color);
1145
+ transition: all 0.2s;
1146
+ }
1147
+ .group-card:hover { border-color: var(--primary-color); transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.3); }
1148
+ .group-avatar { width: 48px; height: 48px; border-radius: 14px; background: linear-gradient(135deg, var(--primary-color), #4752c4); display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
1149
+ .group-info { flex: 1; min-width: 0; }
1150
+ .group-name { font-weight: 700; font-size: 15px; }
1151
+ .group-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
1152
+ .group-members-count { font-size: 11px; color: var(--text-secondary); margin-top: 4px; }
1153
+ .create-group-btn { width: 100%; padding: 12px; background: linear-gradient(135deg, var(--primary-color), #4752c4); color: white; border: none; border-radius: 10px; cursor: pointer; font-size: 15px; font-weight: 700; margin-bottom: 14px; transition: all 0.2s; }
1154
+ .create-group-btn:hover { filter: brightness(1.1); transform: translateY(-2px); }
1155
+
1156
+ .profile-close {
1157
+ position: sticky;
1158
+ top: 8px;
1159
+ z-index: 100;
1160
+ align-self: flex-end;
1161
+ margin: 8px 10px -44px 0;
1162
+ background: rgba(0,0,0,0.55);
1163
+ border: none;
1164
+ color: white;
1165
+ font-size: 18px;
1166
+ cursor: pointer;
1167
+ width: 34px;
1168
+ height: 34px;
1169
+ border-radius: 50%;
1170
+ display: flex;
1171
+ align-items: center;
1172
+ justify-content: center;
1173
+ flex-shrink: 0;
1174
+ transition: background 0.2s;
1175
  }
1176
 
1177
  .profile-header {
 
1207
  .profile-content {
1208
  padding: 24px;
1209
  flex: 1;
1210
+ min-height: 0;
1211
+ overflow: visible;
1212
+ padding-bottom: 34px;
1213
  }
1214
 
1215
  .tab-buttons {
 
1315
  align-items: center;
1316
  }
1317
 
1318
+ .shop-hero {
1319
+ padding: 16px;
1320
+ margin-bottom: 12px;
1321
+ border-radius: 10px;
1322
+ border: 1px solid rgba(255,255,255,0.12);
1323
+ background: linear-gradient(135deg, rgba(88,101,242,0.28), rgba(67,181,129,0.15));
1324
+ }
1325
+
1326
+ .shop-hero-title {
1327
+ font-size: 18px;
1328
+ font-weight: 800;
1329
+ margin-bottom: 4px;
1330
+ }
1331
+
1332
+ .shop-hero-subtitle {
1333
+ font-size: 12px;
1334
+ color: var(--text-secondary);
1335
+ }
1336
+
1337
+ .shop-hero-discount {
1338
+ margin-top: 10px;
1339
+ display: inline-flex;
1340
+ padding: 4px 10px;
1341
+ border-radius: 999px;
1342
+ font-size: 11px;
1343
+ font-weight: 700;
1344
+ color: #fff;
1345
+ background: linear-gradient(135deg, #ff7b54, #ffb347);
1346
+ }
1347
+
1348
  .shop-item-name {
1349
  font-weight: 600;
1350
  font-size: 14px;
 
1366
  font-size: 12px;
1367
  }
1368
 
1369
+ .buy-btn:disabled {
1370
+ opacity: 0.55;
1371
+ cursor: not-allowed;
1372
+ }
1373
+
1374
+ .orb-card {
1375
+ padding: 12px;
1376
+ border: 1px solid var(--border-color);
1377
+ border-radius: 10px;
1378
+ background: var(--bg-color);
1379
+ margin-bottom: 10px;
1380
+ }
1381
+
1382
+ .saved-pill {
1383
+ display: inline-flex;
1384
+ align-items: center;
1385
+ gap: 8px;
1386
+ padding: 8px 12px;
1387
+ border-radius: 999px;
1388
+ border: 1px solid var(--border-color);
1389
+ background: var(--bg-color);
1390
+ margin: 0 8px 8px 0;
1391
+ font-size: 12px;
1392
+ }
1393
+
1394
+ .orb-none {
1395
+ --orb-glow: transparent;
1396
+ }
1397
+
1398
+ .orb-aurora {
1399
+ --primary-color: #57c7ff;
1400
+ --secondary-color: #3d6f9a;
1401
+ --orb-glow: rgba(87, 199, 255, 0.35);
1402
+ }
1403
+
1404
+ .orb-neon-pulse {
1405
+ --primary-color: #42e695;
1406
+ --secondary-color: #1f8c58;
1407
+ --orb-glow: rgba(66, 230, 149, 0.35);
1408
+ }
1409
+
1410
+ .orb-ocean-mist {
1411
+ --primary-color: #5fa8ff;
1412
+ --secondary-color: #2e5384;
1413
+ --orb-glow: rgba(95, 168, 255, 0.3);
1414
+ }
1415
+
1416
+ .orb-ember {
1417
+ --primary-color: #ff8f5e;
1418
+ --secondary-color: #8b3b1d;
1419
+ --orb-glow: rgba(255, 143, 94, 0.35);
1420
+ }
1421
+
1422
+ .orb-aurora .profile-avatar,
1423
+ .orb-neon-pulse .profile-avatar,
1424
+ .orb-ocean-mist .profile-avatar,
1425
+ .orb-ember .profile-avatar {
1426
+ box-shadow: 0 0 0 6px var(--orb-glow);
1427
+ transition: box-shadow 0.3s ease;
1428
+ }
1429
+
1430
  .friend-item {
1431
  padding: 12px;
1432
  background: var(--bg-color);
 
1539
  border-radius: 8px 8px 0 0;
1540
  box-shadow: 0 -4px 24px rgba(0,0,0,0.3);
1541
  display: none;
1542
+ z-index: 1002;
1543
+ overflow: hidden;
 
 
1544
  }
1545
 
1546
  .picker-panel.show {
1547
  display: flex;
1548
+ flex-direction: column;
1549
+ }
1550
+
1551
+ .profile-close:hover { background: rgba(255,255,255,0.25); }
1552
+
1553
+ #profileBackdrop {
1554
+ display: none;
1555
+ position: fixed;
1556
+ inset: 0;
1557
+ background: rgba(0,0,0,0.45);
1558
+ z-index: 999;
1559
+ cursor: pointer;
1560
  }
1561
 
1562
  .picker-tabs {
 
2083
  display: none;
2084
  }
2085
 
2086
+ .build-badge.mobile-essential {
2087
+ display: inline-flex;
2088
+ align-items: center;
2089
+ }
2090
+
2091
  .header-btn {
2092
  font-size: 16px;
2093
  padding: 8px;
 
2096
  .chat-header-actions {
2097
  gap: 4px;
2098
  flex-wrap: nowrap;
2099
+ overflow-x: auto;
2100
+ max-width: 56vw;
2101
+ scrollbar-width: thin;
2102
  }
2103
 
2104
  .chat-header-actions .header-btn {
2105
  padding: 6px;
2106
+ min-width: 32px;
2107
+ flex-shrink: 0;
 
 
 
 
2108
  }
2109
 
2110
 
 
2142
 
2143
 
2144
  .input-area {
2145
+ padding: 10px 8px;
2146
+ gap: 6px;
2147
  flex-shrink: 0;
2148
  border-top: 2px solid var(--border-color);
2149
+ display: grid;
2150
+ grid-template-columns: auto auto auto auto minmax(0, 1fr) auto;
2151
+ align-items: center;
2152
  }
2153
 
2154
  .input-area input {
2155
  font-size: 16px;
2156
+ padding: 9px 12px;
2157
+ min-width: 0;
2158
  }
2159
 
2160
  .input-btn {
2161
+ width: 36px;
2162
+ height: 36px;
2163
+ font-size: 14px;
2164
  flex-shrink: 0;
2165
  }
2166
 
 
2661
 
2662
 
2663
  @media (max-width: 768px) {
2664
+ .chat-header-actions .header-btn {
2665
+ animation: none !important;
2666
+ }
2667
+
2668
+ .friend-item:hover,
2669
+ .group-card:hover {
2670
+ transform: none;
2671
+ box-shadow: none;
2672
+ }
2673
+
2674
  .custom-dialog-content {
2675
  min-width: 90%;
2676
  padding: 24px;
 
2715
  .profile-panel {
2716
  width: 100vw;
2717
  right: -100vw;
2718
+ overflow-y: auto;
2719
+ -webkit-overflow-scrolling: touch;
2720
+ overscroll-behavior: contain;
2721
  }
2722
 
2723
  .profile-panel.show {
 
2745
  }
2746
 
2747
  .channel-sidebar .sidebar-header > div button {
2748
+ display: inline-flex;
2749
+ align-items: center;
2750
+ justify-content: center;
2751
  }
2752
 
2753
+ .channel-sidebar .sidebar-header {
2754
+ gap: 8px;
2755
+ flex-wrap: wrap;
2756
+ }
2757
+
2758
+ .channel-sidebar .sidebar-header h3 {
2759
+ font-size: 15px;
2760
+ white-space: nowrap;
2761
  }
2762
 
2763
 
 
2803
  .chat-header-actions {
2804
  gap: 4px;
2805
  flex-shrink: 0;
2806
+ overflow-x: auto;
2807
+ max-width: 66vw;
2808
+ padding-bottom: 2px;
2809
  }
2810
 
2811
  .chat-header-actions button {
2812
+ display: inline-flex;
2813
+ flex-shrink: 0;
2814
+ min-width: 30px;
2815
+ min-height: 30px;
2816
  }
2817
 
2818
  .chat-header-actions .mobile-essential {
2819
  display: inline-flex;
2820
  }
2821
 
2822
+ .build-badge.mobile-essential {
2823
+ display: inline-flex !important;
2824
+ flex-shrink: 0;
2825
+ }
2826
+
2827
  .build-badge {
2828
  display: none;
2829
  }
 
2896
  left: 0;
2897
  top: 0;
2898
  width: 100vw;
2899
+ height: 100dvh;
2900
+ z-index: 2601;
2901
+ overflow-y: auto !important;
2902
+ -webkit-overflow-scrolling: touch;
2903
+ overscroll-behavior: contain;
2904
  }
2905
 
2906
  .profile-content {
2907
  width: 100%;
2908
  max-width: none;
2909
  border-radius: 0;
2910
+ padding-bottom: 120px;
2911
  }
2912
 
2913
  .friends-modal {
 
2981
  </div>
2982
  <button type="button" class="auth-mini-button" onclick="resetForgottenPassword()">Reset Password</button>
2983
  </div>
2984
+ <div id="authStatus" class="auth-status" aria-live="polite"></div>
2985
  <div class="auth-toggle">
2986
  <span>Don't have an account? <button type="button" onclick="toggleAuthMode()">Register</button></span>
2987
  </div>
 
3048
  <div class="chat-header-title" id="chatTitle">πŸ’¬ Select a friend to chat</div>
3049
  </div>
3050
  <div class="chat-header-actions">
3051
+ <span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v2.6.3</span>
3052
+ <button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat">
3053
  <i class="fas fa-archive"></i>
3054
  </button>
3055
  <button class="header-btn mobile-essential" onclick="startVideoCall()" title="Video call">
 
3058
  <button class="header-btn mobile-essential" onclick="togglePinCurrentChat()" title="Pin/Unpin chat" id="pinChatBtn">
3059
  <i class="fas fa-thumbtack"></i>
3060
  </button>
3061
+ <button class="header-btn success mobile-essential" onclick="addCurrentChatToList()" title="Add chat to list">
3062
  <i class="fas fa-bookmark"></i>
3063
  </button>
3064
+ <button class="header-btn danger-hover mobile-essential" onclick="clearAndCloseCurrentChat()" title="Clear and Close Chat" id="closeChatBtn" style="display: none;">
3065
  <i class="fas fa-times-circle"></i>
3066
  </button>
3067
  <button class="header-btn mobile-essential" onclick="toggleMobileMembers()" title="View members">
 
3073
  <button class="header-btn mobile-essential" onclick="openSettings()" title="Settings">
3074
  <i class="fas fa-cog"></i>
3075
  </button>
3076
+ <button class="header-btn mobile-essential notif-bell-btn" onclick="openNotifPanel()" title="Notifications">
3077
+ <i class="fas fa-bell"></i>
3078
+ <span class="notif-badge" id="notifBadge">0</span>
3079
+ </button>
3080
  <button class="header-btn mobile-essential" onclick="openProfile()" title="Profile">
3081
  <i class="fas fa-user-circle"></i>
3082
  </button>
 
3106
  <button class="input-btn" onclick="document.getElementById('fileInput').click()" title="Upload Image">
3107
  <i class="fas fa-image"></i>
3108
  </button>
3109
+ <button class="input-btn" onclick="document.getElementById('videoInput').click()" title="Upload Video / Reel">
3110
+ <i class="fas fa-film"></i>
3111
  </button>
3112
  <button class="input-btn" onclick="togglePicker()" title="Stickers & GIFs">
3113
  <i class="fas fa-smile"></i>
 
3120
  <i class="fas fa-paper-plane"></i>
3121
  </button>
3122
  <input type="file" id="fileInput" class="input-file" onchange="handleFileUpload(event)" accept="image/*" multiple>
3123
+ <input type="file" id="videoInput" class="input-file" onchange="handleFileUpload(event)" accept="video/mp4,video/webm,video/ogg,video/*" multiple>
3124
  </div>
3125
  </div>
3126
 
 
3132
  </div>
3133
 
3134
 
3135
+ <div id="profileBackdrop" onclick="closeProfile()"></div>
3136
+
3137
+
3138
  <div class="profile-panel" id="profilePanel">
3139
  <button class="profile-close" onclick="closeProfile()"><i class="fas fa-times"></i></button>
3140
+ <div class="profile-banner-wrap" id="profileBannerWrap">
3141
+ <img id="profileBannerImg" class="profile-banner-img" src="" alt="" style="display:none;">
3142
+ <button class="profile-banner-edit-btn" onclick="openBannerPicker()">πŸ–Ό Edit Banner</button>
3143
+ </div>
3144
  <div class="profile-header">
3145
  <div class="profile-avatar" id="profileAvatar">U</div>
3146
  <div class="profile-name" id="profileName">Username</div>
 
3150
  <div class="tab-buttons">
3151
  <button class="tab-btn active" onclick="switchProfileTab('profile', this)">Profile</button>
3152
  <button class="tab-btn" onclick="switchProfileTab('inventory', this)">Inventory</button>
3153
+ <button class="tab-btn" onclick="switchProfileTab('orbs', this)">Orbs</button>
3154
+ <button class="tab-btn" onclick="switchProfileTab('saved', this)">Saved</button>
3155
  </div>
3156
 
3157
 
 
3186
  <div class="tab-content" id="inventoryTab">
3187
  <div id="inventoryList"></div>
3188
  </div>
3189
+
3190
+ <div class="tab-content" id="orbsTab">
3191
+ <div class="orb-card">
3192
+ <label for="orbEffectSelect" style="display:block; font-size:12px; font-weight:700; margin-bottom:8px;">Orb Effect Theme</label>
3193
+ <select id="orbEffectSelect" style="width:100%; padding:10px; border-radius:8px; border:1px solid var(--border-color); background:var(--chat-bg); color:var(--text-primary);" onchange="applyOrbEffect(this.value)">
3194
+ <option value="none">None</option>
3195
+ <option value="aurora">Aurora Glow</option>
3196
+ <option value="neon_pulse">Neon Pulse</option>
3197
+ <option value="ocean_mist">Ocean Mist</option>
3198
+ <option value="ember">Ember Flame</option>
3199
+ </select>
3200
+ <p style="font-size:12px; color: var(--text-secondary); margin-top:8px;">Choose a profile orb effect. Changes apply instantly and are saved to your account locally.</p>
3201
+ </div>
3202
+ </div>
3203
+
3204
+ <div class="tab-content" id="savedTab">
3205
+ <div style="margin-bottom:10px; color:var(--text-secondary); font-size:12px;">Your saved and archived content overview</div>
3206
+ <div>
3207
+ <span class="saved-pill">πŸ–Ό Saved Media: <strong id="savedMediaCount">0</strong></span>
3208
+ <span class="saved-pill">πŸ“¦ Archived Messages: <strong id="savedArchivedCount">0</strong></span>
3209
+ </div>
3210
+ <button class="secondary-btn" onclick="openMediaPreview()" style="margin-top:8px;">Open Saved Media Vault</button>
3211
+ <button class="secondary-btn" onclick="showArchivedMessages()" style="margin-top:8px;">Open Archive Center</button>
3212
+ </div>
3213
  </div>
3214
  </div>
3215
 
 
3217
  <div class="modal-content">
3218
  <h2><i class="fas fa-users"></i> Friends & Friend Requests</h2>
3219
  <h3 style="margin-top: 20px; margin-bottom: 10px;">Pending Requests</h3>
3220
+ <div id="friendRequests" style="max-height: 22vh; overflow-y: auto;"></div>
3221
  <h3 style="margin-top: 20px; margin-bottom: 10px;">Your Friends</h3>
3222
+ <div id="friendsList" style="max-height: 36vh; overflow-y: auto;"></div>
3223
  <button class="save-btn" onclick="closeFriendsModal()" style="margin-top: 20px;">Close</button>
3224
  </div>
3225
  </div>
 
3234
  </div>
3235
  </div>
3236
 
3237
+ <div class="modal hidden" id="archivedChatsModal">
3238
+ <div class="archived-modal-content">
3239
+ <h2 style="margin-bottom:6px;"><i class="fas fa-box-archive"></i> Archived Chats</h2>
3240
+ <p style="color: var(--text-secondary); font-size: 13px; margin-bottom: 8px;">Open, unarchive, or delete chats in one place.</p>
3241
+ <div id="archivedChatsList" class="archived-modal-list"></div>
3242
+ <div style="display:flex; gap:10px; margin-top:10px;">
3243
+ <button class="save-btn" style="background: var(--danger);" onclick="clearArchivedChats();">πŸ—‘ Clear All</button>
3244
+ <button class="secondary-btn" onclick="closeArchivedChatsModal();">Close</button>
3245
+ </div>
3246
+ </div>
3247
+ </div>
3248
+
3249
 
3250
  <div class="toast-container" id="toastContainer"></div>
3251
 
3252
 
3253
  <div class="picker-panel" id="pickerPanel">
3254
  <div class="picker-tabs">
3255
+ <button class="picker-tab active" onclick="switchPickerTab('stickers', this)">πŸ˜€ Stickers</button>
3256
+ <button class="picker-tab" onclick="switchPickerTab('gifs', this)">🎬 GIFs</button>
3257
  </div>
3258
  <div class="picker-content" id="pickerContent">
3259
 
 
3526
 
3527
 
3528
  <div class="modal hidden" id="communitiesModal">
3529
+ <div class="modal-content" style="max-width:600px; max-height:80vh; overflow-y:auto;">
3530
  <h2><i class="fas fa-globe"></i> Communities</h2>
3531
  <p style="margin-top: 10px; color: var(--text-secondary);">Join public communities to discover people with shared interests.</p>
3532
+ <input class="groups-search" placeholder="πŸ” Search communities..." oninput="filterCommunitiesList(this.value)">
3533
+ <div id="communitiesList" style="margin-top: 6px;"></div>
3534
  <button class="save-btn" onclick="closeCommunitiesModal()" style="margin-top: 20px;">Close</button>
3535
  </div>
3536
  </div>
3537
 
3538
 
3539
  <div class="modal hidden" id="groupsModal">
3540
+ <div class="modal-content" style="max-width:600px; max-height:80vh; overflow-y:auto;">
3541
  <h2><i class="fas fa-user-group"></i> Groups</h2>
3542
  <p style="margin-top: 10px; color: var(--text-secondary);">Create and manage your own small group chats.</p>
3543
+ <button class="create-group-btn" onclick="createNewGroup(); closeGroupsModal();" style="margin-top:14px;">βž• Create New Group</button>
3544
+ <input class="groups-search" placeholder="πŸ” Search groups..." oninput="filterGroupsList(this.value)">
3545
+ <div id="groupsList" style="margin-top: 4px;"></div>
3546
  <button class="save-btn" onclick="closeGroupsModal()" style="margin-top: 20px;">Close</button>
3547
  </div>
 
3548
  </div>
3549
 
3550
 
 
3627
 
3628
  <div id="customDialog" style="display: none;"></div>
3629
 
3630
+ <!-- ========== FULL-SCREEN CALL OVERLAY ========== -->
3631
+ <div id="callOverlay">
3632
+ <video id="remoteCallVideo" autoplay playsinline style="position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:0;"></video>
3633
+ <video id="localCallVideo" autoplay muted playsinline style="position:absolute; bottom:110px; right:14px; width:110px; height:150px; border-radius:12px; border:2px solid rgba(255,255,255,0.6); object-fit:cover; z-index:2;"></video>
3634
+
3635
+ <div class="call-overlay-header">
3636
+ <div>
3637
+ <div id="callOverlayPeerName" style="color:#fff; font-size:18px; font-weight:700;"></div>
3638
+ <div id="callTimerLabel" style="color:rgba(255,255,255,0.7); font-size:13px; margin-top:4px;">00:00:00</div>
3639
+ </div>
3640
+ <button onclick="toggleCallDebug()" style="background:rgba(255,255,255,0.18); border:none; color:white; padding:7px 13px; border-radius:8px; cursor:pointer; font-size:12px; font-weight:600;">πŸ”§ Debug</button>
3641
+ </div>
3642
+
3643
+ <div id="callDebugPanel"></div>
3644
+
3645
+ <div class="call-overlay-controls">
3646
+ <button id="muteBtn" class="call-ctrl-btn" onclick="toggleLocalMute()" title="Mute/Unmute">🎀</button>
3647
+ <button id="cameraBtn" class="call-ctrl-btn" onclick="toggleCallCamera()" title="Camera on/off">πŸ“·</button>
3648
+ <button class="call-end-btn" onclick="endVideoCall()" title="End Call">πŸ“΅</button>
3649
+ </div>
3650
+ </div>
3651
+
3652
+ <!-- ========== NOTIFICATION PANEL ========== -->
3653
+ <div id="notifPanel">
3654
+ <div class="notif-panel-header">
3655
+ <span style="font-weight:700; font-size:16px;">πŸ”” Notifications</span>
3656
+ <div style="display:flex; gap:8px; align-items:center;">
3657
+ <button onclick="clearAllNotifications()" style="background:none; border:none; color:var(--text-secondary); font-size:12px; cursor:pointer; padding:4px 8px; border-radius:4px; transition:all 0.15s;" onmouseover="this.style.background='var(--bg-color)'" onmouseout="this.style.background='none'">Clear all</button>
3658
+ <button onclick="closeNotifPanel()" style="background:none; border:none; color:var(--text-secondary); font-size:20px; cursor:pointer; line-height:1;">Γ—</button>
3659
+ </div>
3660
+ </div>
3661
+ <div id="notifList" style="flex:1;">
3662
+ <div style="padding:30px; text-align:center; color:var(--text-secondary);">No notifications yet</div>
3663
+ </div>
3664
+ </div>
3665
+
3666
  <script src="/socket.io/socket.io.js"></script>
3667
  <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
3668
+ <script src="client.js?v=2.6.2"></script>
3669
  </body>
3670
  </html>
3671
 
3672
+
3673
+
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "discord-like-app",
3
- "version": "2.3.6",
4
  "main": "server.js",
5
  "scripts": {
6
  "dev": "nodemon server.js",
 
1
  {
2
  "name": "discord-like-app",
3
+ "version": "2.6.3",
4
  "main": "server.js",
5
  "scripts": {
6
  "dev": "nodemon server.js",