Spaces:
Runtime error
Runtime error
| <!-- GenAI disclosure: I have used GenAI here to fix some bugs and errors that were present in these lines of codes. --> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>FireTech</title> | |
| <link rel="icon" type="image/png" href="images/logo.png"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| /* I'm resetting everything here so I don't have to fight the browser's default margins */ | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| input, textarea { | |
| caret-color: var(--primary-color); | |
| } | |
| :root { | |
| --primary-color: #5865f2; | |
| --secondary-color: #404249; | |
| --bg-color: #36393f; | |
| --chat-bg: #2c2f33; | |
| --sidebar-bg: #2f3136; | |
| --text-primary: #ffffff; | |
| --text-secondary: #b9bbbe; | |
| --ui-text-color: #ffffff; | |
| --border-color: #202225; | |
| --shadow: 0 2px 10px rgba(0,0,0,0.3); | |
| --success: #43b581; | |
| --danger: #f04747; | |
| } | |
| [data-theme="light"] { | |
| --primary-color: #5865f2; | |
| --secondary-color: #99aab5; | |
| --bg-color: #ffffff; | |
| --chat-bg: #f2f3f5; | |
| --sidebar-bg: #f9f9f9; | |
| --text-primary: #2e3338; | |
| --text-secondary: #747f8d; | |
| --ui-text-color: #2e3338; | |
| --border-color: #e3e5e8; | |
| --shadow: 0 2px 10px rgba(0,0,0,0.1); | |
| --success: #43b581; | |
| --danger: #f04747; | |
| } | |
| body { | |
| font-family: 'Whitney', 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
| background: var(--bg-color); | |
| color: var(--text-primary); | |
| overflow: hidden; | |
| } | |
| .auth-container { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(135deg, var(--primary-color), #1a1a2e); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 2000; | |
| } | |
| .auth-box { | |
| background: var(--bg-color); | |
| padding: 40px; | |
| border-radius: 10px; | |
| box-shadow: var(--shadow); | |
| width: 100%; | |
| max-width: 400px; | |
| animation: slideUp 0.3s ease; | |
| } | |
| @keyframes slideUp { | |
| from { transform: translateY(30px); opacity: 0; } | |
| to { transform: translateY(0); opacity: 1; } | |
| } | |
| .auth-box h2 { | |
| margin-bottom: 30px; | |
| color: var(--primary-color); | |
| font-size: 28px; | |
| } | |
| .form-group { | |
| margin-bottom: 20px; | |
| } | |
| .form-group label { | |
| display: block; | |
| margin-bottom: 8px; | |
| font-size: 14px; | |
| font-weight: 500; | |
| } | |
| .form-group input { | |
| width: 100%; | |
| padding: 12px; | |
| background: var(--chat-bg); | |
| border: 1px solid var(--border-color); | |
| border-radius: 4px; | |
| color: var(--text-primary); | |
| font-size: 14px; | |
| transition: all 0.2s ease; | |
| } | |
| .form-group input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 2px rgba(88, 101, 242, 0.1); | |
| } | |
| .auth-button { | |
| width: 100%; | |
| padding: 12px; | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| font-size: 16px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .auth-button:hover { | |
| background: #4752c4; | |
| } | |
| .auth-button:active { | |
| transform: scale(0.98); | |
| } | |
| .auth-toggle { | |
| text-align: center; | |
| margin-top: 15px; | |
| font-size: 14px; | |
| color: var(--text-secondary); | |
| } | |
| .auth-toggle button { | |
| background: none; | |
| border: none; | |
| color: var(--primary-color); | |
| cursor: pointer; | |
| text-decoration: underline; | |
| } | |
| .auth-inline-link { | |
| margin-top: -10px; | |
| margin-bottom: 14px; | |
| text-align: right; | |
| } | |
| .auth-inline-link button { | |
| background: none; | |
| border: none; | |
| color: var(--primary-color); | |
| cursor: pointer; | |
| font-size: 13px; | |
| text-decoration: underline; | |
| padding: 0; | |
| } | |
| .reset-password-panel { | |
| margin-top: 14px; | |
| padding-top: 12px; | |
| border-top: 1px solid var(--border-color); | |
| display: none; | |
| } | |
| .reset-password-panel.show { | |
| display: block; | |
| } | |
| .auth-mini-button { | |
| width: 100%; | |
| margin-top: 8px; | |
| padding: 10px; | |
| border: 1px solid var(--primary-color); | |
| border-radius: 6px; | |
| background: transparent; | |
| color: var(--primary-color); | |
| cursor: pointer; | |
| } | |
| .auth-status { | |
| margin-top: 12px; | |
| font-size: 13px; | |
| min-height: 18px; | |
| color: var(--text-secondary); | |
| text-align: center; | |
| line-height: 1.35; | |
| } | |
| .main-container { | |
| display: grid; | |
| grid-template-columns: 72px 240px 1fr 240px; | |
| height: 100vh; | |
| gap: 0; | |
| } | |
| .main-container.hidden { | |
| display: none; | |
| } | |
| .guild-sidebar { | |
| background: var(--sidebar-bg); | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| padding: 8px 0; | |
| border-right: 1px solid var(--border-color); | |
| } | |
| .guild-item { | |
| width: 56px; | |
| height: 56px; | |
| border-radius: 50%; | |
| background: linear-gradient(135deg, var(--primary-color), #4752c4); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| cursor: pointer; | |
| margin-bottom: 8px; | |
| transition: all 0.2s ease; | |
| font-size: 24px; | |
| } | |
| .guild-item:hover { | |
| border-radius: 40%; | |
| transform: scale(1.1); | |
| } | |
| .guild-item.active { | |
| border-radius: 40%; | |
| background: var(--primary-color); | |
| } | |
| .guild-divider { | |
| width: 32px; | |
| height: 2px; | |
| background: var(--border-color); | |
| margin: 8px 0; | |
| } | |
| /* ====== APP LOADER ====== */ | |
| #appLoader { | |
| position: fixed; inset: 0; z-index: 999999; | |
| background: | |
| radial-gradient(circle at 50% 42%, rgba(92, 126, 255, 0.28) 0%, rgba(92, 126, 255, 0.08) 18%, transparent 36%), | |
| radial-gradient(circle at 50% 70%, rgba(10, 18, 40, 0.65) 0%, transparent 40%), | |
| linear-gradient(180deg, #07101f 0%, #081423 28%, #0d1730 55%, #04070f 100%); | |
| display: flex; align-items: center; justify-content: center; flex-direction: column; | |
| transition: opacity 0.7s ease; user-select: none; | |
| overflow: hidden; | |
| } | |
| #appLoader.fade-out { opacity: 0; pointer-events: none; } | |
| .loader-scene { | |
| position: relative; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .loader-aura { | |
| position: absolute; | |
| width: 220px; | |
| height: 220px; | |
| border-radius: 50%; | |
| background: radial-gradient(circle, rgba(113, 164, 255, 0.48) 0%, rgba(77, 119, 243, 0.16) 35%, rgba(22, 31, 73, 0) 72%); | |
| filter: blur(6px); | |
| animation: loaderAuraPulse 2.8s ease-in-out infinite; | |
| } | |
| .loader-stage-ring { | |
| position: absolute; | |
| width: 300px; | |
| height: 80px; | |
| border-radius: 50%; | |
| background: radial-gradient(circle, rgba(52, 112, 255, 0.26) 0%, rgba(13, 24, 57, 0.08) 45%, transparent 75%); | |
| bottom: 86px; | |
| filter: blur(10px); | |
| } | |
| .loader-fire-emoji { | |
| position: relative; | |
| font-size: 88px; display: block; | |
| animation: loaderFirePulse 1.25s ease-in-out infinite; | |
| filter: drop-shadow(0 0 18px rgba(255, 152, 77, 0.95)) drop-shadow(0 0 36px rgba(80, 135, 255, 0.38)); | |
| z-index: 2; | |
| } | |
| @keyframes loaderFirePulse { | |
| 0%, 100% { transform: translateY(0) scale(1) rotate(-3deg); } | |
| 50% { transform: translateY(-4px) scale(1.16) rotate(3deg); } | |
| } | |
| @keyframes loaderAuraPulse { | |
| 0%, 100% { transform: scale(0.94); opacity: 0.72; } | |
| 50% { transform: scale(1.08); opacity: 1; } | |
| } | |
| .loader-app-name { | |
| font-size: 46px; | |
| font-weight: 900; | |
| letter-spacing: 8px; | |
| text-transform: uppercase; | |
| /* Updated to Blue -> Cyan gradient */ | |
| background: linear-gradient(90deg, #5f7eff 0%, #7b9cff 50%, #9cc4ff 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-top: 12px; | |
| line-height: 1; | |
| } | |
| .loader-tagline { | |
| color: rgba(255,255,255,0.35); font-size: 12px; letter-spacing: 4px; | |
| text-transform: uppercase; margin-top: 10px; font-weight: 500; | |
| } | |
| .loader-progress-wrap { | |
| width: 280px; height: 5px; background: rgba(255,255,255,0.07); | |
| border-radius: 999px; margin-top: 44px; overflow: hidden; position: relative; | |
| } | |
| .loader-progress-bar { | |
| height: 100%; | |
| width: 0%; | |
| border-radius: 999px; | |
| /* Matching the logo's deep blue to light blue */ | |
| background: linear-gradient(90deg, #3470ff, #5f7eff, #9cc4ff); | |
| transition: width 0.18s ease; | |
| position: relative; | |
| box-shadow: 0 0 10px rgba(95, 126, 255, 0.4); | |
| } | |
| .loader-progress-bar::after { | |
| content: ''; position: absolute; right: 0; top: 0; bottom: 0; width: 36px; | |
| background: linear-gradient(90deg, transparent, rgba(255,255,255,0.55)); | |
| border-radius: 0 999px 999px 0; | |
| animation: loaderShimmer 1s ease-in-out infinite; | |
| } | |
| @keyframes loaderShimmer { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } } | |
| .loader-status { | |
| margin-top: 16px; font-size: 11px; color: rgba(255,255,255,0.28); | |
| letter-spacing: 3px; text-transform: uppercase; min-height: 14px; | |
| } | |
| /* ====== LANGUAGE PICKER ====== */ | |
| .lang-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); | |
| gap: 10px; | |
| max-height: 56vh; | |
| overflow-y: auto; | |
| padding-right: 4px; | |
| width: 100%; | |
| } | |
| .lang-btn { | |
| display: flex; align-items: center; gap: 10px; padding: 11px 12px; | |
| background: var(--bg-color); border: 1px solid var(--border-color); | |
| border-radius: 12px; cursor: pointer; text-align: left; transition: all 0.18s; | |
| min-height: 64px; | |
| } | |
| .lang-btn:hover { | |
| border-color: #ff9d4d; | |
| background: linear-gradient(135deg, rgba(255,157,77,0.14), rgba(88,101,242,0.14)); | |
| transform: translateY(-1px); | |
| } | |
| .lang-btn.active { | |
| border-color: var(--primary-color); | |
| background: linear-gradient(135deg, rgba(88,101,242,0.26), rgba(156,196,255,0.16)); | |
| box-shadow: 0 6px 16px rgba(88, 101, 242, 0.25); | |
| } | |
| .lang-flag { | |
| font-size: 22px; | |
| min-width: 38px; | |
| width: 38px; | |
| height: 38px; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| border-radius: 50%; | |
| background: radial-gradient(circle at 30% 20%, rgba(255,255,255,0.25), rgba(88,101,242,0.15)); | |
| border: 1px solid rgba(255,255,255,0.18); | |
| } | |
| .lang-info-name { font-size: 13px; font-weight: 700; } | |
| .lang-info-country { font-size: 11px; color: var(--text-secondary); margin-top: 1px; } | |
| img.twemoji { | |
| width: 1.08em; | |
| height: 1.08em; | |
| vertical-align: -0.14em; | |
| } | |
| #languageSettings { | |
| max-width: 100%; | |
| width: 100%; | |
| } | |
| #languageSettings .settings-item { | |
| max-width: 980px; | |
| margin: 0 auto; | |
| } | |
| @media (max-width: 900px) { | |
| .lang-grid { | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| } | |
| } | |
| @media (max-width: 640px) { | |
| .lang-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .channel-sidebar { | |
| background: var(--sidebar-bg); | |
| border-right: 1px solid var(--border-color); | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 0; | |
| } | |
| .sidebar-header { | |
| padding: 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .sidebar-header h3 { | |
| font-size: 16px; | |
| font-weight: 600; | |
| } | |
| .sidebar-header button { | |
| background: none; | |
| border: none; | |
| color: var(--primary-color); | |
| cursor: pointer; | |
| font-size: 20px; | |
| } | |
| .channels-list { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 8px 0; | |
| scrollbar-gutter: stable; | |
| min-height: 0; | |
| padding-bottom: 24px; | |
| } | |
| .archived-modal-content { | |
| background: var(--chat-bg); | |
| padding: 20px; | |
| border-radius: 10px; | |
| width: min(95vw, 900px); | |
| max-height: 88vh; | |
| display: flex; | |
| flex-direction: column; | |
| box-shadow: 0 16px 44px rgba(0,0,0,0.55); | |
| border: 1px solid var(--border-color); | |
| } | |
| .archived-modal-list { | |
| flex: 1; | |
| overflow-y: auto; | |
| margin-top: 10px; | |
| padding-right: 4px; | |
| min-height: 260px; | |
| scrollbar-gutter: stable; | |
| overscroll-behavior: contain; | |
| } | |
| .archived-modal-list::-webkit-scrollbar { | |
| width: 10px; | |
| } | |
| .archived-modal-list::-webkit-scrollbar-thumb { | |
| background: rgba(255, 255, 255, 0.22); | |
| border-radius: 8px; | |
| border: 2px solid transparent; | |
| background-clip: content-box; | |
| } | |
| .archived-modal-list::-webkit-scrollbar-track { | |
| background: rgba(255, 255, 255, 0.06); | |
| border-radius: 8px; | |
| } | |
| .channel-item { | |
| padding: 8px 16px; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| transition: all 0.2s ease; | |
| min-width: 0; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .channel-label { | |
| min-width: 0; | |
| flex: 1; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .channel-item:hover { | |
| background: var(--chat-bg); | |
| color: var(--text-primary); | |
| } | |
| .channel-item.active { | |
| background: var(--primary-color); | |
| color: white; | |
| } | |
| .channel-item.pinned { | |
| background: rgba(88, 101, 242, 0.1); | |
| border-left: 3px solid var(--primary-color); | |
| font-weight: 600; | |
| } | |
| .channel-item .pin-indicator { | |
| margin-left: auto; | |
| color: var(--primary-color); | |
| font-size: 12px; | |
| } | |
| .channel-icon { | |
| font-size: 16px; | |
| } | |
| .channel-avatar { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 50%; | |
| background: linear-gradient(135deg, var(--primary-color), #4752c4); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: 600; | |
| font-size: 14px; | |
| flex-shrink: 0; | |
| } | |
| .member-avatar { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 50%; | |
| background: linear-gradient(135deg, var(--primary-color), #4752c4); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: 600; | |
| font-size: 14px; | |
| flex-shrink: 0; | |
| } | |
| .channel-section-title { | |
| padding: 10px; | |
| color: var(--text-secondary); | |
| font-size: 12px; | |
| font-weight: bold; | |
| position: relative; | |
| background: var(--sidebar-bg); | |
| border-top: 1px solid var(--border-color); | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .chat-area { | |
| position: relative; | |
| display: flex; | |
| flex-direction: column; | |
| background: var(--chat-bg); | |
| min-height: 0; | |
| overflow: hidden; | |
| } | |
| .chat-header { | |
| padding: 16px 24px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .chat-header-left { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .chat-header-title { | |
| font-size: 18px; | |
| font-weight: 600; | |
| } | |
| .chat-header-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .build-badge { | |
| padding: 4px 8px; | |
| border: 1px solid var(--border-color); | |
| border-radius: 999px; | |
| font-size: 11px; | |
| color: var(--text-secondary); | |
| background: var(--bg-color); | |
| } | |
| .header-btn { | |
| background: none; | |
| border: none; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| font-size: 18px; | |
| transition: all 0.2s ease; | |
| } | |
| @keyframes headerFloat { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-2px); } | |
| } | |
| .chat-header-actions .header-btn { | |
| animation: headerFloat 3.6s ease-in-out infinite; | |
| } | |
| .chat-header-actions .header-btn:nth-child(2) { animation-delay: 0.25s; } | |
| .chat-header-actions .header-btn:nth-child(3) { animation-delay: 0.5s; } | |
| .chat-header-actions .header-btn:nth-child(4) { animation-delay: 0.75s; } | |
| .chat-header-actions .header-btn:nth-child(5) { animation-delay: 1s; } | |
| .header-btn:hover { | |
| color: var(--text-primary); | |
| } | |
| .header-btn.danger { | |
| color: var(--danger); | |
| } | |
| .header-btn.success { | |
| color: var(--success); | |
| } | |
| .mobile-essential { | |
| display: inline-flex; | |
| } | |
| #messages-container { | |
| flex: 1; | |
| min-height: 0; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| padding: 16px 24px; | |
| padding-right: 44px; | |
| padding-bottom: 24px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| scroll-behavior: smooth; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| #messages-container::-webkit-scrollbar { | |
| width: 0; | |
| height: 0; | |
| } | |
| #messages-container { | |
| scrollbar-width: none; | |
| } | |
| .chat-scroll-rail { | |
| position: absolute; | |
| top: 72px; | |
| right: 8px; | |
| bottom: 84px; | |
| width: 14px; | |
| border-radius: 999px; | |
| background: #d8d8d8; | |
| border: 1px solid #c5c5c5; | |
| z-index: 12; | |
| cursor: pointer; | |
| } | |
| .chat-scroll-thumb { | |
| width: 100%; | |
| min-height: 56px; | |
| border-radius: 999px; | |
| background: linear-gradient(180deg, #10d9a6 0%, #00b88f 50%, #009a78 100%); | |
| border: 1px solid rgba(0, 0, 0, 0.08); | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); | |
| transform: translateY(0); | |
| transition: background 0.15s ease; | |
| } | |
| .chat-scroll-thumb:hover { | |
| background: linear-gradient(180deg, #20ecb8 0%, #00c79a 50%, #00ab86 100%); | |
| } | |
| .chat-scroll-rail.hidden { | |
| display: none; | |
| } | |
| .message { | |
| display: flex; | |
| gap: 12px; | |
| animation: fadeIn 0.2s ease; | |
| scroll-snap-align: end; | |
| scroll-snap-stop: always; | |
| min-width: 0; | |
| max-width: 100%; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .message-avatar { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| background: linear-gradient(135deg, var(--primary-color), #4752c4); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: 600; | |
| flex-shrink: 0; | |
| } | |
| .message-content { | |
| flex: 1; | |
| min-width: 0; | |
| max-width: 100%; | |
| } | |
| .message-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin-bottom: 4px; | |
| } | |
| .message-actions { | |
| position: absolute; | |
| top: -8px; | |
| right: 8px; | |
| display: none; | |
| gap: 4px; | |
| background: var(--chat-bg); | |
| padding: 6px 8px; | |
| border-radius: 18px; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.3); | |
| border: 1px solid var(--border-color); | |
| flex-direction: row; | |
| align-items: center; | |
| } | |
| .message.message-actions-open .message-actions { | |
| display: flex; | |
| } | |
| .message-action-btn { | |
| background: transparent; | |
| border: none; | |
| color: var(--text-secondary); | |
| padding: 6px 10px; | |
| border-radius: 12px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| } | |
| .message-action-btn:hover { | |
| background: var(--bg-color); | |
| color: var(--primary-color); | |
| transform: scale(1.05); | |
| } | |
| .message-reactions { | |
| display: flex; | |
| flex-direction: row; | |
| flex-wrap: wrap; | |
| gap: 6px; | |
| margin-top: 8px; | |
| align-items: center; | |
| } | |
| .reaction-item { | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| padding: 2px 8px; | |
| border-radius: 12px; | |
| font-size: 14px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| } | |
| .reaction-item:hover { | |
| background: var(--primary-color); | |
| border-color: var(--primary-color); | |
| transform: scale(1.05); | |
| } | |
| .reaction-count { | |
| font-size: 11px; | |
| color: var(--text-secondary); | |
| font-weight: 600; | |
| } | |
| .message-username { | |
| font-weight: 600; | |
| color: var(--primary-color); | |
| } | |
| .message-time { | |
| font-size: 11px; | |
| color: var(--text-secondary); | |
| display: block; | |
| margin-top: 2px; | |
| } | |
| .message-text { | |
| color: var(--text-primary); | |
| line-height: 1.5; | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| max-width: 100%; | |
| } | |
| .message-media { | |
| margin-top: 8px; | |
| border-radius: 8px; | |
| max-width: 400px; | |
| width: min(100%, 400px); | |
| overflow: hidden; | |
| } | |
| .message-media img { | |
| max-width: 100%; | |
| border-radius: 8px; | |
| display: block; | |
| } | |
| .message-media video { | |
| max-width: 100%; | |
| border-radius: 8px; | |
| display: block; | |
| cursor: pointer; | |
| } | |
| .message-media video { | |
| max-width: 100%; | |
| border-radius: 4px; | |
| } | |
| .draft-preview { | |
| margin: 8px 24px 0; | |
| padding: 10px; | |
| border: 1px solid var(--border-color); | |
| border-radius: 8px; | |
| background: var(--bg-color); | |
| display: none; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 12px; | |
| } | |
| .draft-preview.show { | |
| display: flex; | |
| } | |
| .draft-preview-left { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| min-width: 0; | |
| flex: 1; | |
| } | |
| .draft-preview-thumb { | |
| width: 56px; | |
| height: 56px; | |
| border-radius: 6px; | |
| object-fit: cover; | |
| border: 1px solid var(--border-color); | |
| background: var(--chat-bg); | |
| display: none; | |
| } | |
| .draft-preview-emoji { | |
| font-size: 36px; | |
| line-height: 1; | |
| display: none; | |
| } | |
| .draft-preview-meta { | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .draft-clear-btn { | |
| border: 1px solid var(--danger); | |
| color: var(--danger); | |
| background: transparent; | |
| border-radius: 6px; | |
| padding: 6px 10px; | |
| cursor: pointer; | |
| } | |
| .input-area { | |
| padding: 16px 24px; | |
| border-top: 1px solid var(--border-color); | |
| display: flex; | |
| gap: 12px; | |
| background: var(--chat-bg); | |
| z-index: 10; | |
| flex-shrink: 0; | |
| } | |
| .input-area input { | |
| flex: 1; | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| border-radius: 21px; | |
| padding: 11px 16px; | |
| color: var(--text-primary); | |
| font-size: 14px; | |
| transition: all 0.2s ease; | |
| } | |
| .input-area input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| } | |
| .input-btn { | |
| width: 44px; | |
| height: 44px; | |
| border-radius: 50%; | |
| background: var(--primary-color); | |
| border: none; | |
| color: white; | |
| cursor: pointer; | |
| font-size: 18px; | |
| transition: all 0.2s ease; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .input-btn:hover { | |
| background: var(--primary-color); | |
| opacity: 0.85; | |
| transform: scale(1.05); | |
| } | |
| .input-file { | |
| display: none; | |
| } | |
| .members-sidebar { | |
| background: var(--sidebar-bg); | |
| border-left: 1px solid var(--border-color); | |
| display: flex; | |
| flex-direction: column; | |
| max-width: 240px; | |
| } | |
| .members-header { | |
| padding: 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| font-weight: 600; | |
| font-size: 14px; | |
| } | |
| .members-list { | |
| flex: 1; | |
| overflow-y: scroll; | |
| padding: 8px; | |
| scrollbar-gutter: stable; | |
| } | |
| .member-item { | |
| padding: 8px 12px; | |
| border-radius: 4px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| font-size: 14px; | |
| } | |
| .member-item:hover { | |
| background: var(--chat-bg); | |
| } | |
| .status-indicator { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: var(--success); | |
| } | |
| .status-indicator.offline { | |
| background: var(--text-secondary); | |
| } | |
| .profile-panel { | |
| position: fixed; | |
| right: 0; | |
| top: 0; | |
| width: 400px; | |
| height: 100%; | |
| background: var(--chat-bg); | |
| border-left: 1px solid var(--border-color); | |
| z-index: 1000; | |
| transform: translateX(400px); | |
| transition: transform 0.3s ease; | |
| overflow-y: auto; | |
| display: flex; | |
| flex-direction: column; | |
| visibility: hidden; | |
| -webkit-overflow-scrolling: touch; | |
| overscroll-behavior: contain; | |
| touch-action: pan-y; | |
| pointer-events: none; | |
| } | |
| .profile-panel.show { | |
| transform: translateX(0); | |
| visibility: visible; | |
| pointer-events: auto; | |
| } | |
| .profile-banner-wrap { | |
| position: relative; | |
| width: 100%; | |
| height: 160px; | |
| background: linear-gradient(135deg, var(--primary-color), #4752c4); | |
| overflow: hidden; | |
| flex-shrink: 0; | |
| } | |
| .profile-banner-img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| display: block; | |
| } | |
| .profile-banner-edit-btn { | |
| position: absolute; | |
| bottom: 8px; | |
| right: 8px; | |
| background: rgba(0,0,0,0.55); | |
| border: none; | |
| color: white; | |
| border-radius: 6px; | |
| padding: 4px 10px; | |
| font-size: 12px; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| } | |
| .profile-banner-edit-btn:hover { background: rgba(0,0,0,0.85); } | |
| #callOverlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: 9999; | |
| display: none; | |
| touch-action: manipulation; | |
| background: rgba(0,0,0,0.55); | |
| } | |
| #callOverlay.active { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 16px; | |
| } | |
| .call-overlay-stage { | |
| position: relative; | |
| width: min(920px, 100%); | |
| height: min(84vh, 720px); | |
| border-radius: 18px; | |
| overflow: hidden; | |
| background: #0f1116; | |
| box-shadow: 0 28px 80px rgba(0,0,0,0.55); | |
| border: 1px solid rgba(255,255,255,0.12); | |
| } | |
| #callOverlay:not(.desktop-window) .call-overlay-stage { | |
| width: 100%; | |
| height: 100%; | |
| border-radius: 0; | |
| border: none; | |
| box-shadow: none; | |
| } | |
| #remoteCallVideo, #localCallVideo, #localCallVideoOld { | |
| display: block; | |
| } | |
| #hostedCallContainer { | |
| position: absolute; | |
| inset: 0; | |
| z-index: 1; | |
| display: none; | |
| background: #0f1116; | |
| } | |
| #hostedCallContainer iframe { | |
| width: 100%; | |
| height: 100%; | |
| border: 0; | |
| } | |
| #remoteCallVideo { | |
| pointer-events: none; | |
| } | |
| .call-overlay-header { | |
| position: absolute; | |
| top: 0; left: 0; right: 0; | |
| padding: 16px 20px; | |
| background: linear-gradient(180deg, rgba(0,0,0,0.75), transparent); | |
| z-index: 4; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| pointer-events: auto; | |
| } | |
| .call-overlay-controls { | |
| position: absolute; | |
| bottom: 0; left: 0; right: 0; | |
| padding: 24px 20px 32px; | |
| background: linear-gradient(0deg, rgba(0,0,0,0.75), transparent); | |
| display: flex; | |
| justify-content: center; | |
| gap: 20px; | |
| z-index: 5; | |
| pointer-events: auto; | |
| touch-action: manipulation; | |
| } | |
| .call-ctrl-btn { | |
| width: 64px; height: 64px; | |
| border-radius: 50%; | |
| background: rgba(255,255,255,0.18); | |
| border: 2px solid rgba(255,255,255,0.3); | |
| color: white; | |
| font-size: 24px; | |
| cursor: pointer; | |
| display: flex; align-items: center; justify-content: center; | |
| transition: all 0.2s; | |
| pointer-events: auto; | |
| touch-action: manipulation; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| .call-ctrl-btn:hover { background: rgba(255,255,255,0.35); transform: scale(1.08); } | |
| .call-ctrl-btn:active { transform: scale(0.96); } | |
| .call-ctrl-btn.muted { background: rgba(240,71,71,0.5); border-color: #f04747; } | |
| .call-ctrl-btn.cam-off { background: rgba(240,71,71,0.5); border-color: #f04747; } | |
| .call-end-btn { | |
| width: 72px; height: 72px; | |
| background: #f04747; | |
| border: none; | |
| border-radius: 50%; | |
| color: white; | |
| font-size: 26px; | |
| cursor: pointer; | |
| display: flex; align-items: center; justify-content: center; | |
| transition: all 0.2s; | |
| pointer-events: auto; | |
| touch-action: manipulation; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| .call-end-btn:hover { background: #c0392b; transform: scale(1.1); } | |
| @media (max-width: 700px) { | |
| #callOverlay.active { | |
| padding: 0; | |
| } | |
| .call-overlay-stage { | |
| width: 100%; | |
| height: 100%; | |
| border-radius: 0; | |
| border: none; | |
| box-shadow: none; | |
| } | |
| } | |
| #callDebugPanel { | |
| position: absolute; | |
| top: 80px; right: 10px; | |
| background: rgba(0,0,0,0.88); | |
| color: #00ff88; | |
| font-size: 11px; | |
| padding: 12px; | |
| border-radius: 8px; | |
| z-index: 3; | |
| min-width: 230px; | |
| font-family: monospace; | |
| border: 1px solid #00ff88; | |
| display: none; | |
| } | |
| #callDebugPanel .dbg-row { margin-bottom: 4px; } | |
| #callDebugPanel .dbg-log { | |
| margin-top: 8px; | |
| max-height: 180px; | |
| overflow-y: auto; | |
| border-top: 1px solid rgba(0,255,136,0.35); | |
| padding-top: 8px; | |
| color: #c7ffd9; | |
| } | |
| #callDebugPanel .dbg-log div { | |
| margin-bottom: 4px; | |
| line-height: 1.35; | |
| word-break: break-word; | |
| } | |
| .notif-bell-btn { | |
| position: relative; | |
| } | |
| .notif-badge { | |
| position: absolute; | |
| top: -3px; right: -3px; | |
| background: #f04747; | |
| color: white; | |
| border-radius: 50%; | |
| width: 16px; height: 16px; | |
| font-size: 9px; | |
| font-weight: 700; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| line-height: 1; | |
| } | |
| .notif-badge.visible { display: flex; } | |
| #notifPanel { | |
| position: fixed; | |
| top: 0; right: -360px; | |
| width: 340px; | |
| max-height: 100vh; | |
| background: var(--chat-bg); | |
| border-left: 1px solid var(--border-color); | |
| z-index: 1050; | |
| transition: right 0.3s ease; | |
| overflow-y: auto; | |
| box-shadow: -4px 0 24px rgba(0,0,0,0.4); | |
| display: flex; flex-direction: column; | |
| } | |
| #notifPanel.show { right: 0; } | |
| .notif-panel-header { | |
| padding: 16px 18px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; align-items: center; justify-content: space-between; | |
| position: sticky; top: 0; | |
| background: var(--chat-bg); | |
| z-index: 2; | |
| } | |
| .notif-item { | |
| padding: 12px 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| cursor: pointer; | |
| transition: background 0.15s; | |
| } | |
| .notif-item:hover { background: var(--bg-color); } | |
| .notif-item.notif-unread { background: rgba(88,101,242,0.1); border-left: 3px solid var(--primary-color); } | |
| .notif-item-title { font-size: 13px; font-weight: 600; margin-bottom: 3px; } | |
| .notif-item-body { font-size: 12px; color: var(--text-secondary); } | |
| .notif-item-time { font-size: 10px; color: var(--text-secondary); margin-top: 4px; } | |
| .upload-progress-bar { | |
| height: 3px; | |
| background: linear-gradient(90deg, var(--primary-color), #4752c4); | |
| border-radius: 2px; | |
| width: 0%; | |
| transition: width 0.3s ease; | |
| position: absolute; | |
| top: 0; left: 0; right: 0; | |
| } | |
| .upload-overlay { | |
| position: absolute; | |
| inset: 0; | |
| background: rgba(0,0,0,0.4); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| border-radius: 8px; | |
| z-index: 5; | |
| } | |
| @keyframes spin { to { transform: rotate(360deg); } } | |
| .spinner-ring { | |
| width: 40px; height: 40px; | |
| border: 3px solid rgba(255,255,255,0.2); | |
| border-top-color: white; | |
| border-radius: 50%; | |
| animation: spin 0.7s linear infinite; | |
| } | |
| .input-area { position: relative; } | |
| .input-upload-spinner { | |
| position: absolute; | |
| top: -2px; left: 0; right: 0; | |
| height: 3px; | |
| background: var(--bg-color); | |
| border-radius: 2px; | |
| overflow: hidden; | |
| } | |
| .input-upload-spinner-bar { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--primary-color), var(--success), var(--primary-color)); | |
| background-size: 200% 100%; | |
| animation: shimmerSlide 1s linear infinite; | |
| width: 100%; | |
| } | |
| @keyframes shimmerSlide { | |
| 0% { background-position: 200% 0; } | |
| 100% { background-position: -200% 0; } | |
| } | |
| .message { transition: background 0.15s; border-radius: 8px; padding: 4px 6px; } | |
| .message:hover { background: rgba(88, 101, 242, 0.08); } | |
| .friend-item { transition: all 0.18s ease; } | |
| .friend-item:hover { transform: translateX(3px); box-shadow: -3px 0 0 #ff9d4d; } | |
| .guild-item { transition: all 0.2s; } | |
| .guild-item:hover:not(.active) { border-radius: 16px; background: linear-gradient(135deg, #ff9d4d, #5f7eff); transform: scale(1.08); } | |
| .header-btn { transition: all 0.18s; } | |
| .header-btn:hover { background: rgba(88,101,242,0.25); transform: scale(1.12); border-radius: 6px; box-shadow: 0 2px 8px rgba(88,101,242,0.3); } | |
| .input-btn { transition: all 0.18s; } | |
| .input-btn:hover { background: linear-gradient(135deg, rgba(255,157,77,0.25), rgba(88,101,242,0.25)); color: #ff9d4d; transform: scale(1.1); box-shadow: 0 2px 8px rgba(255,157,77,0.2); } | |
| .tab-btn { transition: all 0.18s; } | |
| .tab-btn:hover:not(.active) { background: rgba(88,101,242,0.15); transform: translateY(-2px); } | |
| .secondary-btn { transition: all 0.18s; } | |
| .secondary-btn:hover { background: rgba(88,101,242,0.28); transform: translateY(-2px); box-shadow: 0 4px 14px rgba(88,101,242,0.35); } | |
| .save-btn { transition: all 0.18s; } | |
| .save-btn:hover { filter: brightness(1.15); transform: translateY(-2px); box-shadow: 0 4px 16px rgba(88,101,242,0.4); } | |
| .message-action-btn { transition: all 0.18s; } | |
| .message-action-btn:hover { background: #ff9d4d ; color: white; transform: scale(1.2); box-shadow: 0 3px 12px rgba(255,157,77,0.4); } | |
| .mobile-nav-item { transition: all 0.2s; } | |
| .mobile-nav-item:hover, .mobile-nav-item.active { color: #ff9d4d; } | |
| .settings-nav-item { transition: all 0.15s; } | |
| .settings-nav-item:hover { background: linear-gradient(135deg, rgba(255,157,77,0.1), rgba(88,101,242,0.1)); color: #ff9d4d; transform: translateX(2px); } | |
| .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; } | |
| .groups-search:focus { outline: none; border-color: var(--primary-color); } | |
| .group-card { | |
| display: flex; align-items: center; gap: 14px; | |
| padding: 14px 16px; | |
| background: var(--bg-color); | |
| border-radius: 10px; | |
| margin-bottom: 10px; | |
| border: 1px solid var(--border-color); | |
| transition: border-color 0.2s, transform 0.2s, box-shadow 0.2s; | |
| } | |
| .group-card:hover { border-color: var(--primary-color); transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.3); } | |
| .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; } | |
| .emoji-glyph { | |
| font-family: 'Segoe UI Emoji', 'Noto Color Emoji', 'Apple Color Emoji', sans-serif; | |
| font-size: 24px; | |
| line-height: 1; | |
| filter: none ; | |
| color: initial; | |
| text-shadow: none; | |
| } | |
| .group-info { flex: 1; min-width: 0; } | |
| .group-name { font-weight: 700; font-size: 15px; } | |
| .group-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; } | |
| .group-members-count { font-size: 11px; color: var(--text-secondary); margin-top: 4px; } | |
| .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; } | |
| .create-group-btn:hover { filter: brightness(1.1); transform: translateY(-2px); } | |
| .profile-close { | |
| position: sticky; | |
| top: 8px; | |
| z-index: 100; | |
| align-self: flex-end; | |
| margin: 8px 10px -44px 0; | |
| background: rgba(0,0,0,0.55); | |
| border: none; | |
| color: white; | |
| font-size: 18px; | |
| cursor: pointer; | |
| width: 34px; | |
| height: 34px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| flex-shrink: 0; | |
| transition: background 0.2s; | |
| } | |
| .profile-header { | |
| padding: 60px 24px 24px; | |
| text-align: center; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .profile-avatar { | |
| width: 80px; | |
| height: 80px; | |
| border-radius: 50%; | |
| background: linear-gradient(135deg, var(--primary-color), #4752c4); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-size: 40px; | |
| margin: 0 auto 12px; | |
| } | |
| .profile-name { | |
| font-size: 20px; | |
| font-weight: 600; | |
| } | |
| .profile-bio { | |
| font-size: 14px; | |
| color: var(--text-secondary); | |
| margin-top: 8px; | |
| } | |
| .profile-content { | |
| padding: 24px; | |
| flex: 1; | |
| min-height: 0; | |
| overflow: visible; | |
| padding-bottom: 34px; | |
| } | |
| .tab-buttons { | |
| display: flex; | |
| gap: 12px; | |
| margin-bottom: 24px; | |
| } | |
| .tab-btn { | |
| flex: 1; | |
| padding: 8px; | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| transition: all 0.2s ease; | |
| } | |
| .tab-btn.active { | |
| background: var(--primary-color); | |
| color: white; | |
| border-color: var(--primary-color); | |
| } | |
| .tab-content { | |
| display: none; | |
| } | |
| .tab-content.active { | |
| display: block; | |
| } | |
| .form-field { | |
| margin-bottom: 16px; | |
| } | |
| .form-field label { | |
| display: block; | |
| font-size: 12px; | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| } | |
| .form-field input, | |
| .form-field textarea { | |
| width: 100%; | |
| padding: 8px; | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| border-radius: 4px; | |
| color: var(--text-primary); | |
| font-size: 14px; | |
| font-family: inherit; | |
| } | |
| .form-field textarea { | |
| resize: vertical; | |
| min-height: 80px; | |
| } | |
| .save-btn { | |
| width: 100%; | |
| padding: 10px; | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .save-btn:hover { | |
| background: #4752c4; | |
| } | |
| .secondary-btn { | |
| width: 100%; | |
| padding: 10px; | |
| background: var(--secondary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .secondary-btn:hover { | |
| opacity: 0.9; | |
| } | |
| .shop-item { | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| border-radius: 4px; | |
| padding: 12px; | |
| margin-bottom: 12px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .shop-hero { | |
| padding: 16px; | |
| margin-bottom: 12px; | |
| border-radius: 10px; | |
| border: 1px solid rgba(255,255,255,0.12); | |
| background: linear-gradient(135deg, rgba(88,101,242,0.28), rgba(67,181,129,0.15)); | |
| } | |
| .shop-hero-title { | |
| font-size: 18px; | |
| font-weight: 800; | |
| margin-bottom: 4px; | |
| } | |
| .shop-hero-subtitle { | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| } | |
| .shop-hero-discount { | |
| margin-top: 10px; | |
| display: inline-flex; | |
| padding: 4px 10px; | |
| border-radius: 999px; | |
| font-size: 11px; | |
| font-weight: 700; | |
| color: #fff; | |
| background: linear-gradient(135deg, #ff7b54, #ffb347); | |
| } | |
| .shop-item-name { | |
| font-weight: 600; | |
| font-size: 14px; | |
| } | |
| .shop-item-price { | |
| color: var(--success); | |
| font-weight: 600; | |
| margin-right: 12px; | |
| } | |
| .buy-btn { | |
| padding: 6px 12px; | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-size: 12px; | |
| } | |
| .buy-btn:disabled { | |
| opacity: 0.55; | |
| cursor: not-allowed; | |
| } | |
| .orb-card { | |
| padding: 12px; | |
| border: 1px solid var(--border-color); | |
| border-radius: 10px; | |
| background: var(--bg-color); | |
| margin-bottom: 10px; | |
| } | |
| .saved-pill { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 8px 12px; | |
| border-radius: 999px; | |
| border: 1px solid var(--border-color); | |
| background: var(--bg-color); | |
| margin: 0 8px 8px 0; | |
| font-size: 12px; | |
| } | |
| .orb-none { | |
| --orb-glow: transparent; | |
| } | |
| .orb-aurora { | |
| --primary-color: #57c7ff; | |
| --secondary-color: #3d6f9a; | |
| --orb-glow: rgba(87, 199, 255, 0.35); | |
| } | |
| .orb-neon-pulse { | |
| --primary-color: #42e695; | |
| --secondary-color: #1f8c58; | |
| --orb-glow: rgba(66, 230, 149, 0.35); | |
| } | |
| .orb-ocean-mist { | |
| --primary-color: #5fa8ff; | |
| --secondary-color: #2e5384; | |
| --orb-glow: rgba(95, 168, 255, 0.3); | |
| } | |
| .orb-ember { | |
| --primary-color: #ff8f5e; | |
| --secondary-color: #8b3b1d; | |
| --orb-glow: rgba(255, 143, 94, 0.35); | |
| } | |
| .orb-aurora .profile-avatar, | |
| .orb-neon-pulse .profile-avatar, | |
| .orb-ocean-mist .profile-avatar, | |
| .orb-ember .profile-avatar { | |
| box-shadow: 0 0 0 6px var(--orb-glow); | |
| transition: box-shadow 0.3s ease; | |
| } | |
| .friend-item { | |
| padding: 12px; | |
| background: var(--bg-color); | |
| border-radius: 4px; | |
| margin-bottom: 12px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .friend-name { | |
| font-weight: 600; | |
| font-size: 14px; | |
| } | |
| .friend-status { | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| } | |
| .coins-display { | |
| font-size: 14px; | |
| color: var(--success); | |
| font-weight: 600; | |
| margin-bottom: 16px; | |
| } | |
| .toast-container { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| z-index: 3000; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .toast { | |
| background: var(--chat-bg); | |
| border-left: 4px solid var(--success); | |
| padding: 16px 20px; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.3); | |
| min-width: 300px; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| animation: slideInRight 0.3s ease, fadeOut 0.3s ease 2.7s; | |
| cursor: pointer; | |
| transition: transform 0.2s ease; | |
| } | |
| .toast:hover { | |
| transform: translateX(-4px); | |
| } | |
| .toast.clickable { | |
| cursor: pointer; | |
| } | |
| .toast.clickable:hover { | |
| background: var(--bg-color); | |
| transform: translateX(-8px) scale(1.02); | |
| } | |
| .toast.error { | |
| border-left-color: var(--danger); | |
| } | |
| .toast.warning { | |
| border-left-color: #faa61a; | |
| } | |
| .toast-icon { | |
| font-size: 20px; | |
| } | |
| .toast-content { | |
| flex: 1; | |
| } | |
| .toast-title { | |
| font-weight: 600; | |
| margin-bottom: 4px; | |
| } | |
| .toast-message { | |
| font-size: 13px; | |
| color: var(--text-secondary); | |
| } | |
| @keyframes slideInRight { | |
| from { transform: translateX(100%); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| @keyframes fadeOut { | |
| to { opacity: 0; transform: translateX(100%); } | |
| } | |
| .picker-panel { | |
| --picker-scale: 1.45; | |
| position: absolute; | |
| bottom: 60px; | |
| left: 50px; | |
| width: calc(440px * var(--picker-scale)); | |
| height: calc(500px * var(--picker-scale)); | |
| max-width: min(96vw, 900px); | |
| max-height: min(82vh, 760px); | |
| background: var(--chat-bg); | |
| border-radius: 8px 8px 0 0; | |
| box-shadow: 0 -4px 24px rgba(0,0,0,0.3); | |
| display: none; | |
| z-index: 1002; | |
| overflow: hidden; | |
| } | |
| .picker-panel.show { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .profile-close:hover { background: rgba(255,255,255,0.25); } | |
| #profileBackdrop { | |
| display: none; | |
| position: fixed; | |
| inset: 0; | |
| background: rgba(0,0,0,0.45); | |
| z-index: 999; | |
| cursor: pointer; | |
| } | |
| .picker-tabs { | |
| display: flex; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .picker-size-controls { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 8px; | |
| padding: 8px 10px; | |
| border-bottom: 1px solid var(--border-color); | |
| background: rgba(0, 0, 0, 0.08); | |
| } | |
| .picker-size-btn { | |
| min-width: 34px; | |
| height: 30px; | |
| border-radius: 8px; | |
| border: 1px solid var(--border-color); | |
| background: var(--secondary-color); | |
| color: var(--text-primary); | |
| cursor: pointer; | |
| font-weight: 700; | |
| } | |
| .picker-size-range { | |
| width: 120px; | |
| } | |
| .picker-size-label { | |
| min-width: 46px; | |
| text-align: right; | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| } | |
| .picker-tab { | |
| flex: 1; | |
| padding: 12px; | |
| background: none; | |
| border: none; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| font-size: 14px; | |
| } | |
| .picker-tab.active { | |
| color: var(--primary-color); | |
| border-bottom: 2px solid var(--primary-color); | |
| } | |
| .picker-content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 14px; | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 12px; | |
| } | |
| .picker-content.gifs-mode { | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: 16px; | |
| padding: 18px; | |
| } | |
| .sticker-item, .gif-item { | |
| font-size: 58px; | |
| font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; | |
| text-align: center; | |
| cursor: pointer; | |
| padding: 10px; | |
| border-radius: 10px; | |
| background: rgba(255,255,255,0.04); | |
| border: 1px solid rgba(255,255,255,0.08); | |
| transition: all 0.2s; | |
| } | |
| .sticker-item:hover, .gif-item:hover { | |
| background: var(--bg-color); | |
| transform: scale(1.06); | |
| } | |
| .gif-item { | |
| width: 100%; | |
| height: 150px; | |
| object-fit: cover; | |
| border-radius: 12px; | |
| } | |
| .voice-recorder { | |
| position: absolute; | |
| bottom: 70px; | |
| right: 20px; | |
| background: var(--chat-bg); | |
| border-radius: 8px; | |
| padding: 20px; | |
| box-shadow: 0 8px 24px rgba(0,0,0,0.4); | |
| display: none; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 12px; | |
| z-index: 100; | |
| min-width: 320px; | |
| } | |
| .voice-preview-container { | |
| width: 100%; | |
| margin-top: 8px; | |
| padding: 12px; | |
| background: rgba(88, 101, 242, 0.12); | |
| border: 2px solid var(--primary-color); | |
| border-radius: 8px; | |
| } | |
| .voice-preview-label { | |
| font-size: 13px; | |
| color: var(--primary-color); | |
| margin-bottom: 8px; | |
| font-weight: 700; | |
| text-align: center; | |
| } | |
| .voice-recorder.show { | |
| display: flex; | |
| } | |
| .record-button { | |
| width: 60px; | |
| height: 60px; | |
| border-radius: 50%; | |
| background: var(--danger); | |
| border: none; | |
| color: white; | |
| font-size: 24px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .record-button:hover { | |
| transform: scale(1.1); | |
| } | |
| .record-button.recording { | |
| animation: pulse 1s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.1); } | |
| } | |
| .record-timer { | |
| font-size: 18px; | |
| font-weight: 600; | |
| color: var(--danger); | |
| } | |
| .settings-panel { | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%) scale(0.96); | |
| width: min(920px, calc(100vw - 36px)); | |
| max-width: 920px; | |
| height: min(82vh, 760px); | |
| background: linear-gradient(180deg, rgba(35, 40, 74, 0.98) 0%, rgba(22, 25, 48, 0.98) 100%); | |
| border: 1px solid rgba(111, 146, 255, 0.16); | |
| border-radius: 22px; | |
| box-shadow: 0 30px 90px rgba(0,0,0,0.48), 0 0 0 1px rgba(255,255,255,0.03) inset; | |
| transition: opacity 0.28s ease, transform 0.28s ease; | |
| z-index: 2500; | |
| display: flex; | |
| flex-direction: column; | |
| opacity: 0; | |
| pointer-events: none; | |
| overflow: hidden; | |
| backdrop-filter: blur(18px); | |
| } | |
| .settings-panel.show { | |
| opacity: 1; | |
| pointer-events: auto; | |
| transform: translate(-50%, -50%) scale(1); | |
| } | |
| .settings-header { | |
| padding: 20px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .settings-header h2 { | |
| font-size: 20px; | |
| color: var(--ui-text-color); | |
| } | |
| .settings-nav { | |
| display: flex; | |
| flex-direction: column; | |
| border-right: 1px solid var(--border-color); | |
| min-width: 140px; | |
| } | |
| .settings-nav-item { | |
| padding: 12px 16px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| font-size: 14px; | |
| border-left: 3px solid transparent; | |
| color: var(--ui-text-color); | |
| } | |
| .settings-nav-item:hover { | |
| background: var(--bg-color); | |
| } | |
| .settings-nav-item.active { | |
| background: var(--bg-color); | |
| border-left-color: var(--primary-color); | |
| color: var(--primary-color); | |
| } | |
| .settings-content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 20px; | |
| } | |
| .settings-body { | |
| display: flex; | |
| flex: 1; | |
| overflow: hidden; | |
| } | |
| .settings-section { | |
| display: none; | |
| } | |
| .settings-section.active { | |
| display: block; | |
| } | |
| .settings-section h3 { | |
| color: var(--ui-text-color); | |
| margin-bottom: 16px; | |
| } | |
| .settings-item { | |
| margin-bottom: 20px; | |
| padding-bottom: 20px; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .settings-item:last-child { | |
| border-bottom: none; | |
| } | |
| .settings-label { | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| font-size: 14px; | |
| color: var(--ui-text-color); | |
| } | |
| .settings-description { | |
| font-size: 12px; | |
| color: var(--text-secondary); | |
| margin-bottom: 8px; | |
| } | |
| .toggle-switch { | |
| position: relative; | |
| display: inline-block; | |
| width: 44px; | |
| height: 24px; | |
| } | |
| .toggle-switch input { | |
| opacity: 0; | |
| width: 0; | |
| height: 0; | |
| } | |
| .toggle-slider { | |
| position: absolute; | |
| cursor: pointer; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background-color: var(--secondary-color); | |
| transition: 0.3s; | |
| border-radius: 24px; | |
| } | |
| .toggle-slider:before { | |
| position: absolute; | |
| content: ""; | |
| height: 18px; | |
| width: 18px; | |
| left: 3px; | |
| bottom: 3px; | |
| background-color: white; | |
| transition: 0.3s; | |
| border-radius: 50%; | |
| } | |
| .toggle-switch input:checked + .toggle-slider { | |
| background-color: var(--success); | |
| } | |
| .toggle-switch input:checked + .toggle-slider:before { | |
| transform: translateX(20px); | |
| } | |
| .modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0,0,0,0.6); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 1500; | |
| } | |
| .modal.hidden { | |
| display: none; | |
| } | |
| .modal-content { | |
| background: var(--chat-bg); | |
| padding: 32px; | |
| border-radius: 8px; | |
| max-width: 500px; | |
| width: 90%; | |
| box-shadow: 0 10px 40px rgba(0,0,0,0.5); | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| } | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--secondary-color); | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #5a5d60; | |
| } | |
| .mobile-bottom-nav { | |
| display: none; | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| background: var(--sidebar-bg); | |
| border-top: 2px solid var(--border-color); | |
| z-index: 1000; | |
| flex-direction: row; | |
| justify-content: space-around; | |
| padding: 8px 0; | |
| box-shadow: 0 -4px 20px rgba(0,0,0,0.3); | |
| } | |
| .mobile-members-panel { | |
| position: fixed; | |
| right: -100%; | |
| top: 0; | |
| width: 80%; | |
| max-width: 300px; | |
| height: 100vh; | |
| background: var(--sidebar-bg); | |
| border-left: 1px solid var(--border-color); | |
| z-index: 1500; | |
| transition: right 0.3s ease; | |
| display: flex; | |
| flex-direction: column; | |
| box-shadow: -4px 0 20px rgba(0,0,0,0.5); | |
| } | |
| .mobile-members-panel.show { | |
| right: 0; | |
| } | |
| .mobile-members-header { | |
| padding: 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .mobile-members-header h3 { | |
| font-size: 16px; | |
| font-weight: 600; | |
| } | |
| .mobile-members-list { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 8px; | |
| } | |
| .mobile-nav-item { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 4px; | |
| padding: 8px; | |
| border: none; | |
| background: none; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| position: relative; | |
| } | |
| .mobile-nav-item.active { | |
| color: var(--primary-color); | |
| } | |
| .mobile-nav-item i { | |
| font-size: 22px; | |
| } | |
| .mobile-nav-item span { | |
| font-size: 10px; | |
| font-weight: 500; | |
| } | |
| .mobile-nav-badge { | |
| position: absolute; | |
| top: 4px; | |
| right: 20%; | |
| background: var(--danger); | |
| color: white; | |
| border-radius: 10px; | |
| padding: 2px 6px; | |
| font-size: 10px; | |
| font-weight: bold; | |
| min-width: 18px; | |
| text-align: center; | |
| } | |
| @media (max-width: 1200px) { | |
| .main-container { | |
| grid-template-columns: 72px 240px 1fr; | |
| } | |
| .members-sidebar { | |
| display: none; | |
| } | |
| .profile-panel { | |
| width: 300px; | |
| transform: translateX(300px); | |
| } | |
| .profile-panel.show { | |
| transform: translateX(0); | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| body { | |
| overflow: hidden; | |
| } | |
| .main-container { | |
| grid-template-columns: 45px 1fr; | |
| height: 100vh; | |
| height: 100dvh; | |
| max-height: -webkit-fill-available; | |
| } | |
| .guild-sidebar { | |
| padding: 2px 0; | |
| width: 45px; | |
| } | |
| .guild-item { | |
| width: 40px; | |
| height: 40px; | |
| font-size: 18px; | |
| margin-bottom: 4px; | |
| } | |
| .guild-divider { | |
| width: 24px; | |
| margin: 4px 0; | |
| } | |
| /* Mobile Channel Sidebar */ | |
| .channel-sidebar { | |
| display: none; | |
| position: fixed; | |
| left: 0; | |
| top: 0; | |
| width: 85%; | |
| max-width: 320px; | |
| height: 100%; | |
| height: 100dvh; | |
| z-index: 999; | |
| box-shadow: 4px 0 20px rgba(0,0,0,0.5); | |
| } | |
| .channel-sidebar.show { | |
| display: flex; | |
| } | |
| .channel-sidebar.show::before { | |
| content: ''; | |
| position: fixed; | |
| left: 0; | |
| top: 0; | |
| width: 100vw; | |
| height: 100vh; | |
| background: rgba(0,0,0,0.5); | |
| z-index: -1; | |
| } | |
| .chat-area { | |
| height: 100vh; | |
| height: 100dvh; | |
| max-height: -webkit-fill-available; | |
| } | |
| .chat-header { | |
| padding: 12px 16px; | |
| flex-shrink: 0; | |
| } | |
| .chat-header-left { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .chat-header-title { | |
| font-size: 16px; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .build-badge { | |
| display: none; | |
| } | |
| .build-badge.mobile-essential { | |
| display: inline-flex; | |
| align-items: center; | |
| } | |
| .header-btn { | |
| font-size: 16px; | |
| padding: 8px; | |
| } | |
| .chat-header-actions { | |
| gap: 4px; | |
| flex-wrap: nowrap; | |
| overflow-x: auto; | |
| max-width: 56vw; | |
| scrollbar-width: thin; | |
| } | |
| .chat-header-actions .header-btn { | |
| padding: 6px; | |
| min-width: 32px; | |
| flex-shrink: 0; | |
| } | |
| #messages-container { | |
| flex: 1; | |
| min-height: 0; | |
| max-height: none; | |
| padding: 12px 16px; | |
| padding-bottom: 16px; | |
| -webkit-overflow-scrolling: touch; | |
| overscroll-behavior: contain; | |
| } | |
| .message { | |
| gap: 8px; | |
| } | |
| .message-avatar { | |
| width: 36px; | |
| height: 36px; | |
| font-size: 16px; | |
| } | |
| .message-username { | |
| font-size: 14px; | |
| } | |
| .message-text { | |
| font-size: 14px; | |
| } | |
| .message-media { | |
| max-width: 90%; | |
| } | |
| .input-area { | |
| padding: 10px 8px; | |
| gap: 6px; | |
| flex-shrink: 0; | |
| border-top: 2px solid var(--border-color); | |
| display: grid; | |
| grid-template-columns: auto auto auto auto minmax(0, 1fr) auto; | |
| align-items: center; | |
| } | |
| .input-area input { | |
| font-size: 16px; | |
| padding: 9px 12px; | |
| min-width: 0; | |
| } | |
| .input-btn { | |
| width: 36px; | |
| height: 36px; | |
| font-size: 14px; | |
| flex-shrink: 0; | |
| } | |
| .chat-scroll-rail { | |
| right: 4px; | |
| top: 64px; | |
| bottom: 74px; | |
| width: 12px; | |
| } | |
| .chat-scroll-thumb { | |
| min-height: 40px; | |
| } | |
| .picker-panel { | |
| width: 100%; | |
| left: 0; | |
| bottom: 0; | |
| height: 68vh; | |
| max-height: 68vh; | |
| border-radius: 16px 16px 0 0; | |
| } | |
| .voice-recorder { | |
| width: 90%; | |
| left: 5%; | |
| right: auto; | |
| bottom: 80px; | |
| } | |
| .draft-preview { | |
| margin: 8px 16px 0; | |
| padding: 8px; | |
| } | |
| .settings-panel { | |
| width: 100%; | |
| max-width: none; | |
| height: 100%; | |
| top: 0; | |
| left: 0; | |
| border-radius: 0; | |
| transform: translateY(18px); | |
| } | |
| .settings-panel.show { | |
| transform: translateY(0); | |
| } | |
| .settings-body { | |
| flex-direction: column; | |
| } | |
| .settings-nav { | |
| flex-direction: row; | |
| overflow-x: auto; | |
| border-right: none; | |
| border-bottom: 1px solid var(--border-color); | |
| min-width: auto; | |
| } | |
| .settings-nav-item { | |
| white-space: nowrap; | |
| border-left: none; | |
| border-bottom: 3px solid transparent; | |
| font-size: 13px; | |
| padding: 10px 14px; | |
| } | |
| .settings-nav-item.active { | |
| border-left: none; | |
| border-bottom-color: var(--primary-color); | |
| } | |
| .toast-container { | |
| top: 10px; | |
| right: 10px; | |
| left: 10px; | |
| } | |
| .toast { | |
| min-width: auto; | |
| padding: 12px 16px; | |
| } | |
| .profile-panel { | |
| width: 100%; | |
| } | |
| .members-sidebar { | |
| display: none ; | |
| } | |
| } | |
| .custom-dialog { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.7); | |
| backdrop-filter: blur(8px); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 9999; | |
| animation: fadeIn 0.2s ease; | |
| } | |
| .custom-dialog-content { | |
| background: var(--chat-bg); | |
| border-radius: 16px; | |
| padding: 32px; | |
| min-width: 400px; | |
| max-width: 90%; | |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.8); | |
| animation: slideUp 0.3s ease; | |
| border: 2px solid var(--primary-color); | |
| } | |
| .custom-dialog-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| margin-bottom: 20px; | |
| } | |
| .custom-dialog-icon { | |
| font-size: 32px; | |
| } | |
| .custom-dialog-title { | |
| font-size: 22px; | |
| font-weight: 700; | |
| color: var(--ui-text-color); | |
| } | |
| .custom-dialog-message { | |
| font-size: 15px; | |
| color: var(--text-primary); | |
| margin-bottom: 24px; | |
| line-height: 1.6; | |
| } | |
| .custom-dialog-input { | |
| width: 100%; | |
| padding: 12px; | |
| background: var(--bg-color); | |
| border: 2px solid var(--border-color); | |
| border-radius: 8px; | |
| color: var(--text-primary); | |
| font-size: 14px; | |
| margin-bottom: 20px; | |
| transition: all 0.2s; | |
| } | |
| .custom-dialog-input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(88, 101, 242, 0.1); | |
| } | |
| .custom-dialog-buttons { | |
| display: flex; | |
| gap: 12px; | |
| justify-content: flex-end; | |
| } | |
| .loader-logo { | |
| position: relative; | |
| width: 110px; | |
| height: auto; | |
| z-index: 10; | |
| /* This creates a layered glow: one sharp blue, one soft cyan */ | |
| filter: | |
| drop-shadow(0 0 10px rgba(95, 126, 255, 0.8)) | |
| drop-shadow(0 0 30px rgba(156, 196, 255, 0.4)); | |
| /* Applying three animations at once: float, flicker, and subtle rotate */ | |
| animation: | |
| fireFloat 3s ease-in-out infinite, | |
| fireFlicker 1.5s infinite alternate, | |
| fireIgnite 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| } | |
| .custom-dialog-btn { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 8px; | |
| font-size: 14px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| min-width: 100px; | |
| } | |
| /* 1. Makes the flame float up and down gently */ | |
| @keyframes fireFloat { | |
| 0%, 100% { transform: translateY(0) rotate(-1deg); } | |
| 50% { transform: translateY(-12px) rotate(1deg); } | |
| } | |
| /* 2. Simulates the flickering intensity of fire */ | |
| @keyframes fireFlicker { | |
| 0%, 100% { opacity: 1; filter: brightness(1) drop-shadow(0 0 10px rgba(95, 126, 255, 0.8)); } | |
| 25% { opacity: 0.95; filter: brightness(1.2) drop-shadow(0 0 15px rgba(95, 126, 255, 1)); } | |
| 50% { opacity: 1; filter: brightness(0.9); } | |
| 75% { opacity: 0.98; filter: brightness(1.1) drop-shadow(0 0 12px rgba(156, 196, 255, 0.9)); } | |
| } | |
| /* 3. The "Pop Up" effect when the page first loads */ | |
| @keyframes fireIgnite { | |
| 0% { transform: scale(0) rotate(-20deg); opacity: 0; } | |
| 100% { transform: scale(1) rotate(0deg); opacity: 1; } | |
| } | |
| .custom-dialog-btn-primary { | |
| background: var(--primary-color); | |
| color: white; | |
| } | |
| .custom-dialog-btn-primary:hover { | |
| background: #4752c4; | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(88, 101, 242, 0.4); | |
| } | |
| .custom-dialog-btn-danger { | |
| background: var(--danger); | |
| color: white; | |
| } | |
| .custom-dialog-btn-danger:hover { | |
| background: #d93636; | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(240, 71, 71, 0.4); | |
| } | |
| .custom-dialog-btn-secondary { | |
| background: var(--secondary-color); | |
| color: var(--text-primary); | |
| } | |
| .custom-dialog-btn-secondary:hover { | |
| opacity: 0.8; | |
| transform: translateY(-2px); | |
| } | |
| .community-modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.7); | |
| backdrop-filter: blur(8px); | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 2600; | |
| } | |
| .community-modal.show { | |
| display: flex; | |
| } | |
| .community-modal-content { | |
| background: var(--chat-bg); | |
| border-radius: 14px; | |
| width: min(92vw, 520px); | |
| max-height: 88vh; | |
| overflow: hidden; | |
| border: 1px solid var(--border-color); | |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55); | |
| } | |
| .community-modal-header { | |
| padding: 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| .community-modal-body { | |
| padding: 12px 16px 16px; | |
| overflow-y: auto; | |
| max-height: calc(88vh - 68px); | |
| } | |
| .community-member-card { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| padding: 10px; | |
| border-radius: 10px; | |
| cursor: pointer; | |
| } | |
| .community-member-card:hover { | |
| background: var(--bg-color); | |
| } | |
| .community-role-pill { | |
| margin-left: auto; | |
| font-size: 11px; | |
| font-weight: 600; | |
| padding: 2px 8px; | |
| border-radius: 999px; | |
| border: 1px solid var(--border-color); | |
| color: var(--text-secondary); | |
| } | |
| .community-role-pill.leader { | |
| color: #ffc107; | |
| border-color: rgba(255, 193, 7, 0.45); | |
| background: rgba(255, 193, 7, 0.1); | |
| } | |
| .friend-search-container { | |
| padding: 12px 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .friend-search-input { | |
| width: 100%; | |
| padding: 10px 12px 10px 38px; | |
| background: var(--bg-color); | |
| border: 1px solid var(--border-color); | |
| border-radius: 20px; | |
| color: var(--text-primary); | |
| font-size: 13px; | |
| transition: all 0.2s; | |
| } | |
| .friend-search-input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 2px rgba(88, 101, 242, 0.15); | |
| } | |
| .friend-search-wrapper { | |
| position: relative; | |
| } | |
| .friend-search-icon { | |
| position: absolute; | |
| left: 12px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| color: var(--text-secondary); | |
| font-size: 14px; | |
| } | |
| .qr-modal { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.8); | |
| backdrop-filter: blur(10px); | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 9998; | |
| } | |
| .qr-modal.show { | |
| display: flex; | |
| } | |
| .qr-modal-content { | |
| background: var(--chat-bg); | |
| border-radius: 20px; | |
| padding: 40px; | |
| text-align: center; | |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.9); | |
| border: 2px solid var(--primary-color); | |
| max-width: 450px; | |
| } | |
| .qr-modal-title { | |
| font-size: 24px; | |
| font-weight: 700; | |
| color: var(--ui-text-color); | |
| margin-bottom: 16px; | |
| } | |
| .qr-modal-subtitle { | |
| font-size: 14px; | |
| color: var(--text-secondary); | |
| margin-bottom: 24px; | |
| } | |
| .qr-code-container { | |
| background: white; | |
| padding: 20px; | |
| border-radius: 12px; | |
| display: inline-block; | |
| margin-bottom: 20px; | |
| } | |
| #qrCodeCanvas { | |
| display: block; | |
| } | |
| .qr-modal-close { | |
| margin-top: 12px; | |
| padding: 12px 32px; | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.2s; | |
| } | |
| .qr-modal-close:hover { | |
| background: #4752c4; | |
| transform: translateY(-2px); | |
| } | |
| .media-preview-panel { | |
| position: fixed; | |
| bottom: -100%; | |
| left: 0; | |
| right: 0; | |
| height: 60vh; | |
| background: var(--chat-bg); | |
| border-top: 3px solid var(--primary-color); | |
| z-index: 1500; | |
| transition: bottom 0.4s cubic-bezier(0.4, 0, 0.2, 1); | |
| box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.5); | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .media-preview-panel.show { | |
| bottom: 0; | |
| } | |
| .media-preview-header { | |
| padding: 20px 24px; | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| background: var(--bg-color); | |
| } | |
| .media-preview-title { | |
| font-size: 18px; | |
| font-weight: 600; | |
| color: var(--ui-text-color); | |
| } | |
| .media-preview-close { | |
| background: none; | |
| border: none; | |
| color: var(--text-secondary); | |
| cursor: pointer; | |
| font-size: 24px; | |
| padding: 8px; | |
| transition: all 0.2s; | |
| } | |
| .media-preview-close:hover { | |
| color: var(--danger); | |
| transform: rotate(90deg); | |
| } | |
| .media-preview-content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 24px; | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 16px; | |
| align-content: flex-start; | |
| } | |
| .media-preview-item { | |
| position: relative; | |
| width: 200px; | |
| height: 200px; | |
| border-radius: 12px; | |
| overflow: hidden; | |
| border: 2px solid var(--border-color); | |
| transition: all 0.2s; | |
| } | |
| .media-preview-item:hover { | |
| transform: scale(1.05); | |
| border-color: var(--primary-color); | |
| box-shadow: 0 8px 24px rgba(88, 101, 242, 0.3); | |
| } | |
| .media-preview-item img, | |
| .media-preview-item video { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| } | |
| .danger-hover:hover { | |
| color: var(--danger) ; | |
| transform: scale(1.08); | |
| filter: drop-shadow(0 0 8px rgba(240, 71, 71, 0.6)); | |
| } | |
| .save-btn.danger-hover:hover { | |
| color: white ; | |
| transform: scale(1.02) ; | |
| } | |
| .success-hover:hover { | |
| color: var(--success) ; | |
| transform: scale(1.1); | |
| filter: drop-shadow(0 0 8px rgba(67, 181, 129, 0.6)); | |
| } | |
| .primary-hover:hover { | |
| color: var(--primary-color) ; | |
| transform: scale(1.1); | |
| filter: drop-shadow(0 0 8px rgba(88, 101, 242, 0.6)); | |
| } | |
| @media (max-width: 768px) { | |
| .chat-header-actions .header-btn { | |
| animation: none ; | |
| } | |
| .friend-item:hover, | |
| .group-card:hover { | |
| transform: none; | |
| box-shadow: none; | |
| } | |
| .custom-dialog-content { | |
| min-width: 90%; | |
| padding: 24px; | |
| } | |
| .media-preview-panel { | |
| height: 70vh; | |
| } | |
| .media-preview-item { | |
| width: calc(50% - 8px); | |
| height: 150px; | |
| } | |
| .qr-modal-content { | |
| margin: 20px; | |
| padding: 24px; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .main-container { | |
| grid-template-columns: 1fr; | |
| height: calc(100vh - 68px); | |
| height: calc(100dvh - 68px); | |
| padding-bottom: 68px; | |
| } | |
| .mobile-bottom-nav { | |
| display: flex; | |
| } | |
| .guild-sidebar { | |
| display: none ; | |
| } | |
| .members-sidebar { | |
| display: none ; | |
| } | |
| .profile-panel { | |
| width: 100vw; | |
| right: -100vw; | |
| overflow-y: auto; | |
| -webkit-overflow-scrolling: touch; | |
| overscroll-behavior: contain; | |
| } | |
| .profile-panel.show { | |
| right: 0; | |
| } | |
| .channel-sidebar { | |
| position: fixed; | |
| left: 0; | |
| top: 0; | |
| width: 85%; | |
| max-width: 320px; | |
| height: 100vh; | |
| height: 100dvh; | |
| z-index: 1500; | |
| display: none; | |
| flex-direction: column; | |
| transform: translateX(-100%); | |
| transition: transform 0.3s ease; | |
| } | |
| .channel-sidebar.show { | |
| display: flex; | |
| transform: translateX(0); | |
| } | |
| .channel-sidebar .sidebar-header > div button { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .channel-sidebar .sidebar-header { | |
| gap: 8px; | |
| flex-wrap: wrap; | |
| } | |
| .channel-sidebar .sidebar-header h3 { | |
| font-size: 15px; | |
| white-space: nowrap; | |
| } | |
| .sidebar-overlay { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0,0,0,0.6); | |
| z-index: 1499; | |
| } | |
| .sidebar-overlay.show { | |
| display: block; | |
| } | |
| .chat-area { | |
| display: flex; | |
| flex-direction: column; | |
| height: calc(100vh - 68px); | |
| height: calc(100dvh - 68px); | |
| width: 100vw; | |
| max-width: 100%; | |
| } | |
| .chat-header { | |
| padding: 12px 16px; | |
| flex-shrink: 0; | |
| } | |
| .chat-header-title { | |
| font-size: 16px; | |
| font-weight: 600; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| flex: 1; | |
| } | |
| .chat-header-actions { | |
| gap: 4px; | |
| flex-shrink: 0; | |
| overflow-x: auto; | |
| max-width: 66vw; | |
| padding-bottom: 2px; | |
| } | |
| .chat-header-actions button { | |
| display: inline-flex; | |
| flex-shrink: 0; | |
| min-width: 30px; | |
| min-height: 30px; | |
| } | |
| .chat-header-actions .mobile-essential { | |
| display: inline-flex; | |
| } | |
| .build-badge.mobile-essential { | |
| display: inline-flex ; | |
| flex-shrink: 0; | |
| } | |
| .build-badge { | |
| display: none; | |
| } | |
| #messages-container { | |
| flex: 1; | |
| min-height: 0; | |
| max-height: none; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| padding: 12px 16px; | |
| padding-bottom: 16px; | |
| gap: 8px; | |
| } | |
| .message { | |
| gap: 8px; | |
| } | |
| .message-avatar { | |
| width: 32px; | |
| height: 32px; | |
| min-width: 32px; | |
| } | |
| .message-input-area { | |
| flex-shrink: 0; | |
| padding: 12px 16px; | |
| } | |
| .message-input-section { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| #messageInput { | |
| flex: 1; | |
| padding: 10px 12px; | |
| font-size: 14px; | |
| } | |
| .message-input-btn { | |
| padding: 8px 12px; | |
| font-size: 14px; | |
| } | |
| .chat-scroll-rail { | |
| right: 4px; | |
| width: 8px; | |
| } | |
| .media-preview-item { | |
| width: 100%; | |
| height: 200px; | |
| } | |
| .custom-dialog-buttons { | |
| flex-direction: column; | |
| } | |
| .custom-dialog-btn { | |
| width: 100%; | |
| } | |
| .profile-panel { | |
| position: fixed; | |
| left: 0; | |
| top: 0; | |
| width: 100vw; | |
| height: 100dvh; | |
| z-index: 2601; | |
| overflow-y: auto ; | |
| -webkit-overflow-scrolling: touch; | |
| overscroll-behavior: contain; | |
| } | |
| .profile-content { | |
| width: 100%; | |
| max-width: none; | |
| border-radius: 0; | |
| padding-bottom: 120px; | |
| } | |
| .friends-modal { | |
| position: fixed; | |
| left: 0; | |
| top: 0; | |
| width: 100vw; | |
| height: 100vh; | |
| border-radius: 0; | |
| max-width: none; | |
| } | |
| .modal-content { | |
| border-radius: 0; | |
| } | |
| .qr-modal-content { | |
| margin: 20px; | |
| padding: 16px; | |
| } | |
| } | |
| @media (min-width: 481px) and (max-width: 768px) { | |
| .main-container { | |
| grid-template-columns: 72px 1fr; | |
| } | |
| .members-sidebar { | |
| display: none ; | |
| } | |
| .channel-sidebar { | |
| width: 200px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- ====== FIRE APP LOADER ====== --> | |
| <div id="appLoader"> | |
| <div class="loader-scene"> | |
| <div class="loader-aura"></div> | |
| <div class="loader-stage-ring"></div> | |
| <img src="images/logo.png" alt="App Logo" class="loader-logo"> | |
| </div> | |
| <div class="loader-app-name">FireTech</div> | |
| <div class="loader-tagline">Secure your conversations. Trust the fire.</div> | |
| <div class="loader-progress-wrap"> | |
| <div class="loader-progress-bar" id="loaderBar"></div> | |
| </div> | |
| <div class="loader-status" id="loaderStatus">Igniting...</div> | |
| </div> | |
| <div class="auth-container" id="authContainer"> | |
| <div class="auth-box"> | |
| <h2 id="authTitle">Login</h2> | |
| <form id="authForm" onsubmit="handleAuth(event)"> | |
| <div id="registerFields" style="display: none;"> | |
| <div class="form-group"> | |
| <label>Username</label> | |
| <input type="text" id="username" placeholder="Choose a username" required> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label>Email</label> | |
| <input type="email" id="email" placeholder="Enter your email" required> | |
| </div> | |
| <div class="form-group"> | |
| <label>Password</label> | |
| <input type="password" id="password" placeholder="Enter your password" required> | |
| </div> | |
| <div class="auth-inline-link" id="forgotPasswordWrap"> | |
| <button type="button" onclick="toggleForgotPasswordPanel()">Forgot password?</button> | |
| </div> | |
| <button type="submit" class="auth-button" id="authButton">Login</button> | |
| </form> | |
| <div class="reset-password-panel" id="resetPasswordPanel"> | |
| <div class="form-group" style="margin-bottom: 12px;"> | |
| <label>Reset Email</label> | |
| <input type="email" id="resetEmail" placeholder="Enter your account email"> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 12px;"> | |
| <label>New Password</label> | |
| <input type="password" id="resetNewPassword" placeholder="Enter new password (min 6 chars)"> | |
| </div> | |
| <button type="button" class="auth-mini-button" onclick="resetForgottenPassword()">Reset Password</button> | |
| </div> | |
| <div id="authStatus" class="auth-status" aria-live="polite"></div> | |
| <div class="auth-toggle"> | |
| <span>Don't have an account? <button type="button" onclick="toggleAuthMode()">Register</button></span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="main-container" id="mainApp"> | |
| <div class="guild-sidebar"> | |
| <div class="guild-item active" onclick="showSection('chat')" title="Chat"> | |
| <i class="fas fa-comment"></i> | |
| </div> | |
| <div class="guild-item" onclick="showSection('friends')" title="Friends"> | |
| <i class="fas fa-users"></i> | |
| </div> | |
| <div class="guild-item" onclick="showSection('shop')" title="Shop"> | |
| <i class="fas fa-store"></i> | |
| </div> | |
| <div class="guild-divider"></div> | |
| <div class="guild-item" onclick="openFireTechBot()" title="FireTech Security Bot" style="background: linear-gradient(135deg, #ff9d4d, #5f7eff); font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center;"> | |
| β‘ | |
| </div> | |
| <div class="guild-item" onclick="showArchivedMessages()" title="Archived Messages"> | |
| <i class="fas fa-archive"></i> | |
| </div> | |
| <div class="guild-item" onclick="openCommunitiesModal()" title="Communities"> | |
| <i class="fas fa-globe"></i> | |
| </div> | |
| <div class="guild-item" onclick="openGroupsModal()" title="Groups"> | |
| <i class="fas fa-user-group"></i> | |
| </div> | |
| </div> | |
| <div class="channel-sidebar" id="channelSidebar"> | |
| <div class="sidebar-header"> | |
| <h3>FireTech</h3> | |
| <div style="display: flex; gap: 6px; flex-wrap: wrap;"> | |
| <button onclick="createNewGroup()" title="Create Group" style="padding: 6px 10px; background: var(--primary-color); border: none; border-radius: 6px; color: white; cursor: pointer; font-size: 11px; font-weight: 600;"> | |
| <i class="fas fa-plus"></i> New | |
| </button> | |
| <button onclick="showQuickActionsMenu()" title="Quick Actions" style="padding: 6px 10px; background: var(--secondary-color); border: none; border-radius: 6px; color: white; cursor: pointer; font-size: 11px;"> | |
| <i class="fas fa-ellipsis-h"></i> | |
| </button> | |
| <button onclick="toggleChannelSidebar()" class="danger-hover" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 18px; padding: 4px 8px;"><i class="fas fa-times"></i></button> | |
| </div> | |
| </div> | |
| <div class="friend-search-container"> | |
| <div class="friend-search-wrapper"> | |
| <i class="fas fa-search friend-search-icon"></i> | |
| <input type="text" id="friendSearchInput" class="friend-search-input" placeholder="Search friends..." oninput="filterFriends(this.value)"> | |
| </div> | |
| </div> | |
| <div class="channels-list" id="channelsList"> | |
| </div> | |
| </div> | |
| <div class="chat-area"> | |
| <div class="chat-header"> | |
| <div class="chat-header-left"> | |
| <button class="header-btn" onclick="toggleChannelSidebar()"> | |
| <i class="fas fa-bars"></i> | |
| </button> | |
| <div class="chat-header-title" id="chatTitle">π¬ Select a friend to chat</div> | |
| </div> | |
| <div class="chat-header-actions"> | |
| <span class="build-badge mobile-essential" id="buildVersionBadge" title="Frontend build version">v3.2.8</span> | |
| <button class="header-btn mobile-essential" onclick="toggleArchiveChat()" title="Archive chat"> | |
| <i class="fas fa-archive"></i> | |
| </button> | |
| <button class="header-btn mobile-essential" onclick="startVideoCall()" title="Video call"> | |
| <i class="fas fa-video"></i> | |
| </button> | |
| <button class="header-btn mobile-essential" onclick="togglePinCurrentChat()" title="Pin/Unpin chat" id="pinChatBtn"> | |
| <i class="fas fa-thumbtack"></i> | |
| </button> | |
| <button class="header-btn success mobile-essential" onclick="addCurrentChatToList()" title="Add chat to list"> | |
| <i class="fas fa-bookmark"></i> | |
| </button> | |
| <button class="header-btn danger-hover mobile-essential" onclick="clearAndCloseCurrentChat()" title="Clear and Close Chat" id="closeChatBtn" style="display: none;"> | |
| <i class="fas fa-times-circle"></i> | |
| </button> | |
| <button class="header-btn mobile-essential" onclick="toggleMobileMembers()" title="View members"> | |
| <i class="fas fa-users"></i> | |
| </button> | |
| <button class="header-btn mobile-essential" onclick="openSettings()" title="Settings"> | |
| <i class="fas fa-cog"></i> | |
| </button> | |
| <button class="header-btn mobile-essential notif-bell-btn" onclick="openNotifPanel()" title="Notifications"> | |
| <i class="fas fa-bell"></i> | |
| <span class="notif-badge" id="notifBadge">0</span> | |
| </button> | |
| <button class="header-btn mobile-essential" onclick="openProfile()" title="Profile"> | |
| <i class="fas fa-user-circle"></i> | |
| </button> | |
| <button class="header-btn danger-hover mobile-essential" onclick="logout()" title="Logout"> | |
| <i class="fas fa-sign-out-alt"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="messages-container"></div> | |
| <div id="chatScrollRail" class="chat-scroll-rail hidden"> | |
| <div id="chatScrollThumb" class="chat-scroll-thumb"></div> | |
| </div> | |
| <div id="mediaDraftPreview" class="draft-preview"> | |
| <div class="draft-preview-left"> | |
| <img id="draftPreviewThumb" class="draft-preview-thumb" alt="Selected media preview"> | |
| <div id="draftPreviewEmoji" class="draft-preview-emoji"></div> | |
| <div id="draftPreviewMeta" class="draft-preview-meta">Media selected. Press Send when ready.</div> | |
| </div> | |
| <button class="draft-clear-btn" onclick="clearPendingMediaDraft()">Clear</button> | |
| </div> | |
| <div id="typingIndicator" style="display: none; padding: 10px; color: var(--text-secondary); font-size: 12px; font-style: italic;"></div> | |
| <div class="input-area"> | |
| <button class="input-btn" onclick="document.getElementById('fileInput').click()" title="Upload Image"> | |
| <i class="fas fa-image"></i> | |
| </button> | |
| <button class="input-btn" onclick="document.getElementById('videoInput').click()" title="Upload Video / Reel"> | |
| <i class="fas fa-film"></i> | |
| </button> | |
| <button class="input-btn" onclick="togglePicker()" title="Stickers & GIFs"> | |
| <i class="fas fa-smile"></i> | |
| </button> | |
| <button class="input-btn" onclick="toggleVoiceRecorder()" title="Voice message"> | |
| <i class="fas fa-microphone"></i> | |
| </button> | |
| <input type="text" id="messageInput" placeholder="Message..." onkeypress="handleMessageKeypress(event)"> | |
| <button class="input-btn" onclick="sendMessage()" title="Send"> | |
| <i class="fas fa-paper-plane"></i> | |
| </button> | |
| <input type="file" id="fileInput" class="input-file" onchange="handleFileUpload(event)" accept="image/*" multiple> | |
| <input type="file" id="videoInput" class="input-file" onchange="handleFileUpload(event)" accept="video/mp4,video/webm,video/ogg,video/*" multiple> | |
| </div> | |
| </div> | |
| <div class="members-sidebar"> | |
| <div class="members-header">π₯ Online Members</div> | |
| <div class="members-list" id="membersList"></div> | |
| </div> | |
| </div> | |
| <div id="profileBackdrop" onclick="closeProfile()"></div> | |
| <div class="profile-panel" id="profilePanel"> | |
| <button class="profile-close" onclick="closeProfile()"><i class="fas fa-times"></i></button> | |
| <div class="profile-banner-wrap" id="profileBannerWrap"> | |
| <img id="profileBannerImg" class="profile-banner-img" src="" alt="" style="display:none;"> | |
| <button class="profile-banner-edit-btn" onclick="openBannerPicker()">πΌ Edit Banner</button> | |
| </div> | |
| <div class="profile-header"> | |
| <div class="profile-avatar" id="profileAvatar">U</div> | |
| <div class="profile-name" id="profileName">Username</div> | |
| <div class="profile-bio" id="profileBio">No bio yet</div> | |
| </div> | |
| <div class="profile-content"> | |
| <div class="tab-buttons"> | |
| <button class="tab-btn active" onclick="switchProfileTab('profile', this)">Profile</button> | |
| <button class="tab-btn" onclick="switchProfileTab('inventory', this)">Inventory</button> | |
| <button class="tab-btn" onclick="switchProfileTab('orbs', this)">Orbs</button> | |
| <button class="tab-btn" onclick="switchProfileTab('saved', this)">Saved</button> | |
| </div> | |
| <div class="tab-content active" id="profileTab"> | |
| <div class="form-field"> | |
| <label>Profile Picture</label> | |
| <button class="save-btn" onclick="document.getElementById('profileImageInput').click()">Upload Profile Picture</button> | |
| <input type="file" id="profileImageInput" class="input-file" onchange="uploadProfileImage(event)" accept="image/*" style="display: none;"> | |
| <p style="font-size: 12px; color: var(--text-secondary); margin-top: 5px;">Click to upload your profile picture</p> | |
| </div> | |
| <div class="form-field"> | |
| <label>Share Profile</label> | |
| <button class="save-btn" onclick="shareProfileLink()" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">π Copy Profile Link</button> | |
| <p style="font-size: 12px; color: var(--text-secondary); margin-top: 5px;">Share this link with friends to connect</p> | |
| </div> | |
| <div class="form-field"> | |
| <label>Username</label> | |
| <input type="text" id="editUsername" placeholder="Username"> | |
| </div> | |
| <div class="form-field"> | |
| <label>Bio</label> | |
| <textarea id="editBio" placeholder="Tell us about yourself"></textarea> | |
| </div> | |
| <div class="form-field"> | |
| <label>Phone Number</label> | |
| <input type="tel" id="editPhoneNumber" placeholder="Add your phone number"> | |
| </div> | |
| <button class="save-btn" onclick="saveProfile()">Save Profile</button> | |
| </div> | |
| <div class="tab-content" id="inventoryTab"> | |
| <div id="inventoryList"></div> | |
| </div> | |
| <div class="tab-content" id="orbsTab"> | |
| <div class="orb-card"> | |
| <label for="orbEffectSelect" style="display:block; font-size:12px; font-weight:700; margin-bottom:8px;">Orb Effect Theme</label> | |
| <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)"> | |
| <option value="none">None</option> | |
| <option value="aurora">Aurora Glow</option> | |
| <option value="neon_pulse">Neon Pulse</option> | |
| <option value="ocean_mist">Ocean Mist</option> | |
| <option value="ember">Ember Flame</option> | |
| </select> | |
| <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> | |
| </div> | |
| </div> | |
| <div class="tab-content" id="savedTab"> | |
| <div style="margin-bottom:10px; color:var(--text-secondary); font-size:12px;">Your saved and archived content overview</div> | |
| <div> | |
| <span class="saved-pill">πΌ Saved Media: <strong id="savedMediaCount">0</strong></span> | |
| <span class="saved-pill">π¦ Archived Messages: <strong id="savedArchivedCount">0</strong></span> | |
| </div> | |
| <button class="secondary-btn" onclick="openMediaPreview()" style="margin-top:8px;">Open Saved Media Vault</button> | |
| <button class="secondary-btn" onclick="showArchivedMessages()" style="margin-top:8px;">Open Archive Center</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="modal hidden" id="friendsModal"> | |
| <div class="modal-content"> | |
| <h2><i class="fas fa-users"></i> Friends & Friend Requests</h2> | |
| <h3 style="margin-top: 20px; margin-bottom: 10px;">Pending Requests</h3> | |
| <div id="friendRequests" style="max-height: 22vh; overflow-y: auto;"></div> | |
| <h3 style="margin-top: 20px; margin-bottom: 10px;">Your Friends</h3> | |
| <div id="friendsList" style="max-height: 36vh; overflow-y: auto;"></div> | |
| <button class="save-btn" onclick="closeFriendsModal()" style="margin-top: 20px;">Close</button> | |
| </div> | |
| </div> | |
| <div class="modal hidden" id="shopModal"> | |
| <div class="modal-content"> | |
| <h2><i class="fas fa-store"></i> Shop</h2> | |
| <div class="coins-display" id="coinsDisplay">π° Coins: ...</div> | |
| <div id="shopList"></div> | |
| <button class="save-btn" onclick="closeShopModal()" style="margin-top: 20px;">Close</button> | |
| </div> | |
| </div> | |
| <div class="modal hidden" id="archivedChatsModal"> | |
| <div class="archived-modal-content"> | |
| <h2 style="margin-bottom:6px;"><i class="fas fa-box-archive"></i> Archived Chats</h2> | |
| <p style="color: var(--text-secondary); font-size: 13px; margin-bottom: 8px;">Open, unarchive, or delete chats in one place.</p> | |
| <div id="archivedChatsList" class="archived-modal-list"></div> | |
| <div style="display:flex; gap:10px; margin-top:10px;"> | |
| <button class="save-btn" style="background: var(--danger);" onclick="clearArchivedChats();">π Clear All</button> | |
| <button class="secondary-btn" onclick="closeArchivedChatsModal();">Close</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="toast-container" id="toastContainer"></div> | |
| <div class="picker-panel" id="pickerPanel"> | |
| <div class="picker-tabs"> | |
| <button class="picker-tab active" onclick="switchPickerTab('stickers', this)">π Stickers</button> | |
| <button class="picker-tab" onclick="switchPickerTab('gifs', this)">π¬ GIFs</button> | |
| </div> | |
| <div class="picker-size-controls"> | |
| <button class="picker-size-btn" onclick="adjustPickerSize(-0.1)" title="Smaller picker">A-</button> | |
| <input id="pickerSizeRange" class="picker-size-range" type="range" min="1" max="2" step="0.05" value="1.45" oninput="setPickerScale(this.value)"> | |
| <button class="picker-size-btn" onclick="adjustPickerSize(0.1)" title="Larger picker">A+</button> | |
| <span id="pickerSizeLabel" class="picker-size-label">145%</span> | |
| </div> | |
| <div class="picker-content" id="pickerContent"> | |
| </div> | |
| </div> | |
| <div class="voice-recorder" id="voiceRecorder"> | |
| <div class="record-timer" id="recordTimer">00:00</div> | |
| <button class="record-button" id="recordButton" onclick="toggleRecording()"> | |
| <i class="fas fa-microphone"></i> | |
| </button> | |
| <div class="voice-preview-container" id="voicePreviewContainer" style="display: none;"> | |
| <div class="voice-preview-label">π§ Preview your recording:</div> | |
| <audio id="voicePreview" controls style="width: 100%; margin-bottom: 8px;"></audio> | |
| </div> | |
| <div style="display: flex; gap: 10px; width: 100%;"> | |
| <button class="save-btn" onclick="sendVoiceMessage()" style="padding: 8px 16px; flex: 1;" disabled>Send Voice Message</button> | |
| <button class="save-btn" onclick="cancelRecording()" style="padding: 8px 16px; background: var(--danger); flex: 1;">Cancel</button> | |
| </div> | |
| </div> | |
| <div class="settings-panel" id="settingsPanel"> | |
| <div class="settings-header"> | |
| <h2>βοΈ Settings</h2> | |
| <button class="header-btn" onclick="closeSettings()"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="settings-body"> | |
| <div class="settings-nav"> | |
| <div class="settings-nav-item active" onclick="switchSettingsTab('account', this)">πͺͺ Account</div> | |
| <div class="settings-nav-item" onclick="switchSettingsTab('privacy', this)">π‘οΈ Privacy</div> | |
| <div class="settings-nav-item" onclick="switchSettingsTab('chat', this)">π¨οΈ Chat</div> | |
| <div class="settings-nav-item" onclick="switchSettingsTab('notifications', this)">π¬ Notifications</div> | |
| <div class="settings-nav-item" onclick="switchSettingsTab('appearance', this)">πͺ Appearance</div> | |
| <div class="settings-nav-item" onclick="switchSettingsTab('language', this)">π§ Language</div> | |
| <div class="settings-nav-item" onclick="switchSettingsTab('stats', this)">π Statistics</div> | |
| </div> | |
| <div class="settings-content"> | |
| <div class="settings-section active" id="accountSettings"> | |
| <h3>Account Settings</h3> | |
| <div class="settings-item"> | |
| <div class="settings-label">Email</div> | |
| <div class="settings-description">Your current email address</div> | |
| <input type="email" id="settingsEmail" class="form-group input" readonly style="background: var(--bg-color); color: var(--text-secondary);"> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Change Username</div> | |
| <div class="settings-description">Update your display name</div> | |
| <input type="text" id="settingsUsername" placeholder="New username" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); margin-bottom: 8px;"> | |
| <button class="save-btn" onclick="updateUsername()">Update Username</button> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Delete Account</div> | |
| <div class="settings-description">Permanently delete your account and all data</div> | |
| <button class="save-btn danger-hover" onclick="showToast('Feature coming soon!', 'warning')" style="background: var(--danger);">Delete Account</button> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Switch Account</div> | |
| <div class="settings-description">Quickly switch between previously signed-in accounts</div> | |
| <select id="accountSwitcher" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); margin-bottom: 8px;"></select> | |
| <button class="secondary-btn" onclick="switchAccount()">Switch Account</button> | |
| </div> | |
| </div> | |
| <div class="settings-section" id="privacySettings"> | |
| <h3>Privacy & Safety</h3> | |
| <div class="settings-item"> | |
| <div class="settings-label">Who can send you friend requests</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="allowFriendRequests"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Show online status</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="showOnlineStatus"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Read receipts</div> | |
| <div class="settings-description">Let others know when you've read their messages</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="readReceipts"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="settings-section" id="chatSettings"> | |
| <h3>Chat Settings</h3> | |
| <div class="settings-item"> | |
| <div class="settings-label">Enter to send</div> | |
| <div class="settings-description">Press Enter to send messages (Shift+Enter for new line)</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="enterToSend"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Show typing indicator</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="showTypingIndicator"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Auto-play GIFs</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="autoplayGifs"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">π€ Microphone</div> | |
| <div class="settings-description">Select audio input device for voice messages</div> | |
| <select id="microphoneSelector" onchange="saveAudioSettings()" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); margin-top: 8px;"> | |
| <option value="default">Default Microphone</option> | |
| </select> | |
| <button class="secondary-btn" onclick="refreshAudioDevices()" style="margin-top: 8px; padding: 6px 12px; font-size: 13px;">π Refresh Devices</button> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">π Speaker / Earphones</div> | |
| <div class="settings-description">Select audio output device for playback</div> | |
| <select id="speakerSelector" onchange="saveAudioSettings()" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); margin-top: 8px;"> | |
| <option value="default">Default Speaker</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="settings-section" id="notificationSettings"> | |
| <h3>Notifications</h3> | |
| <div class="settings-item"> | |
| <div class="settings-label">Desktop notifications</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" id="desktopNotifications"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Message sound</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" checked id="messageSound"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Notification settings</div> | |
| <div class="settings-description">All messages, Only mentions, Nothing</div> | |
| <select id="notificationMode" onchange="saveNotificationSettings()" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary);"> | |
| <option value="all">All messages</option> | |
| <option value="mentions">Only mentions</option> | |
| <option value="none">Nothing</option> | |
| </select> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Notify on sent messages (this device)</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" id="notifyOnSent" onchange="saveNotificationSettings()"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Notify on received messages (this device)</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" id="notifyOnReceived" checked onchange="saveNotificationSettings()"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="settings-section" id="appearanceSettings"> | |
| <h3>Appearance</h3> | |
| <div class="settings-item"> | |
| <div class="settings-label">Theme</div> | |
| <div class="settings-description">Choose your preferred theme</div> | |
| <select id="themeSelector" onchange="changeTheme(this.value)" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary);"> | |
| <option value="dark">Dark</option> | |
| <option value="light">Light</option> | |
| <option value="custom">Custom Colors</option> | |
| </select> | |
| </div> | |
| <div class="settings-item" id="customColorSection" style="display: none;"> | |
| <div class="settings-label">π¨ Customize Colors</div> | |
| <div class="settings-description">Change background, text, and icon colors</div> | |
| <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; margin-top: 10px;"> | |
| <div> | |
| <label style="display: block; margin-bottom: 4px; font-size: 13px; color: var(--text-secondary);">Background</label> | |
| <input type="color" id="bgColorPicker" value="#1e1f22" oninput="applySimpleCustomColors()" style="width: 100%; height: 40px; border: 1px solid var(--border-color); border-radius: 4px; cursor: pointer;"> | |
| </div> | |
| <div> | |
| <label style="display: block; margin-bottom: 4px; font-size: 13px; color: var(--text-secondary);">Text Color</label> | |
| <input type="color" id="textColorPicker" value="#ffffff" oninput="applySimpleCustomColors()" style="width: 100%; height: 40px; border: 1px solid var(--border-color); border-radius: 4px; cursor: pointer;"> | |
| </div> | |
| <div> | |
| <label style="display: block; margin-bottom: 4px; font-size: 13px; color: var(--text-secondary);">Icons/Accents</label> | |
| <input type="color" id="accentColorPicker" value="#5865F2" oninput="applySimpleCustomColors()" style="width: 100%; height: 40px; border: 1px solid var(--border-color); border-radius: 4px; cursor: pointer;"> | |
| </div> | |
| </div> | |
| <button class="secondary-btn" onclick="resetSimpleCustomColors()" style="margin-top: 10px; width: 100%; padding: 8px;">Reset to Default</button> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Compact mode</div> | |
| <div class="settings-description">Show more messages on screen</div> | |
| <label class="toggle-switch"> | |
| <input type="checkbox" id="compactMode"> | |
| <span class="toggle-slider"></span> | |
| </label> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Message font size</div> | |
| <select id="fontSizeSelector" onchange="saveAppearanceSettings()" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary);"> | |
| <option value="small">Small</option> | |
| <option value="medium" selected>Medium</option> | |
| <option value="large">Large</option> | |
| </select> | |
| </div> | |
| <div class="settings-item"> | |
| <div class="settings-label">Disappearing messages</div> | |
| <div class="settings-description">Auto-remove newly received/sent messages from your screen</div> | |
| <select id="disappearTime" onchange="saveChatSettings()" style="width: 100%; padding: 10px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary);"> | |
| <option value="0">Off</option> | |
| <option value="30">30 seconds</option> | |
| <option value="60">1 minute</option> | |
| <option value="300">5 minutes</option> | |
| <option value="3600">1 hour</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="settings-section" id="statsSettings"> | |
| <h3>π Your Statistics</h3> | |
| <div class="settings-item" style="padding: 20px; background: var(--bg-color); border-radius: 8px;"> | |
| <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;"> | |
| <div style="background: var(--chat-bg); padding: 16px; border-radius: 6px; text-align: center; border: 1px solid var(--border-color);"> | |
| <div style="font-size: 32px; font-weight: bold; color: var(--primary-color);" id="statMessagesCount">0</div> | |
| <div style="font-size: 13px; color: var(--text-secondary); margin-top: 8px;">Messages Sent</div> | |
| </div> | |
| <div style="background: var(--chat-bg); padding: 16px; border-radius: 6px; text-align: center; border: 1px solid var(--border-color);"> | |
| <div style="font-size: 32px; font-weight: bold; color: var(--primary-color);" id="statTotalChars">0</div> | |
| <div style="font-size: 13px; color: var(--text-secondary); margin-top: 8px;">Characters Typed</div> | |
| </div> | |
| <div style="background: var(--chat-bg); padding: 16px; border-radius: 6px; text-align: center; border: 1px solid var(--border-color);"> | |
| <div style="font-size: 32px; font-weight: bold; color: var(--primary-color);" id="statReactionsGiven">0</div> | |
| <div style="font-size: 13px; color: var(--text-secondary); margin-top: 8px;">Reactions Given</div> | |
| </div> | |
| <div style="background: var(--chat-bg); padding: 16px; border-radius: 6px; text-align: center; border: 1px solid var(--border-color);"> | |
| <div style="font-size: 32px; font-weight: bold; color: var(--primary-color);" id="statQuizCorrect">0</div> | |
| <div style="font-size: 13px; color: var(--text-secondary); margin-top: 8px;">Quiz Correct</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="settings-item"> | |
| <button class="save-btn" onclick="resetUserStats()" style="width: 100%;">Reset Statistics</button> | |
| </div> | |
| <div class="settings-item"> | |
| <button class="primary-btn" onclick="startQuiz()" style="width: 100%; padding: 12px; background: var(--primary-color); color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: bold;">π― Events & Challenges</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Language Settings --> | |
| <div class="settings-section" id="languageSettings"> | |
| <h3>π Language</h3> | |
| <div class="settings-item"> | |
| <label class="settings-label">App Language</label> | |
| <p style="font-size:13px; color:var(--text-secondary); margin:0 0 14px;">Choose your preferred language. UI text will update immediately.</p> | |
| <div style="display:flex; align-items:center; gap:10px; margin-bottom:16px; padding:10px 14px; background:var(--bg-color); border-radius:10px; border:1px solid var(--border-color);"> | |
| <span style="font-size:20px;">π</span> | |
| <span style="font-size:14px; font-weight:600;">Current:</span> | |
| <span id="currentLangDisplay" style="font-size:14px; font-weight:700; color:var(--primary-color);">πΊπΈ English</span> | |
| </div> | |
| <div class="lang-grid" id="langGrid"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="modal hidden" id="communitiesModal"> | |
| <div class="modal-content" style="max-width:min(96vw, 760px); width:min(96vw, 760px); max-height:86vh; overflow-y:auto;"> | |
| <h2><i class="fas fa-globe"></i> Communities</h2> | |
| <p style="margin-top: 10px; color: var(--text-secondary);">Join public communities to discover people with shared interests.</p> | |
| <input class="groups-search" placeholder="π Search communities..." oninput="filterCommunitiesList(this.value)"> | |
| <div id="communitiesList" style="margin-top: 6px;"></div> | |
| <button class="save-btn" onclick="closeCommunitiesModal()" style="margin-top: 20px;">Close</button> | |
| </div> | |
| </div> | |
| <div class="modal hidden" id="groupsModal"> | |
| <div class="modal-content" style="max-width:min(96vw, 760px); width:min(96vw, 760px); max-height:86vh; overflow-y:auto;"> | |
| <h2><i class="fas fa-user-group"></i> Groups</h2> | |
| <p style="margin-top: 10px; color: var(--text-secondary);">Create and manage your own small group chats.</p> | |
| <button class="create-group-btn" onclick="createNewGroup(); closeGroupsModal();" style="margin-top:14px;">β Create New Group</button> | |
| <input class="groups-search" placeholder="π Search groups..." oninput="filterGroupsList(this.value)"> | |
| <div id="groupsList" style="margin-top: 4px;"></div> | |
| <button class="save-btn" onclick="closeGroupsModal()" style="margin-top: 20px;">Close</button> | |
| </div> | |
| </div> | |
| <div class="community-modal" id="communityDetailsModal"> | |
| <div class="community-modal-content"> | |
| <div class="community-modal-header"> | |
| <h3 id="communityDetailsTitle">Community</h3> | |
| <button class="header-btn" onclick="closeCommunityDetails()"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="community-modal-body" id="communityDetailsBody"></div> | |
| </div> | |
| </div> | |
| <div class="qr-modal" id="qrModal"> | |
| <div class="qr-modal-content"> | |
| <h2 class="qr-modal-title">π± Friend Request QR Code</h2> | |
| <p class="qr-modal-subtitle">Let your friends scan this code to send you a friend request!</p> | |
| <div class="qr-code-container"> | |
| <canvas id="qrCodeCanvas" width="200" height="200"></canvas> | |
| </div> | |
| <p style="font-size: 13px; color: var(--text-secondary); margin-bottom: 16px;">Your ID: <strong id="qrUserId" style="color: var(--primary-color);"></strong></p> | |
| <button class="qr-modal-close" onclick="closeQRCodeModal()">Close</button> | |
| </div> | |
| </div> | |
| <div class="media-preview-panel" id="mediaPreviewPanel"> | |
| <div class="media-preview-header"> | |
| <h3 class="media-preview-title">πΈ Copied Media</h3> | |
| <button class="media-preview-close" onclick="closeMediaPreview()"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="media-preview-content" id="mediaPreviewContent"> | |
| </div> | |
| </div> | |
| <div class="mobile-bottom-nav" id="mobileBottomNav"> | |
| <button class="mobile-nav-item active" onclick="showMobileSection('chats')" data-section="chats"> | |
| <i class="fas fa-comment"></i> | |
| <span>Chats</span> | |
| </button> | |
| <button class="mobile-nav-item" onclick="showMobileSection('communities')" data-section="communities"> | |
| <i class="fas fa-globe"></i> | |
| <span>Communities</span> | |
| </button> | |
| <button class="mobile-nav-item" onclick="showMobileSection('groups')" data-section="groups"> | |
| <i class="fas fa-user-group"></i> | |
| <span>Groups</span> | |
| </button> | |
| <button class="mobile-nav-item" onclick="showMobileSection('friends')" data-section="friends"> | |
| <i class="fas fa-users"></i> | |
| <span>Friends</span> | |
| </button> | |
| <button class="mobile-nav-item" onclick="showMobileSection('settings')" data-section="settings"> | |
| <i class="fas fa-cog"></i> | |
| <span>Settings</span> | |
| </button> | |
| </div> | |
| <div class="sidebar-overlay" id="sidebarOverlay" onclick="closeMobileSidebar()"></div> | |
| <div class="mobile-members-panel" id="mobileMembersPanel"> | |
| <div class="mobile-members-header"> | |
| <h3>π₯ Online Members</h3> | |
| <button class="header-btn" onclick="toggleMobileMembers()" style="font-size: 20px;"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="mobile-members-list" id="mobileMembersList"> | |
| </div> | |
| </div> | |
| <div id="customDialog" style="display: none;"></div> | |
| <div id="callOverlay"> | |
| <div class="call-overlay-stage"> | |
| <div id="hostedCallContainer"></div> | |
| <video id="remoteCallVideo" autoplay playsinline style="position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:0;"></video> | |
| <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> | |
| <div class="call-overlay-header"> | |
| <div> | |
| <div id="callOverlayPeerName" style="color:#fff; font-size:18px; font-weight:700;"></div> | |
| <div id="callTimerLabel" style="color:rgba(255,255,255,0.7); font-size:13px; margin-top:4px;">00:00:00</div> | |
| <div id="callStatusLabel" style="color:#8fffc2; font-size:12px; margin-top:4px;">Preparing call...</div> | |
| </div> | |
| <button id="callDebugBtn" 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> | |
| </div> | |
| <div id="callDebugPanel"></div> | |
| <div class="call-overlay-controls"> | |
| <button id="muteBtn" class="call-ctrl-btn" title="Mute/Unmute">π€</button> | |
| <button id="cameraBtn" class="call-ctrl-btn" title="Camera on/off">π·</button> | |
| <button id="endCallBtn" class="call-end-btn" title="End Call">π΅</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="notifPanel"> | |
| <div class="notif-panel-header"> | |
| <span style="font-weight:700; font-size:16px;">π Notifications</span> | |
| <div style="display:flex; gap:8px; align-items:center;"> | |
| <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> | |
| <button onclick="closeNotifPanel()" style="background:none; border:none; color:var(--text-secondary); font-size:20px; cursor:pointer; line-height:1;">Γ</button> | |
| </div> | |
| </div> | |
| <div id="notifList" style="flex:1;"> | |
| <div style="padding:30px; text-align:center; color:var(--text-secondary);">No notifications yet</div> | |
| </div> | |
| </div> | |
| <script src="/socket.io/socket.io.js"></script> | |
| <script src="https://meet.jit.si/external_api.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/twemoji@14.0.2/dist/twemoji.min.js" crossorigin="anonymous"></script> | |
| <script src="client.js?v=3.2.8"></script> | |
| </body> | |
| </html> | |