:root { --cl-black: hsl(140, 1%, 6%); --cl-gray-0: hsl(140, 2%, 8%); --cl-gray-1: hsl(140, 2%, 12%); --cl-gray-2: hsl(140, 4%, 16%); --cl-gray-3: hsl(140, 4%, 24%); --cl-gray-4: hsl(140, 4%, 36%); --cl-gray-5: hsl(140, 4%, 44%); --cl-gray-6: hsl(80, 8%, 52%); --cl-gray-7: hsl(70, 8%, 58%); --cl-gray-8: hsl(60, 16%, 66%); --cl-gray-9: hsl(40, 32%, 78%); --cl-gray-10: hsl(30, 32%, 84%); --cl-white: hsl(26, 64%, 88%); --cl-red-6: hsl(4, 83%, 67%); --cl-red-7: hsl(4, 75%, 75%); --cl-orange-6: hsl(26, 84%, 62%); --cl-orange-7: hsl(26, 84%, 74%); --cl-yellow: hsl(37, 80%, 69%); --cl-green-6: hsl(120, 41%, 64%); --cl-green-7: hsl(120, 42%, 75%); --cl-cyan-6: hsl(160, 41%, 64%); --cl-cyan-7: hsl(160, 32%, 75%); --cl-blue-6: hsl(200, 55%, 64%); --cl-blue-8: hsl(201, 55%, 80%); --cl-magenta-7: hsl(320, 59%, 72%); --cl-magenta-8: hsl(320, 61%, 80%); } * { box-sizing: border-box; border-radius: 0px !important; } body { min-height: 100vh; margin: 5vh 10vw; display: flex; justify-content: center; font-family: "Iosevka", "Roboto Mono", monospace; background-color: var(--cl-black); color: var(--cl-white); } .app-container { position: relative; width: 100%; max-width: 760px; height: fit-content; background-color: var(--cl-gray-0); border: 2px solid var(--cl-gray-2); } .app-container::before { display: none; } .banner { width: 100%; height: auto; display: block; border-bottom: 2px solid var(--cl-gray-2); } .content-wrapper { position: relative; padding: 2rem; } .progress-bar { position: absolute; top: 0; left: 0; z-index: 10; width: 100%; height: 4px; background-color: var(--cl-orange-6); } .header { margin-bottom: 1.75rem; text-align: left; } .eyebrow { display: block; margin-bottom: 0.65rem; color: var(--cl-gray-6); font-size: 0.85rem; font-weight: bold; text-transform: uppercase; } .eyebrow::before, .eyebrow::after { display: none; } .header h1 { margin: 0 0 0.5rem; color: var(--cl-white); font-size: 2.2rem; font-weight: bold; margin-top: 25px } .header p { max-width: 100%; margin: 0; color: var(--cl-gray-7); font-size: 1rem; line-height: 1.6; } .status-badge { display: inline-flex; align-items: center; margin-top: 1rem; padding: 4px 12px; font-size: 0.85rem; font-weight: bold; text-transform: uppercase; border: 2px solid; } .status-online { color: var(--cl-green-6); border-color: var(--cl-green-6); background-color: transparent; } .status-offline { color: var(--cl-red-6); border-color: var(--cl-red-6); background-color: transparent; } .pulse-dot { width: 10px; height: 10px; margin-right: 0.75rem; background-color: currentColor; } .server-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; } .stat-item { display: flex; flex-direction: column; align-items: flex-start; margin-bottom: 10px; padding: 0.75rem; border: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-0); } .stat-label { margin-bottom: 0.5rem; color: var(--cl-gray-6); font-size: 0.75rem; font-weight: bold; text-transform: uppercase; } .stat-value { color: var(--cl-white); font-size: 1.25rem; font-weight: bold; } .btn-primary { display: block; width: 100%; margin-bottom: 1rem; padding: 12px; color: var(--cl-orange-6); text-align: center; text-decoration: none; text-transform: uppercase; font-size: 1rem; font-weight: bold; border: 2px solid var(--cl-orange-6); background-color: transparent; } .btn-primary::before { content: "[ "; } .btn-primary::after { content: " ]"; } .btn-primary:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } .help-text { margin: 1rem 0 2rem; color: var(--cl-gray-6); text-align: left; font-size: 0.9rem; } .help-text a { color: var(--cl-orange-6); text-decoration: none; border-bottom: 2px solid var(--cl-orange-6); } .help-text a:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } .channel-list { display: flex; flex-direction: column; gap: 1rem; } .channel { border: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-1); } .channel-header { padding: 0.75rem 1rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; color: var(--cl-white); border-bottom: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-2); } .channel-title-group { display: flex; align-items: center; margin: 0; } .channel-title-group::before { content: ">"; margin-right: 0.75rem; color: var(--cl-orange-6); font-weight: bold; } .channel-title-group h2 { margin: 0; font-size: 1rem; font-weight: bold; } .channel-icon { display: none; } .channel-meta { padding: 4px 8px; color: var(--cl-cyan-6); font-size: 0.85rem; font-weight: bold; border: 2px solid var(--cl-cyan-6); } .client-list { margin: 0; padding: 0.5rem; list-style: none; } .client { padding: 0.5rem 1rem; display: flex; align-items: center; color: var(--cl-gray-8); font-size: 0.95rem; border: 2px solid transparent; } .client::before { content: "-"; margin-right: 1rem; color: var(--cl-gray-5); } .client:hover { color: var(--cl-white); background-color: var(--cl-gray-2); border-color: var(--cl-gray-4); } .role-icon, .client-no-role-icon { display: none; } .client-afk { color: var(--cl-red-6); font-size: 0.85rem; margin-left: 0.5rem; } .client-stream { color: var(--cl-blue-6); font-size: 0.85rem; margin-left: 0.5rem; } .empty-server { padding: 2rem 1rem; color: var(--cl-gray-6); text-align: center; font-size: 1rem; border: 2px dashed var(--cl-gray-4); background-color: var(--cl-gray-1); } .footer-links { margin-top: 2.5rem; padding-top: 1.5rem; display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 1rem; border-top: 2px solid var(--cl-gray-2); } .footer-links a { color: var(--cl-orange-6); font-size: 0.9rem; font-weight: bold; text-decoration: none; border: 2px solid transparent; padding: 2px 4px; } .footer-links a:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); } .credits { margin-top: 1.5rem; color: var(--cl-gray-6); text-align: left; font-size: 0.85rem; } .credits a { color: var(--cl-orange-6); text-decoration: none; border-bottom: 2px solid var(--cl-orange-6); } .credits a:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } #ajax-container { transition: none; } /* --------------------------------------------------------------------------- Web voice --------------------------------------------------------------------------- */ body.voice-live { padding-bottom: 6.5rem; } /* Top login bar (left = status, right = [ login ]) */ .voice-topbar { border-bottom: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-1); } .voice-topbar-bar { padding: 0.65rem 1.25rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; } .voice-topbar-identity { color: var(--cl-gray-7); font-size: 0.85rem; font-weight: bold; text-transform: uppercase; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .voice-topbar-identity[data-ready="1"] { color: var(--cl-green-6); } .voice-topbar-actions { display: flex; align-items: center; gap: 0.6rem; flex-shrink: 0; } .voice-topbar-btn { padding: 4px 10px; background-color: var(--cl-gray-0); } .voice-login-btn { padding: 4px 10px; color: var(--cl-orange-6); font-family: inherit; font-size: 0.85rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-orange-6); background-color: var(--cl-gray-0); cursor: pointer; flex-shrink: 0; } .voice-login-btn::before { content: "[ "; } .voice-login-btn::after { content: " ]"; } .voice-login-btn:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } .voice-topbar-hint { margin: 0; padding: 0.5rem 1.25rem 0.75rem; color: var(--cl-gray-7); font-size: 0.85rem; border-top: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-0); } .voice-topbar-hint[data-kind="error"] { color: var(--cl-red-6); } /* Join buttons on every channel card */ .channel-actions { display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0; } .channel-join, .channel-here { padding: 4px 10px; font-family: inherit; font-size: 0.85rem; font-weight: bold; text-transform: uppercase; border: 2px solid; background-color: transparent; } .channel-join { color: var(--cl-orange-6); border-color: var(--cl-orange-6); background-color: var(--cl-gray-0); cursor: pointer; } .channel-join::before, .channel-here::before { content: "[ "; } .channel-join::after, .channel-here::after { content: " ]"; } .channel-join:hover, .channel-join:focus-visible { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; outline: none; } .voice-connecting .channel-join { opacity: 0.5; pointer-events: none; } .channel-here { color: var(--cl-green-6); border-color: var(--cl-green-6); background-color: var(--cl-gray-0); } .channel-lock { margin-left: 0.75rem; padding: 0 4px; color: var(--cl-yellow); font-size: 0.75rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-yellow); } .channel.is-current { border-color: var(--cl-green-6); } .channel.is-current .channel-header { border-bottom-color: var(--cl-green-6); } /* Live clients, per-user volume controls & direct message buttons */ .voice-live #refresh-bar { display: none; } .client.is-self .client-name { color: var(--cl-white); font-weight: bold; } .client-you { color: var(--cl-gray-6); font-size: 0.85rem; margin-left: 0.5rem; } .client.is-talking::before { content: ">"; color: var(--cl-green-6); } .client.is-talking .client-name { color: var(--cl-green-6); } .client-muted { color: var(--cl-gray-6); font-size: 0.85rem; margin-left: 0.5rem; } .client-controls { margin-left: auto; display: flex; align-items: center; gap: 0.65rem; flex-shrink: 0; } .client-volume { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--cl-gray-6); font-size: 0.75rem; font-weight: bold; } .client-volume-slider { width: 80px; margin: 0; accent-color: var(--cl-orange-6); cursor: pointer; } .client-volume-value { min-width: 3.1rem; text-align: right; color: var(--cl-gray-7); font-variant-numeric: tabular-nums; } .client-msg-btn { padding: 2px 6px; color: var(--cl-gray-6); font-family: inherit; font-size: 0.75rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-gray-3); background-color: var(--cl-gray-0); cursor: pointer; } .client-msg-btn::before { content: "[ "; } .client-msg-btn::after { content: " ]"; } .client-msg-btn:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } .client-msg-btn.is-active { color: var(--cl-cyan-6); border-color: var(--cl-cyan-6); } .client-msg-btn.has-unread { color: var(--cl-orange-6); border-color: var(--cl-orange-6); } /* Inline channel & private message chat underneath the joined channel */ .channel-chat { border-top: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-0); } .channel-chat-header { padding: 0.45rem 0.75rem; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; border-bottom: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-1); } .channel-chat-tabs { display: flex; align-items: center; flex-wrap: wrap; gap: 0.45rem; } .channel-chat-tab { padding: 2px 8px; color: var(--cl-gray-6); font-family: inherit; font-size: 0.78rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-gray-3); background-color: var(--cl-gray-0); cursor: pointer; } .channel-chat-tab::before { content: "[ "; } .channel-chat-tab::after { content: " ]"; } .channel-chat-tab:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } .channel-chat-tab.is-active { color: var(--cl-cyan-6); border-color: var(--cl-cyan-6); } .channel-chat-tab.is-dm.is-active { color: var(--cl-magenta-7); border-color: var(--cl-magenta-7); } .channel-chat-tab.has-unread { color: var(--cl-orange-6); border-color: var(--cl-orange-6); } .channel-chat-messages { max-height: 190px; overflow-y: auto; padding: 0.65rem 1rem; display: flex; flex-direction: column; gap: 0.35rem; } .channel-chat-empty { color: var(--cl-gray-5); font-size: 0.85rem; } .channel-chat-msg { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.45rem; font-size: 0.88rem; line-height: 1.4; word-break: break-word; } .channel-chat-time { color: var(--cl-gray-5); font-size: 0.75rem; flex-shrink: 0; } .channel-chat-author { color: var(--cl-orange-6); font-weight: bold; flex-shrink: 0; } .channel-chat-msg.is-self .channel-chat-author { color: var(--cl-green-6); } .channel-chat-msg.is-private .channel-chat-author { color: var(--cl-magenta-7); } .channel-chat-msg.is-server .channel-chat-author { color: var(--cl-cyan-6); } .channel-chat-text { color: var(--cl-white); } .channel-chat-form { padding: 0.55rem 0.75rem; display: flex; align-items: stretch; gap: 0.5rem; border-top: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-1); } .channel-chat-input { flex: 1 1 auto; min-width: 0; padding: 0.45rem 0.65rem; color: var(--cl-white); font-family: inherit; font-size: 0.9rem; border: 2px solid var(--cl-gray-3); background-color: var(--cl-gray-0); outline: none; } .channel-chat-input:focus { border-color: var(--cl-orange-6); } .channel-chat-send { padding: 0.45rem 0.85rem; color: var(--cl-orange-6); font-family: inherit; font-size: 0.85rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-orange-6); background-color: var(--cl-gray-0); cursor: pointer; } .channel-chat-send::before { content: "[ "; } .channel-chat-send::after { content: " ]"; } .channel-chat-send:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } /* Fixed voice controls bar at the bottom of the screen while connected */ .voice-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; border-top: 2px solid var(--cl-green-6); background-color: var(--cl-gray-0); box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.65); } .voice-bar-main { max-width: 760px; margin: 0 auto; padding: 0.75rem 1.5rem; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 1rem; } .voice-bar-info { display: flex; align-items: center; gap: 1rem; min-width: 0; } .voice-live-badge { display: inline-flex; align-items: center; padding: 4px 10px; color: var(--cl-green-6); font-size: 0.8rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-green-6); } .voice-live-badge .pulse-dot { width: 8px; height: 8px; margin-right: 0.6rem; } .voice-where { display: flex; align-items: baseline; gap: 0.6rem; min-width: 0; font-weight: bold; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .voice-where #voice-channel::before { content: "> "; color: var(--cl-orange-6); } .voice-as { color: var(--cl-gray-6); font-weight: normal; } .voice-buttons { display: flex; flex-wrap: wrap; gap: 0.6rem; } .btn-voice { padding: 6px 12px; color: var(--cl-gray-8); font-family: inherit; font-size: 0.85rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-gray-4); background-color: transparent; cursor: pointer; user-select: none; touch-action: none; } .btn-voice::before { content: "[ "; } .btn-voice::after { content: " ]"; } .btn-voice:hover { color: var(--cl-black); background-color: var(--cl-magenta-7); border-color: transparent; } .btn-voice[aria-pressed="true"] { color: var(--cl-red-6); border-color: var(--cl-red-6); } .btn-voice.btn-voice-rnnoise[aria-pressed="true"] { color: var(--cl-green-6); border-color: var(--cl-green-6); } .btn-voice[aria-expanded="true"] { color: var(--cl-orange-6); border-color: var(--cl-orange-6); } .btn-voice.is-active { color: var(--cl-black); background-color: var(--cl-green-6); border-color: var(--cl-green-6); } .btn-voice-talk { color: var(--cl-green-6); border-color: var(--cl-green-6); } .btn-voice-danger { color: var(--cl-red-6); border-color: var(--cl-red-6); } .voice-meter { position: relative; height: 4px; background-color: var(--cl-gray-2); } .voice-meter-fill { width: 0%; height: 100%; background-color: var(--cl-gray-5); } .voice-meter-fill.is-open { background-color: var(--cl-green-6); } .voice-meter-threshold { position: absolute; top: -3px; bottom: -3px; width: 2px; background-color: var(--cl-orange-6); } .voice-settings { max-width: 760px; margin: 0 auto; padding: 1rem 1.5rem; display: grid; grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr); align-items: end; gap: 1.5rem; border-bottom: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-1); } .voice-setting { display: flex; flex-direction: column; align-items: flex-start; } .voice-wasm-desc { margin: 0; color: var(--cl-gray-7); font-size: 0.85rem; line-height: 1.45; } .voice-wasm-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 0.55rem; } .voice-wasm-status[data-state="cached"] { color: var(--cl-green-6); border-color: var(--cl-green-6); } .voice-wasm-status[data-state="loading"] { color: var(--cl-orange-6); border-color: var(--cl-orange-6); } .voice-wasm-status[data-state="error"] { color: var(--cl-red-6); border-color: var(--cl-red-6); } .voice-setting input[type="range"] { width: 100%; margin: 0.35rem 0; accent-color: var(--cl-orange-6); } .voice-bar-message { max-width: 760px; margin: 0 auto; padding: 0.5rem 1.5rem; color: var(--cl-gray-7); font-size: 0.85rem; border-bottom: 2px solid var(--cl-gray-2); } .voice-bar-message[data-kind="error"] { color: var(--cl-red-6); } /* Notice shown above the channel list after a call ends */ .voice-notice { margin: 0 0 1.5rem; padding: 0.75rem 1rem; color: var(--cl-gray-8); font-size: 0.9rem; border: 2px solid var(--cl-gray-4); background-color: var(--cl-gray-1); } .voice-notice::before { content: "! "; color: var(--cl-orange-6); font-weight: bold; } .voice-notice[data-kind="error"] { color: var(--cl-red-6); border-color: var(--cl-red-6); } /* Login modal ([ login ] button dialog) */ .voice-dialog { width: min(460px, calc(100vw - 2rem)); padding: 0; color: var(--cl-white); font-family: inherit; border: 2px solid var(--cl-orange-6); background-color: var(--cl-gray-0); } .voice-dialog::backdrop { background-color: hsla(140, 1%, 6%, 0.82); } .voice-dialog-header { padding: 0.85rem 1.25rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; border-bottom: 2px solid var(--cl-gray-2); background-color: var(--cl-gray-2); } .voice-dialog-header h2 { margin: 0; font-size: 0.95rem; text-transform: uppercase; } .voice-dialog-header h2::before { content: "> "; color: var(--cl-orange-6); } .voice-dialog-target { padding: 3px 8px; color: var(--cl-cyan-6); font-size: 0.8rem; font-weight: bold; text-transform: uppercase; border: 2px solid var(--cl-cyan-6); max-width: 55%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .voice-dialog-body { padding: 1.25rem; display: flex; flex-direction: column; gap: 1rem; } .voice-field { display: flex; flex-direction: column; gap: 0.4rem; } .voice-field-tag { color: var(--cl-orange-6); font-size: 0.85rem; font-weight: bold; text-transform: uppercase; } .voice-field input { width: 100%; padding: 0.65rem 0.8rem; color: var(--cl-white); font-family: inherit; font-size: 0.95rem; border: 2px solid var(--cl-gray-3); background-color: var(--cl-gray-1); outline: none; } .voice-field input:focus { border-color: var(--cl-orange-6); } .voice-dialog-message { margin: 0; color: var(--cl-gray-7); font-size: 0.85rem; } .voice-dialog-message[data-kind="error"] { color: var(--cl-red-6); } .voice-dialog-actions { padding: 0.85rem 1.25rem 1.25rem; display: flex; justify-content: flex-end; align-items: stretch; gap: 0.75rem; } .voice-dialog-actions .voice-submit { width: auto; min-width: 8rem; margin: 0; font-family: inherit; cursor: pointer; } .voice-dialog-actions .voice-submit:disabled { color: var(--cl-gray-5); border-color: var(--cl-gray-4); background-color: transparent; cursor: wait; } [hidden] { display: none !important; } @media (max-width: 640px) { body { margin: 2vh 4vw; } .content-wrapper { padding: 1.25rem; } .server-stats { grid-template-columns: 1fr; } .channel-header { align-items: flex-start; flex-direction: column; gap: 0.75rem; } .channel-actions { width: 100%; justify-content: space-between; } .client { flex-wrap: wrap; gap: 0.4rem; } .voice-settings { grid-template-columns: 1fr; gap: 1rem; } .voice-bar-main, .voice-settings, .voice-bar-message { padding-left: 1rem; padding-right: 1rem; } .voice-buttons { width: 100%; } }