diff --git a/desktop/index.html b/desktop/index.html
index fac5aa8..cb1de11 100644
--- a/desktop/index.html
+++ b/desktop/index.html
@@ -1,3 +1,4 @@
+
@@ -8,7 +9,7 @@
-
+
@@ -116,8 +117,7 @@
-
+
diff --git a/desktop/styles.css b/desktop/styles.css
deleted file mode 100644
index fda1104..0000000
--- a/desktop/styles.css
+++ /dev/null
@@ -1,1629 +0,0 @@
-:root {
- /* ── Backgrounds ─────────────────────────────────────────── */
- --bg-darker: #16171b;
- --bg-sidebar: #1e2025;
- --bg-main: #23252b;
- --bg-secondary: #1a1c21;
- --bg-tertiary: #111216;
- --bg-modifier-selected: rgba(99, 102, 241, 0.15);
- --bg-modifier-hover: rgba(255, 255, 255, 0.04);
- --bg-input: #2a2d35;
-
- /* ── Text ────────────────────────────────────────────────── */
- --text-normal: #c9cdd4;
- --text-muted: #7c818a;
- --text-strong: #eef0f4;
- --text-link: #818cf8;
-
- /* ── Accents ─────────────────────────────────────────────── */
- --brand: #6366f1;
- --brand-hover: #4f46e5;
- --brand-gradient: linear-gradient(135deg, #6366f1, #a855f7);
- --brand-glow: rgba(99, 102, 241, 0.35);
- --green: #22c55e;
- --danger: #ef4444;
- --yellow: #f59e0b;
-
- /* ── Misc ────────────────────────────────────────────────── */
- --font-main: "Inter", "Noto Sans", "Helvetica Neue", Helvetica, Arial,
- sans-serif;
- --radius-sm: 6px;
- --radius-md: 10px;
- --radius-lg: 14px;
- --radius-xl: 20px;
- --transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Reset & Base */
-/* ═══════════════════════════════════════════════════════════ */
-* {
- box-sizing: border-box;
-}
-
-body {
- margin: 0;
- height: 100vh;
- height: 100dvh;
- background: var(--bg-darker);
- color: var(--text-normal);
- font-family: var(--font-main);
- overflow: hidden;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-/* ── Scrollbars ────────────────────────────────────────────── */
-::-webkit-scrollbar {
- width: 6px;
- height: 6px;
-}
-
-::-webkit-scrollbar-track {
- background: transparent;
-}
-
-::-webkit-scrollbar-thumb {
- background: rgba(255, 255, 255, 0.08);
- border-radius: 100px;
-}
-
-::-webkit-scrollbar-thumb:hover {
- background: rgba(255, 255, 255, 0.14);
-}
-
-/* ── Base Elements ─────────────────────────────────────────── */
-button {
- border: 0;
- cursor: pointer;
- transition: all var(--transition);
- background: none;
- color: inherit;
- font: inherit;
- padding: 0;
-}
-
-input,
-select {
- border: 0;
- outline: none;
- background: var(--bg-input);
- color: var(--text-normal);
- font: inherit;
-}
-
-.hidden {
- display: none !important;
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Auth Screen */
-/* ═══════════════════════════════════════════════════════════ */
-.auth-screen {
- display: grid;
- place-items: center;
- height: 100vh;
- /* Subtle animated gradient background */
- background: linear-gradient(135deg, #0f0c29, #16171b 40%, #1a1c2e 70%, #0f0c29);
- background-size: 400% 400%;
- animation: gradientShift 12s ease infinite;
-}
-
-@keyframes gradientShift {
-
- 0%,
- 100% {
- background-position: 0% 50%;
- }
-
- 50% {
- background-position: 100% 50%;
- }
-}
-
-.auth-card {
- width: min(440px, 92vw);
- background: rgba(30, 32, 37, 0.75);
- backdrop-filter: blur(24px) saturate(1.4);
- -webkit-backdrop-filter: blur(24px) saturate(1.4);
- border: 1px solid rgba(255, 255, 255, 0.06);
- border-radius: var(--radius-xl);
- padding: 40px 36px;
- box-shadow: 0 8px 40px rgba(0, 0, 0, 0.5), 0 0 80px rgba(99, 102, 241, 0.08);
- text-align: center;
-}
-
-.brand-large {
- width: 80px;
- height: 80px;
- background: var(--brand-gradient);
- color: #fff;
- border-radius: 22px;
- display: grid;
- place-items: center;
- font-size: 38px;
- font-weight: 800;
- margin: 0 auto 24px;
- box-shadow: 0 4px 24px var(--brand-glow);
- transition: transform var(--transition), box-shadow var(--transition);
-}
-
-.brand-large:hover {
- transform: scale(1.05);
- box-shadow: 0 6px 32px var(--brand-glow);
-}
-
-.auth-card h1 {
- margin: 0 0 8px;
- color: var(--text-strong);
- font-weight: 800;
- font-size: 28px;
- letter-spacing: -0.5px;
-}
-
-.auth-card p {
- margin: 0 0 28px;
- color: var(--text-muted);
- font-size: 15px;
-}
-
-#login-btn {
- width: 100%;
- background: var(--brand-gradient);
- color: #fff;
- padding: 14px;
- border-radius: var(--radius-md);
- font-weight: 600;
- font-size: 16px;
- letter-spacing: 0.2px;
- box-shadow: 0 2px 16px var(--brand-glow);
- transition: all var(--transition);
-}
-
-#login-btn:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 24px var(--brand-glow);
- filter: brightness(1.08);
-}
-
-#login-btn:active {
- transform: translateY(0);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Main Layout */
-/* ═══════════════════════════════════════════════════════════ */
-.shell {
- height: 100vh;
- height: 100dvh;
- display: grid;
- grid-template-columns: 72px 248px 1fr 248px;
- background: var(--bg-main);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Server Rail */
-/* ═══════════════════════════════════════════════════════════ */
-.server-rail {
- background: var(--bg-darker);
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 12px 0;
- gap: 8px;
- overflow-y: auto;
- scrollbar-width: none;
-}
-
-.server-rail::-webkit-scrollbar {
- display: none;
-}
-
-.guild-list {
- display: flex;
- flex-direction: column;
- gap: 8px;
- padding: 6px 0;
-}
-
-.brand,
-.guild-pill {
- width: 48px;
- height: 48px;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all var(--transition);
- position: relative;
- background: var(--bg-sidebar);
-}
-
-.brand {
- background: var(--brand-gradient);
- color: #fff;
- border-radius: 16px;
- margin-bottom: 2px;
- box-shadow: 0 2px 12px var(--brand-glow);
-}
-
-.brand:hover {
- border-radius: 16px;
- box-shadow: 0 4px 20px var(--brand-glow);
-}
-
-.separator {
- width: 32px;
- height: 2px;
- background: rgba(255, 255, 255, 0.06);
- margin-bottom: 2px;
- border-radius: 1px;
-}
-
-.guild-pill:hover,
-.guild-pill.active {
- border-radius: 16px;
- background: var(--brand);
- color: #fff;
- box-shadow: 0 2px 12px var(--brand-glow);
-}
-
-.guild-pill::before {
- content: "";
- position: absolute;
- left: -12px;
- width: 4px;
- height: 0;
- background: #fff;
- border-radius: 0 4px 4px 0;
- transition: all var(--transition);
-}
-
-.guild-pill:hover::before {
- height: 20px;
-}
-
-.guild-pill.active::before {
- height: 40px;
-}
-
-.action-pill {
- color: var(--green);
-}
-
-.action-pill:hover {
- background: var(--green);
- color: #fff;
- box-shadow: 0 2px 12px rgba(34, 197, 94, 0.3);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Channel Sidebar */
-/* ═══════════════════════════════════════════════════════════ */
-.channel-sidebar {
- background: var(--bg-sidebar);
- display: flex;
- flex-direction: column;
-}
-
-.sidebar-header {
- padding: 0 16px;
- height: 48px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- border-bottom: 1px solid rgba(255, 255, 255, 0.04);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
- cursor: pointer;
- transition: background-color var(--transition);
-}
-
-.sidebar-header:hover {
- background: var(--bg-modifier-hover);
-}
-
-.sidebar-header h2 {
- margin: 0;
- font-size: 15px;
- font-weight: 700;
- color: var(--text-strong);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- letter-spacing: -0.2px;
-}
-
-.sidebar-header-actions {
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.header-action-btn {
- width: 28px;
- height: 28px;
- border-radius: var(--radius-sm);
- display: grid;
- place-items: center;
- color: var(--text-muted);
- transition: all var(--transition);
-}
-
-.header-action-btn:hover {
- background: var(--bg-modifier-hover);
- color: var(--text-strong);
-}
-
-.copied-badge {
- background: var(--brand);
- color: #fff;
- font-size: 11px;
- font-weight: 700;
- padding: 2px 6px;
- border-radius: 4px;
- text-transform: uppercase;
- letter-spacing: 0.4px;
- animation: fadeInOut 2s ease forwards;
- pointer-events: none;
- white-space: nowrap;
- order: -1;
- margin-right: 4px;
-}
-
-@keyframes fadeInOut {
- 0% {
- opacity: 0;
- transform: translateY(4px);
- }
-
- 15% {
- opacity: 1;
- transform: translateY(0);
- }
-
- 85% {
- opacity: 1;
- transform: translateY(0);
- }
-
- 100% {
- opacity: 0;
- transform: translateY(-4px);
- }
-}
-
-.header-action-btn i {
- width: 16px;
- height: 16px;
-}
-
-.sidebar-scroll {
- flex: 1;
- overflow-y: auto;
- padding-top: 12px;
-}
-
-.sidebar-group {
- margin-bottom: 20px;
-}
-
-.group-title {
- padding: 0 8px 0 2px;
- display: flex;
- align-items: center;
- color: var(--text-muted);
- font-size: 11px;
- font-weight: 700;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: color var(--transition);
-}
-
-.group-title:hover {
- color: var(--text-normal);
-}
-
-.group-toggle {
- width: 12px;
- height: 12px;
- margin-right: 2px;
-}
-
-.group-title span {
- flex: 1;
-}
-
-.add-btn {
- width: 20px;
- height: 20px;
- border-radius: var(--radius-sm);
- opacity: 0.5;
- transition: opacity var(--transition), background-color var(--transition),
- transform var(--transition);
- display: grid;
- place-items: center;
-}
-
-.add-btn:hover {
- opacity: 1;
- background: var(--bg-modifier-hover);
- transform: scale(1.1);
-}
-
-.add-btn i {
- width: 16px;
- height: 16px;
-}
-
-.channel-list {
- padding: 0 8px;
- display: flex;
- flex-direction: column;
- gap: 2px;
-}
-
-.channel-row {
- display: flex;
- align-items: center;
- padding: 7px 10px;
- border-radius: var(--radius-sm);
- color: var(--text-muted);
- font-weight: 500;
- gap: 8px;
- transition: all var(--transition);
- border-left: 3px solid transparent;
-}
-
-.channel-row:hover {
- background: var(--bg-modifier-hover);
- color: var(--text-normal);
-}
-
-.channel-row.active {
- background: var(--bg-modifier-selected);
- color: var(--text-strong);
- border-left-color: var(--brand);
-}
-
-.channel-row i {
- width: 20px;
- height: 20px;
- opacity: 0.5;
-}
-
-.channel-row.active i {
- opacity: 0.9;
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Sidebar Footer */
-/* ═══════════════════════════════════════════════════════════ */
-.sidebar-footer {
- background: var(--bg-secondary);
- padding: 0;
-}
-
-.user-panel {
- padding: 8px 10px;
- display: flex;
- align-items: center;
- gap: 10px;
- height: 52px;
- transition: background-color var(--transition);
- border-radius: var(--radius-sm);
- margin: 2px;
-}
-
-.user-panel:hover {
- background: var(--bg-modifier-hover);
-}
-
-.avatar-wrapper {
- position: relative;
-}
-
-.avatar {
- width: 32px;
- height: 32px;
- border-radius: 50%;
- background: var(--brand-gradient);
- color: #fff;
- display: grid;
- place-items: center;
- font-weight: 700;
- font-size: 13px;
-}
-
-.status-dot {
- position: absolute;
- bottom: -2px;
- right: -2px;
- width: 14px;
- height: 14px;
- border-radius: 50%;
- border: 3px solid var(--bg-secondary);
-}
-
-.status-dot.online {
- background: var(--green);
- box-shadow: 0 0 6px rgba(34, 197, 94, 0.4);
-}
-
-.status-dot.idle {
- background: var(--yellow);
- box-shadow: 0 0 6px rgba(245, 158, 11, 0.4);
-}
-
-.voice-muted-icon {
- width: 14px;
- height: 14px;
- color: var(--danger);
- margin-left: 6px;
- vertical-align: text-bottom;
-}
-
-.user-volume-control {
- width: 100%;
- display: none;
- /* Hidden by default */
- align-items: center;
- gap: 8px;
- padding: 4px 8px 4px 28px;
- margin-top: 2px;
- box-sizing: border-box;
- background: rgba(0, 0, 0, 0.2);
- border-radius: 4px;
- overflow: hidden;
-}
-
-.user-volume-control.show-volume {
- display: flex;
- /* Show when active */
-}
-
-.volume-slider {
- -webkit-appearance: none;
- appearance: none;
- background: var(--bg-darker);
- border-radius: 2px;
- outline: none;
- flex: 1;
- height: 4px;
- cursor: pointer;
- min-width: 0;
-}
-
-.vol-pct {
- font-size: 10px;
- opacity: 0.6;
- min-width: 30px;
- text-align: right;
-}
-
-.volume-slider::-webkit-slider-thumb {
- -webkit-appearance: none;
- appearance: none;
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background: var(--brand);
- cursor: pointer;
- box-shadow: 0 0 4px var(--brand-glow);
-}
-
-.volume-slider::-moz-range-thumb {
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background: var(--brand);
- cursor: pointer;
- box-shadow: 0 0 4px var(--brand-glow);
-}
-
-.update-notifier {
- display: flex;
- align-items: center;
- margin-right: 8px;
-}
-
-.update-notifier button {
- background: none;
- border: none;
- padding: 4px;
- color: var(--brand);
- cursor: pointer;
- transition: transform 0.2s;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.update-notifier button:hover {
- transform: scale(1.2);
- color: var(--brand-glow);
-}
-
-.update-notifier button i {
- width: 16px;
- height: 16px;
-}
-
-
-.user-info {
- flex: 1;
- min-width: 0;
-}
-
-.display-name {
- font-size: 14px;
- font-weight: 600;
- color: var(--text-strong);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.user-status {
- font-size: 12px;
- color: var(--text-muted);
-}
-
-.user-actions {
- display: flex;
- gap: 2px;
-}
-
-.user-actions button {
- width: 32px;
- height: 32px;
- border-radius: var(--radius-sm);
- display: grid;
- place-items: center;
- color: var(--text-muted);
- transition: all var(--transition);
-}
-
-.user-actions button:hover {
- background: var(--bg-modifier-hover);
- color: var(--text-strong);
-}
-
-.user-actions i {
- width: 20px;
- height: 20px;
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Voice Connection */
-/* ═══════════════════════════════════════════════════════════ */
-.voice-connection {
- padding: 10px 12px;
- background: var(--bg-secondary);
- border-bottom: 1px solid rgba(255, 255, 255, 0.03);
-}
-
-.vc-info {
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.vc-icon {
- color: var(--green);
- width: 20px;
- filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.4));
-}
-
-.vc-text {
- flex: 1;
- display: flex;
- flex-direction: column;
-}
-
-.vc-status {
- color: var(--green);
- font-size: 14px;
- font-weight: 700;
-}
-
-.vc-name {
- color: var(--text-muted);
- font-size: 12px;
-}
-
-.vc-actions {
- display: flex;
- gap: 4px;
-}
-
-.vc-actions button {
- width: 32px;
- height: 32px;
- border-radius: var(--radius-sm);
- color: var(--text-muted);
- display: grid;
- place-items: center;
- transition: all var(--transition);
-}
-
-.vc-actions button:hover {
- background: var(--bg-modifier-hover);
- color: var(--text-strong);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Video Grid */
-/* ═══════════════════════════════════════════════════════════ */
-.video-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
- gap: 16px;
- padding: 16px;
- background: var(--bg-tertiary);
- flex: 1;
- min-height: 0;
- overflow-y: auto;
-}
-
-.video-grid.hidden {
- display: none;
-}
-
-.video-item {
- position: relative;
- aspect-ratio: 16 / 9;
- background: #000;
- border-radius: var(--radius-lg);
- overflow: hidden;
- transition: all var(--transition);
- cursor: pointer;
- z-index: 1;
-}
-
-.video-item:hover {
- box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);
- z-index: 2;
-}
-
-.video-item video {
- width: 100%;
- height: 100%;
- object-fit: contain;
- background: #000;
- pointer-events: none;
-}
-
-/* Fullscreen Feed Support */
-.video-grid.has-fullscreen {
- display: flex;
- padding: 0;
- overflow: hidden;
- position: absolute;
- top: 48px;
- /* Below chat-header */
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 100;
- background: var(--bg-main);
-}
-
-.video-grid.has-fullscreen .video-item {
- display: none;
-}
-
-.video-grid.has-fullscreen .video-item.fullscreen {
- display: block;
- flex: 1;
- width: 100%;
- height: 100%;
- border-radius: 0;
- cursor: zoom-out;
- z-index: 10;
- aspect-ratio: auto;
-}
-
-.video-item .video-label {
- position: absolute;
- bottom: 8px;
- left: 8px;
- background: rgba(0, 0, 0, 0.6);
- backdrop-filter: blur(8px);
- color: #fff;
- padding: 3px 10px;
- border-radius: 100px;
- font-size: 12px;
- font-weight: 500;
- pointer-events: none;
- z-index: 5;
-}
-
-/* Voice Activity */
-.voice-speaking .avatar {
- box-shadow: 0 0 0 2px var(--green), 0 0 8px rgba(34, 197, 94, 0.3);
-}
-
-.video-item.speaking {
- box-shadow: 0 0 0 3px var(--green), 0 0 16px rgba(34, 197, 94, 0.25);
-}
-
-.video-item.speaking .video-label {
- background: var(--green);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Chat Input */
-/* ═══════════════════════════════════════════════════════════ */
-.chat-input-wrapper {
- padding: 0 16px 24px;
-}
-
-.message-form {
- background: var(--bg-input);
- border-radius: var(--radius-md);
- padding: 2px 12px;
- display: flex;
- align-items: center;
- gap: 12px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
-}
-
-.input-action-btn {
- color: var(--text-muted);
- width: 36px;
- height: 36px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: var(--radius-sm);
-}
-
-.input-action-btn:hover {
- color: var(--text-normal);
- background: var(--bg-modifier-hover);
-}
-
-.message-form input {
- flex: 1;
- background: none;
- border: 0;
- padding: 12px 0;
- font-size: 15px;
- color: var(--text-normal);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* GIF Picker Modal */
-/* ═══════════════════════════════════════════════════════════ */
-.gif-modal {
- width: min(500px, 95vw) !important;
- max-height: 600px;
- display: flex;
- flex-direction: column;
- padding: 0 !important;
- overflow: hidden;
-}
-
-.gif-modal .modal-header {
- padding: 16px 20px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- border-bottom: 1px solid rgba(255, 255, 255, 0.05);
-}
-
-.gif-modal .modal-header h2 {
- margin: 0;
- font-size: 18px;
-}
-
-.gif-search-wrapper {
- padding: 16px 20px;
- position: relative;
-}
-
-.gif-search-wrapper input {
- width: 100%;
- background: var(--bg-darker);
- border: 1px solid rgba(255, 255, 255, 0.1);
- border-radius: var(--radius-md);
- padding: 12px 14px 12px 40px;
- color: #fff;
- font-size: 14px;
- transition: border-color var(--transition);
-}
-
-.gif-search-wrapper input:focus {
- border-color: var(--brand);
-}
-
-.gif-search-wrapper .search-icon {
- position: absolute;
- left: 32px;
- top: 50%;
- transform: translateY(-50%);
- width: 18px;
- height: 18px;
- color: var(--text-muted);
-}
-
-.gif-results-grid {
- flex: 1;
- overflow-y: auto;
- padding: 0 20px 20px;
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- grid-auto-rows: min-content;
- gap: 8px;
- min-height: 300px;
-}
-
-.gif-item {
- border-radius: var(--radius-sm);
- overflow: hidden;
- cursor: pointer;
- background: var(--bg-sidebar);
- width: 100%;
- aspect-ratio: 16 / 9;
- transition: transform var(--transition);
-}
-
-.gif-item:hover {
- transform: scale(1.02);
- filter: brightness(1.1);
-}
-
-.gif-item img {
- width: 100%;
- height: 100%;
- object-fit: cover;
-}
-
-.gif-loading {
- grid-column: 1 / -1;
- text-align: center;
- padding: 40px;
- color: var(--text-muted);
-}
-
-/* ── GIF in messages ────────────────────────────────────────── */
-.msg-gif {
- margin-top: 8px;
- max-width: 100%;
- max-height: 300px;
- border-radius: var(--radius-md);
- overflow: hidden;
- display: block;
-}
-
-.msg-gif img {
- max-width: 100%;
- max-height: 300px;
- display: block;
- object-fit: contain;
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Sound Board */
-/* ═══════════════════════════════════════════════════════════ */
-.soundboard-container {
- padding: 12px;
- background: var(--bg-secondary);
- border-top: 1px solid rgba(255, 255, 255, 0.03);
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.soundboard-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-size: 12px;
- font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.4px;
- color: var(--text-muted);
-}
-
-.soundboard-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
- gap: 8px;
- max-height: 200px;
- overflow-y: auto;
-}
-
-.sound-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 4px;
- padding: 10px 8px;
- background: var(--bg-darker);
- border-radius: var(--radius-md);
- cursor: pointer;
- transition: all var(--transition);
- border: 1px solid transparent;
- position: relative;
-}
-
-.sound-item:hover {
- background: var(--bg-modifier-hover);
- transform: translateY(-2px);
- border-color: rgba(255, 255, 255, 0.06);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
-}
-
-.sound-item:active {
- transform: scale(0.95);
-}
-
-.sound-delete {
- position: absolute;
- top: 4px;
- right: 4px;
- width: 18px;
- height: 18px;
- border-radius: 50%;
- background: rgba(0, 0, 0, 0.6);
- color: var(--text-muted);
- display: grid;
- place-items: center;
- opacity: 0;
- transition: all var(--transition);
- z-index: 2;
-}
-
-.sound-delete:hover {
- background: var(--danger);
- color: #fff;
- transform: scale(1.1);
-}
-
-.sound-item:hover .sound-delete {
- opacity: 1;
-}
-
-.sound-icon {
- font-size: 24px;
- display: block;
- object-fit: contain;
-}
-
-.sound-name {
- font-size: 11px;
- text-align: center;
- color: var(--text-normal);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- width: 100%;
-}
-
-.btn-add-sound {
- font-size: 12px;
- color: var(--brand);
- cursor: pointer;
- transition: color var(--transition);
-}
-
-.btn-add-sound:hover {
- color: var(--text-link);
- text-decoration: underline;
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Chat Pane */
-/* ═══════════════════════════════════════════════════════════ */
-.chat-pane {
- position: relative;
- display: flex;
- flex-direction: column;
- background: var(--bg-main);
- min-width: 0;
- min-height: 0;
-}
-
-.chat-header {
- height: 48px;
- padding: 0 16px;
- display: flex;
- align-items: center;
- gap: 8px;
- border-bottom: 1px solid rgba(255, 255, 255, 0.04);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
-}
-
-.header-icon {
- color: var(--text-muted);
- width: 24px;
-}
-
-.chat-header h3 {
- margin: 0;
- font-size: 16px;
- font-weight: 700;
- color: var(--text-strong);
- letter-spacing: -0.2px;
-}
-
-.message-list {
- flex: 1;
- overflow-y: scroll;
- padding: 16px 0;
-}
-
-.msg {
- padding: 4px 16px;
- display: flex;
- gap: 16px;
- margin-top: 1.0625rem;
- border-radius: var(--radius-sm);
- transition: background-color var(--transition);
- border-left: 3px solid transparent;
-}
-
-.msg:hover {
- background: rgba(255, 255, 255, 0.015);
- border-left-color: rgba(99, 102, 241, 0.3);
-}
-
-.msg-avatar {
- width: 40px;
- height: 40px;
- border-radius: 50%;
- background: var(--brand-gradient);
- flex-shrink: 0;
- display: grid;
- place-items: center;
- color: #fff;
- font-weight: 600;
- font-size: 15px;
-}
-
-.msg-content {
- flex: 1;
- min-width: 0;
-}
-
-.msg-header {
- display: flex;
- align-items: baseline;
- gap: 8px;
- margin-bottom: 4px;
-}
-
-.msg-author {
- font-weight: 600;
- color: var(--text-strong);
- cursor: pointer;
- font-size: 1rem;
- transition: color var(--transition);
-}
-
-.msg-author:hover {
- color: var(--text-link);
- text-decoration: underline;
-}
-
-.msg-time {
- font-size: 11px;
- color: var(--text-muted);
-}
-
-.msg-body {
- color: var(--text-normal);
- line-height: 1.45rem;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-.msg-grouped {
- margin-top: 0;
- padding-top: 0;
- padding-bottom: 0;
-}
-
-.msg-grouped .msg-avatar,
-.msg-grouped .msg-header {
- display: none;
-}
-
-.msg-grouped .msg-content {
- padding-left: 56px;
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Chat Input */
-/* ═══════════════════════════════════════════════════════════ */
-.chat-input-wrapper {
- padding: 0 16px 24px;
- padding-bottom: clamp(24px, calc(24px + env(safe-area-inset-bottom)), 40px);
-}
-
-.message-form {
- background: var(--bg-input);
- border-radius: var(--radius-lg);
- padding: 12px 18px;
- border: 1px solid rgba(255, 255, 255, 0.04);
- transition: border-color var(--transition), box-shadow var(--transition);
-}
-
-.message-form:focus-within {
- border-color: rgba(99, 102, 241, 0.4);
- box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
-}
-
-.message-form input {
- width: 100%;
- background: transparent;
- color: var(--text-normal);
- font-size: 15px;
-}
-
-.message-form input::placeholder {
- color: var(--text-muted);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Member List / Utility Sidebar */
-/* ═══════════════════════════════════════════════════════════ */
-.utility-sidebar {
- background: var(--bg-sidebar);
- display: flex;
- flex-direction: column;
-}
-
-.member-list-wrapper {
- flex: 1;
- overflow-y: auto;
- padding: 12px 8px;
-}
-
-.member-row {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 7px 10px;
- border-radius: var(--radius-sm);
- color: var(--text-muted);
- cursor: pointer;
- transition: all var(--transition);
-}
-
-.member-row:hover {
- background: var(--bg-modifier-hover);
- color: var(--text-normal);
-}
-
-.member-avatar {
- width: 32px;
- height: 32px;
- border-radius: 50%;
- background: var(--brand-gradient);
- color: #fff;
- display: grid;
- place-items: center;
- font-size: 13px;
- font-weight: 600;
- flex-shrink: 0;
-}
-
-.member-name {
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-/* ── Presence Badges ───────────────────────────────────────── */
-.avatar-wrapper {
- position: relative;
- display: inline-block;
-}
-
-.status-badge {
- position: absolute;
- bottom: -2px;
- right: -2px;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- border: 2px solid var(--bg-sidebar);
- background: #747f8d;
-}
-
-.status-badge.online {
- background: var(--green);
- box-shadow: 0 0 6px rgba(34, 197, 94, 0.4);
-}
-
-.member-avatar,
-.msg-avatar {
- position: relative;
-}
-
-.status-dot {
- position: absolute;
- bottom: 0;
- right: 0;
- width: 10px;
- height: 10px;
- border-radius: 50%;
- border: 2px solid var(--bg-sidebar);
- background: #747f8d;
-}
-
-.status-dot.online {
- background: var(--green);
- box-shadow: 0 0 6px rgba(34, 197, 94, 0.4);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Modals */
-/* ═══════════════════════════════════════════════════════════ */
-.modal-container {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.7);
- backdrop-filter: blur(6px);
- -webkit-backdrop-filter: blur(6px);
- display: grid;
- place-items: center;
- z-index: 1000;
-}
-
-.modal {
- background: rgba(30, 32, 37, 0.92);
- backdrop-filter: blur(20px) saturate(1.4);
- -webkit-backdrop-filter: blur(20px) saturate(1.4);
- border: 1px solid rgba(255, 255, 255, 0.06);
- width: min(460px, 95vw);
- border-radius: var(--radius-xl);
- padding: 28px;
- color: var(--text-normal);
- box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
-}
-
-.modal h2 {
- margin: 0 0 20px;
- text-align: center;
- color: var(--text-strong);
- font-weight: 700;
- font-size: 22px;
- letter-spacing: -0.3px;
-}
-
-.form-item {
- margin-bottom: 20px;
-}
-
-.form-item label {
- display: block;
- font-size: 11px;
- font-weight: 700;
- color: var(--text-muted);
- margin-bottom: 8px;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.form-item input {
- width: 100%;
- padding: 11px 14px;
- border-radius: var(--radius-md);
- background: var(--bg-darker);
- border: 1px solid rgba(255, 255, 255, 0.04);
- transition: border-color var(--transition), box-shadow var(--transition);
-}
-
-.form-item input:focus {
- border-color: rgba(99, 102, 241, 0.4);
- box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
-}
-
-.modal-footer {
- margin-top: 24px;
- display: flex;
- justify-content: flex-end;
- gap: 12px;
-}
-
-.cancel-btn {
- padding: 10px 20px;
- color: var(--text-muted);
- font-weight: 500;
- border-radius: var(--radius-md);
- transition: all var(--transition);
-}
-
-.cancel-btn:hover {
- color: var(--text-strong);
- background: var(--bg-modifier-hover);
-}
-
-.submit-btn {
- background: var(--brand-gradient);
- color: #fff;
- padding: 10px 24px;
- border-radius: var(--radius-md);
- font-weight: 600;
- box-shadow: 0 2px 12px var(--brand-glow);
- transition: all var(--transition);
-}
-
-.submit-btn:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 20px var(--brand-glow);
- filter: brightness(1.06);
-}
-
-.submit-btn:active {
- transform: translateY(0);
-}
-
-/* ── Radio Group (Channel Type) ────────────────────────────── */
-.radio-group {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.radio-item {
- cursor: pointer;
- position: relative;
-}
-
-.radio-item input {
- position: absolute;
- opacity: 0;
-}
-
-.radio-box {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px;
- background: var(--bg-modifier-hover);
- border-radius: var(--radius-md);
- border: 1px solid transparent;
- transition: all var(--transition);
-}
-
-.radio-item input:checked+.radio-box {
- background: var(--bg-modifier-selected);
- border-color: rgba(99, 102, 241, 0.3);
- color: var(--text-strong);
-}
-
-.radio-box i {
- width: 24px;
- height: 24px;
- color: var(--text-muted);
-}
-
-.radio-text {
- display: flex;
- flex-direction: column;
-}
-
-.radio-text strong {
- font-size: 16px;
-}
-
-.radio-text span {
- font-size: 12px;
- color: var(--text-muted);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Mobile Overlay */
-/* ═══════════════════════════════════════════════════════════ */
-.overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.7);
- z-index: 90;
- opacity: 1;
- transition: opacity 0.2s ease;
-}
-
-.overlay.hidden {
- opacity: 0;
- pointer-events: none;
- visibility: hidden;
-}
-
-/* ── Mobile Toggle Buttons ─────────────────────────────────── */
-.mobile-toggle-btn {
- display: none;
- width: 32px;
- height: 32px;
- align-items: center;
- justify-content: center;
- color: var(--text-normal);
- background: transparent;
- margin-right: 8px;
-}
-
-.mobile-toggle-btn:hover {
- background: var(--bg-modifier-hover);
- border-radius: var(--radius-sm);
-}
-
-/* ═══════════════════════════════════════════════════════════ */
-/* Responsive */
-/* ═══════════════════════════════════════════════════════════ */
-@media (max-width: 1100px) {
- .shell {
- grid-template-columns: 72px 248px 1fr;
- }
-
- .utility-sidebar {
- position: fixed;
- top: 0;
- bottom: 0;
- right: 0;
- width: 248px;
- z-index: 100;
- box-shadow: -2px 0 20px rgba(0, 0, 0, 0.5);
- transform: translateX(100%);
- transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
- }
-
- .utility-sidebar.active {
- transform: translateX(0);
- display: flex;
- }
-
- .chat-header .mobile-toggle-btn {
- display: flex;
- }
-}
-
-@media (max-width: 768px) {
- .shell {
- grid-template-columns: 1fr;
- }
-
- .server-rail,
- .channel-sidebar {
- position: fixed;
- top: 0;
- bottom: 0;
- z-index: 100;
- transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
- }
-
- .server-rail {
- left: 0;
- width: 72px;
- transform: translateX(-100%);
- }
-
- .channel-sidebar {
- left: 72px;
- width: 248px;
- transform: translateX(-320px);
- box-shadow: 2px 0 20px rgba(0, 0, 0, 0.5);
- }
-
- .shell.menu-open .server-rail {
- transform: translateX(0);
- }
-
- .shell.menu-open .channel-sidebar {
- transform: translateX(0);
- display: flex;
- }
-
- .chat-header {
- padding: 0 8px;
- }
-}
\ No newline at end of file
diff --git a/package.json b/package.json
index 6967283..f5c75b8 100644
--- a/package.json
+++ b/package.json
@@ -10,11 +10,12 @@
},
"main": "main.js",
"scripts": {
- "start": "electron .",
- "dev": "electron .",
- "dist": "electron-builder --publish never",
- "dist:linux": "electron-builder --linux --publish never",
- "dist:win": "electron-builder --win --publish never"
+ "build:html": "node scripts/generate-html.js",
+ "start": "npm run build:html && electron .",
+ "dev": "npm run build:html && electron .",
+ "dist": "npm run build:html && electron-builder --publish never",
+ "dist:linux": "npm run build:html && electron-builder --linux --publish never",
+ "dist:win": "npm run build:html && electron-builder --win --publish never"
},
"build": {
"appId": "me.flegr.chattz",
diff --git a/scripts/generate-html.js b/scripts/generate-html.js
new file mode 100644
index 0000000..1b3497b
--- /dev/null
+++ b/scripts/generate-html.js
@@ -0,0 +1,53 @@
+const fs = require('fs');
+const path = require('path');
+
+const root = path.resolve(__dirname, '..');
+const templatePath = path.join(root, 'shared-html', 'index.template.html');
+const template = fs.readFileSync(templatePath, 'utf8');
+
+const variants = {
+ web: {
+ styles_href: '/static/styles.css',
+ app_src: '/static/app.js?v=20260227-shared-core-1',
+ web_downloads: `
`,
+ desktop_updater: '',
+ outPath: path.join(root, 'static', 'index.html'),
+ },
+ desktop: {
+ styles_href: '../static/styles.css',
+ app_src: 'app.js?v=20260227-shared-core-1',
+ web_downloads: '',
+ desktop_updater: `
+
+
+
`,
+ outPath: path.join(root, 'desktop', 'index.html'),
+ },
+};
+
+for (const variant of Object.values(variants)) {
+ let output = template;
+ for (const [key, value] of Object.entries(variant)) {
+ if (key === 'outPath') continue;
+ const token = `{{${key}}}`;
+ if (value === '') {
+ output = output.replace(new RegExp(`^[ \\t]*\\{\\{${key}\\}\\}[ \\t]*\\n?`, 'm'), '');
+ continue;
+ }
+ output = output.replaceAll(token, value);
+ }
+
+ if (/\{\{[a-z_]+\}\}/i.test(output)) {
+ throw new Error(`Unresolved template placeholders remain in ${variant.outPath}`);
+ }
+
+ fs.writeFileSync(
+ variant.outPath,
+ `\n${output}`,
+ 'utf8'
+ );
+}
diff --git a/shared-html/index.template.html b/shared-html/index.template.html
new file mode 100644
index 0000000..9780068
--- /dev/null
+++ b/shared-html/index.template.html
@@ -0,0 +1,272 @@
+
+
+
+
+
+
+
Chattz
+
+
+
+
+
+
+
+
+
+
+
+
C
+
Chattz
+
Sign in to open your servers.
+
+ {{web_downloads}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/index.html b/static/index.html
index 6386f77..65093cb 100644
--- a/static/index.html
+++ b/static/index.html
@@ -1,3 +1,4 @@
+